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

kabc

address.cpp

00001 /*
00002     This file is part of libkabc.
00003     Copyright (c) 2001 Cornelius Schumacher <schumacher@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 "address.h"
00022 
00023 #include <krandom.h>
00024 #include <kdebug.h>
00025 #include <klocale.h>
00026 #include <kconfig.h>
00027 #include <kstandarddirs.h>
00028 #include <kconfiggroup.h>
00029 
00030 #include <QtCore/QFile>
00031 #include <QtCore/QMap>
00032 #include <QtCore/QTextStream>
00033 #include <QtCore/QSharedData>
00034 
00035 using namespace KABC;
00036 
00037 // template tags for address formatting localization
00038 #define KABC_FMTTAG_realname   QString::fromLatin1("%n")
00039 #define KABC_FMTTAG_REALNAME   QString::fromLatin1("%N")
00040 #define KABC_FMTTAG_company    QString::fromLatin1("%cm")
00041 #define KABC_FMTTAG_COMPANY    QString::fromLatin1("%CM")
00042 #define KABC_FMTTAG_pobox      QString::fromLatin1("%p")
00043 #define KABC_FMTTAG_street     QString::fromLatin1("%s")
00044 #define KABC_FMTTAG_STREET     QString::fromLatin1("%S")
00045 #define KABC_FMTTAG_zipcode    QString::fromLatin1("%z")
00046 #define KABC_FMTTAG_location   QString::fromLatin1("%l")
00047 #define KABC_FMTTAG_LOCATION   QString::fromLatin1("%L")
00048 #define KABC_FMTTAG_region     QString::fromLatin1("%r")
00049 #define KABC_FMTTAG_REGION     QString::fromLatin1("%R")
00050 #define KABC_FMTTAG_newline    QString::fromLatin1("\\n")
00051 #define KABC_FMTTAG_condcomma  QString::fromLatin1("%,")
00052 #define KABC_FMTTAG_condwhite  QString::fromLatin1("%w")
00053 #define KABC_FMTTAG_purgeempty QString::fromLatin1("%0")
00054 
00060 static int findBalancedBracket( const QString &tsection, int pos )
00061 {
00062   int balancecounter = 0;
00063   for ( int i = pos + 1; i < tsection.length(); ++i ) {
00064     if ( QLatin1Char( ')' ) == tsection[i] && 0 == balancecounter ) {
00065       // found end of brackets
00066       return i;
00067     } else {
00068       if ( QLatin1Char( '(' ) == tsection[i] ) {
00069         // nested brackets
00070         balancecounter++;
00071       }
00072     }
00073   }
00074   return -1;
00075 }
00076 
00083 static bool parseAddressTemplateSection( const QString &tsection, QString &result,
00084                                          const QString &realName, const QString &orgaName,
00085                                          const KABC::Address &address )
00086 {
00087   // This method first parses and substitutes any bracketed sections and
00088   // after that replaces any tags with their values. If a bracketed section
00089   // or a tag evaluate to zero, they are not just removed but replaced
00090   // with a placeholder. This is because in the last step conditionals are
00091   // resolved which depend on information about zero-evaluations.
00092   result = tsection;
00093   int stpos = 0;
00094   bool ret = false;
00095 
00096   // first check for brackets that have to be evaluated first
00097   int fpos = result.indexOf( KABC_FMTTAG_purgeempty, stpos );
00098   while ( -1 != fpos ) {
00099     int bpos1 = fpos + KABC_FMTTAG_purgeempty.length();
00100     int bpos2;
00101     // expect opening bracket and find next balanced closing bracket. If
00102     // next char is no opening bracket, continue parsing (no valid tag)
00103     if ( QLatin1Char( '(' ) == result[bpos1] ) {
00104       bpos2 = findBalancedBracket( result, bpos1 );
00105       if ( -1 != bpos2 ) {
00106         // we have balanced brackets, recursively parse:
00107         QString rplstr;
00108         bool purge = !parseAddressTemplateSection( result.mid( bpos1+1,
00109                                                    bpos2-bpos1-1 ), rplstr,
00110                                                    realName, orgaName, address );
00111         if ( purge ) {
00112           // purge -> remove all
00113           // replace with !_P_!, so conditional tags work later
00114           result.replace( fpos, bpos2 - fpos + 1, QLatin1String( "!_P_!" ) );
00115           // leave stpos as it is
00116         } else {
00117           // no purge -> replace with recursively parsed string
00118           result.replace( fpos, bpos2 - fpos + 1, rplstr );
00119           ret = true;
00120           stpos = fpos + rplstr.length();
00121         }
00122       } else {
00123         // unbalanced brackets:  keep on parsing (should not happen
00124         // and will result in bad formatting)
00125         stpos = bpos1;
00126       }
00127     }
00128     fpos = result.indexOf( KABC_FMTTAG_purgeempty, stpos );
00129   }
00130 
00131   // after sorting out all purge tags, we just search'n'replace the rest,
00132   // keeping track of whether at least one tag evaluates to something.
00133   // The following macro needs QString for R_FIELD
00134   // It substitutes !_P_! for empty fields so conditional tags work later
00135 #define REPLTAG(R_TAG,R_FIELD) \
00136   if ( result.indexOf( R_TAG, false ) != -1 ) { \
00137     QString rpl = R_FIELD.isEmpty() ? QLatin1String( "!_P_!" ) : R_FIELD; \
00138     result.replace( R_TAG, rpl ); \
00139     if ( !R_FIELD.isEmpty() ) { \
00140       ret = true; \
00141     } \
00142   }
00143   REPLTAG( KABC_FMTTAG_realname, realName );
00144   REPLTAG( KABC_FMTTAG_REALNAME, realName.toUpper() );
00145   REPLTAG( KABC_FMTTAG_company, orgaName );
00146   REPLTAG( KABC_FMTTAG_COMPANY, orgaName.toUpper() );
00147   REPLTAG( KABC_FMTTAG_pobox, address.postOfficeBox() );
00148   REPLTAG( KABC_FMTTAG_street, address.street() );
00149   REPLTAG( KABC_FMTTAG_STREET, address.street().toUpper() );
00150   REPLTAG( KABC_FMTTAG_zipcode, address.postalCode() );
00151   REPLTAG( KABC_FMTTAG_location, address.locality() );
00152   REPLTAG( KABC_FMTTAG_LOCATION, address.locality().toUpper() );
00153   REPLTAG( KABC_FMTTAG_region, address.region() );
00154   REPLTAG( KABC_FMTTAG_REGION, address.region().toUpper() );
00155   result.replace( KABC_FMTTAG_newline, QLatin1String( "\n" ) );
00156 #undef REPLTAG
00157 
00158   // conditional comma
00159   fpos = result.indexOf( KABC_FMTTAG_condcomma, 0 );
00160   while ( -1 != fpos ) {
00161     const QString str1 = result.mid( fpos - 5, 5 );
00162     const QString str2 = result.mid( fpos + 2, 5 );
00163     if ( str1 != QLatin1String( "!_P_!" ) && str2 != QLatin1String( "!_P_!" ) ) {
00164       result.replace( fpos, 2, QLatin1String( ", " ) );
00165     } else {
00166       result.remove( fpos, 2 );
00167     }
00168     fpos = result.indexOf( KABC_FMTTAG_condcomma, fpos );
00169   }
00170   // conditional whitespace
00171   fpos = result.indexOf( KABC_FMTTAG_condwhite, 0 );
00172   while ( -1 != fpos ) {
00173     const QString str1 = result.mid( fpos - 5, 5 );
00174     const QString str2 = result.mid( fpos + 2, 5 );
00175     if ( str1 != QLatin1String( "!_P_!" ) && str2 != QLatin1String( "!_P_!" ) ) {
00176       result.replace( fpos, 2, QLatin1String( " " ) );
00177     } else {
00178       result.remove( fpos, 2 );
00179     }
00180     fpos = result.indexOf( KABC_FMTTAG_condwhite, fpos );
00181   }
00182 
00183   // remove purged:
00184   result.remove( QLatin1String( "!_P_!" ) );
00185 
00186   return ret;
00187 }
00188 
00189 class Address::Private : public QSharedData
00190 {
00191   public:
00192     Private()
00193       : mEmpty( true ), mType( 0 )
00194     {
00195       mId = KRandom::randomString( 10 );
00196     }
00197 
00198     Private( const Private &other )
00199       : QSharedData( other )
00200     {
00201       mEmpty = other.mEmpty;
00202       mId = other.mId;
00203       mType = other.mType;
00204 
00205       mPostOfficeBox = other.mPostOfficeBox;
00206       mExtended = other.mExtended;
00207       mStreet = other.mStreet;
00208       mLocality = other.mLocality;
00209       mRegion = other.mRegion;
00210       mPostalCode = other.mPostalCode;
00211       mCountry = other.mCountry;
00212       mLabel = other.mLabel;
00213     }
00214 
00215     bool mEmpty;
00216     QString mId;
00217     Type mType;
00218 
00219     QString mPostOfficeBox;
00220     QString mExtended;
00221     QString mStreet;
00222     QString mLocality;
00223     QString mRegion;
00224     QString mPostalCode;
00225     QString mCountry;
00226     QString mLabel;
00227 };
00228 
00229 Address::Address()
00230   : d( new Private )
00231 {
00232 }
00233 
00234 Address::Address( Type type )
00235   : d( new Private )
00236 {
00237   d->mType = type;
00238 }
00239 
00240 Address::Address( const Address &other )
00241   : d( other.d )
00242 {
00243 }
00244 
00245 Address::~Address()
00246 {
00247 }
00248 
00249 Address &Address::operator=( const Address &other )
00250 {
00251   if ( this != &other ) {
00252     d = other.d;
00253   }
00254 
00255   return *this;
00256 }
00257 
00258 bool Address::operator==( const Address &other ) const
00259 {
00260   if ( d->mId != other.d->mId ) {
00261     return false;
00262   }
00263   if ( d->mType != other.d->mType ) {
00264     return false;
00265   }
00266   if ( d->mPostOfficeBox != other.d->mPostOfficeBox ) {
00267     return false;
00268   }
00269   if ( d->mExtended != other.d->mExtended ) {
00270     return false;
00271   }
00272   if ( d->mStreet != other.d->mStreet ) {
00273     return false;
00274   }
00275   if ( d->mLocality != other.d->mLocality ) {
00276     return false;
00277   }
00278   if ( d->mRegion != other.d->mRegion ) {
00279     return false;
00280   }
00281   if ( d->mPostalCode != other.d->mPostalCode ) {
00282     return false;
00283   }
00284   if ( d->mCountry != other.d->mCountry ) {
00285     return false;
00286   }
00287   if ( d->mLabel != other.d->mLabel ) {
00288     return false;
00289   }
00290 
00291   return true;
00292 }
00293 
00294 bool Address::operator!=( const Address &a ) const
00295 {
00296   return !( a == *this );
00297 }
00298 
00299 bool Address::isEmpty() const
00300 {
00301   return d->mEmpty;
00302 }
00303 
00304 void Address::clear()
00305 {
00306   *this = Address();
00307 }
00308 
00309 void Address::setId( const QString &id )
00310 {
00311   d->mEmpty = false;
00312   d->mId = id;
00313 }
00314 
00315 QString Address::id() const
00316 {
00317   return d->mId;
00318 }
00319 
00320 void Address::setType( Type type )
00321 {
00322   d->mEmpty = false;
00323   d->mType = type;
00324 }
00325 
00326 Address::Type Address::type() const
00327 {
00328   return d->mType;
00329 }
00330 
00331 QString Address::typeLabel() const
00332 {
00333   QString label;
00334   bool first = true;
00335 
00336   const TypeList list = typeList();
00337 
00338   TypeList::ConstIterator it;
00339   for ( it = list.begin(); it != list.end(); ++it ) {
00340     if ( ( type() & (*it) ) && ( (*it) != Pref ) ) {
00341       if ( !first ) {
00342         label.append( QLatin1Char( '/' ) );
00343       }
00344       label.append( typeLabel( *it ) );
00345       if ( first ) {
00346         first = false;
00347       }
00348     }
00349   }
00350 
00351   return label;
00352 }
00353 
00354 void Address::setPostOfficeBox( const QString &postOfficeBox )
00355 {
00356   d->mEmpty = false;
00357   d->mPostOfficeBox = postOfficeBox;
00358 }
00359 
00360 QString Address::postOfficeBox() const
00361 {
00362   return d->mPostOfficeBox;
00363 }
00364 
00365 QString Address::postOfficeBoxLabel()
00366 {
00367   return i18n( "Post Office Box" );
00368 }
00369 
00370 void Address::setExtended( const QString &extended )
00371 {
00372   d->mEmpty = false;
00373   d->mExtended = extended;
00374 }
00375 
00376 QString Address::extended() const
00377 {
00378   return d->mExtended;
00379 }
00380 
00381 QString Address::extendedLabel()
00382 {
00383   return i18n( "Extended Address Information" );
00384 }
00385 
00386 void Address::setStreet( const QString &street )
00387 {
00388   d->mEmpty = false;
00389   d->mStreet = street;
00390 }
00391 
00392 QString Address::street() const
00393 {
00394   return d->mStreet;
00395 }
00396 
00397 QString Address::streetLabel()
00398 {
00399   return i18n( "Street" );
00400 }
00401 
00402 void Address::setLocality( const QString &locality )
00403 {
00404   d->mEmpty = false;
00405   d->mLocality = locality;
00406 }
00407 
00408 QString Address::locality() const
00409 {
00410   return d->mLocality;
00411 }
00412 
00413 QString Address::localityLabel()
00414 {
00415   return i18n( "Locality" );
00416 }
00417 
00418 void Address::setRegion( const QString &region )
00419 {
00420   d->mEmpty = false;
00421   d->mRegion = region;
00422 }
00423 
00424 QString Address::region() const
00425 {
00426   return d->mRegion;
00427 }
00428 
00429 QString Address::regionLabel()
00430 {
00431   return i18n( "Region" );
00432 }
00433 
00434 void Address::setPostalCode( const QString &postalCode )
00435 {
00436   d->mEmpty = false;
00437   d->mPostalCode = postalCode;
00438 }
00439 
00440 QString Address::postalCode() const
00441 {
00442   return d->mPostalCode;
00443 }
00444 
00445 QString Address::postalCodeLabel()
00446 {
00447   return i18n( "Postal Code" );
00448 }
00449 
00450 void Address::setCountry( const QString &country )
00451 {
00452   d->mEmpty = false;
00453   d->mCountry = country;
00454 }
00455 
00456 QString Address::country() const
00457 {
00458   return d->mCountry;
00459 }
00460 
00461 QString Address::countryLabel()
00462 {
00463   return i18n( "Country" );
00464 }
00465 
00466 void Address::setLabel( const QString &label )
00467 {
00468   d->mEmpty = false;
00469   d->mLabel = label;
00470 }
00471 
00472 QString Address::label() const
00473 {
00474   return d->mLabel;
00475 }
00476 
00477 QString Address::labelLabel()
00478 {
00479   return i18n( "Delivery Label" );
00480 }
00481 
00482 Address::TypeList Address::typeList()
00483 {
00484   static TypeList list;
00485 
00486   if ( list.isEmpty() ) {
00487     list << Dom << Intl << Postal << Parcel << Home << Work << Pref;
00488   }
00489 
00490   return list;
00491 }
00492 
00493 QString Address::typeLabel( Type type )
00494 {
00495   if ( type & Pref ) {
00496     return i18nc( "Preferred address", "Preferred" );
00497   }
00498 
00499   switch ( type ) {
00500     case Dom:
00501       return i18nc( "Address is in home country", "Domestic" );
00502       break;
00503     case Intl:
00504       return i18nc( "Address is not in home country", "International" );
00505       break;
00506     case Postal:
00507       return i18nc( "Address for delivering letters", "Postal" );
00508       break;
00509     case Parcel:
00510       return i18nc( "Address for delivering packages", "Parcel" );
00511       break;
00512     case Home:
00513       return i18nc( "Home Address", "Home" );
00514       break;
00515     case Work:
00516       return i18nc( "Work Address", "Work" );
00517       break;
00518     case Pref:
00519       return i18n( "Preferred Address" );
00520       break;
00521     default:
00522       return i18nc( "another type of address", "Other" );
00523       break;
00524   }
00525 }
00526 
00527 QString Address::toString() const
00528 {
00529   QString str;
00530 
00531   str += QLatin1String( "Address {\n" );
00532   str += QString::fromLatin1( "  IsEmpty: %1\n" ).
00533          arg( d->mEmpty ? QLatin1String( "true" ) : QLatin1String( "false" ) );
00534   str += QString::fromLatin1( "  Id: %1\n" ).arg( d->mId );
00535   str += QString::fromLatin1( "  Type: %1\n" ).arg( typeLabel( d->mType ) );
00536   str += QString::fromLatin1( "  Post office box: %1\n" ).arg( d->mPostOfficeBox );
00537   str += QString::fromLatin1( "  Extended: %1\n" ).arg( d->mExtended );
00538   str += QString::fromLatin1( "  Street: %1\n" ).arg( d->mStreet );
00539   str += QString::fromLatin1( "  Locality: %1\n" ).arg( d->mLocality );
00540   str += QString::fromLatin1( "  Region: %1\n" ).arg( d->mRegion );
00541   str += QString::fromLatin1( "  Postal code: %1\n" ).arg( d->mPostalCode );
00542   str += QString::fromLatin1( "  Country: %1\n" ).arg( d->mCountry );
00543   str += QString::fromLatin1( "  Label: %1\n" ).arg( d->mLabel );
00544   str += QLatin1String( "}\n" );
00545 
00546   return str;
00547 }
00548 
00549 QString Address::formattedAddress( const QString &realName,
00550                                    const QString &orgaName ) const
00551 {
00552   QString ciso;
00553   QString addrTemplate;
00554   QString ret;
00555 
00556   // FIXME: first check for iso-country-field and prefer that one
00557   if ( !country().isEmpty() ) {
00558     ciso = countryToISO( country() );
00559   } else {
00560     // fall back to our own country
00561     ciso = KGlobal::locale()->country();
00562   }
00563   KConfig entry( KStandardDirs::locate( "locale",
00564         QLatin1String( "l10n/" ) + ciso + QLatin1String( "/entry.desktop" ) ) );
00565 
00566   KConfigGroup group = entry.group( "KCM Locale" );
00567   // decide whether this needs special business address formatting
00568   if ( orgaName.isEmpty() ) {
00569     addrTemplate = group.readEntry( "AddressFormat" );
00570   } else {
00571     addrTemplate = group.readEntry( "BusinessAddressFormat" );
00572     if ( addrTemplate.isEmpty() ) {
00573       addrTemplate = group.readEntry( "AddressFormat" );
00574     }
00575   }
00576 
00577   // in the case there's no format found at all, default to what we've always
00578   // used:
00579   if ( addrTemplate.isEmpty() ) {
00580     kWarning(5700) << "address format database incomplete"
00581         << "(no format for locale" << ciso
00582         << "found). Using default address formatting.";
00583     addrTemplate = QLatin1String( "%0(%n\\n)%0(%cm\\n)%0(%s\\n)%0(PO BOX %p\\n)%0(%l%w%r)%,%z" );
00584   }
00585 
00586   // scan
00587   parseAddressTemplateSection( addrTemplate, ret, realName, orgaName, *this );
00588 
00589   // now add the country line if needed (formatting this time according to
00590   // the rules of our own system country )
00591   if ( !country().isEmpty() ) {
00592     KConfig entry( KStandardDirs::locate( "locale", QLatin1String( "l10n/" ) +
00593                                           KGlobal::locale()->country() +
00594                                           QLatin1String( "/entry.desktop" ) ) );
00595     KConfigGroup group = entry.group( "KCM Locale" );
00596     QString cpos = group.readEntry( "AddressCountryPosition" );
00597     if ( QLatin1String( "BELOW" ) == cpos || cpos.isEmpty() ) {
00598       ret = ret + QLatin1String( "\n\n" ) + country().toUpper();
00599     } else if ( QLatin1String( "below" ) == cpos ) {
00600       ret = ret + QLatin1String( "\n\n" ) + country();
00601     } else if ( QLatin1String( "ABOVE" ) == cpos ) {
00602       ret = country().toUpper() + QLatin1String( "\n\n" ) + ret;
00603     } else if ( QLatin1String( "above" ) == cpos ) {
00604       ret = country() + QLatin1String( "\n\n" ) + ret;
00605     }
00606   }
00607 
00608   return ret;
00609 }
00610 
00611 QString Address::countryToISO( const QString &cname )
00612 {
00613   // we search a map file for translations from country names to
00614   // iso codes, storing caching things in a QMap for faster future
00615   // access.
00616   typedef QMap<QString, QString> stringMap;
00617   K_GLOBAL_STATIC( stringMap, sISOMap )
00618 
00619   QMap<QString, QString>::ConstIterator it;
00620   it = sISOMap->constFind( cname );
00621   if ( it != sISOMap->constEnd() ) {
00622     return it.value();
00623   }
00624 
00625   QString mapfile = KGlobal::dirs()->findResource( "data",
00626           QLatin1String( "kabc/countrytransl.map" ) );
00627 
00628   QFile file( mapfile );
00629   if ( file.open( QIODevice::ReadOnly ) ) {
00630     QTextStream s( &file );
00631     QString strbuf = s.readLine();
00632     while ( !strbuf.isEmpty() ) {
00633       QStringList countryInfo = strbuf.split( QLatin1Char( '\t' ), QString::KeepEmptyParts );
00634       if ( countryInfo[ 0 ] == cname ) {
00635         file.close();
00636         sISOMap->insert( cname, countryInfo[ 1 ] );
00637         return countryInfo[ 1 ];
00638       }
00639       strbuf = s.readLine();
00640     }
00641     file.close();
00642   }
00643 
00644   // fall back to system country
00645   sISOMap->insert( cname, KGlobal::locale()->country() );
00646   return KGlobal::locale()->country();
00647 }
00648 
00649 QString Address::ISOtoCountry( const QString &ISOname )
00650 {
00651   // get country name from ISO country code (e.g. "no" -> i18n("Norway"))
00652   if ( ISOname.simplified().isEmpty() ) {
00653     return QString();
00654   }
00655 
00656   QString mapfile = KGlobal::dirs()->findResource( "data",
00657           QLatin1String( "kabc/countrytransl.map" ) );
00658 
00659   QFile file( mapfile );
00660   if ( file.open( QIODevice::ReadOnly ) ) {
00661     QTextStream s( &file );
00662     QString searchStr = QLatin1Char( '\t' ) + ISOname.simplified().toLower();
00663     QString strbuf = s.readLine();
00664     int pos;
00665     while ( !strbuf.isEmpty() ) {
00666       if ( ( pos = strbuf.indexOf( searchStr ) ) != -1 ) {
00667         file.close();
00668         return i18n( strbuf.left( pos ).toUtf8() );
00669       }
00670       strbuf = s.readLine();
00671     }
00672     file.close();
00673   }
00674 
00675   return ISOname;
00676 }
00677 
00678 QDataStream &KABC::operator<<( QDataStream &s, const Address &addr )
00679 {
00680   return s << addr.d->mId << (uint)addr.d->mType << addr.d->mPostOfficeBox
00681            << addr.d->mExtended << addr.d->mStreet << addr.d->mLocality
00682            << addr.d->mRegion << addr.d->mPostalCode << addr.d->mCountry
00683            << addr.d->mLabel << addr.d->mEmpty;
00684 }
00685 
00686 QDataStream &KABC::operator>>( QDataStream &s, Address &addr )
00687 {
00688   uint type;
00689   s >> addr.d->mId >> type >> addr.d->mPostOfficeBox >> addr.d->mExtended
00690     >> addr.d->mStreet >> addr.d->mLocality >> addr.d->mRegion
00691     >> addr.d->mPostalCode >> addr.d->mCountry >> addr.d->mLabel
00692     >> addr.d->mEmpty;
00693 
00694   addr.d->mType = Address::Type( type );
00695 
00696   return s;
00697 }

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
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  • kldap
  • kmime
  • kpimidentities
  • kpimtextedit
  •   richtextbuilders
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Generated for KDE-PIM Libraries by doxygen 1.6.1
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