kabc
vcardparser.cpp
00001 /* 00002 This file is part of libkabc. 00003 Copyright (c) 2003 Tobias Koenig <tokoe@kde.org> 00004 00005 This library is free software; you can redistribute it and/or 00006 modify it under the terms of the GNU Library General Public 00007 License as published by the Free Software Foundation; either 00008 version 2 of the License, or (at your option) any later version. 00009 00010 This library is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 Library General Public License for more details. 00014 00015 You should have received a copy of the GNU Library General Public License 00016 along with this library; see the file COPYING.LIB. If not, write to 00017 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00018 Boston, MA 02110-1301, USA. 00019 */ 00020 00021 #include "vcardparser.h" 00022 #include <kcodecs.h> 00023 #include <kdebug.h> 00024 #include <QtCore/QTextCodec> 00025 00026 #define FOLD_WIDTH 75 00027 00028 using namespace KABC; 00029 00030 static void addEscapes( QByteArray &str ) 00031 { 00032 str.replace( '\\', (char *)"\\\\" ); 00033 str.replace( ',', (char *)"\\," ); 00034 str.replace( '\r', (char *)"\\r" ); 00035 str.replace( '\n', (char *)"\\n" ); 00036 } 00037 00038 static void removeEscapes( QByteArray &str ) 00039 { 00040 str.replace( (char *)"\\n", "\n" ); 00041 str.replace( (char *)"\\N", "\n" ); 00042 str.replace( (char *)"\\r", "\r" ); 00043 str.replace( (char *)"\\,", "," ); 00044 str.replace( (char *)"\\\\", "\\" ); 00045 } 00046 00047 VCardParser::VCardParser() 00048 { 00049 } 00050 00051 VCardParser::~VCardParser() 00052 { 00053 } 00054 00055 VCard::List VCardParser::parseVCards( const QByteArray &text ) 00056 { 00057 VCard currentVCard; 00058 VCard::List vCardList; 00059 QByteArray currentLine; 00060 00061 QList<QByteArray> lines = text.split( '\n' ); 00062 00063 bool inVCard = false; 00064 QList<QByteArray>::Iterator it( lines.begin() ); 00065 QList<QByteArray>::Iterator linesEnd( lines.end() ); 00066 for ( ; it != linesEnd; ++it ) { 00067 // remove the trailing \r, left from \r\n 00068 if ( (*it).endsWith( '\r' ) ) { 00069 (*it).chop( 1 ); 00070 } 00071 00072 if ( (*it).startsWith( ' ' ) || (*it).startsWith( '\t' ) ) { //folded line => append to previous 00073 currentLine.append( (*it).mid( 1 ) ); 00074 continue; 00075 } else { 00076 if ( (*it).trimmed().isEmpty() ) { // empty line 00077 continue; 00078 } 00079 if ( inVCard && !currentLine.isEmpty() ) { // now parse the line 00080 int colon = currentLine.indexOf( ':' ); 00081 if ( colon == -1 ) { // invalid line 00082 currentLine = (*it); 00083 continue; 00084 } 00085 00086 VCardLine vCardLine; 00087 const QByteArray key = currentLine.left( colon ).trimmed(); 00088 QByteArray value = currentLine.mid( colon + 1 ); 00089 00090 QList<QByteArray> params = key.split( ';' ); 00091 00092 // check for group 00093 int groupPos = params[ 0 ].indexOf( '.' ); 00094 if ( groupPos != -1 ) { 00095 vCardLine.setGroup( QString::fromLatin1( params[ 0 ].left( groupPos ) ) ); 00096 vCardLine.setIdentifier( QString::fromLatin1( params[ 0 ].mid( groupPos + 1 ) ) ); 00097 } else { 00098 vCardLine.setIdentifier( QString::fromLatin1( params[ 0 ] ) ); 00099 } 00100 00101 if ( params.count() > 1 ) { // find all parameters 00102 QList<QByteArray>::ConstIterator paramIt( params.constBegin() ); 00103 for ( ++paramIt; paramIt != params.constEnd(); ++paramIt ) { 00104 QList<QByteArray> pair = (*paramIt).split( '=' ); 00105 if ( pair.count() == 1 ) { 00106 // correct the fucking 2.1 'standard' 00107 if ( pair[ 0 ].toLower() == "quoted-printable" ) { 00108 pair[ 0 ] = "encoding"; 00109 pair.append( "quoted-printable" ); 00110 } else if ( pair[ 0 ].toLower() == "base64" ) { 00111 pair[ 0 ] = "encoding"; 00112 pair.append( "base64" ); 00113 } else { 00114 pair.prepend( "type" ); 00115 } 00116 } 00117 if ( pair[ 1 ].indexOf( ',' ) != -1 ) { // parameter in type=x,y,z format 00118 const QList<QByteArray> args = pair[ 1 ].split( ',' ); 00119 QList<QByteArray>::ConstIterator argIt; 00120 for ( argIt = args.constBegin(); argIt != args.constEnd(); ++argIt ) { 00121 vCardLine.addParameter( QString::fromLatin1( pair[ 0 ].toLower() ), 00122 QString::fromLatin1( *argIt ) ); 00123 } 00124 } else { 00125 vCardLine.addParameter( QString::fromLatin1( pair[ 0 ].toLower() ), 00126 QString::fromLatin1( pair[ 1 ] ) ); 00127 } 00128 } 00129 } 00130 00131 removeEscapes( value ); 00132 00133 QByteArray output; 00134 bool wasBase64Encoded = false; 00135 00136 if ( vCardLine.parameterList().contains( QLatin1String( "encoding" ) ) ) { 00137 const QString encoding = vCardLine.parameter( QLatin1String( "encoding" ) ).toLower(); 00138 00139 // have to decode the data 00140 if ( encoding == QLatin1String( "b" ) || encoding == QLatin1String( "base64" ) ) { 00141 output = QByteArray::fromBase64( value ); 00142 wasBase64Encoded = true; 00143 } 00144 else if ( encoding == QLatin1String( "quoted-printable" ) ) { 00145 // join any qp-folded lines 00146 while ( value.endsWith( '=' ) && it != linesEnd ) { 00147 value.chop( 1 ); // remove the '=' 00148 value.append( *it ); 00149 ++it; 00150 } 00151 KCodecs::quotedPrintableDecode( value, output ); 00152 } else if ( encoding == QLatin1String( "8bit" ) ) { 00153 output = value; 00154 } else { 00155 qDebug( "Unknown vcard encoding type!" ); 00156 } 00157 } else { 00158 output = value; 00159 } 00160 00161 if ( vCardLine.parameterList().contains( QLatin1String( "charset" ) ) ) { 00162 // have to convert the data 00163 QTextCodec *codec = QTextCodec::codecForName( 00164 vCardLine.parameter( QLatin1String( "charset" ) ).toLatin1() ); 00165 if ( codec ) { 00166 vCardLine.setValue( codec->toUnicode( output ) ); 00167 } else { 00168 vCardLine.setValue( QString::fromUtf8( output ) ); 00169 } 00170 } else if ( wasBase64Encoded ) { 00171 vCardLine.setValue( output ); 00172 } else { 00173 vCardLine.setValue( QString::fromUtf8( output ) ); 00174 } 00175 00176 currentVCard.addLine( vCardLine ); 00177 } 00178 00179 // we do not save the start and end tag as vcardline 00180 if ( (*it).toLower().startsWith( "begin:vcard" ) ) { //krazy:exclude=strings 00181 inVCard = true; 00182 currentLine.clear(); 00183 currentVCard.clear(); // flush vcard 00184 continue; 00185 } 00186 00187 if ( (*it).toLower().startsWith( "end:vcard" ) ) { //krazy:exclude=strings 00188 inVCard = false; 00189 vCardList.append( currentVCard ); 00190 currentLine.clear(); 00191 currentVCard.clear(); // flush vcard 00192 continue; 00193 } 00194 00195 currentLine = (*it); 00196 } 00197 } 00198 00199 return vCardList; 00200 } 00201 00202 QByteArray VCardParser::createVCards( const VCard::List &list ) 00203 { 00204 QByteArray text; 00205 QByteArray textLine; 00206 QString encodingType; 00207 QStringList idents; 00208 QStringList params; 00209 QStringList values; 00210 QStringList::ConstIterator identIt; 00211 QStringList::Iterator paramIt; 00212 QStringList::ConstIterator valueIt; 00213 00214 VCardLine::List lines; 00215 VCardLine::List::ConstIterator lineIt; 00216 VCard::List::ConstIterator cardIt; 00217 00218 bool hasEncoding; 00219 00220 text.reserve( list.size() * 300 ); // reserve memory to be more efficient 00221 00222 // iterate over the cards 00223 VCard::List::ConstIterator listEnd( list.end() ); 00224 for ( cardIt = list.begin(); cardIt != listEnd; ++cardIt ) { 00225 text.append( "BEGIN:VCARD\r\n" ); 00226 00227 idents = (*cardIt).identifiers(); 00228 for ( identIt = idents.constBegin(); identIt != idents.constEnd(); ++identIt ) { 00229 lines = (*cardIt).lines( (*identIt) ); 00230 00231 // iterate over the lines 00232 for ( lineIt = lines.constBegin(); lineIt != lines.constEnd(); ++lineIt ) { 00233 QVariant val = (*lineIt).value(); 00234 if ( val.isValid() ) { 00235 if ( (*lineIt).hasGroup() ) { 00236 textLine = (*lineIt).group().toLatin1() + '.' + (*lineIt).identifier().toLatin1(); 00237 } else { 00238 textLine = (*lineIt).identifier().toLatin1(); 00239 } 00240 00241 params = (*lineIt).parameterList(); 00242 hasEncoding = false; 00243 if ( params.count() > 0 ) { // we have parameters 00244 for ( paramIt = params.begin(); paramIt != params.end(); ++paramIt ) { 00245 if ( (*paramIt) == QLatin1String( "encoding" ) ) { 00246 hasEncoding = true; 00247 encodingType = (*lineIt).parameter( QLatin1String( "encoding" ) ).toLower(); 00248 } 00249 00250 values = (*lineIt).parameters( *paramIt ); 00251 for ( valueIt = values.constBegin(); valueIt != values.constEnd(); ++valueIt ) { 00252 textLine.append( ';' + (*paramIt).toLatin1().toUpper() ); 00253 if ( !(*valueIt).isEmpty() ) { 00254 textLine.append( '=' + (*valueIt).toLatin1() ); 00255 } 00256 } 00257 } 00258 } 00259 00260 QByteArray input, output; 00261 00262 // handle charset 00263 if ( (*lineIt).parameterList().contains( QLatin1String( "charset" ) ) ) { 00264 // have to convert the data 00265 const QString value = (*lineIt).value().toString(); 00266 QTextCodec *codec = QTextCodec::codecForName( 00267 (*lineIt).parameter( QLatin1String( "charset" ) ).toLatin1() ); 00268 if ( codec ) { 00269 input = codec->fromUnicode( value ); 00270 } else { 00271 input = value.toUtf8(); 00272 } 00273 } else if ( (*lineIt).value().type() == QVariant::ByteArray ) { 00274 input = (*lineIt).value().toByteArray(); 00275 } else { 00276 input = (*lineIt).value().toString().toUtf8(); 00277 } 00278 00279 // handle encoding 00280 if ( hasEncoding ) { // have to encode the data 00281 if ( encodingType == QLatin1String( "b" ) ) { 00282 output = input.toBase64(); 00283 } else if ( encodingType == QLatin1String( "quoted-printable" ) ) { 00284 KCodecs::quotedPrintableEncode( input, output, false ); 00285 } 00286 } else { 00287 output = input; 00288 } 00289 00290 addEscapes( output ); 00291 00292 if ( !output.isEmpty() ) { 00293 textLine.append( ':' + output ); 00294 00295 if ( textLine.length() > FOLD_WIDTH ) { // we have to fold the line 00296 for ( int i = 0; i <= ( textLine.length() / FOLD_WIDTH ); ++i ) { 00297 text.append( 00298 ( i == 0 ? "" : " " ) + textLine.mid( i * FOLD_WIDTH, FOLD_WIDTH ) + "\r\n" ); 00299 } 00300 } else { 00301 text.append( textLine + "\r\n" ); 00302 } 00303 } 00304 } 00305 } 00306 } 00307 00308 text.append( "END:VCARD\r\n" ); 00309 text.append( "\r\n" ); 00310 } 00311 00312 return text; 00313 }
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Mon May 14 2012 05:09:42 by doxygen 1.7.5 written by Dimitri van Heesch, © 1997-2006
Documentation copyright © 1996-2012 The KDE developers.
Generated on Mon May 14 2012 05:09:42 by doxygen 1.7.5 written by Dimitri van Heesch, © 1997-2006
KDE's Doxygen guidelines are available online.