• Skip to content
  • Skip to link menu
KDE 4.1 API Reference
  • KDE API Reference
  • KDE-PIM Libraries
  • Sitemap
  • Contact Us
 

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 *)"\\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     // remove the trailing \r, left from \r\n
00067     if ( (*it).endsWith( '\r' ) ) {
00068         (*it).chop( 1 );
00069     }
00070 
00071     if ( (*it).startsWith( ' ' ) || (*it).startsWith( '\t' ) ) { //folded line => append to previous
00072       currentLine.append( (*it).mid( 1 ) );
00073       continue;
00074     } else {
00075       if ( (*it).trimmed().isEmpty() ) { // empty line
00076         continue;
00077       }
00078       if ( inVCard && !currentLine.isEmpty() ) { // now parse the line
00079         int colon = currentLine.indexOf( ':' );
00080         if ( colon == -1 ) { // invalid line
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         // check for group
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 ) { // find all parameters
00101           QList<QByteArray>::ConstIterator paramIt( params.begin() );
00102           for ( ++paramIt; paramIt != params.end(); ++paramIt ) {
00103             QList<QByteArray> pair = (*paramIt).split( '=' );
00104             if ( pair.count() == 1 ) {
00105               // correct the fucking 2.1 'standard'
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 ) { // parameter in type=x,y,z format
00117               const QList<QByteArray> args = pair[ 1 ].split( ',' );
00118               QList<QByteArray>::ConstIterator argIt;
00119               for ( argIt = args.begin(); argIt != args.end(); ++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" ) ) { // have to decode the data
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             // join any qp-folded lines
00141             while ( value.endsWith( '=' ) && it != linesEnd ) {
00142               value.chop( 1 ); // remove the '='
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" ) ) { // have to convert the data
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       // we do not save the start and end tag as vcardline
00172       if ( (*it).toLower().startsWith( "begin:vcard" ) ) {
00173         inVCard = true;
00174         currentLine.clear();
00175         currentVCard.clear(); // flush vcard
00176         continue;
00177       }
00178 
00179       if ( (*it).toLower().startsWith( "end:vcard" ) ) {
00180         inVCard = false;
00181         vCardList.append( currentVCard );
00182         currentLine.clear();
00183         currentVCard.clear(); // flush vcard
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 ); // reserve memory to be more efficient
00213 
00214   // iterate over the cards
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       // iterate over the lines
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 ) { // we have parameters
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           // handle charset
00255           if ( (*lineIt).parameterList().contains( "charset" ) ) { // have to convert the data
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           // handle encoding
00271           if ( hasEncoding ) { // have to encode the data
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 ) { // we have to fold the line
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 }

kabc

Skip menu "kabc"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

KDE-PIM Libraries

Skip menu "KDE-PIM Libraries"
  • akonadi
  • kabc
  • kblog
  • kcal
  • kimap
  • kioslave
  •   imap4
  •   mbox
  • kldap
  • kmime
  • kpimidentities
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Generated for KDE-PIM Libraries by doxygen 1.5.6
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal