vcard21parser.cpp Source File (kabc Library)

| # kabc Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Source Files

# 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 }

This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Jan 28 13:29:23 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001