kabc
vcardparser.cpp
00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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 *)"\\r", "\r" );
00042 str.replace( (char *)"\\,", "," );
00043 str.replace( (char *)"\\\\", "\\" );
00044 }
00045
00046 VCardParser::VCardParser()
00047 {
00048 }
00049
00050 VCardParser::~VCardParser()
00051 {
00052 }
00053
00054 VCard::List VCardParser::parseVCards( const QByteArray &text )
00055 {
00056 VCard currentVCard;
00057 VCard::List vCardList;
00058 QByteArray currentLine;
00059
00060 QList<QByteArray> lines = text.split( '\n' );
00061
00062 bool inVCard = false;
00063 QList<QByteArray>::Iterator it( lines.begin() );
00064 QList<QByteArray>::Iterator linesEnd( lines.end() );
00065 for ( ; it != linesEnd; ++it ) {
00066
00067 if ( (*it).endsWith( '\r' ) ) {
00068 (*it).chop( 1 );
00069 }
00070
00071 if ( (*it).startsWith( ' ' ) || (*it).startsWith( '\t' ) ) {
00072 currentLine.append( (*it).mid( 1 ) );
00073 continue;
00074 } else {
00075 if ( (*it).trimmed().isEmpty() ) {
00076 continue;
00077 }
00078 if ( inVCard && !currentLine.isEmpty() ) {
00079 int colon = currentLine.indexOf( ':' );
00080 if ( colon == -1 ) {
00081 currentLine = (*it);
00082 continue;
00083 }
00084
00085 VCardLine vCardLine;
00086 const QByteArray key = currentLine.left( colon ).trimmed();
00087 QByteArray value = currentLine.mid( colon + 1 );
00088
00089 QList<QByteArray> params = key.split( ';' );
00090
00091
00092 int groupPos = params[ 0 ].indexOf( '.' );
00093 if ( groupPos != -1 ) {
00094 vCardLine.setGroup( QString::fromLatin1( params[ 0 ].left( groupPos ) ) );
00095 vCardLine.setIdentifier( QString::fromLatin1( params[ 0 ].mid( groupPos + 1 ) ) );
00096 } else {
00097 vCardLine.setIdentifier( QString::fromLatin1( params[ 0 ] ) );
00098 }
00099
00100 if ( params.count() > 1 ) {
00101 QList<QByteArray>::ConstIterator paramIt( params.constBegin() );
00102 for ( ++paramIt; paramIt != params.constEnd(); ++paramIt ) {
00103 QList<QByteArray> pair = (*paramIt).split( '=' );
00104 if ( pair.count() == 1 ) {
00105
00106 if ( pair[ 0 ].toLower() == "quoted-printable" ) {
00107 pair[ 0 ] = "encoding";
00108 pair.append( "quoted-printable" );
00109 } else if ( pair[ 0 ].toLower() == "base64" ) {
00110 pair[ 0 ] = "encoding";
00111 pair.append( "base64" );
00112 } else {
00113 pair.prepend( "type" );
00114 }
00115 }
00116 if ( pair[ 1 ].indexOf( ',' ) != -1 ) {
00117 const QList<QByteArray> args = pair[ 1 ].split( ',' );
00118 QList<QByteArray>::ConstIterator argIt;
00119 for ( argIt = args.constBegin(); argIt != args.constEnd(); ++argIt ) {
00120 vCardLine.addParameter( QString::fromLatin1( pair[ 0 ].toLower() ),
00121 QString::fromLatin1( *argIt ) );
00122 }
00123 } else {
00124 vCardLine.addParameter( QString::fromLatin1( pair[ 0 ].toLower() ),
00125 QString::fromLatin1( pair[ 1 ] ) );
00126 }
00127 }
00128 }
00129
00130 removeEscapes( value );
00131
00132 QByteArray output;
00133 bool wasBase64Encoded = false;
00134
00135 if ( vCardLine.parameterList().contains( QLatin1String( "encoding" ) ) ) {
00136
00137 if ( vCardLine.parameter( QLatin1String( "encoding" ) ).toLower() ==
00138 QLatin1String( "b" ) ||
00139 vCardLine.parameter( QLatin1String( "encoding" ) ).toLower() ==
00140 QLatin1String( "base64" ) ) {
00141 output = QByteArray::fromBase64( value );
00142 wasBase64Encoded = true;
00143 }
00144 else if ( vCardLine.parameter( QLatin1String( "encoding" ) ).toLower() ==
00145 QLatin1String( "quoted-printable" ) ) {
00146
00147 while ( value.endsWith( '=' ) && it != linesEnd ) {
00148 value.chop( 1 );
00149 value.append( *it );
00150 ++it;
00151 }
00152 KCodecs::quotedPrintableDecode( value, output );
00153 } else {
00154 qDebug( "Unknown vcard encoding type!" );
00155 }
00156 } else {
00157 output = value;
00158 }
00159
00160 if ( vCardLine.parameterList().contains( QLatin1String( "charset" ) ) ) {
00161
00162 QTextCodec *codec = QTextCodec::codecForName(
00163 vCardLine.parameter( QLatin1String( "charset" ) ).toLatin1() );
00164 if ( codec ) {
00165 vCardLine.setValue( codec->toUnicode( output ) );
00166 } else {
00167 vCardLine.setValue( QString::fromUtf8( output ) );
00168 }
00169 } else if ( wasBase64Encoded ) {
00170 vCardLine.setValue( output );
00171 } else {
00172 vCardLine.setValue( QString::fromUtf8( output ) );
00173 }
00174
00175 currentVCard.addLine( vCardLine );
00176 }
00177
00178
00179 if ( (*it).toLower().startsWith( "begin:vcard" ) ) {
00180 inVCard = true;
00181 currentLine.clear();
00182 currentVCard.clear();
00183 continue;
00184 }
00185
00186 if ( (*it).toLower().startsWith( "end:vcard" ) ) {
00187 inVCard = false;
00188 vCardList.append( currentVCard );
00189 currentLine.clear();
00190 currentVCard.clear();
00191 continue;
00192 }
00193
00194 currentLine = (*it);
00195 }
00196 }
00197
00198 return vCardList;
00199 }
00200
00201 QByteArray VCardParser::createVCards( const VCard::List &list )
00202 {
00203 QByteArray text;
00204 QByteArray textLine;
00205 QString encodingType;
00206 QStringList idents;
00207 QStringList params;
00208 QStringList values;
00209 QStringList::ConstIterator identIt;
00210 QStringList::Iterator paramIt;
00211 QStringList::ConstIterator valueIt;
00212
00213 VCardLine::List lines;
00214 VCardLine::List::ConstIterator lineIt;
00215 VCard::List::ConstIterator cardIt;
00216
00217 bool hasEncoding;
00218
00219 text.reserve( list.size() * 300 );
00220
00221
00222 VCard::List::ConstIterator listEnd( list.end() );
00223 for ( cardIt = list.begin(); cardIt != listEnd; ++cardIt ) {
00224 text.append( "BEGIN:VCARD\r\n" );
00225
00226 idents = (*cardIt).identifiers();
00227 for ( identIt = idents.constBegin(); identIt != idents.constEnd(); ++identIt ) {
00228 lines = (*cardIt).lines( (*identIt) );
00229
00230
00231 for ( lineIt = lines.constBegin(); lineIt != lines.constEnd(); ++lineIt ) {
00232 QVariant val = (*lineIt).value();
00233 if ( val.isValid() ) {
00234 if ( (*lineIt).hasGroup() ) {
00235 textLine = (*lineIt).group().toLatin1() + '.' + (*lineIt).identifier().toLatin1();
00236 } else {
00237 textLine = (*lineIt).identifier().toLatin1();
00238 }
00239
00240 params = (*lineIt).parameterList();
00241 hasEncoding = false;
00242 if ( params.count() > 0 ) {
00243 for ( paramIt = params.begin(); paramIt != params.end(); ++paramIt ) {
00244 if ( (*paramIt) == QLatin1String( "encoding" ) ) {
00245 hasEncoding = true;
00246 encodingType = (*lineIt).parameter( QLatin1String( "encoding" ) ).toLower();
00247 }
00248
00249 values = (*lineIt).parameters( *paramIt );
00250 for ( valueIt = values.constBegin(); valueIt != values.constEnd(); ++valueIt ) {
00251 textLine.append( ';' + (*paramIt).toLatin1().toUpper() );
00252 if ( !(*valueIt).isEmpty() ) {
00253 textLine.append( '=' + (*valueIt).toLatin1() );
00254 }
00255 }
00256 }
00257 }
00258
00259 QByteArray input, output;
00260
00261
00262 if ( (*lineIt).parameterList().contains( QLatin1String( "charset" ) ) ) {
00263
00264 const QString value = (*lineIt).value().toString();
00265 QTextCodec *codec = QTextCodec::codecForName(
00266 (*lineIt).parameter( QLatin1String( "charset" ) ).toLatin1() );
00267 if ( codec ) {
00268 input = codec->fromUnicode( value );
00269 } else {
00270 input = value.toUtf8();
00271 }
00272 } else if ( (*lineIt).value().type() == QVariant::ByteArray ) {
00273 input = (*lineIt).value().toByteArray();
00274 } else {
00275 input = (*lineIt).value().toString().toUtf8();
00276 }
00277
00278
00279 if ( hasEncoding ) {
00280 if ( encodingType == QLatin1String( "b" ) ) {
00281 output = input.toBase64();
00282 } else if ( encodingType == QLatin1String( "quoted-printable" ) ) {
00283 KCodecs::quotedPrintableEncode( input, output, false );
00284 }
00285 } else {
00286 output = input;
00287 }
00288
00289 addEscapes( output );
00290
00291 if ( !output.isEmpty() ) {
00292 textLine.append( ':' + output );
00293
00294 if ( textLine.length() > FOLD_WIDTH ) {
00295 for ( int i = 0; i <= ( textLine.length() / FOLD_WIDTH ); ++i ) {
00296 text.append(
00297 ( i == 0 ? "" : " " ) + textLine.mid( i * FOLD_WIDTH, FOLD_WIDTH ) + "\r\n" );
00298 }
00299 } else {
00300 text.append( textLine + "\r\n" );
00301 }
00302 }
00303 }
00304 }
00305 }
00306
00307 text.append( "END:VCARD\r\n" );
00308 text.append( "\r\n" );
00309 }
00310
00311 return text;
00312 }