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

kmail

kmacctimap.cpp

Go to the documentation of this file.
00001 
00023 #include "kmacctimap.h"
00024 
00025 using KMail::SieveConfig;
00026 
00027 #include "kmmessage.h"
00028 #include "broadcaststatus.h"
00029 using KPIM::BroadcastStatus;
00030 #include "kmfoldertree.h"
00031 #include "kmfoldermgr.h"
00032 #include "kmfolderimap.h"
00033 #include "kmmainwin.h"
00034 #include "kmmsgdict.h"
00035 #include "kmfilter.h"
00036 #include "kmfiltermgr.h"
00037 #include "folderstorage.h"
00038 #include "imapjob.h"
00039 #include "actionscheduler.h"
00040 using KMail::ActionScheduler;
00041 using KMail::ImapJob;
00042 using KMail::ImapAccountBase;
00043 #include "progressmanager.h"
00044 using KPIM::ProgressItem;
00045 using KPIM::ProgressManager;
00046 
00047 #include <kio/scheduler.h>
00048 #include <kio/slave.h>
00049 #include <kmessagebox.h>
00050 #include <kdebug.h>
00051 #include <qtextdocument.h>
00052 
00053 #include <QList>
00054 
00055 #include <errno.h>
00056 
00057 //-----------------------------------------------------------------------------
00058 KMAcctImap::KMAcctImap(AccountManager* aOwner, const QString& aAccountName, uint id):
00059   KMail::ImapAccountBase(aOwner, aAccountName, id),
00060   mCountRemainChecks( 0 )
00061 {
00062   mFolder = 0;
00063   mScheduler = 0;
00064   mNoopTimer.start( 60000 ); // // send a noop every minute
00065   connect(kmkernel->imapFolderMgr(), SIGNAL(changed()),
00066       this, SLOT(slotUpdateFolderList()));
00067   mErrorTimer.setSingleShot( true );
00068   connect(&mErrorTimer, SIGNAL(timeout()), SLOT(slotResetConnectionError()));
00069 
00070   QString serNumUri = KStandardDirs::locateLocal( "data", "kmail/unfiltered." +
00071                                             QString("%1").arg(KAccount::id()) );
00072   KConfig config( serNumUri );
00073   QStringList serNums =
00074       config.group("<default>").readEntry( "unfiltered", QStringList() );
00075 
00076   for ( QStringList::ConstIterator it = serNums.begin();
00077     it != serNums.end(); ++it ) {
00078       mFilterSerNums.append( (*it).toUInt() );
00079       mFilterSerNumsToSave.insert( *it, 1 );
00080     }
00081 }
00082 
00083 
00084 //-----------------------------------------------------------------------------
00085 KMAcctImap::~KMAcctImap()
00086 {
00087   killAllJobs( true );
00088 
00089   QString serNumUri = KStandardDirs::locateLocal( "data", "kmail/unfiltered." +
00090                                             QString("%1").arg(KAccount::id()) );
00091   KConfig config( serNumUri );
00092   QStringList serNums;
00093   QHashIterator<QString, int> it( mFilterSerNumsToSave );
00094   while ( it.hasNext() ) {
00095     serNums.append( it.key() );
00096   }
00097   config.group("<default>").writeEntry( "unfiltered", serNums );
00098   qDeleteAll( mOpenFolders );
00099 }
00100 
00101 //-----------------------------------------------------------------------------
00102 void KMAcctImap::pseudoAssign( const KMAccount * a ) {
00103   killAllJobs( true );
00104   if (mFolder)
00105   {
00106     mFolder->setContentState(KMFolderImap::imapNoInformation);
00107     mFolder->setSubfolderState(KMFolderImap::imapNoInformation);
00108   }
00109   ImapAccountBase::pseudoAssign( a );
00110 }
00111 
00112 //-----------------------------------------------------------------------------
00113 void KMAcctImap::setImapFolder(KMFolderImap *aFolder)
00114 {
00115   mFolder = aFolder;
00116   mFolder->setImapPath( "/" );
00117 }
00118 
00119 
00120 //-----------------------------------------------------------------------------
00121 
00122 bool KMAcctImap::handleError( int errorCode, const QString &errorMsg, KIO::Job* job, const QString& context, bool abortSync )
00123 {
00124   /* TODO check where to handle this one better. */
00125   if ( errorCode == KIO::ERR_DOES_NOT_EXIST ) {
00126     // folder is gone, so reload the folderlist
00127     if ( mFolder )
00128       mFolder->listDirectory();
00129     return true;
00130   }
00131   return ImapAccountBase::handleError( errorCode, errorMsg, job, context, abortSync );
00132 }
00133 
00134 void KMAcctImap::registerJob( KMail::ImapJob *job )
00135 {
00136   if ( !job )
00137     return;
00138   if ( mImapJobList.contains( job ) )
00139     return;
00140   mImapJobList.append( job );
00141 }
00142 
00143 void KMAcctImap::unregisterJob( KMail::ImapJob *job )
00144 {
00145   if ( !job )
00146     return;
00147   mImapJobList.removeAll( job );
00148 }
00149 
00150 
00151 //-----------------------------------------------------------------------------
00152 void KMAcctImap::killAllJobs( bool disconnectSlave )
00153 {
00154   QMap<KJob*, jobData>::Iterator it = mapJobData.begin();
00155   for ( ; it != mapJobData.end(); ++it)
00156   {
00157     QList<KMMessage*> msgList = (*it).msgList;
00158     QList<KMMessage*>::Iterator it2 = msgList.begin();
00159     for ( ; it2 != msgList.end(); ++it2 ) {
00160        KMMessage *msg = *it2;
00161        if ( msg->transferInProgress() ) {
00162           kDebug(5006) << "Resetting mail";
00163           msg->setTransferInProgress( false );
00164        }
00165     }
00166     if ((*it).parent)
00167     {
00168       // clear folder state
00169       KMFolderImap *fld = static_cast<KMFolderImap*>((*it).parent->storage());
00170       fld->setCheckingValidity(false);
00171       fld->quiet(false);
00172       fld->setContentState(KMFolderImap::imapNoInformation);
00173       fld->setSubfolderState(KMFolderImap::imapNoInformation);
00174       fld->sendFolderComplete(false);
00175       fld->removeJobs();
00176     }
00177     if ( (*it).progressItem )
00178     {
00179       (*it).progressItem->setComplete();
00180     }
00181   }
00182   if (mSlave && mapJobData.begin() != mapJobData.end())
00183   {
00184     mSlave->kill();
00185     mSlave = 0;
00186   }
00187   // remove the jobs
00188   mapJobData.clear();
00189   KMAccount::deleteFolderJobs();
00190 
00191   while( mImapJobList.count() > 0 )
00192     mImapJobList.takeFirst()->kill();
00193 
00194   mImapJobList.clear();
00195   // make sure that no new-mail-check is blocked
00196   if (mCountRemainChecks > 0)
00197   {
00198     checkDone( false, CheckOK ); // returned 0 new messages
00199     mCountRemainChecks = 0;
00200   }
00201   if ( disconnectSlave && slave() ) {
00202     KIO::Scheduler::disconnectSlave( slave() );
00203     mSlave = 0;
00204   }
00205 }
00206 
00207 //-----------------------------------------------------------------------------
00208 void KMAcctImap::ignoreJobsForMessage( KMMessage* msg )
00209 {
00210   if (!msg) return;
00211   QList<ImapJob*>::const_iterator it;
00212   for ( it = mImapJobList.constBegin(); it != mImapJobList.constEnd() && (*it); ++it )
00213   {
00214     ImapJob *job = (*it);
00215     if ( job->msgList().first() == msg )
00216     {
00217       job->kill();
00218     }
00219   }
00220 }
00221 
00222 //-----------------------------------------------------------------------------
00223 void KMAcctImap::ignoreJobsForFolder( KMFolder* folder )
00224 {
00225   QList<ImapJob*>::const_iterator it;
00226   for ( it = mImapJobList.begin(); (*it) && it != mImapJobList.constEnd(); ++it )
00227   {
00228     ImapJob *job = (*it);
00229     if ( !job->msgList().isEmpty() && job->msgList().first()->parent() == folder )
00230     {
00231       job->kill();
00232     }
00233   }
00234 }
00235 
00236 //-----------------------------------------------------------------------------
00237 void KMAcctImap::removeSlaveJobsForFolder( KMFolder* folder )
00238 {
00239   // Make sure the folder is not referenced in any kio slave jobs
00240   QMap<KJob*, jobData>::Iterator it = mapJobData.begin();
00241   while ( it != mapJobData.end() ) {
00242      QMap<KJob*, jobData>::Iterator i = it;
00243      it++;
00244      if ( (*i).parent ) {
00245         if ( (*i).parent == folder ) {
00246            mapJobData.erase(i);
00247         }
00248      }
00249   }
00250 }
00251 
00252 //-----------------------------------------------------------------------------
00253 void KMAcctImap::cancelMailCheck()
00254 {
00255   // Make list of folders to reset, like in killAllJobs
00256   QList<KMFolderImap*> folderList;
00257   QMap<KJob*, jobData>::Iterator it = mapJobData.begin();
00258   for (; it != mapJobData.end(); ++it) {
00259     if ( (*it).cancellable && (*it).parent ) {
00260       folderList << static_cast<KMFolderImap*>((*it).parent->storage());
00261     }
00262   }
00263   // Kill jobs
00264   // FIXME
00265   // ImapAccountBase::cancelMailCheck();
00266   killAllJobs( true );
00267   // emit folderComplete, this is important for
00268   // KMAccount::checkingMail() to be reset, in case we restart checking mail later.
00269   for( QList<KMFolderImap*>::Iterator it = folderList.begin(); it != folderList.end(); ++it ) {
00270     KMFolderImap *fld = *it;
00271     fld->sendFolderComplete(false);
00272   }
00273 }
00274 
00275 //-----------------------------------------------------------------------------
00276 void KMAcctImap::processNewMail(bool interactive)
00277 {
00278   kDebug(5006) <<"processNewMail" << mCheckingSingleFolder <<",status="<<makeConnection();
00279   if ( !mFolder || !mFolder->folder() || !mFolder->folder()->child() ||
00280        makeConnection() == ImapAccountBase::Error ) {
00281     // checks for mCountRemainChecks
00282     checkDone( false, CheckError );
00283     mCountRemainChecks = 0;
00284     mCheckingSingleFolder = false;
00285     return;
00286   }
00287   // if necessary then initialize the list of folders which should be checked
00288   if( mMailCheckFolders.isEmpty() )
00289   {
00290     slotUpdateFolderList();
00291     // if no folders should be checked then the check is finished
00292     if( mMailCheckFolders.isEmpty() )
00293     {
00294       checkDone( false, CheckOK );
00295       mCheckingSingleFolder = false;
00296       return;
00297     }
00298   }
00299   // Ok, we're really checking, get a progress item;
00300   Q_ASSERT( !mMailCheckProgressItem );
00301   mMailCheckProgressItem =
00302     ProgressManager::createProgressItem(
00303         "MailCheckAccount" + name(),
00304         i18nc( "@info:status", "Checking account: %1", Qt::escape( name() ) ),
00305         QString(), // status
00306         true, // can be canceled
00307         useSSL() || useTLS() );
00308 
00309   mMailCheckProgressItem->setTotalItems( mMailCheckFolders.count() );
00310   connect ( mMailCheckProgressItem,
00311             SIGNAL( progressItemCanceled( KPIM::ProgressItem*) ),
00312             this,
00313             SLOT( slotMailCheckCanceled() ) );
00314 
00315   QList<QPointer<KMFolder> >::Iterator it;
00316   // first get the current count of unread-messages
00317   mCountRemainChecks = 0;
00318   mCountUnread = 0;
00319   mUnreadBeforeCheck.clear();
00320   for (it = mMailCheckFolders.begin(); it != mMailCheckFolders.end(); ++it)
00321   {
00322     KMFolder *folder = *it;
00323     if (folder && !folder->noContent())
00324     {
00325       mUnreadBeforeCheck[folder->idString()] = folder->countUnread();
00326     }
00327   }
00328   bool gotError = false;
00329   // then check for new mails
00330   for ( it = mMailCheckFolders.begin(); it != mMailCheckFolders.end(); ++it ) {
00331     KMFolder *folder = *it;
00332     if ( folder && !folder->noContent() ) {
00333       KMFolderImap *imapFolder = static_cast<KMFolderImap*>(folder->storage());
00334       if ( imapFolder->getContentState() != KMFolderImap::imapListingInProgress
00335         && imapFolder->getContentState() != KMFolderImap::imapDownloadInProgress )
00336       {
00337         // connect the result-signals for new-mail-notification
00338         mCountRemainChecks++;
00339 
00340         if ( imapFolder->isSelected() ) {
00341           connect(imapFolder, SIGNAL(folderComplete(KMFolderImap*, bool)),
00342               this, SLOT(postProcessNewMail(KMFolderImap*, bool)));
00343           imapFolder->getFolder();
00344         } else if ( kmkernel->filterMgr()->atLeastOneIncomingFilterAppliesTo( id() ) &&
00345                     imapFolder->folder()->isSystemFolder() &&
00346                     imapFolder->imapPath() == "/INBOX/" ) {
00347           // will be closed in the folderSelected slot
00348           imapFolder->open( "acctimap" );
00349           // first get new headers before we select the folder
00350           imapFolder->setSelected( true );
00351           connect( imapFolder, SIGNAL( folderComplete( KMFolderImap*, bool ) ),
00352                    this, SLOT( slotFolderSelected( KMFolderImap*, bool) ) );
00353           imapFolder->getFolder();
00354         } else {
00355           connect(imapFolder, SIGNAL(numUnreadMsgsChanged(KMFolder*)),
00356                   this, SLOT(postProcessNewMail(KMFolder*)));
00357           bool ok = imapFolder->processNewMail(interactive); // this removes the local kmfolderimap if its imapPath is somehow empty, and removing it calls createFolderList, invalidating mMailCheckFolders, and causing a crash
00358           if ( !ok ) {
00359             // there was an error so cancel
00360             mCountRemainChecks--;
00361             gotError = true;
00362             if ( mMailCheckProgressItem ) {
00363               mMailCheckProgressItem->incCompletedItems();
00364               mMailCheckProgressItem->updateProgress();
00365             }
00366             // since the list of folders might have been updated at this point, mMailCheckFolders may be invalid, so break
00367             break;
00368           }
00369         }
00370       }
00371     }
00372   } // end for
00373   if ( gotError )
00374     slotUpdateFolderList();
00375   // for the case the account is down and all folders report errors
00376   if ( mCountRemainChecks == 0 )
00377   {
00378     mCountLastUnread = 0; // => mCountUnread - mCountLastUnread == new count
00379     ImapAccountBase::postProcessNewMail();
00380     mUnreadBeforeCheck.clear();
00381     mCheckingSingleFolder = false;
00382   }
00383 }
00384 
00385 //-----------------------------------------------------------------------------
00386 void KMAcctImap::postProcessNewMail(KMFolderImap* folder, bool)
00387 {
00388   disconnect(folder, SIGNAL(folderComplete(KMFolderImap*, bool)),
00389       this, SLOT(postProcessNewMail(KMFolderImap*, bool)));
00390   postProcessNewMail(static_cast<KMFolder*>(folder->folder()));
00391 }
00392 
00393 void KMAcctImap::postProcessNewMail( KMFolder * folder )
00394 {
00395   disconnect( folder->storage(), SIGNAL(numUnreadMsgsChanged(KMFolder*)),
00396               this, SLOT(postProcessNewMail(KMFolder*)) );
00397 
00398   if ( mMailCheckProgressItem ) {
00399     mMailCheckProgressItem->incCompletedItems();
00400     mMailCheckProgressItem->updateProgress();
00401     mMailCheckProgressItem->setStatus( folder->prettyUrl()
00402       + i18nc("@info:status Number of emails retrieved.", " completed") );
00403   }
00404   mCountRemainChecks--;
00405 
00406   // count the unread messages
00407   const QString folderId = folder->idString();
00408   int newInFolder = folder->countUnread();
00409   if ( mUnreadBeforeCheck.contains( folderId )  )
00410     newInFolder -= mUnreadBeforeCheck[folderId];
00411   if ( newInFolder > 0 ) {
00412     addToNewInFolder( folderId, newInFolder );
00413     mCountUnread += newInFolder;
00414   }
00415 
00416   // Filter messages
00417   QListIterator<quint32> filterIt( mFilterSerNums );
00418   QList<quint32> inTransit;
00419 
00420   if (ActionScheduler::isEnabled() ||
00421       kmkernel->filterMgr()->atLeastOneOnlineImapFolderTarget()) {
00422     KMFilterMgr::FilterSet set = KMFilterMgr::Inbound;
00423     QList<KMFilter*> filters = kmkernel->filterMgr()->filters();
00424     if (!mScheduler) {
00425       mScheduler = new KMail::ActionScheduler( set, filters );
00426       mScheduler->setAccountId( id() );
00427       connect( mScheduler, SIGNAL(filtered(quint32)), this, SLOT(slotFiltered(quint32)) );
00428     } else {
00429       mScheduler->setFilterList( filters );
00430     }
00431   }
00432 
00433   while ( filterIt.hasNext() ) {
00434     int idx = -1;
00435     KMFolder *folder = 0;
00436     KMMessage *msg = 0;
00437     quint32 sernum = filterIt.next();
00438     KMMsgDict::instance()->getLocation( sernum, &folder, &idx );
00439     // It's possible that the message has been deleted or moved into a
00440     // different folder, or that the serNum is stale
00441     if ( !folder ) {
00442       mFilterSerNumsToSave.remove( QString( "%1" ).arg( sernum ) );
00443       continue;
00444     }
00445 
00446     KMFolderImap *imapFolder = dynamic_cast<KMFolderImap*>(folder->storage());
00447     if (!imapFolder ||
00448         !imapFolder->folder()->isSystemFolder() ||
00449         !(imapFolder->imapPath() == "/INBOX/") ) { // sanity checking
00450       mFilterSerNumsToSave.remove( QString( "%1" ).arg( sernum ) );
00451       continue;
00452     }
00453 
00454     if (idx != -1) {
00455 
00456       msg = folder->getMsg( idx );
00457       if (!msg) { // sanity checking
00458         mFilterSerNumsToSave.remove( QString( "%1" ).arg( sernum ) );
00459         continue;
00460       }
00461 
00462       if (ActionScheduler::isEnabled() ||
00463           kmkernel->filterMgr()->atLeastOneOnlineImapFolderTarget()) {
00464         mScheduler->execFilters( msg );
00465       } else {
00466         if (msg->transferInProgress()) {
00467           inTransit.append( sernum );
00468           continue;
00469         }
00470         msg->setTransferInProgress(true);
00471         if ( !msg->isComplete() ) {
00472           FolderJob *job = folder->createJob(msg);
00473           connect(job, SIGNAL(messageRetrieved(KMMessage*)),
00474             SLOT(slotFilterMsg(KMMessage*)));
00475           job->start();
00476         } else {
00477           mFilterSerNumsToSave.remove( QString( "%1" ).arg( sernum ) );
00478           if (slotFilterMsg(msg) == 2) break;
00479         }
00480       }
00481     }
00482   }
00483   mFilterSerNums = inTransit;
00484 
00485   if (mCountRemainChecks == 0)
00486   {
00487     // all checks are done
00488     mCountLastUnread = 0; // => mCountUnread - mCountLastUnread == new count
00489     // when we check only one folder (=selected) and we have new mails
00490     // then do not display a summary as the normal status message is better
00491     bool showStatus = ( mCheckingSingleFolder && mCountUnread > 0 ) ? false : true;
00492     ImapAccountBase::postProcessNewMail( showStatus );
00493     mUnreadBeforeCheck.clear();
00494     mCheckingSingleFolder = false;
00495   }
00496 }
00497 
00498 //-----------------------------------------------------------------------------
00499 void KMAcctImap::slotFiltered(quint32 serNum)
00500 {
00501     mFilterSerNumsToSave.remove( QString( "%1" ).arg( serNum ) );
00502 }
00503 
00504 //-----------------------------------------------------------------------------
00505 void KMAcctImap::slotUpdateFolderList()
00506 {
00507   if ( !mFolder || !mFolder->folder() || !mFolder->folder()->child() )
00508   {
00509     kWarning(5006) << "Return";
00510     return;
00511   }
00512   QStringList strList;
00513   mMailCheckFolders.clear();
00514   kmkernel->imapFolderMgr()->createFolderList(&strList, &mMailCheckFolders,
00515     mFolder->folder()->child(), QString(), false);
00516   // the new list
00517   QList<QPointer<KMFolder> > includedFolders;
00518   // check for excluded folders
00519   QList<QPointer<KMFolder> >::Iterator it;
00520   for (it = mMailCheckFolders.begin(); it != mMailCheckFolders.end(); ++it)
00521   {
00522     KMFolderImap* folder = static_cast<KMFolderImap*>(((KMFolder*)(*it))->storage());
00523     if (folder->includeInMailCheck())
00524       includedFolders.append(*it);
00525   }
00526   mMailCheckFolders = includedFolders;
00527 }
00528 
00529 //-----------------------------------------------------------------------------
00530 void KMAcctImap::listDirectory()
00531 {
00532   mFolder->listDirectory();
00533 }
00534 
00535 //-----------------------------------------------------------------------------
00536 void KMAcctImap::readConfig(KConfigGroup& config)
00537 {
00538   ImapAccountBase::readConfig( config );
00539 }
00540 
00541 //-----------------------------------------------------------------------------
00542 void KMAcctImap::slotMailCheckCanceled()
00543 {
00544   if( mMailCheckProgressItem )
00545     mMailCheckProgressItem->setComplete();
00546   cancelMailCheck();
00547 }
00548 
00549 //-----------------------------------------------------------------------------
00550 FolderStorage* KMAcctImap::rootFolder() const
00551 {
00552   return mFolder;
00553 }
00554 
00555 ImapAccountBase::ConnectionState KMAcctImap::makeConnection()
00556 {
00557   if ( mSlaveConnectionError )
00558   {
00559     mErrorTimer.start( 100 ); // Clear error flag
00560     return Error;
00561   }
00562   return ImapAccountBase::makeConnection();
00563 }
00564 
00565 void KMAcctImap::slotResetConnectionError()
00566 {
00567   mSlaveConnectionError = false;
00568   kDebug(5006) ;
00569 }
00570 
00571 void KMAcctImap::slotFolderSelected( KMFolderImap* folder, bool )
00572 {
00573   folder->setSelected( false );
00574   disconnect( folder, SIGNAL( folderComplete( KMFolderImap*, bool ) ),
00575           this, SLOT( slotFolderSelected( KMFolderImap*, bool) ) );
00576   postProcessNewMail( static_cast<KMFolder*>(folder->folder()) );
00577   folder->close( "acctimap" );
00578 }
00579 
00580 void KMAcctImap::execFilters(quint32 serNum)
00581 {
00582   if ( !kmkernel->filterMgr()->atLeastOneFilterAppliesTo( id() ) ) return;
00583   if ( mFilterSerNums.contains( serNum ) )
00584       return;
00585 
00586   mFilterSerNums.append( serNum );
00587   mFilterSerNumsToSave.insert( QString( "%1" ).arg( serNum ), 1 );
00588 }
00589 
00590 int KMAcctImap::slotFilterMsg( KMMessage *msg )
00591 {
00592   if ( !msg ) {
00593     // messageRetrieved(0) is always possible
00594     return -1;
00595   }
00596   msg->setTransferInProgress(false);
00597   quint32 serNum = msg->getMsgSerNum();
00598   if ( serNum )
00599     mFilterSerNumsToSave.remove( QString( "%1" ).arg( serNum ) );
00600 
00601   int filterResult = kmkernel->filterMgr()->process(msg,
00602                                                     KMFilterMgr::Inbound,
00603                                                     true,
00604                                                     id() );
00605   if (filterResult == 2) {
00606     // something went horribly wrong (out of space?)
00607     kmkernel->emergencyExit(
00608       i18nc( "@info:status", "Unable to process messages: " ) + QString::fromLocal8Bit(strerror(errno)));
00609     return 2;
00610   }
00611   if (msg->parent()) { // unGet this msg
00612     int idx = -1;
00613     KMFolder * p = 0;
00614     KMMsgDict::instance()->getLocation( msg, &p, &idx );
00615     assert( p == msg->parent() ); assert( idx >= 0 );
00616     p->unGetMsg( idx );
00617   }
00618 
00619   return filterResult;
00620 }
00621 
00622 #include "kmacctimap.moc"

kmail

Skip menu "kmail"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • 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