• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • kdepim
  • Sitemap
  • Contact Us
 

console/kabcclient

kabcclient.cpp

Go to the documentation of this file.
00001 //
00002 //  Copyright (C) 2005 - 2008 Kevin Krammer <kevin.krammer@gmx.at>
00003 //  Copyright (C) 2005 Tobias Koenig <tokoe@kde.org>
00004 //
00005 //  This program is free software; you can redistribute it and/or modify
00006 //  it under the terms of the GNU General Public License as published by
00007 //  the Free Software Foundation; either version 2 of the License, or
00008 //  (at your option) any later version.
00009 //
00010 //  This program 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
00013 //  GNU General Public License for more details.
00014 //
00015 //  You should have received a copy of the GNU General Public License
00016 //  along with this program; if not, write to the Free Software
00017 //  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00018 //
00019 
00020 // local includes
00021 #include "kabcclient.h"
00022 #include "formatfactory.h"
00023 #include "inputformat.h"
00024 #include "outputformat.h"
00025 
00026 // standard includes
00027 #include <iostream>
00028 #include <set>
00029 #include <string>
00030 
00031 // Qt includes
00032 #include <QtCore/QTextCodec>
00033 #include <QtCore/QTimer>
00034 
00035 // KDE includes
00036 #include <kapplication.h>
00037 #include <klocale.h>
00038 #include <krandom.h>
00039 
00040 // KABC includes
00041 #include <kabc/addressee.h>
00042 #include <kabc/addresseelist.h>
00043 #include <kabc/stdaddressbook.h>
00044 
00045 using namespace KABC;
00046 
00047 // error messages
00048 static const char saveError[] = I18N_NOOP("Saving modifications to addressbook failed");
00049 static const char ambiguousMatch[] = I18N_NOOP("Input number %1 matches more than one contact. "
00050                                                "Skipping it to avoid undesired results");
00051 
00053 
00054 KABCClient::KABCClient(Operation operation, FormatFactory* factory)
00055     : QObject(0),
00056       m_operation(operation),
00057       m_formatFactory(factory),
00058       m_inputFormat(0),
00059       m_outputFormat(0),
00060       m_inputCodec(0),
00061       m_outputCodec(0),
00062       m_addressBook(0),
00063       m_inputStream(0),
00064       m_matchCaseSensitivity(Qt::CaseInsensitive),
00065       m_allowSaving(true)
00066 {
00067 }
00068 
00070 
00071 KABCClient::~KABCClient()
00072 {
00073     delete m_inputFormat;
00074     delete m_outputFormat;
00075 }
00076 
00078 
00079 bool KABCClient::setInputFormat(const QByteArray& name)
00080 {
00081     switch (m_operation)
00082     {
00083         // no formatted input
00084         case List:
00085             return true;
00086 
00087         case Add:
00088         case Merge:
00089             if (name == "uid" || name == "search" || name == "dialog")
00090             {
00091                 QString operation = QString::fromUtf8(m_operation == Add ? "add" : "merge");
00092                 QString error = i18n("Input format '%1' not usable with operation '%2'",
00093                                      QString::fromLocal8Bit(name), operation);
00094                 std::cerr << error.toLocal8Bit().data();
00095                 std::cerr << std::endl;
00096                 return false;
00097             }
00098 
00099         default:
00100             break;
00101     }
00102 
00103     m_inputFormat = m_formatFactory->inputFormat(name);
00104 
00105     return m_inputFormat != 0;
00106 }
00107 
00109 
00110 bool KABCClient::setOutputFormat(const QByteArray& name)
00111 {
00112     m_outputFormat = m_formatFactory->outputFormat(name);
00113 
00114     return m_outputFormat != 0;
00115 }
00116 
00118 
00119 bool KABCClient::setInputOptions(const QByteArray& options)
00120 {
00121     if (m_operation == List) return true;
00122 
00123     if (m_inputFormat == 0) return false;
00124 
00125     return m_inputFormat->setOptions(options);
00126 }
00127 
00129 
00130 bool KABCClient::setOutputOptions(const QByteArray& options)
00131 {
00132     if (m_outputFormat == 0) return false;
00133 
00134     return m_outputFormat->setOptions(options);
00135 }
00136 
00138 
00139 bool KABCClient::setInputCodec(const QByteArray& name)
00140 {
00141     if (m_operation == List) return true; // no input -> no input codec
00142 
00143     if (m_inputFormat == 0) return false;
00144 
00145     m_inputCodec = codecForName(name);
00146 
00147     if (m_inputCodec == 0) return false;
00148 
00149     return m_inputFormat->setCodec(m_inputCodec);
00150 }
00151 
00153 
00154 bool KABCClient::setOutputCodec(const QByteArray& name)
00155 {
00156     if (m_outputFormat == 0) return false;
00157 
00158     m_outputCodec = codecForName(name);
00159 
00160     if (m_outputCodec == 0) return false;
00161 
00162     return m_outputFormat->setCodec(m_outputCodec);
00163 }
00164 
00166 
00167 void KABCClient::setInputStream(std::istream* stream)
00168 {
00169     m_inputStream = stream;
00170 }
00171 
00173 
00174 bool KABCClient::initOperation()
00175 {
00176     if (m_inputStream == 0 && m_operation != List) return false;
00177 
00178 //  Async Loading and starting operation of signal does not work
00179 //  in case no resources can be loaded and a new standard resource is created
00180 //  because in this case AddressBook doesn't emit signals :(
00181 //  Workaround by loading synchronous and having the slot called by a
00182 //  single shot timer
00183 
00184 //     m_addressBook = KABC::StdAddressBook::self(true);
00185     m_addressBook = KABC::StdAddressBook::self(false);
00186     if (m_addressBook == 0) return false;
00187 
00188     KABC::StdAddressBook::setAutomaticSave(false);
00189 
00190 //     QObject::connect(m_addressBook, SIGNAL(addressBookChanged(AddressBook*)),
00191 //                      this, SLOT(slotAddressBookLoaded()));
00192     QTimer::singleShot(0, this, SLOT(slotAddressBookLoaded()));
00193 
00194     return true;
00195 }
00196 
00198 
00199 int KABCClient::performAdd()
00200 {
00201     // create a set of all currently existing UIDs
00202     std::set<QString> uids;
00203     AddressBook::ConstIterator it    = m_addressBook->begin();
00204     AddressBook::ConstIterator endIt = m_addressBook->end();
00205     for (; it != endIt; ++it)
00206     {
00207         uids.insert((*it).uid());
00208     }
00209 
00210     bool wantSave = false;
00211     while (!m_inputStream->bad() && !m_inputStream->eof())
00212     {
00213         Addressee addressee = m_inputFormat->readAddressee(*m_inputStream);
00214         if (addressee.isEmpty()) continue;
00215 
00216         // make sure we really append and don't overwrite
00217         if (addressee.uid().isEmpty() || uids.find(addressee.uid()) != uids.end())
00218         {
00219             addressee.setUid(KRandom::randomString(10));
00220             uids.insert(addressee.uid());
00221         }
00222 
00223         m_addressBook->insertAddressee(addressee);
00224         wantSave = true;
00225 
00226         m_outputFormat->writeAddressee(addressee, std::cout);
00227         std::cout << std::endl;
00228     }
00229 
00230     if (!wantSave) return 2; // nothing added
00231 
00232     if (m_allowSaving)
00233     {
00234         Ticket* saveTicket = m_addressBook->requestSaveTicket();
00235         if (saveTicket == 0)
00236         {
00237             std::cerr << i18n(saveError).toLocal8Bit().data() << std::endl;
00238             return 3;
00239         }
00240 
00241         bool saved = m_addressBook->save(saveTicket);
00242 
00243         if (!saved)
00244         {
00245             std::cerr << i18n(saveError).toLocal8Bit().data() << std::endl;
00246             return 3;
00247         }
00248     }
00249 
00250     return (m_inputStream->bad() ? 1 : 0);
00251 }
00252 
00254 
00255 int KABCClient::performRemove()
00256 {
00257     bool wantSave = false;
00258 
00259     uint count = 0;
00260     while (!m_inputStream->bad() && !m_inputStream->eof())
00261     {
00262         Addressee search = m_inputFormat->readAddressee(*m_inputStream);
00263         if (search.isEmpty()) continue;
00264 
00265         count++;
00266 
00267         AddresseeList result;
00268 
00269         AddressBook::ConstIterator it    = m_addressBook->begin();
00270         AddressBook::ConstIterator endIt = m_addressBook->end();
00271         for (; it != endIt; ++it)
00272         {
00273             if (!search.uid().isEmpty() && (*it).uid() == search.uid())
00274             {
00275                 result.append(*it);
00276             }
00277             else if (!search.realName().isEmpty() &&
00278                      (*it).realName().indexOf(search.realName(), 0, m_matchCaseSensitivity) != -1)
00279             {
00280                 result.append(*it);
00281             }
00282             else if (!search.familyName().isEmpty() &&
00283                      (*it).realName().indexOf(search.familyName(), 0, m_matchCaseSensitivity) != -1)
00284             {
00285                 if (!search.givenName().isEmpty())
00286                 {
00287                     if ((*it).realName().indexOf(search.givenName(), 0, m_matchCaseSensitivity) != -1)
00288                     {
00289                         result.append(*it);
00290                     }
00291                 }
00292                 else
00293                     result.append(*it);
00294             }
00295             else if (!search.givenName().isEmpty() &&
00296                      (*it).realName().indexOf(search.givenName(), 0, m_matchCaseSensitivity) != -1)
00297             {
00298                 result.append(*it);
00299             }
00300             else if (!search.preferredEmail().isEmpty())
00301             {
00302                 QStringList matches =
00303                     (*it).emails().filter(search.preferredEmail(), m_matchCaseSensitivity);
00304                 if (matches.count() > 0)
00305                 {
00306                     result.append(*it);
00307                 }
00308             }
00309 
00310             if (result.count() > 1) break;
00311         }
00312 
00313         // only work with unambiguous matches
00314         if (result.count() == 1)
00315         {
00316             m_addressBook->removeAddressee(result[0]);
00317             wantSave = true;
00318 
00319             m_outputFormat->writeAddressee(result[0], std::cout);
00320             std::cout << std::endl;
00321         }
00322         else if (result.count() > 1)
00323         {
00324             std::cerr << i18n(ambiguousMatch).arg(count).toLocal8Bit().data() << std::endl;
00325         }
00326     }
00327 
00328     if (!wantSave) return 2; // nothing removed
00329 
00330     if (m_allowSaving)
00331     {
00332         Ticket* saveTicket = m_addressBook->requestSaveTicket();
00333         if (saveTicket == 0)
00334         {
00335             std::cerr << i18n(saveError).toLocal8Bit().data() << std::endl;
00336             return 3;
00337         }
00338 
00339         bool saved = m_addressBook->save(saveTicket);
00340 
00341         if (!saved)
00342         {
00343             std::cerr << i18n(saveError).toLocal8Bit().data() << std::endl;
00344             return 3;
00345         }
00346     }
00347 
00348     return (m_inputStream->bad() ? 1 : 0);
00349 }
00350 
00352 
00353 int KABCClient::performMerge()
00354 {
00355     bool wantSave = false;
00356 
00357     uint count = 0;
00358     while (!m_inputStream->bad() && !m_inputStream->eof())
00359     {
00360         Addressee addressee = m_inputFormat->readAddressee(*m_inputStream);
00361         if (addressee.isEmpty()) continue;
00362 
00363         count++;
00364 
00365         AddresseeList result;
00366 
00367         AddressBook::ConstIterator it    = m_addressBook->begin();
00368         AddressBook::ConstIterator endIt = m_addressBook->end();
00369         for (; it != endIt; ++it)
00370         {
00371             if (!addressee.uid().isEmpty() && (*it).uid() == addressee.uid())
00372             {
00373                 result.append(*it);
00374             }
00375             else if (!addressee.realName().isEmpty() &&
00376                      (*it).realName().indexOf(addressee.realName(), 0, m_matchCaseSensitivity) != -1)
00377             {
00378                 result.append(*it);
00379             }
00380             else if (!addressee.familyName().isEmpty() &&
00381                      (*it).realName().indexOf(addressee.familyName(), 0, m_matchCaseSensitivity) != -1)
00382             {
00383                 if (!addressee.givenName().isEmpty())
00384                 {
00385                     if ((*it).realName().indexOf(addressee.givenName(),
00386                                               0, m_matchCaseSensitivity) != -1)
00387                     {
00388                         result.append(*it);
00389                     }
00390                 }
00391                 else
00392                     result.append(*it);
00393             }
00394             else if (!addressee.givenName().isEmpty() &&
00395                      (*it).realName().indexOf(addressee.givenName(), 0, m_matchCaseSensitivity) != -1)
00396             {
00397                 result.append(*it);
00398             }
00399             else if (!addressee.preferredEmail().isEmpty())
00400             {
00401                 QStringList matches =
00402                     (*it).emails().filter(addressee.preferredEmail(), m_matchCaseSensitivity);
00403                 if (matches.count() > 0)
00404                 {
00405                     result.append(*it);
00406                 }
00407             }
00408 
00409             if (result.count() > 1) break;
00410         }
00411 
00412         // only work with unambiguous matches
00413         if (result.count() == 1)
00414         {
00415             Addressee master = result[0];
00416             mergeAddressees(master, addressee);
00417 
00418             m_addressBook->insertAddressee(master);
00419             wantSave = true;
00420 
00421             m_outputFormat->writeAddressee(master, std::cout);
00422             std::cout << std::endl;
00423         }
00424         else if (result.count() > 1)
00425         {
00426             std::cerr << i18n(ambiguousMatch).arg(count).toLocal8Bit().data() << std::endl;
00427         }
00428     }
00429 
00430     if (!wantSave) return 2; // nothing merged
00431 
00432     if (m_allowSaving)
00433     {
00434         Ticket* saveTicket = m_addressBook->requestSaveTicket();
00435         if (saveTicket == 0)
00436         {
00437             std::cerr << i18n(saveError).toLocal8Bit().data() << std::endl;
00438             return 3;
00439         }
00440 
00441         bool saved = m_addressBook->save(saveTicket);
00442 
00443         if (!saved)
00444         {
00445             std::cerr << i18n(saveError).toLocal8Bit().data() << std::endl;
00446             return 3;
00447         }
00448     }
00449 
00450     return (m_inputStream->bad() ? 1 : 0);
00451 }
00452 
00454 
00455 int KABCClient::performList()
00456 {
00457     AddresseeList list = m_addressBook->allAddressees();
00458 
00459     return m_outputFormat->writeAddresseeList(list, std::cout) ? 0 : 1;
00460 }
00461 
00463 
00464 int KABCClient::performSearch()
00465 {
00466     int resultValue = 2; // i.e. search didn't find any match
00467 
00468     AddressBook::ConstIterator endIt = m_addressBook->end();
00469 
00470     while (!m_inputStream->bad() && !m_inputStream->eof())
00471     {
00472         Addressee search = m_inputFormat->readAddressee(*m_inputStream);
00473         if (search.isEmpty()) continue;
00474 
00475         AddresseeList result;
00476 
00477         AddressBook::ConstIterator it = m_addressBook->begin();
00478         for (; it != endIt; ++it)
00479         {
00480             if (!search.uid().isEmpty() && (*it).uid() == search.uid())
00481             {
00482                 result.append(*it);
00483             }
00484             else if (!search.realName().isEmpty() &&
00485                      (*it).realName().indexOf(search.realName(), 0, m_matchCaseSensitivity) != -1)
00486             {
00487                 result.append(*it);
00488             }
00489             else if (!search.familyName().isEmpty() &&
00490                      (*it).realName().indexOf(search.familyName(), 0, m_matchCaseSensitivity) != -1)
00491             {
00492                 if (!search.givenName().isEmpty())
00493                 {
00494                     if ((*it).realName().indexOf(search.givenName(), 0, m_matchCaseSensitivity) != -1)
00495                     {
00496                         result.append(*it);
00497                     }
00498                 }
00499                 else
00500                     result.append(*it);
00501             }
00502             else if (!search.givenName().isEmpty() &&
00503                      (*it).realName().indexOf(search.givenName(), 0, m_matchCaseSensitivity) != -1)
00504             {
00505                 result.append(*it);
00506             }
00507             else if (!search.preferredEmail().isEmpty())
00508             {
00509                 QStringList matches =
00510                     (*it).emails().filter(search.preferredEmail(), m_matchCaseSensitivity);
00511                 if (matches.count() > 0)
00512                 {
00513                     result.append(*it);
00514                 }
00515             }
00516         }
00517 
00518         if (result.count() > 0)
00519         {
00520             resultValue = 0;
00521 
00522             if (!m_outputFormat->writeAddresseeList(result, std::cout))
00523             {
00524                 return 1;
00525             }
00526         }
00527     }
00528 
00529     return resultValue;
00530 }
00531 
00533 // taken from KAddressBook/KABCTools (c) Tobias Koenig
00534 
00535 void KABCClient::mergePictures(KABC::Picture& master, const KABC::Picture slave)
00536 {
00537     if (master.isIntern())
00538     {
00539         if (master.data().isNull())
00540         {
00541             if (slave.isIntern() && !slave.data().isNull())
00542                 master.setData(slave.data());
00543             else if (!slave.isIntern() && !slave.url().isEmpty())
00544                 master.setUrl(slave.url());
00545         }
00546     }
00547     else
00548     {
00549         if (master.url().isEmpty())
00550         {
00551             if (slave.isIntern() && !slave.data().isNull())
00552                 master.setData( slave.data() );
00553             else if (!slave.isIntern() && !slave.url().isEmpty())
00554                 master.setUrl(slave.url());
00555         }
00556     }
00557 }
00558 
00560 // derived from KAddressBook/KABCTools::mergeContacts (c) Tobias Koenig
00561 
00562 void KABCClient::mergeAddressees(KABC::Addressee& master, const KABC::Addressee& slave)
00563 {
00564     if (slave.isEmpty()) return;
00565 
00566     // ADR + LABEL
00567     const KABC::Address::List addresses = slave.addresses();
00568     KABC::Address::List masterAddresses = master.addresses();
00569     KABC::Address::List::ConstIterator addrIt ;
00570     for (addrIt = addresses.begin(); addrIt != addresses.end(); ++addrIt)
00571     {
00572         if (!masterAddresses.contains(*addrIt))
00573             master.insertAddress(*addrIt);
00574     }
00575 
00576     // BIRTHDAY
00577     if (master.birthday().isNull() && !slave.birthday().isNull())
00578         master.setBirthday(slave.birthday());
00579 
00580     // CATEGORIES
00581     const QStringList categories       = slave.categories();
00582     const QStringList masterCategories = master.categories();
00583 
00584     QStringList newCategories = masterCategories;
00585     QStringList::ConstIterator it;
00586     for (it = categories.begin(); it != categories.end(); ++it)
00587     {
00588         if (!masterCategories.contains(*it))
00589             newCategories.append(*it);
00590     }
00591     master.setCategories(newCategories);
00592 
00593     // CLASS
00594     if (!master.secrecy().isValid() && slave.secrecy().isValid())
00595         master.setSecrecy(slave.secrecy());
00596 
00597     // EMAIL
00598     const QStringList emails       = slave.emails();
00599     const QStringList masterEmails = master.emails();
00600 
00601     for (it = emails.begin(); it != emails.end(); ++it)
00602     {
00603         if (!masterEmails.contains(*it))
00604             master.insertEmail(*it, false);
00605     }
00606 
00607     // FN
00608     if (master.formattedName().isEmpty() && !slave.formattedName().isEmpty())
00609         master.setFormattedName(slave.formattedName());
00610 
00611     // GEO
00612     if (!master.geo().isValid() && slave.geo().isValid())
00613         master.setGeo(slave.geo());
00614 
00615     /*
00616     // KEY
00617     */
00618     // LOGO
00619     KABC::Picture logo = master.logo();
00620     mergePictures(logo, slave.logo());
00621     master.setLogo(logo);
00622 
00623     // MAILER
00624     if (master.mailer().isEmpty() && !slave.mailer().isEmpty())
00625         master.setMailer(slave.mailer());
00626 
00627     // N
00628     if (master.assembledName().isEmpty() && !slave.assembledName().isEmpty())
00629         master.setNameFromString(slave.assembledName());
00630 
00631     // NICKNAME
00632     if (master.nickName().isEmpty() && !slave.nickName().isEmpty())
00633         master.setNickName(slave.nickName());
00634 
00635     // NOTE
00636     if (master.note().isEmpty() && !slave.note().isEmpty())
00637         master.setNote(slave.note());
00638 
00639     // ORG
00640     if (master.organization().isEmpty() && !slave.organization().isEmpty())
00641         master.setOrganization(slave.organization());
00642 
00643     // PHOTO
00644     KABC::Picture photo = master.photo();
00645     mergePictures(photo, slave.photo());
00646     master.setPhoto( photo );
00647 
00648     // PROID
00649     if (master.productId().isEmpty() && !slave.productId().isEmpty())
00650         master.setProductId(slave.productId());
00651 
00652     // REV
00653     if (master.revision().isNull() && !slave.revision().isNull())
00654         master.setRevision(slave.revision());
00655 
00656     // ROLE
00657     if (master.role().isEmpty() && !slave.role().isEmpty())
00658         master.setRole(slave.role());
00659 
00660     // SORT-STRING
00661     if (master.sortString().isEmpty() && !slave.sortString().isEmpty())
00662         master.setSortString(slave.sortString());
00663 
00664     /*
00665     // SOUND
00666     */
00667 
00668     // TEL
00669     const KABC::PhoneNumber::List phones       = slave.phoneNumbers();
00670     const KABC::PhoneNumber::List masterPhones = master.phoneNumbers();
00671 
00672     KABC::PhoneNumber::List::ConstIterator phoneIt;
00673     for (phoneIt = phones.begin(); phoneIt != phones.end(); ++phoneIt)
00674     {
00675         if (!masterPhones.contains(*phoneIt))
00676             master.insertPhoneNumber(*phoneIt);
00677     }
00678 
00679     // TITLE
00680     if (master.title().isEmpty() && !slave.title().isEmpty())
00681         master.setTitle(slave.title());
00682 
00683     // TZ
00684     if (!master.timeZone().isValid() && slave.timeZone().isValid())
00685         master.setTimeZone(slave.timeZone());
00686 
00687     // ignore UID we keep the master's one
00688 
00689     // URL
00690     if (master.url().isEmpty() && !slave.url().isEmpty())
00691         master.setUrl(slave.url());
00692 
00693     // X-
00694     const QStringList customs       = slave.customs();
00695     const QStringList masterCustoms = master.customs();
00696 
00697     QStringList newCustoms = masterCustoms;
00698     for (it = customs.begin(); it != customs.end(); ++it)
00699     {
00700         if (!masterCustoms.contains(*it))
00701             newCustoms.append(*it);
00702     }
00703     master.setCustoms(newCustoms);
00704 }
00705 
00707 
00708 QTextCodec* KABCClient::codecForName(const QByteArray& name)
00709 {
00710     if (name.isEmpty()) return 0;
00711 
00712     if (name.toLower() == "utf-8" || name.toLower() == "utf8" || name == "utf")
00713     {
00714         return QTextCodec::codecForName("UTF-8");
00715     }
00716 
00717     if (name.toLower() == "local" || name.toLower() == "locale")
00718     {
00719         return QTextCodec::codecForLocale();
00720     }
00721 
00722     return QTextCodec::codecForName(name.toUpper());
00723 }
00724 
00726 
00727 void KABCClient::slotAddressBookLoaded()
00728 {
00729     // disconnect so we are not disturbed during operations
00730     QObject::disconnect(m_addressBook, SIGNAL(addressBookChanged(AddressBook*)),
00731                         this, SLOT(slotAddressBookLoaded()));
00732 
00733     int result = 1;
00734 
00735     switch (m_operation)
00736     {
00737         case Add:
00738             result = performAdd();
00739             break;
00740 
00741         case Remove:
00742             result = performRemove();
00743             break;
00744 
00745         case Merge:
00746             result = performMerge();
00747             break;
00748 
00749         case List:
00750             result = performList();
00751             break;
00752 
00753         case Search:
00754             result = performSearch();
00755             break;
00756 
00757         default:
00758             break;
00759     }
00760 
00761     KApplication::kApplication()->exit(result);
00762 }
00763 
00764 // End of file
00765 
00766 #include "kabcclient.moc"

console/kabcclient

Skip menu "console/kabcclient"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members
  • Related Pages

kdepim

Skip menu "kdepim"
  • akonadi
  •   clients
  •   kabc
  •   kcal
  •   kcm
  • akregator
  • console
  •   kabcclient
  •   konsolekalendar
  • kaddressbook
  • kalarm
  •   lib
  • kdgantt
  • kdgantt1
  • kjots
  • kleopatra
  • kmail
  • kmobiletools
  • knode
  • knotes
  • kontact
  • kontactinterfaces
  • korganizer
  •   korgac
  • kpilot
  • ktimetracker
  • libkdepim
  • libkholidays
  • libkleo
  • libkpgp
  • maildir
Generated for kdepim by doxygen 1.5.4
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