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() ), *argIt );
00121 }
00122 } else {
00123 vCardLine.addParameter( QString::fromLatin1( pair[ 0 ].toLower() ), pair[ 1 ] );
00124 }
00125 }
00126 }
00127
00128 removeEscapes( value );
00129
00130 QByteArray output;
00131 bool wasBase64Encoded = false;
00132
00133 if ( vCardLine.parameterList().contains( "encoding" ) ) {
00134 if ( vCardLine.parameter( "encoding" ).toLower() == "b" ||
00135 vCardLine.parameter( "encoding" ).toLower() == "base64" ) {
00136 output = QByteArray::fromBase64( value );
00137 wasBase64Encoded = true;
00138 }
00139 else if ( vCardLine.parameter( "encoding" ).toLower() == "quoted-printable" ) {
00140
00141 while ( value.endsWith( '=' ) && it != linesEnd ) {
00142 value.chop( 1 );
00143 value.append( *it );
00144 ++it;
00145 }
00146 KCodecs::quotedPrintableDecode( value, output );
00147 } else {
00148 qDebug( "Unknown vcard encoding type!" );
00149 }
00150 } else {
00151 output = value;
00152 }
00153
00154 if ( vCardLine.parameterList().contains( "charset" ) ) {
00155 QTextCodec *codec =
00156 QTextCodec::codecForName( vCardLine.parameter( "charset" ).toLatin1() );
00157 if ( codec ) {
00158 vCardLine.setValue( codec->toUnicode( output ) );
00159 } else {
00160 vCardLine.setValue( QString::fromUtf8( output ) );
00161 }
00162 } else if ( wasBase64Encoded ) {
00163 vCardLine.setValue( output );
00164 } else {
00165 vCardLine.setValue( QString::fromUtf8( output ) );
00166 }
00167
00168 currentVCard.addLine( vCardLine );
00169 }
00170
00171
00172 if ( (*it).toLower().startsWith( "begin:vcard" ) ) {
00173 inVCard = true;
00174 currentLine.clear();
00175 currentVCard.clear();
00176 continue;
00177 }
00178
00179 if ( (*it).toLower().startsWith( "end:vcard" ) ) {
00180 inVCard = false;
00181 vCardList.append( currentVCard );
00182 currentLine.clear();
00183 currentVCard.clear();
00184 continue;
00185 }
00186
00187 currentLine = (*it);
00188 }
00189 }
00190
00191 return vCardList;
00192 }
00193
00194 QByteArray VCardParser::createVCards( const VCard::List &list )
00195 {
00196 QByteArray text;
00197 QByteArray textLine;
00198 QString encodingType;
00199 QStringList idents;
00200 QStringList params;
00201 QStringList values;
00202 QStringList::ConstIterator identIt;
00203 QStringList::Iterator paramIt;
00204 QStringList::ConstIterator valueIt;
00205
00206 VCardLine::List lines;
00207 VCardLine::List::ConstIterator lineIt;
00208 VCard::List::ConstIterator cardIt;
00209
00210 bool hasEncoding;
00211
00212 text.reserve( list.size() * 300 );
00213
00214
00215 VCard::List::ConstIterator listEnd( list.end() );
00216 for ( cardIt = list.begin(); cardIt != listEnd; ++cardIt ) {
00217 text.append( "BEGIN:VCARD\r\n" );
00218
00219 idents = (*cardIt).identifiers();
00220 for ( identIt = idents.constBegin(); identIt != idents.constEnd(); ++identIt ) {
00221 lines = (*cardIt).lines( (*identIt) );
00222
00223
00224 for ( lineIt = lines.constBegin(); lineIt != lines.constEnd(); ++lineIt ) {
00225 QVariant val = (*lineIt).value();
00226 if ( val.isValid() ) {
00227 if ( (*lineIt).hasGroup() ) {
00228 textLine = (*lineIt).group().toLatin1() + '.' + (*lineIt).identifier().toLatin1();
00229 } else {
00230 textLine = (*lineIt).identifier().toLatin1();
00231 }
00232
00233 params = (*lineIt).parameterList();
00234 hasEncoding = false;
00235 if ( params.count() > 0 ) {
00236 for ( paramIt = params.begin(); paramIt != params.end(); ++paramIt ) {
00237 if ( (*paramIt) == "encoding" ) {
00238 hasEncoding = true;
00239 encodingType = (*lineIt).parameter( "encoding" ).toLower();
00240 }
00241
00242 values = (*lineIt).parameters( *paramIt );
00243 for ( valueIt = values.constBegin(); valueIt != values.constEnd(); ++valueIt ) {
00244 textLine.append( ';' + (*paramIt).toLatin1().toUpper() );
00245 if ( !(*valueIt).isEmpty() ) {
00246 textLine.append( '=' + (*valueIt).toLatin1() );
00247 }
00248 }
00249 }
00250 }
00251
00252 QByteArray input, output;
00253
00254
00255 if ( (*lineIt).parameterList().contains( "charset" ) ) {
00256 const QString value = (*lineIt).value().toString();
00257 QTextCodec *codec =
00258 QTextCodec::codecForName( (*lineIt).parameter( "charset" ).toLatin1() );
00259 if ( codec ) {
00260 input = codec->fromUnicode( value );
00261 } else {
00262 input = value.toUtf8();
00263 }
00264 } else if ( (*lineIt).value().type() == QVariant::ByteArray ) {
00265 input = (*lineIt).value().toByteArray();
00266 } else {
00267 input = (*lineIt).value().toString().toUtf8();
00268 }
00269
00270
00271 if ( hasEncoding ) {
00272 if ( encodingType == "b" ) {
00273 output = input.toBase64();
00274 } else if ( encodingType == "quoted-printable" ) {
00275 KCodecs::quotedPrintableEncode( input, output, false );
00276 }
00277 } else {
00278 output = input;
00279 }
00280
00281 addEscapes( output );
00282
00283 if ( !output.isEmpty() ) {
00284 textLine.append( ':' + output );
00285
00286 if ( textLine.length() > FOLD_WIDTH ) {
00287 for ( int i = 0; i <= ( textLine.length() / FOLD_WIDTH ); ++i ) {
00288 text.append(
00289 ( i == 0 ? "" : " " ) + textLine.mid( i * FOLD_WIDTH, FOLD_WIDTH ) + "\r\n" );
00290 }
00291 } else {
00292 text.append( textLine + "\r\n" );
00293 }
00294 }
00295 }
00296 }
00297 }
00298
00299 text.append( "END:VCARD\r\n" );
00300 text.append( "\r\n" );
00301 }
00302
00303 return text;
00304 }