kabc Library API Documentation

vcard21parser.cpp

00001 /*
00002     This file is part of libkabc.
00003     Copyright (c) 2001 Mark Westcott <mark@houseoffish.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., 59 Temple Place - Suite 330,
00018     Boston, MA 02111-1307, USA.
00019 */
00020 
00021 #include <qmap.h>
00022 #include <qregexp.h>
00023 
00024 #include "vcard21parser.h"
00025 
00026 using namespace KABC;
00027 
00028 bool VCardLine::isValid() const
00029 {
00030   // Invalid: if it is "begin:vcard" or "end:vcard"
00031   if ( name == VCARD_BEGIN_N || name == VCARD_END_N )
00032     return false;
00033 
00034   if ( name[0] == 'x' && name[1] == '-' ) // A custom x- line
00035     return true;
00036 
00037   // This is long but it makes it a bit faster (and saves me from using
00038   // a trie which is probably the ideal situation, but a bit memory heavy)
00039   switch( name[0] ) {
00040     case 'a':
00041       if ( name == VCARD_ADR && qualified &&
00042                    (qualifiers.contains(VCARD_ADR_DOM)    ||
00043                     qualifiers.contains(VCARD_ADR_INTL)   ||
00044                     qualifiers.contains(VCARD_ADR_POSTAL) ||
00045                     qualifiers.contains(VCARD_ADR_HOME)   ||
00046                     qualifiers.contains(VCARD_ADR_WORK)   ||
00047                     qualifiers.contains(VCARD_ADR_PREF)
00048          ) )
00049         return true;
00050 
00051       if ( name == VCARD_AGENT )
00052         return true;
00053       break;
00054 
00055     case 'b':
00056       if ( name == VCARD_BDAY )
00057         return true;
00058       break;
00059 
00060     case 'c':
00061       if ( name == VCARD_CATEGORIES )
00062         return true;
00063       if ( name == VCARD_CLASS && qualified &&
00064                    (qualifiers.contains(VCARD_CLASS_PUBLIC)      ||
00065                     qualifiers.contains(VCARD_CLASS_PRIVATE)     ||
00066                     qualifiers.contains(VCARD_CLASS_CONFIDENTIAL)
00067          ) )
00068         return true;
00069       break;
00070 
00071     case 'e':
00072       if ( name == VCARD_EMAIL && qualified &&
00073                   (qualifiers.contains(VCARD_EMAIL_INTERNET) ||
00074                    qualifiers.contains(VCARD_EMAIL_PREF)     ||
00075                    qualifiers.contains(VCARD_EMAIL_X400)
00076          ) )
00077         return true;
00078       break;
00079 
00080     case 'f':
00081       if ( name == VCARD_FN )
00082         return true;
00083       break;
00084 
00085     case 'g':
00086       if ( name == VCARD_GEO )
00087         return true;
00088       break;
00089 
00090     case 'k':
00091       if ( name == VCARD_KEY && qualified &&
00092                    (qualifiers.contains(VCARD_KEY_X509) ||
00093                     qualifiers.contains(VCARD_KEY_PGP)
00094          ) )
00095         return true;
00096       break;
00097 
00098     case 'l':
00099       if ( name == VCARD_LABEL )
00100         return true;
00101       if ( name == VCARD_LOGO )
00102         return true;
00103       break;
00104 
00105     case 'm':
00106       if ( name == VCARD_MAILER )
00107         return true;
00108       break;
00109 
00110     case 'n':
00111       if ( name == VCARD_N )
00112         return true;
00113       if ( name == VCARD_NAME )
00114         return true;
00115       if ( name == VCARD_NICKNAME )
00116         return true;
00117       if ( name == VCARD_NOTE )
00118         return true;
00119       break;
00120 
00121     case 'o':
00122       if ( name == VCARD_ORG )
00123         return true;
00124       break;
00125 
00126     case 'p':
00127       if ( name == VCARD_PHOTO )
00128         return true;
00129       if ( name == VCARD_PROFILE )
00130         return true;
00131       if ( name == VCARD_PRODID )
00132         return true;
00133       break;
00134 
00135     case 'r':
00136       if ( name == VCARD_ROLE )
00137         return true;
00138       if ( name == VCARD_REV )
00139         return true;
00140       break;
00141 
00142     case 's':
00143       if ( name == VCARD_SOURCE )
00144         return true;
00145       if ( name == VCARD_SOUND )
00146         return true;
00147       break;
00148 
00149     case 't':
00150       if ( name == VCARD_TEL && qualified &&
00151                    (qualifiers.contains(VCARD_TEL_HOME)  ||
00152                     qualifiers.contains(VCARD_TEL_WORK)  ||
00153                     qualifiers.contains(VCARD_TEL_PREF)  ||
00154                     qualifiers.contains(VCARD_TEL_VOICE) ||
00155                     qualifiers.contains(VCARD_TEL_FAX)   ||
00156                     qualifiers.contains(VCARD_TEL_MSG)   ||
00157                     qualifiers.contains(VCARD_TEL_CELL)  ||
00158                     qualifiers.contains(VCARD_TEL_PAGER) ||
00159                     qualifiers.contains(VCARD_TEL_BBS)   ||
00160                     qualifiers.contains(VCARD_TEL_MODEM) ||
00161                     qualifiers.contains(VCARD_TEL_CAR)   ||
00162                     qualifiers.contains(VCARD_TEL_ISDN)  ||
00163                     qualifiers.contains(VCARD_TEL_VIDEO) ||
00164                     qualifiers.contains(VCARD_TEL_PCS)
00165          ) )
00166         return true;
00167       if ( name == VCARD_TZ )
00168         return true;
00169       if ( name == VCARD_TITLE )
00170         return true;
00171       break;
00172 
00173     case 'u':
00174       if ( name == VCARD_URL )
00175         return true;
00176       if ( name == VCARD_UID )
00177         return true;
00178       break;
00179 
00180     case 'v':
00181       if ( name == VCARD_VERSION )
00182         return true;
00183       break;
00184     default:
00185       break;
00186   }
00187 
00188   return false;
00189 }
00190 
00191 
00192 void VCardLine::qpDecode( QString& x )
00193 {
00194   QString y = x;
00195   int c;
00196 
00197   x = "";
00198   c = y.length();
00199 
00200   for (int i = 0; i < c; i++) {
00201     if (y[i] == '=') {
00202       char p = y[++i].latin1();
00203       char q = y[++i].latin1();
00204       x += (char) ((p <= '9' ? p - '0': p - 'A' + 10)*16 +
00205                   (q <= '9' ? q - '0': q - 'A' + 10));
00206     } else {
00207       x += y[i];
00208     }
00209   }
00210 }
00211 
00212 
00213 VCard21Parser::VCard21Parser()
00214 {
00215 }
00216 
00217 VCard21Parser::~VCard21Parser()
00218 {
00219 }
00220 
00221 void VCard21Parser::readFromString(KABC::AddressBook *addressbook, const QString &data)
00222 {
00223   KABC::Addressee mAddressee = readFromString(data);
00224   addressbook->insertAddressee(mAddressee);
00225 }
00226 
00227 KABC::Addressee VCard21Parser::readFromString( const QString &data)
00228 {
00229   KABC::Addressee addressee;
00230   VCard21ParserImpl *mVCard = VCard21ParserImpl::parseVCard(data);
00231   QString tmpStr;
00232 
00233   // Check if parsing failed
00234   if (mVCard == 0)
00235   {
00236      kdDebug() << "Parsing failed" << endl;
00237      return addressee;
00238   }         
00239   //set the addressees name and formated name
00240   QStringList tmpList = mVCard->getValues(VCARD_N);
00241   QString formattedName = "";
00242   if (tmpList.count() > 0)
00243     addressee.setFamilyName(tmpList[0]);
00244   if (tmpList.count() > 1)
00245     addressee.setGivenName(tmpList[1]);
00246   if (tmpList.count() > 2)
00247     addressee.setAdditionalName(tmpList[2]);
00248   if (tmpList.count() > 3)
00249     addressee.setPrefix(tmpList[3]);
00250   if (tmpList.count() > 4)
00251     addressee.setSuffix(tmpList[4]);
00252 
00253   tmpStr = (mVCard->getValue(VCARD_FN));
00254   if (!tmpStr.isEmpty())
00255     addressee.setFormattedName(tmpStr);
00256 
00257   //set the addressee's nick name
00258   tmpStr = mVCard->getValue(VCARD_NICKNAME);
00259   addressee.setNickName(tmpStr);
00260   //set the addressee's organisation
00261   tmpStr = mVCard->getValue(VCARD_ORG);
00262   addressee.setOrganization(tmpStr);
00263   //set the addressee's title
00264   tmpStr = mVCard->getValue(VCARD_TITLE);
00265   addressee.setTitle(tmpStr);
00266   //set the addressee's email - we can only deal with two.  The preferenced one and one other.
00267   tmpStr = mVCard->getValue(VCARD_EMAIL, VCARD_EMAIL_INTERNET);
00268   addressee.insertEmail(tmpStr, false);
00269   tmpStr = mVCard->getValue(VCARD_EMAIL,VCARD_EMAIL_PREF);
00270   addressee.insertEmail(tmpStr, true);
00271   //set the addressee's url
00272   tmpStr = mVCard->getValue(VCARD_URL);
00273 
00274   if (!tmpStr.isEmpty()) {
00275     KURL url(tmpStr);
00276     addressee.setUrl(url);
00277   }
00278 
00279   //set the addressee's birthday
00280   tmpStr = mVCard->getValue(VCARD_BDAY);
00281   addressee.setBirthday(QDateTime::fromString(tmpStr,Qt::ISODate));
00282 
00283   //set the addressee's phone numbers
00284   for ( QValueListIterator<VCardLine> i = mVCard->_vcdata->begin();i != mVCard->_vcdata->end(); ++i ) {
00285     if ( (*i).name == VCARD_TEL ) {
00286       int type = 0;
00287       if ( (*i).qualified ) {
00288         if ( (*i).qualifiers.contains( VCARD_TEL_HOME ) )
00289           type |= PhoneNumber::Home;
00290         if ( (*i).qualifiers.contains( VCARD_TEL_WORK ) )
00291           type |= PhoneNumber::Work;
00292         if ( (*i).qualifiers.contains( VCARD_TEL_PREF ) )
00293           type |= PhoneNumber::Pref;
00294         if ( (*i).qualifiers.contains( VCARD_TEL_VOICE ) )
00295           type |= PhoneNumber::Voice;
00296         if ( (*i).qualifiers.contains( VCARD_TEL_FAX ) )
00297           type |= PhoneNumber::Fax;
00298         if ( (*i).qualifiers.contains( VCARD_TEL_MSG ) )
00299           type |= PhoneNumber::Msg;
00300         if ( (*i).qualifiers.contains( VCARD_TEL_CELL ) )
00301           type |= PhoneNumber::Cell;
00302         if ( (*i).qualifiers.contains( VCARD_TEL_PAGER ) )
00303           type |= PhoneNumber::Pager;
00304         if ( (*i).qualifiers.contains( VCARD_TEL_BBS ) )
00305           type |= PhoneNumber::Bbs;
00306         if ( (*i).qualifiers.contains( VCARD_TEL_MODEM ) )
00307           type |= PhoneNumber::Modem;
00308         if ( (*i).qualifiers.contains( VCARD_TEL_CAR ) )
00309           type |= PhoneNumber::Car;
00310         if ( (*i).qualifiers.contains( VCARD_TEL_ISDN ) )
00311           type |= PhoneNumber::Isdn;
00312         if ( (*i).qualifiers.contains( VCARD_TEL_VIDEO ) )
00313           type |= PhoneNumber::Video;
00314         if ( (*i).qualifiers.contains( VCARD_TEL_PCS ) )
00315           type |= PhoneNumber::Pcs;
00316       }
00317       addressee.insertPhoneNumber( PhoneNumber( (*i).parameters[ 0 ], type ) );
00318     }
00319   }
00320 
00321   //set the addressee's addresses
00322   for ( QValueListIterator<VCardLine> i = mVCard->_vcdata->begin();i != mVCard->_vcdata->end(); ++i ) {
00323     if ( (*i).name == VCARD_ADR ) {
00324       int type = 0;
00325       if ( (*i).qualified ) {
00326         if ( (*i).qualifiers.contains( VCARD_ADR_DOM ) )
00327           type |= Address::Dom;
00328         if ( (*i).qualifiers.contains( VCARD_ADR_INTL ) )
00329           type |= Address::Intl;
00330         if ( (*i).qualifiers.contains( VCARD_ADR_POSTAL ) )
00331           type |= Address::Postal;
00332         if ( (*i).qualifiers.contains( VCARD_ADR_PARCEL ) )
00333           type |= Address::Parcel;
00334         if ( (*i).qualifiers.contains( VCARD_ADR_HOME ) )
00335           type |= Address::Home;
00336         if ( (*i).qualifiers.contains( VCARD_ADR_WORK ) )
00337           type |= Address::Work;
00338         if ( (*i).qualifiers.contains( VCARD_ADR_PREF ) )
00339           type |= Address::Pref;
00340       }
00341       addressee.insertAddress( readAddressFromQStringList( (*i).parameters, type ) );
00342     }
00343   }
00344 
00345   //set the addressee's delivery label
00346   tmpStr = mVCard->getValue(VCARD_LABEL);
00347   if (!tmpStr.isEmpty()) {
00348     tmpStr.replace(QRegExp("\\r\\n"),"\n");
00349     Address tmpAddress;
00350     tmpAddress.setLabel(tmpStr);
00351     addressee.insertAddress(tmpAddress);
00352   }
00353 
00354   //set the addressee's notes
00355   tmpStr = mVCard->getValue(VCARD_NOTE);
00356   tmpStr.replace(QRegExp("\\r\\n"),"\n");
00357   addressee.setNote(tmpStr);
00358 
00359   //set the addressee's timezone
00360   tmpStr = mVCard->getValue(VCARD_TZ);
00361   TimeZone tmpZone(tmpStr.toInt());
00362   addressee.setTimeZone(tmpZone);
00363 
00364   //set the addressee's geographical position
00365   tmpList = mVCard->getValues(VCARD_GEO);
00366   if (tmpList.count()==2)
00367   {
00368     tmpStr = tmpList[0];
00369     float glat = tmpStr.toFloat();
00370     tmpStr = tmpList[1];
00371     float glong = tmpStr.toFloat();
00372     Geo tmpGeo(glat,glong);
00373     addressee.setGeo(tmpGeo);
00374   }
00375 
00376   //set the last revision date
00377   tmpStr = mVCard->getValue(VCARD_REV);
00378   addressee.setRevision(QDateTime::fromString(tmpStr,Qt::ISODate));
00379 
00380   //set the role of the addressee
00381   tmpStr = mVCard->getValue(VCARD_ROLE);
00382   addressee.setRole(tmpStr);
00383 
00384   return addressee;
00385 }
00386 
00387 
00388 
00389 KABC::Address VCard21Parser::readAddressFromQStringList ( const QStringList &data, const int type )
00390 {
00391   KABC::Address mAddress;
00392   mAddress.setType( type );
00393 
00394   if ( data.count() > 0 )
00395     mAddress.setPostOfficeBox( data[0] );
00396   if ( data.count() > 1 )
00397     mAddress.setExtended( data[1] );
00398   if ( data.count() > 2 )
00399     mAddress.setStreet( data[2] );
00400   if ( data.count() > 3 )
00401     mAddress.setLocality( data[3] );
00402   if ( data.count() > 4 )
00403     mAddress.setRegion( data[4] );
00404   if ( data.count() > 5 )
00405     mAddress.setPostalCode( data[5] );
00406   if ( data.count() > 6 )
00407     mAddress.setCountry( data[6] );
00408 
00409   return mAddress;
00410 }
00411 
00412 
00413 VCard21ParserImpl *VCard21ParserImpl::parseVCard( const QString& vc, int *err ) 
00414 {
00415   int _err = 0;
00416   int _state = VC_STATE_BEGIN;
00417 
00418   QValueList<VCardLine> *_vcdata;
00419   QValueList<QString> lines;
00420 
00421   _vcdata = new QValueList<VCardLine>;
00422 
00423   lines = QStringList::split( QRegExp( "[\x0d\x0a]" ), vc );
00424   
00425   // for each line in the vCard
00426   for ( QStringList::Iterator j = lines.begin(); j != lines.end(); ++j ) {
00427     VCardLine _vcl;
00428 
00429     // take spaces off the end - ugly but necessary hack
00430     for ( int g = (*j).length()-1; g > 0 && (*j)[g].isSpace(); --g )
00431       (*j)[g] = 0;
00432 
00433     // first token:
00434     //   verify state, update if necessary
00435     if ( _state & VC_STATE_BEGIN) {
00436       if ( !qstricmp( (*j).latin1(), VCARD_BEGIN ) ) {
00437         _state = VC_STATE_BODY;
00438         continue;
00439       } else {
00440         _err = VC_ERR_NO_BEGIN;
00441         break;
00442       }
00443     } else if ( _state & VC_STATE_BODY ) {
00444       if ( !qstricmp( (*j).latin1(), VCARD_END ) ) {
00445         _state |= VC_STATE_END;
00446         break;
00447       }
00448 
00449       // split into two tokens
00450       int colon = (*j).find( ':' );
00451       if ( colon < 0 ) {
00452         _err = VC_ERR_INVALID_LINE;
00453         break;
00454       }
00455 
00456       QString key = (*j).left( colon );
00457       QString value = (*j).mid( colon + 1 );
00458 
00459       // check for qualifiers and
00460       // set name, qualified, qualifier(s)
00461       QStringList keyTokens = QStringList::split( QRegExp(";"), key );
00462       bool qp = false, first_pass = true;
00463       bool b64 = false;
00464 
00465       if ( keyTokens.count() > 0 ) {
00466         _vcl.qualified = false;
00467         _vcl.name = keyTokens[ 0 ].lower();
00468 
00469         for ( QStringList::Iterator z = keyTokens.begin(); z != keyTokens.end(); ++z ) {
00470           QString zz = (*z).lower();
00471           if ( zz == VCARD_QUOTED_PRINTABLE || zz == VCARD_ENCODING_QUOTED_PRINTABLE ) {
00472             qp = true;
00473           } else if ( zz == VCARD_BASE64 ) {
00474             b64 = true;
00475           } else if ( !first_pass ) {
00476             _vcl.qualified = true;
00477             _vcl.qualifiers.append( zz );
00478           }
00479           first_pass = false;
00480         }
00481       } else {
00482         _err = VC_ERR_INVALID_LINE;
00483       }
00484 
00485       if ( _err != 0 )
00486         break;
00487 
00488       if ( _vcl.name == VCARD_VERSION )
00489         _state |= VC_STATE_HAVE_VERSION;
00490 
00491       if ( _vcl.name == VCARD_N || _vcl.name == VCARD_FN )
00492         _state |= VC_STATE_HAVE_N;
00493 
00494       // second token:
00495       //    split into tokens by ;
00496       //    add to parameters vector
00497       if ( b64 ) {
00498         if ( value[ value.length() - 1 ] != '=' )
00499           do {
00500             value += *( ++j );
00501           } while ( (*j)[ (*j).length() - 1 ] != '=' );
00502       } else {
00503         if ( qp ) { // join any split lines
00504           while ( value[ value.length() - 1 ] == '=' ) {
00505             value.remove( value.length() - 1, 1 );
00506             value.append(*( ++j ));
00507           }
00508         }
00509         _vcl.parameters = QStringList::split( QRegExp(";"), value, true );
00510         if ( qp ) { // decode the quoted printable
00511           for ( QStringList::Iterator z = _vcl.parameters.begin(); z != _vcl.parameters.end(); ++z )
00512             _vcl.qpDecode( *z );
00513         }
00514       }
00515     } else {
00516       _err = VC_ERR_INTERNAL;
00517       break;
00518     }
00519 
00520     // validate VCardLine
00521     if ( !_vcl.isValid() ) {
00522       _err = VC_ERR_INVALID_LINE;
00523       break;
00524     }
00525 
00526     // add to vector
00527     _vcdata->append( _vcl );
00528   }
00529 
00530   // errors to check at the last minute (exit state related)
00531   if ( _err == 0 ) {
00532     if ( !( _state & VC_STATE_END ) ) // we have to have an end!!
00533       _err = VC_ERR_NO_END;
00534 
00535     if ( !( _state & VC_STATE_HAVE_N ) || // we have to have the mandatories!
00536          !( _state & VC_STATE_HAVE_VERSION ) )
00537       _err = VC_ERR_MISSING_MANDATORY;
00538   }
00539 
00540   // set the error message if we can, and only return an object
00541   // if the vCard was valid.
00542   if ( err )
00543     *err = _err;
00544 
00545   if ( _err != 0 ) {
00546     delete _vcdata;
00547     return 0;
00548   }
00549 
00550   return new VCard21ParserImpl( _vcdata );
00551 }
00552 
00553 VCard21ParserImpl::VCard21ParserImpl(QValueList<VCardLine> *_vcd) : _vcdata(_vcd)
00554 {
00555 }
00556 
00557 
00558 QString VCard21ParserImpl::getValue(const QString& name, const QString& qualifier)
00559 {
00560   QString failed = "";
00561   const QString lowname = name.lower();
00562   const QString lowqualifier = qualifier.lower();
00563 
00564   for (QValueListIterator<VCardLine> i = _vcdata->begin();i != _vcdata->end();++i) {
00565    if ((*i).name == lowname && (*i).qualified && (*i).qualifiers.contains(lowqualifier)) {
00566     if ((*i).parameters.count() > 0)
00567      return (*i).parameters[0];
00568     else return failed;
00569     }
00570   }
00571   return failed;
00572 }
00573 
00574 
00575 QString VCard21ParserImpl::getValue(const QString& name)
00576 {
00577   QString failed = "";
00578   const QString lowname = name.lower();
00579 
00580   for (QValueListIterator<VCardLine> i = _vcdata->begin();i != _vcdata->end();++i) {
00581     if ((*i).name == lowname && !(*i).qualified) {
00582       if ((*i).parameters.count() > 0)
00583         return (*i).parameters[0];
00584       else return failed;
00585     }
00586    }
00587   return failed;
00588 }
00589 
00590 
00591 QStringList VCard21ParserImpl::getValues(const QString& name)
00592 {
00593   //QString failedstr = "";
00594   QStringList failed;
00595   const QString lowname = name.lower();
00596   for (QValueListIterator<VCardLine> i = _vcdata->begin();i != _vcdata->end();++i) {
00597     if ((*i).name == lowname && !(*i).qualified)
00598       return (*i).parameters;
00599   }
00600   //failed.append(failedstr);
00601   return failed;
00602 }
00603 
00604 QStringList VCard21ParserImpl::getValues(const QString& name, const QString& qualifier)
00605 {
00606   //QString failedstr = "";
00607   QStringList failed;
00608   const QString lowname = name.lower();
00609   const QString lowqualifier = qualifier.lower();
00610   for (QValueListIterator<VCardLine> i = _vcdata->begin();i != _vcdata->end();++i) {
00611     if ((*i).name == lowname && (*i).qualified && (*i).qualifiers.contains(lowqualifier))
00612        return (*i).parameters;
00613   }
00614   //failed.append(failedstr);
00615   return failed;
00616 }
KDE Logo
This file is part of the documentation for kdelibs Version 3.1.0.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Oct 8 12:22:08 2003 by doxygen 1.2.18 written by Dimitri van Heesch, © 1997-2001