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