• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdepimlibs-4.8.5 API Reference
  • KDE Home
  • 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, bool excludeEscapteComma )
00031 {
00032   str.replace( '\\', (char *)"\\\\" );
00033   if(!excludeEscapteComma)
00034     str.replace( ',', (char *)"\\," );
00035   str.replace( '\r', (char *)"\\r" );
00036   str.replace( '\n', (char *)"\\n" );
00037 }
00038 
00039 static void removeEscapes( QByteArray &str )
00040 {
00041   str.replace( (char *)"\\n", "\n" );
00042   str.replace( (char *)"\\N", "\n" );
00043   str.replace( (char *)"\\r", "\r" );
00044   str.replace( (char *)"\\,", "," );
00045   str.replace( (char *)"\\\\", "\\" );
00046 }
00047 
00048 VCardParser::VCardParser()
00049 {
00050 }
00051 
00052 VCardParser::~VCardParser()
00053 {
00054 }
00055 
00056 VCard::List VCardParser::parseVCards( const QByteArray &text )
00057 {
00058   VCard currentVCard;
00059   VCard::List vCardList;
00060   QByteArray currentLine;
00061 
00062   QList<QByteArray> lines = text.split( '\n' );
00063 
00064   bool inVCard = false;
00065   QList<QByteArray>::Iterator it( lines.begin() );
00066   QList<QByteArray>::Iterator linesEnd( lines.end() );
00067   for ( ; it != linesEnd; ++it ) {
00068     // remove the trailing \r, left from \r\n
00069     if ( (*it).endsWith( '\r' ) ) {
00070         (*it).chop( 1 );
00071     }
00072 
00073     if ( (*it).startsWith( ' ' ) || (*it).startsWith( '\t' ) ) { //folded line => append to previous
00074       currentLine.append( (*it).mid( 1 ) );
00075       continue;
00076     } else {
00077       if ( (*it).trimmed().isEmpty() ) { // empty line
00078         continue;
00079       }
00080       if ( inVCard && !currentLine.isEmpty() ) { // now parse the line
00081         int colon = currentLine.indexOf( ':' );
00082         if ( colon == -1 ) { // invalid line
00083           currentLine = (*it);
00084           continue;
00085         }
00086 
00087         VCardLine vCardLine;
00088         const QByteArray key = currentLine.left( colon ).trimmed();
00089         QByteArray value = currentLine.mid( colon + 1 );
00090 
00091         QList<QByteArray> params = key.split( ';' );
00092 
00093         // check for group
00094         int groupPos = params[ 0 ].indexOf( '.' );
00095         if ( groupPos != -1 ) {
00096           vCardLine.setGroup( QString::fromLatin1( params[ 0 ].left( groupPos ) ) );
00097           vCardLine.setIdentifier( QString::fromLatin1( params[ 0 ].mid( groupPos + 1 ) ) );
00098         } else {
00099           vCardLine.setIdentifier( QString::fromLatin1( params[ 0 ] ) );
00100         }
00101 
00102         if ( params.count() > 1 ) { // find all parameters
00103           QList<QByteArray>::ConstIterator paramIt( params.constBegin() );
00104           for ( ++paramIt; paramIt != params.constEnd(); ++paramIt ) {
00105             QList<QByteArray> pair = (*paramIt).split( '=' );
00106             if ( pair.count() == 1 ) {
00107               // correct the fucking 2.1 'standard'
00108               if ( pair[ 0 ].toLower() == "quoted-printable" ) {
00109                 pair[ 0 ] = "encoding";
00110                 pair.append( "quoted-printable" );
00111               } else if ( pair[ 0 ].toLower() == "base64" ) {
00112                 pair[ 0 ] = "encoding";
00113                 pair.append( "base64" );
00114               } else {
00115                 pair.prepend( "type" );
00116               }
00117             }
00118             if ( pair[ 1 ].indexOf( ',' ) != -1 ) { // parameter in type=x,y,z format
00119               const QList<QByteArray> args = pair[ 1 ].split( ',' );
00120               QList<QByteArray>::ConstIterator argIt;
00121               for ( argIt = args.constBegin(); argIt != args.constEnd(); ++argIt ) {
00122                 vCardLine.addParameter( QString::fromLatin1( pair[ 0 ].toLower() ),
00123                                         QString::fromLatin1( *argIt ) );
00124               }
00125             } else {
00126               vCardLine.addParameter( QString::fromLatin1( pair[ 0 ].toLower() ),
00127                                       QString::fromLatin1( pair[ 1 ] ) );
00128             }
00129           }
00130         }
00131 
00132         removeEscapes( value );
00133 
00134         QByteArray output;
00135         bool wasBase64Encoded = false;
00136 
00137         if ( vCardLine.parameterList().contains( QLatin1String( "encoding" ) ) ) {
00138           const QString encoding = vCardLine.parameter( QLatin1String( "encoding" ) ).toLower();
00139 
00140           // have to decode the data
00141           if ( encoding == QLatin1String( "b" ) || encoding == QLatin1String( "base64" ) ) {
00142             output = QByteArray::fromBase64( value );
00143             wasBase64Encoded = true;
00144           }
00145           else if ( encoding == QLatin1String( "quoted-printable" ) ) {
00146             // join any qp-folded lines
00147             while ( value.endsWith( '=' ) && it != linesEnd ) {
00148               value.chop( 1 ); // remove the '='
00149               value.append( *it );
00150               ++it;
00151             }
00152             KCodecs::quotedPrintableDecode( value, output );
00153           } else if ( encoding == QLatin1String( "8bit" ) ) {
00154             output = value;
00155           } else {
00156             qDebug( "Unknown vcard encoding type!" );
00157           }
00158         } else {
00159           output = value;
00160         }
00161 
00162         if ( vCardLine.parameterList().contains( QLatin1String( "charset" ) ) ) {
00163           // have to convert the data
00164           QTextCodec *codec = QTextCodec::codecForName(
00165             vCardLine.parameter( QLatin1String( "charset" ) ).toLatin1() );
00166           if ( codec ) {
00167             vCardLine.setValue( codec->toUnicode( output ) );
00168           } else {
00169             vCardLine.setValue( QString::fromUtf8( output ) );
00170           }
00171         } else if ( wasBase64Encoded ) {
00172             vCardLine.setValue( output );
00173         } else {
00174             vCardLine.setValue( QString::fromUtf8( output ) );
00175         }
00176 
00177         currentVCard.addLine( vCardLine );
00178       }
00179 
00180       // we do not save the start and end tag as vcardline
00181       if ( (*it).toLower().startsWith( "begin:vcard" ) ) { //krazy:exclude=strings
00182         inVCard = true;
00183         currentLine.clear();
00184         currentVCard.clear(); // flush vcard
00185         continue;
00186       }
00187 
00188       if ( (*it).toLower().startsWith( "end:vcard" ) ) { //krazy:exclude=strings
00189         inVCard = false;
00190         vCardList.append( currentVCard );
00191         currentLine.clear();
00192         currentVCard.clear(); // flush vcard
00193         continue;
00194       }
00195 
00196       currentLine = (*it);
00197     }
00198   }
00199 
00200   return vCardList;
00201 }
00202 
00203 QByteArray VCardParser::createVCards( const VCard::List &list )
00204 {
00205   QByteArray text;
00206   QByteArray textLine;
00207   QString encodingType;
00208   QStringList idents;
00209   QStringList params;
00210   QStringList values;
00211   QStringList::ConstIterator identIt;
00212   QStringList::Iterator paramIt;
00213   QStringList::ConstIterator valueIt;
00214 
00215   VCardLine::List lines;
00216   VCardLine::List::ConstIterator lineIt;
00217   VCard::List::ConstIterator cardIt;
00218 
00219   bool hasEncoding;
00220 
00221   text.reserve( list.size() * 300 ); // reserve memory to be more efficient
00222 
00223   // iterate over the cards
00224   VCard::List::ConstIterator listEnd( list.end() );
00225   for ( cardIt = list.begin(); cardIt != listEnd; ++cardIt ) {
00226     text.append( "BEGIN:VCARD\r\n" );
00227 
00228     idents = (*cardIt).identifiers();
00229     for ( identIt = idents.constBegin(); identIt != idents.constEnd(); ++identIt ) {
00230       lines = (*cardIt).lines( (*identIt) );
00231 
00232       // iterate over the lines
00233       for ( lineIt = lines.constBegin(); lineIt != lines.constEnd(); ++lineIt ) {
00234         QVariant val = (*lineIt).value();
00235         if ( val.isValid() ) {
00236           if ( (*lineIt).hasGroup() ) {
00237             textLine = (*lineIt).group().toLatin1() + '.' + (*lineIt).identifier().toLatin1();
00238           } else {
00239             textLine = (*lineIt).identifier().toLatin1();
00240           }
00241 
00242           params = (*lineIt).parameterList();
00243           hasEncoding = false;
00244           if ( params.count() > 0 ) { // we have parameters
00245             for ( paramIt = params.begin(); paramIt != params.end(); ++paramIt ) {
00246               if ( (*paramIt) == QLatin1String( "encoding" ) ) {
00247                 hasEncoding = true;
00248                 encodingType = (*lineIt).parameter( QLatin1String( "encoding" ) ).toLower();
00249               }
00250 
00251               values = (*lineIt).parameters( *paramIt );
00252               for ( valueIt = values.constBegin(); valueIt != values.constEnd(); ++valueIt ) {
00253                 textLine.append( ';' + (*paramIt).toLatin1().toUpper() );
00254                 if ( !(*valueIt).isEmpty() ) {
00255                   textLine.append( '=' + (*valueIt).toLatin1() );
00256                 }
00257               }
00258             }
00259           }
00260 
00261           QByteArray input, output;
00262 
00263           // handle charset
00264           if ( (*lineIt).parameterList().contains( QLatin1String( "charset" ) ) ) {
00265             // have to convert the data
00266             const QString value = (*lineIt).value().toString();
00267             QTextCodec *codec = QTextCodec::codecForName(
00268               (*lineIt).parameter( QLatin1String( "charset" ) ).toLatin1() );
00269             if ( codec ) {
00270               input = codec->fromUnicode( value );
00271             } else {
00272               input = value.toUtf8();
00273             }
00274           } else if ( (*lineIt).value().type() == QVariant::ByteArray ) {
00275             input = (*lineIt).value().toByteArray();
00276           } else {
00277             input = (*lineIt).value().toString().toUtf8();
00278           }
00279 
00280           // handle encoding
00281           if ( hasEncoding ) { // have to encode the data
00282             if ( encodingType == QLatin1String( "b" ) ) {
00283               output = input.toBase64();
00284             } else if ( encodingType == QLatin1String( "quoted-printable" ) ) {
00285               KCodecs::quotedPrintableEncode( input, output, false );
00286             }
00287           } else {
00288             output = input;
00289           }
00290           addEscapes( output, (*lineIt).identifier() == QLatin1String("CATEGORIES") );
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 Aug 27 2012 22:10:24 by doxygen 1.7.5 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

kabc

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

kdepimlibs-4.8.5 API Reference

Skip menu "kdepimlibs-4.8.5 API Reference"
  • akonadi
  •   contact
  •   kmime
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  •   richtextbuilders
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal