00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <qcstring.h>
00022 #include <qregexp.h>
00023 #include <qtextcodec.h>
00024 #include <qvaluelist.h>
00025
00026 #include <kmdcodec.h>
00027 #include <kdebug.h>
00028
00029 #include "vcardparser.h"
00030
00031 #define FOLD_WIDTH 75
00032
00033 using namespace KABC;
00034
00035 typedef QValueList<QCString> QCStringList;
00036
00037 QValueList<QCString> splitCString( const QCString &str, char sep )
00038 {
00039 QValueList<QCString> list;
00040 int start = 0;
00041 int end;
00042 while ((end = str.find(sep, start)) != -1) {
00043 list.append(str.mid(start, end - start));
00044 start = end + 1;
00045 }
00046 list.append(str.mid(start));
00047
00048 return list;
00049 }
00050
00051 QValueList<QCString> splitCString( const QCString &str, const QRegExp &exp )
00052 {
00053 QValueList<QCString> list;
00054 int start = 0;
00055 int end;
00056 while ((end = str.find(exp, start)) != -1) {
00057 list.append(str.mid(start, end - start));
00058 start = end + 1;
00059 }
00060 list.append(str.mid(start));
00061
00062 return list;
00063 }
00064
00065 bool cStringStartsWith( const QCString &str, const QCString &pattern )
00066 {
00067 const int length = pattern.length();
00068 if ( length == 0 )
00069 return true;
00070
00071 const QCString part = str.left( length );
00072 return (pattern == part);
00073 }
00074
00075 static void addEscapes( QCString &str )
00076 {
00077 str.replace( '\\', "\\\\" );
00078 str.replace( ',', "\\," );
00079 str.replace( '\r', "\\r" );
00080 str.replace( '\n', "\\n" );
00081 }
00082
00083 static void removeEscapes( QCString &str )
00084 {
00085 str.replace( "\\r", "\r" );
00086 str.replace( "\\n", "\n" );
00087 str.replace( "\\,", "," );
00088 str.replace( "\\\\", "\\" );
00089 }
00090
00091 VCardParser::VCardParser()
00092 {
00093 }
00094
00095 VCardParser::~VCardParser()
00096 {
00097 }
00098
00099 VCard::List VCardParser::parseVCards( const QString& text )
00100 {
00101 return parseVCardsRaw( text.utf8() );
00102 }
00103
00104 VCard::List VCardParser::parseVCardsRaw( const QCString& text )
00105 {
00106
00107 static QRegExp sep( "[\x0d\x0a]" );
00108
00109 VCard currentVCard;
00110 VCard::List vCardList;
00111 QCString currentLine;
00112
00113 const QCStringList lines = splitCString( text, sep );
00114 QCStringList::ConstIterator it;
00115
00116 bool inVCard = false;
00117 QCStringList::ConstIterator linesEnd( lines.end() );
00118 for ( it = lines.begin(); it != linesEnd; ++it ) {
00119
00120 if ( (*it).isEmpty() )
00121 continue;
00122
00123 if ( (*it)[ 0 ] == ' ' || (*it)[ 0 ] == '\t' ) {
00124 currentLine.append( (*it).mid( 1 ) );
00125 continue;
00126 } else {
00127 if ( inVCard && !currentLine.isEmpty() ) {
00128 int colon = currentLine.find( ':' );
00129 if ( colon == -1 ) {
00130 currentLine = (*it);
00131 continue;
00132 }
00133
00134 VCardLine vCardLine;
00135 const QCString key = currentLine.left( colon ).stripWhiteSpace();
00136 QCString value = currentLine.mid( colon + 1 );
00137
00138 QCStringList params = splitCString( key, ';' );
00139
00140
00141 if ( params[0].find( '.' ) != -1 ) {
00142 const QCStringList groupList = splitCString( params[0], '.' );
00143 vCardLine.setGroup( QString::fromLatin1( groupList[0] ) );
00144 vCardLine.setIdentifier( QString::fromLatin1( groupList[1] ) );
00145 } else
00146 vCardLine.setIdentifier( QString::fromLatin1( params[0] ) );
00147
00148 if ( params.count() > 1 ) {
00149 QCStringList::ConstIterator paramIt = params.begin();
00150 for ( ++paramIt; paramIt != params.end(); ++paramIt ) {
00151 QCStringList pair = splitCString( *paramIt, '=' );
00152 if ( pair.size() == 1 ) {
00153
00154 if ( pair[0].lower() == "quoted-printable" ) {
00155 pair[0] = "encoding";
00156 pair[1] = "quoted-printable";
00157 } else if ( pair[0].lower() == "base64" ) {
00158 pair[0] = "encoding";
00159 pair[1] = "base64";
00160 } else {
00161 pair.prepend( "type" );
00162 }
00163 }
00164
00165 if ( pair[1].find( ',' ) != -1 ) {
00166 const QCStringList args = splitCString( pair[ 1 ], ',' );
00167 QCStringList::ConstIterator argIt;
00168 for ( argIt = args.begin(); argIt != args.end(); ++argIt )
00169 vCardLine.addParameter( QString::fromLatin1( pair[0].lower() ), QString::fromLatin1( *argIt ) );
00170 } else
00171 vCardLine.addParameter( QString::fromLatin1( pair[0].lower() ), QString::fromLatin1( pair[1] ) );
00172 }
00173 }
00174
00175 removeEscapes( value );
00176
00177 QByteArray output;
00178 bool wasBase64Encoded = false;
00179
00180 if ( vCardLine.parameterList().findIndex( "encoding" ) != -1 ) {
00181 QByteArray input = value;
00182 if ( vCardLine.parameter( "encoding" ).lower() == "b" ||
00183 vCardLine.parameter( "encoding" ).lower() == "base64" ) {
00184 KCodecs::base64Decode( input, output );
00185 wasBase64Encoded = true;
00186 }
00187 else if ( vCardLine.parameter( "encoding" ).lower() == "quoted-printable" ) {
00188
00189 while ( value.at( value.length() - 1 ) == '=' && it != linesEnd ) {
00190 value = value.remove( value.length() - 1, 1 ) + (*it);
00191 ++it;
00192 }
00193 input = value;
00194 KCodecs::quotedPrintableDecode( input, output );
00195 }
00196 } else {
00197 output = value;
00198 }
00199
00200 if ( vCardLine.parameterList().findIndex( "charset" ) != -1 ) {
00201 QTextCodec *codec =
00202 QTextCodec::codecForName( vCardLine.parameter( "charset" ).latin1() );
00203 if ( codec ) {
00204 vCardLine.setValue( codec->toUnicode( output ) );
00205 } else {
00206 #if defined(KABC_VCARD_ENCODING_FIX)
00207 vCardLine.setValue( QString::fromUtf8( output ) );
00208 #else
00209 vCardLine.setValue( QString::fromLatin1( output ) );
00210 #endif
00211 }
00212 } else if ( wasBase64Encoded ) {
00213 vCardLine.setValue( output );
00214 } else {
00215 #if defined(KABC_VCARD_ENCODING_FIX)
00216 vCardLine.setValue( QString::fromUtf8( output ) );
00217 #else
00218 vCardLine.setValue( QString::fromLatin1( output ) );
00219 #endif
00220 }
00221
00222 currentVCard.addLine( vCardLine );
00223 }
00224
00225
00226 if ( cStringStartsWith( (*it).lower(), QCString( "begin:vcard" ) ) ) {
00227 inVCard = true;
00228 currentLine = QCString();
00229 currentVCard.clear();
00230 continue;
00231 }
00232
00233 if ( cStringStartsWith( (*it).lower(), QCString( "end:vcard" ) ) ) {
00234 inVCard = false;
00235 vCardList.append( currentVCard );
00236 currentLine = QCString();
00237 currentVCard.clear();
00238 continue;
00239 }
00240
00241 currentLine = (*it);
00242 }
00243 }
00244
00245 return vCardList;
00246 }
00247
00248 QString VCardParser::createVCards( const VCard::List& list )
00249 {
00250 return QString::fromUtf8( createVCardsRaw( list ) );
00251 }
00252
00253 QCString VCardParser::createVCardsRaw( const VCard::List& list )
00254 {
00255 QCString text;
00256 QCString textLine;
00257 QString encodingType;
00258 QStringList idents;
00259 QStringList params;
00260 QStringList values;
00261 QStringList::ConstIterator identIt;
00262 QStringList::Iterator paramIt;
00263 QStringList::ConstIterator valueIt;
00264
00265 VCardLine::List lines;
00266 VCardLine::List::ConstIterator lineIt;
00267 VCard::List::ConstIterator cardIt;
00268
00269 bool hasEncoding;
00270
00271
00272
00273
00274 VCard::List::ConstIterator listEnd( list.end() );
00275 for ( cardIt = list.begin(); cardIt != listEnd; ++cardIt ) {
00276 text.append( "BEGIN:VCARD\r\n" );
00277
00278 idents = (*cardIt).identifiers();
00279 for ( identIt = idents.constBegin(); identIt != idents.constEnd(); ++identIt ) {
00280 lines = (*cardIt).lines( (*identIt) );
00281
00282
00283 for ( lineIt = lines.constBegin(); lineIt != lines.constEnd(); ++lineIt ) {
00284 if ( !(*lineIt).value().asString().isEmpty() ) {
00285 if ( (*lineIt).hasGroup() )
00286 textLine = (*lineIt).group().latin1() + QCString( "." ) + (*lineIt).identifier().latin1();
00287 else
00288 textLine = (*lineIt).identifier().latin1();
00289
00290 params = (*lineIt).parameterList();
00291 hasEncoding = false;
00292 if ( params.count() > 0 ) {
00293 for ( paramIt = params.begin(); paramIt != params.end(); ++paramIt ) {
00294 if ( (*paramIt) == "encoding" ) {
00295 hasEncoding = true;
00296 encodingType = (*lineIt).parameter( "encoding" ).lower();
00297 }
00298
00299 values = (*lineIt).parameters( *paramIt );
00300 for ( valueIt = values.constBegin(); valueIt != values.constEnd(); ++valueIt ) {
00301 textLine.append( QCString( ";" ) + (*paramIt).upper().latin1() );
00302 if ( !(*valueIt).isEmpty() )
00303 textLine.append( QCString( "=" ) + (*valueIt).latin1() );
00304 }
00305 }
00306 }
00307
00308 if ( hasEncoding ) {
00309 QByteArray input, output;
00310 if ( encodingType == "b" ) {
00311 input = (*lineIt).value().toByteArray();
00312 KCodecs::base64Encode( input, output );
00313 } else if ( encodingType == "quoted-printable" ) {
00314 input = (*lineIt).value().toString().utf8();
00315 input.resize( input.size() - 1 );
00316 KCodecs::quotedPrintableEncode( input, output, false );
00317 }
00318
00319 QCString value( output );
00320 addEscapes( value );
00321 textLine.append( ":" + value );
00322 } else {
00323 QCString value( (*lineIt).value().toString().utf8() );
00324 addEscapes( value );
00325 textLine.append( ":" + value );
00326 }
00327
00328 if ( textLine.length() > FOLD_WIDTH ) {
00329 for ( uint i = 0; i <= ( textLine.length() / FOLD_WIDTH ); ++i )
00330 text.append( ( i == 0 ? "" : " " ) + textLine.mid( i * FOLD_WIDTH, FOLD_WIDTH ) + "\r\n" );
00331 } else
00332 text.append( textLine + "\r\n" );
00333 }
00334 }
00335 }
00336
00337 text.append( "END:VCARD\r\n" );
00338 text.append( "\r\n" );
00339 }
00340
00341 return text;
00342 }