kmail

accountmanager.cpp
00001 // KMail Account Manager
00002 
00003 #ifdef HAVE_CONFIG_H
00004 #include <config.h>
00005 #endif
00006 
00007 #include "accountmanager.h"
00008 
00009 #include "kmaccount.h"
00010 #include "kmacctfolder.h"
00011 #include "kmacctmaildir.h"
00012 #include "kmacctlocal.h"
00013 #include "popaccount.h"
00014 #include "kmacctimap.h"
00015 #include "networkaccount.h"
00016 #include "kmacctcachedimap.h"
00017 #include "broadcaststatus.h"
00018 #include "kmfiltermgr.h"
00019 #include "globalsettings.h"
00020 
00021 #include <dcopclient.h>
00022 #include <klocale.h>
00023 #include <kmessagebox.h>
00024 #include <kdebug.h>
00025 #include <kconfig.h>
00026 #include <kapplication.h>
00027 
00028 #include <tqregexp.h>
00029 #include <tqvaluelist.h>
00030 
00031 using namespace KMail;
00032 
00033 //-----------------------------------------------------------------------------
00034 AccountManager::AccountManager()
00035     :TQObject(), mNewMailArrived( false ), mInteractive( false ),
00036      mTotalNewMailsArrived( 0 ), mDisplaySummary( false )
00037 {
00038   mAcctChecking.clear();
00039   mAcctTodo.clear();
00040 }
00041 
00042 //-----------------------------------------------------------------------------
00043 AccountManager::~AccountManager()
00044 {
00045   writeConfig( false );
00046 }
00047 
00048 
00049 //-----------------------------------------------------------------------------
00050 void AccountManager::writeConfig( bool withSync )
00051 {
00052   KConfig* config = KMKernel::config();
00053   TQString groupName;
00054 
00055   KConfigGroupSaver saver(config, "General");
00056   config->writeEntry("accounts", mAcctList.count());
00057 
00058   // first delete all account groups in the config file:
00059   TQStringList accountGroups =
00060     config->groupList().grep( TQRegExp( "Account \\d+" ) );
00061   for ( TQStringList::Iterator it = accountGroups.begin() ;
00062     it != accountGroups.end() ; ++it )
00063     config->deleteGroup( *it );
00064 
00065   // now write new account groups:
00066   int i = 1;
00067   for ( AccountList::ConstIterator it( mAcctList.begin() ), end( mAcctList.end() ); it != end; ++it, ++i ) {
00068     groupName.sprintf("Account %d", i);
00069     KConfigGroupSaver saver(config, groupName);
00070     (*it)->writeConfig(*config);
00071   }
00072   if (withSync) config->sync();
00073 }
00074 
00075 
00076 //-----------------------------------------------------------------------------
00077 void AccountManager::readConfig(void)
00078 {
00079   KConfig* config = KMKernel::config();
00080   KMAccount* acct;
00081   TQString acctType, acctName;
00082   TQCString groupName;
00083   int i, num;
00084   uint id;
00085 
00086   for ( AccountList::Iterator it( mAcctList.begin() ), end( mAcctList.end() ); it != end; ++it )
00087       delete *it;
00088   mAcctList.clear();
00089 
00090   KConfigGroup general(config, "General");
00091   num = general.readNumEntry("accounts", 0);
00092 
00093   for (i=1; i<=num; i++)
00094   {
00095     groupName.sprintf("Account %d", i);
00096     KConfigGroupSaver saver(config, groupName);
00097     acctType = config->readEntry("Type");
00098     // Provide backwards compatibility
00099     if (acctType == "advanced pop" || acctType == "experimental pop")
00100       acctType = "pop";
00101     acctName = config->readEntry("Name");
00102     id = config->readUnsignedNumEntry("Id", 0);
00103     if (acctName.isEmpty()) acctName = i18n("Account %1").arg(i);
00104     acct = create(acctType, acctName, id);
00105     if (!acct) continue;
00106     add(acct);
00107     acct->readConfig(*config);
00108   }
00109 }
00110 
00111 
00112 //-----------------------------------------------------------------------------
00113 void AccountManager::singleCheckMail(KMAccount *account, bool interactive)
00114 {
00115   mNewMailArrived = false;
00116   mInteractive = interactive;
00117 
00118  // if sync has been requested by the user then check if check-interval was disabled by user, if yes, then 
00119  // de-install the timer
00120  // Safe guard against an infinite sync loop (kolab/issue2607)
00121   if ( mInteractive ) 
00122       account->readTimerConfig();
00123 
00124   // queue the account
00125   mAcctTodo.append(account);
00126 
00127   if (account->checkingMail())
00128   {
00129     kdDebug(5006) << "account " << account->name() << " busy, queuing" << endl;
00130     return;
00131   }
00132 
00133   processNextCheck(false);
00134 }
00135 
00136 //-----------------------------------------------------------------------------
00137 void AccountManager::processNextCheck( bool _newMail )
00138 {
00139   kdDebug(5006) << "processNextCheck, remaining " << mAcctTodo.count() << endl;
00140   if ( _newMail )
00141     mNewMailArrived = true;
00142 
00143   for ( AccountList::Iterator it( mAcctChecking.begin() ), end( mAcctChecking.end() ); it != end;  ) {
00144     KMAccount* acct = *it;
00145     ++it;
00146     if ( acct->checkingMail() )
00147       continue;
00148     // check done
00149     kdDebug(5006) << "account " << acct->name() << " finished check" << endl;
00150     mAcctChecking.remove( acct );
00151     kmkernel->filterMgr()->deref();
00152     disconnect( acct, TQT_SIGNAL( finishedCheck( bool, CheckStatus ) ),
00153                       this, TQT_SLOT( processNextCheck( bool ) ) );
00154   }
00155   if ( mAcctChecking.isEmpty() ) {
00156     // all checks finished, display summary
00157     if ( mDisplaySummary )
00158       KPIM::BroadcastStatus::instance()->setStatusMsgTransmissionCompleted(
00159           mTotalNewMailsArrived );
00160     emit checkedMail( mNewMailArrived, mInteractive, mTotalNewInFolder );
00161     mTotalNewMailsArrived = 0;
00162     mTotalNewInFolder.clear();
00163     mDisplaySummary = false;
00164   }
00165   if ( mAcctTodo.isEmpty() ) return;
00166 
00167   TQString accountHostName;
00168 
00169   KMAccount *curAccount = 0;
00170   for ( AccountList::Iterator it ( mAcctTodo.begin() ), last ( mAcctTodo.end() ); it != last; ) {
00171     KMAccount *acct = *it;
00172     ++it;
00173     if ( !acct->checkingMail() && acct->mailCheckCanProceed() ) {
00174       curAccount = acct;
00175       mAcctTodo.remove( acct );
00176       break;
00177     }
00178   }
00179   if ( !curAccount ) return; // no account or all of them are already checking
00180 
00181   if ( curAccount->type() != "imap" && curAccount->type() != "cachedimap" &&
00182        curAccount->folder() == 0 ) {
00183     TQString tmp = i18n("Account %1 has no mailbox defined:\n"
00184         "mail checking aborted;\n"
00185         "check your account settings.")
00186       .arg(curAccount->name());
00187     KMessageBox::information(0,tmp);
00188     emit checkedMail( false, mInteractive, mTotalNewInFolder );
00189     mTotalNewMailsArrived = 0;
00190     mTotalNewInFolder.clear();
00191     return;
00192   }
00193 
00194   if ( curAccount->type() == "imap" || curAccount->type() == "cachedimap" || curAccount->type() == "pop" )
00195   {
00196     // Check with the network status daemon whether the network is available
00197     const int NetWorkStatusUnknown = 1;
00198     const int NetWorkStatusOnline = 8;
00199     TQCString replyType;
00200     TQByteArray params;
00201     TQByteArray reply;
00202 
00203     TQDataStream stream( params, IO_WriteOnly );
00204     stream << static_cast<NetworkAccount*>( curAccount )->host();
00205 
00206     if ( kapp->dcopClient()->call( "kded", "networkstatus", "status(TQString)",
00207                             params, replyType, reply ) && ( replyType == "int" ) )
00208     {
00209       int result;
00210       TQDataStream stream2(  reply, IO_ReadOnly );
00211       stream2 >> result;
00212       kdDebug() << k_funcinfo << "networkstatus status = " << result << endl;
00213       // if it's not unknown (no networks announced by network control apps), and not offline, give up now
00214       if ( ( result != NetWorkStatusUnknown ) && ( result != NetWorkStatusOnline ) )
00215       {
00216         emit checkedMail( false, mInteractive, mTotalNewInFolder );
00217         return;
00218      }
00219     }
00220   }
00221 
00222   connect( curAccount, TQT_SIGNAL( finishedCheck( bool, CheckStatus ) ),
00223                 this, TQT_SLOT( processNextCheck( bool ) ) );
00224 
00225   KPIM::BroadcastStatus::instance()->setStatusMsg(
00226       i18n("Checking account %1 for new mail").arg(curAccount->name()));
00227 
00228   kdDebug(5006) << "processing next mail check for " << curAccount->name() << endl;
00229 
00230   curAccount->setCheckingMail( true );
00231   mAcctChecking.append( curAccount );
00232   kmkernel->filterMgr()->ref();
00233   curAccount->processNewMail( mInteractive );
00234 }
00235 
00236 //-----------------------------------------------------------------------------
00237 KMAccount* AccountManager::create( const TQString &aType, const TQString &aName, uint id )
00238 {
00239   KMAccount* act = 0;
00240   if ( id == 0 )
00241     id = createId();
00242 
00243   if ( aType == "local" ) {
00244     act = new KMAcctLocal(this, aName.isEmpty() ? i18n("Local Account") : aName, id);
00245     act->setFolder( kmkernel->inboxFolder() );
00246   } else if ( aType == "maildir" ) {
00247     act = new KMAcctMaildir(this, aName.isEmpty() ? i18n("Local Account") : aName, id);
00248     act->setFolder( kmkernel->inboxFolder() );
00249   } else if ( aType == "pop" ) {
00250     act = new KMail::PopAccount(this, aName.isEmpty() ? i18n("POP Account") : aName, id);
00251     act->setFolder( kmkernel->inboxFolder() );
00252   } else if ( aType == "imap" ) {
00253     act = new KMAcctImap(this, aName.isEmpty() ? i18n("IMAP Account") : aName, id);
00254   } else if (aType == "cachedimap") {
00255     act = new KMAcctCachedImap(this, aName.isEmpty() ? i18n("IMAP Account") : aName, id);
00256   }
00257   if ( !act ) {
00258       kdWarning(5006) << "Attempt to instantiate a non-existing account type!" << endl;
00259       return 0;
00260   }
00261   connect( act, TQT_SIGNAL( newMailsProcessed( const TQMap<TQString, int> & ) ),
00262                 this, TQT_SLOT( addToTotalNewMailCount( const TQMap<TQString, int> & ) ) );
00263   return act;
00264 }
00265 
00266 
00267 //-----------------------------------------------------------------------------
00268 void AccountManager::add( KMAccount *account )
00269 {
00270   if ( account ) {
00271     mAcctList.append( account );
00272     // init folder's account list
00273     KMAcctFolder *folder = static_cast<KMAcctFolder*>( account->folder() );
00274     if ( folder && !folder->hasAccounts() ) {
00275       folder->addAccount( account );
00276     }
00277     emit accountAdded( account );
00278     account->installTimer();
00279   }
00280 }
00281 
00282 
00283 //-----------------------------------------------------------------------------
00284 KMAccount* AccountManager::findByName(const TQString &aName) const
00285 {
00286   if ( aName.isEmpty() ) return 0;
00287 
00288   for ( AccountList::ConstIterator it( mAcctList.begin() ), end( mAcctList.end() ); it != end; ++it ) {
00289     if ( (*it)->name() == aName ) return (*it);
00290   }
00291   return 0;
00292 }
00293 
00294 
00295 //-----------------------------------------------------------------------------
00296 KMAccount* AccountManager::find( const uint id ) const
00297 {
00298   if (id == 0) return 0;
00299   for ( AccountList::ConstIterator it( mAcctList.begin() ), end( mAcctList.end() ); it != end; ++it ) {
00300     if ( (*it)->id() == id ) return (*it);
00301   }
00302   return 0;
00303 }
00304 
00305 
00306 //-----------------------------------------------------------------------------
00307 KMAccount* AccountManager::first()
00308 {
00309   if ( !mAcctList.empty() ) {
00310     mPtrListInterfaceProxyIterator = mAcctList.begin();
00311     return *mPtrListInterfaceProxyIterator;
00312   } else {
00313     return 0;
00314   }
00315 }
00316 
00317 //-----------------------------------------------------------------------------
00318 KMAccount* AccountManager::next()
00319 {
00320     ++mPtrListInterfaceProxyIterator;
00321     if ( mPtrListInterfaceProxyIterator == mAcctList.end() )
00322         return 0;
00323     else
00324         return *mPtrListInterfaceProxyIterator;
00325 }
00326 
00327 //-----------------------------------------------------------------------------
00328 bool AccountManager::remove( KMAccount* acct )
00329 {
00330   if( !acct )
00331     return false;
00332   mAcctList.remove( acct );
00333   emit accountRemoved( acct );
00334   return true;
00335 }
00336 
00337 //-----------------------------------------------------------------------------
00338 void AccountManager::checkMail( bool _interactive )
00339 {
00340   mNewMailArrived = false;
00341 
00342   if ( mAcctList.isEmpty() ) {
00343     KMessageBox::information( 0,i18n("You need to add an account in the network "
00344                     "section of the settings in order to receive mail.") );
00345     return;
00346   }
00347   mDisplaySummary = true;
00348 
00349   mTotalNewMailsArrived=0;
00350   mTotalNewInFolder.clear();
00351 
00352   for ( AccountList::Iterator it( mAcctList.begin() ), end( mAcctList.end() ); it != end; ++it ) {
00353     if ( !(*it)->checkExclude() )
00354       singleCheckMail( (*it), _interactive);
00355   }
00356 }
00357 
00358 
00359 //-----------------------------------------------------------------------------
00360 void AccountManager::singleInvalidateIMAPFolders(KMAccount *account) {
00361   account->invalidateIMAPFolders();
00362 }
00363 
00364 
00365 void AccountManager::invalidateIMAPFolders()
00366 {
00367   for ( AccountList::ConstIterator it( mAcctList.begin() ), end( mAcctList.end() ); it != end; ++it )
00368     singleInvalidateIMAPFolders( *it );
00369 }
00370 
00371 
00372 //-----------------------------------------------------------------------------
00373 TQStringList  AccountManager::getAccounts() const
00374 {
00375   TQStringList strList;
00376   for ( AccountList::ConstIterator it( mAcctList.begin() ), end( mAcctList.end() ); it != end; ++it ) {
00377     strList.append( (*it)->name() );
00378   }
00379   return strList;
00380 }
00381 
00382 //-----------------------------------------------------------------------------
00383 void AccountManager::intCheckMail(int item, bool _interactive)
00384 {
00385   mNewMailArrived = false;
00386   mTotalNewMailsArrived = 0;
00387   mTotalNewInFolder.clear();
00388   if ( KMAccount *acct = mAcctList[ item ] )
00389     singleCheckMail( acct, _interactive );
00390   mDisplaySummary = false;
00391 }
00392 
00393 
00394 //-----------------------------------------------------------------------------
00395 void AccountManager::addToTotalNewMailCount( const TQMap<TQString, int> & newInFolder )
00396 {
00397   for ( TQMap<TQString, int>::const_iterator it = newInFolder.begin();
00398         it != newInFolder.end(); ++it ) {
00399     mTotalNewMailsArrived += it.data();
00400     if ( mTotalNewInFolder.find( it.key() ) == mTotalNewInFolder.end() )
00401       mTotalNewInFolder[it.key()] = it.data();
00402     else
00403       mTotalNewInFolder[it.key()] += it.data();
00404   }
00405 }
00406 
00407 //-----------------------------------------------------------------------------
00408 uint AccountManager::createId()
00409 {
00410   TQValueList<uint> usedIds;
00411   for ( AccountList::ConstIterator it( mAcctList.begin() ), end( mAcctList.end() ); it != end; ++it ) {
00412     usedIds << (*it)->id();
00413   }
00414 
00415   usedIds << 0; // 0 is default for unknown
00416   int newId;
00417   do
00418   {
00419     newId = kapp->random();
00420   } while ( usedIds.find(newId) != usedIds.end() );
00421 
00422   return newId;
00423 }
00424 
00425 //-----------------------------------------------------------------------------
00426 void AccountManager::cancelMailCheck()
00427 {
00428   for ( AccountList::ConstIterator it( mAcctList.begin() ), end( mAcctList.end() ); it != end; ++it ) {
00429     (*it)->cancelMailCheck();
00430   }
00431 }
00432 
00433 
00434 //-----------------------------------------------------------------------------
00435 void AccountManager::readPasswords()
00436 {
00437   for ( AccountList::ConstIterator it( mAcctList.begin() ), end( mAcctList.end() ); it != end; ++it ) {
00438     NetworkAccount *acct = dynamic_cast<NetworkAccount*>( (*it) );
00439     if ( acct )
00440       acct->readPassword();
00441   }
00442 }
00443 
00444 #include "accountmanager.moc"