kmail

kmaccount.cpp

Go to the documentation of this file.
00001 // KMail Account
00002 #include <config.h>
00003 
00004 #include "kmaccount.h"
00005 
00006 #include "accountmanager.h"
00007 using KMail::AccountManager;
00008 #include "globalsettings.h"
00009 #include "kmacctfolder.h"
00010 #include "kmfoldermgr.h"
00011 #include "kmfiltermgr.h"
00012 #include "messagesender.h"
00013 #include "kmmessage.h"
00014 #include "broadcaststatus.h"
00015 using KPIM::BroadcastStatus;
00016 #include "kmfoldercachedimap.h"
00017 
00018 #include "progressmanager.h"
00019 using KPIM::ProgressItem;
00020 using KPIM::ProgressManager;
00021 
00022 #include <libkpimidentities/identitymanager.h>
00023 #include <libkpimidentities/identity.h>
00024 
00025 using KMail::FolderJob;
00026 
00027 #include <kapplication.h>
00028 #include <klocale.h>
00029 #include <kmessagebox.h>
00030 #include <kdebug.h>
00031 #include <kconfig.h>
00032 
00033 #include <qeventloop.h>
00034 
00035 #include <stdlib.h>
00036 #include <unistd.h>
00037 #include <errno.h>
00038 
00039 #include <assert.h>
00040 
00041 //----------------------
00042 #include "kmaccount.moc"
00043 
00044 //-----------------------------------------------------------------------------
00045 KMPrecommand::KMPrecommand(const QString &precommand, QObject *parent)
00046   : QObject(parent), mPrecommand(precommand)
00047 {
00048   BroadcastStatus::instance()->setStatusMsg(
00049       i18n("Executing precommand %1").arg(precommand ));
00050 
00051   mPrecommandProcess.setUseShell(true);
00052   mPrecommandProcess << precommand;
00053 
00054   connect(&mPrecommandProcess, SIGNAL(processExited(KProcess *)),
00055           SLOT(precommandExited(KProcess *)));
00056 }
00057 
00058 //-----------------------------------------------------------------------------
00059 KMPrecommand::~KMPrecommand()
00060 {
00061 }
00062 
00063 
00064 //-----------------------------------------------------------------------------
00065 bool KMPrecommand::start()
00066 {
00067   bool ok = mPrecommandProcess.start( KProcess::NotifyOnExit );
00068   if (!ok) KMessageBox::error(0, i18n("Could not execute precommand '%1'.")
00069     .arg(mPrecommand));
00070   return ok;
00071 }
00072 
00073 
00074 //-----------------------------------------------------------------------------
00075 void KMPrecommand::precommandExited(KProcess *p)
00076 {
00077   int exitCode = p->normalExit() ? p->exitStatus() : -1;
00078   if (exitCode)
00079     KMessageBox::error(0, i18n("The precommand exited with code %1:\n%2")
00080       .arg(exitCode).arg(strerror(exitCode)));
00081   emit finished(!exitCode);
00082 }
00083 
00084 
00085 //-----------------------------------------------------------------------------
00086 KMAccount::KMAccount(AccountManager* aOwner, const QString& aName, uint id)
00087   : KAccount( id, aName ),
00088     mTrash(KMKernel::self()->trashFolder()->idString()),
00089     mOwner(aOwner),
00090     mFolder(0),
00091     mTimer(0),
00092     mInterval(0),
00093     mExclude(false),
00094     mCheckingMail(false),
00095     mPrecommandSuccess(true),
00096     mHasInbox(false),
00097     mMailCheckProgressItem(0),
00098     mIdentityId(0)
00099 {
00100   assert(aOwner != 0);
00101 }
00102 
00103 void KMAccount::init() {
00104   mTrash = kmkernel->trashFolder()->idString();
00105   mExclude = false;
00106   mInterval = 0;
00107   mNewInFolder.clear();
00108 }
00109 
00110 //-----------------------------------------------------------------------------
00111 KMAccount::~KMAccount()
00112 {
00113   if ( (kmkernel && !kmkernel->shuttingDown()) && mFolder ) mFolder->removeAccount(this);
00114   if (mTimer) deinstallTimer();
00115 }
00116 
00117 
00118 //-----------------------------------------------------------------------------
00119 void KMAccount::setName(const QString& aName)
00120 {
00121   mName = aName;
00122 }
00123 
00124 
00125 //-----------------------------------------------------------------------------
00126 void KMAccount::clearPasswd()
00127 {
00128 }
00129 
00130 
00131 //-----------------------------------------------------------------------------
00132 void KMAccount::setFolder(KMFolder* aFolder, bool addAccount)
00133 {
00134   if(!aFolder) {
00135     //kdDebug(5006) << "KMAccount::setFolder() : aFolder == 0" << endl;
00136     mFolder = 0;
00137     return;
00138   }
00139   mFolder = (KMAcctFolder*)aFolder;
00140   if (addAccount) mFolder->addAccount(this);
00141 }
00142 
00143 
00144 //-----------------------------------------------------------------------------
00145 void KMAccount::readConfig(KConfig& config)
00146 {
00147   QString folderName;
00148   mFolder = 0;
00149   folderName = config.readEntry("Folder");
00150   setCheckInterval(config.readNumEntry("check-interval", 0));
00151   setTrash(config.readEntry("trash", kmkernel->trashFolder()->idString()));
00152   setCheckExclude(config.readBoolEntry("check-exclude", false));
00153   setPrecommand(config.readPathEntry("precommand"));
00154   setIdentityId(config.readNumEntry("identity-id", 0));
00155   if (!folderName.isEmpty())
00156   {
00157     setFolder(kmkernel->folderMgr()->findIdString(folderName), true);
00158   }
00159 
00160   if (mInterval == 0)
00161     deinstallTimer();
00162   else
00163     installTimer();
00164 }
00165 
00166 void KMAccount::readTimerConfig()
00167 {
00168   // Re-reads and checks check-interval value and deinstalls timer incase check-interval
00169   // for mail check is disabled.
00170   // Or else, the mail sync goes into a infinite loop (kolab/issue2607)
00171   if (mInterval == 0)
00172     deinstallTimer();
00173   else
00174     installTimer();
00175 }
00176 
00177 //-----------------------------------------------------------------------------
00178 void KMAccount::writeConfig(KConfig& config)
00179 {
00180   // ID, Name
00181   KAccount::writeConfig(config);
00182 
00183   config.writeEntry("Type", type());
00184   config.writeEntry("Folder", mFolder ? mFolder->idString() : QString::null);
00185   config.writeEntry("check-interval", mInterval);
00186   config.writeEntry("check-exclude", mExclude);
00187   config.writePathEntry("precommand", mPrecommand);
00188   config.writeEntry("trash", mTrash);
00189   if ( mIdentityId && mIdentityId != kmkernel->identityManager()->defaultIdentity().uoid() )
00190     config.writeEntry("identity-id", mIdentityId);
00191   else
00192     config.deleteEntry("identity-id");
00193 }
00194 
00195 
00196 //-----------------------------------------------------------------------------
00197 void KMAccount::sendReceipt(KMMessage* aMsg)
00198 {
00199   KConfig* cfg = KMKernel::config();
00200   bool sendReceipts;
00201 
00202   KConfigGroupSaver saver(cfg, "General");
00203 
00204   sendReceipts = cfg->readBoolEntry("send-receipts", false);
00205   if (!sendReceipts) return;
00206 
00207   KMMessage *newMsg = aMsg->createDeliveryReceipt();
00208   if (newMsg) {
00209     mReceipts.append(newMsg);
00210     QTimer::singleShot( 0, this, SLOT( sendReceipts() ) );
00211   }
00212 }
00213 
00214 
00215 //-----------------------------------------------------------------------------
00216 bool KMAccount::processNewMsg(KMMessage* aMsg)
00217 {
00218   int rc, processResult;
00219 
00220   assert(aMsg != 0);
00221 
00222   // Save this one for readding
00223   KMFolderCachedImap* parent = 0;
00224   if( type() == "cachedimap" )
00225     parent = static_cast<KMFolderCachedImap*>( aMsg->storage() );
00226 
00227   // checks whether we should send delivery receipts
00228   // and sends them.
00229   sendReceipt(aMsg);
00230 
00231   // Set status of new messages that are marked as old to read, otherwise
00232   // the user won't see which messages newly arrived.
00233   // This is only valid for pop accounts and produces wrong stati for imap.
00234   if ( type() != "cachedimap" && type() != "imap" ) {
00235     if ( aMsg->isOld() )
00236       aMsg->setStatus(KMMsgStatusUnread);  // -sanders
00237     //    aMsg->setStatus(KMMsgStatusRead);
00238     else
00239       aMsg->setStatus(KMMsgStatusNew);
00240   }
00241 /*
00242 QFile fileD0( "testdat_xx-kmaccount-0" );
00243 if( fileD0.open( IO_WriteOnly ) ) {
00244     QDataStream ds( &fileD0 );
00245     ds.writeRawBytes( aMsg->asString(), aMsg->asString().length() );
00246     fileD0.close();  // If data is 0 we just create a zero length file.
00247 }
00248 */
00249   // 0==message moved; 1==processing ok, no move; 2==critical error, abort!
00250 
00251   processResult = kmkernel->filterMgr()->process(aMsg,KMFilterMgr::Inbound,true,id());
00252   if (processResult == 2) {
00253     perror("Critical error: Unable to collect mail (out of space?)");
00254     KMessageBox::information(0,(i18n("Critical error: "
00255       "Unable to collect mail: ")) + QString::fromLocal8Bit(strerror(errno)));
00256     return false;
00257   }
00258   else if (processResult == 1)
00259   {
00260     if( type() == "cachedimap" )
00261       ; // already done by caller: parent->addMsgInternal( aMsg, false );
00262     else {
00263       // TODO: Perhaps it would be best, if this if was handled by a virtual
00264       // method, so the if( !dimap ) above could die?
00265       kmkernel->filterMgr()->tempOpenFolder(mFolder);
00266       rc = mFolder->addMsg(aMsg);
00267 /*
00268 QFile fileD0( "testdat_xx-kmaccount-1" );
00269 if( fileD0.open( IO_WriteOnly ) ) {
00270     QDataStream ds( &fileD0 );
00271     ds.writeRawBytes( aMsg->asString(), aMsg->asString().length() );
00272     fileD0.close();  // If data is 0 we just create a zero length file.
00273 }
00274 */
00275       if (rc) {
00276         perror("failed to add message");
00277         KMessageBox::information(0, i18n("Failed to add message:\n") +
00278                                  QString(strerror(rc)));
00279         return false;
00280       }
00281       int count = mFolder->count();
00282       // If count == 1, the message is immediately displayed
00283       if (count != 1) mFolder->unGetMsg(count - 1);
00284     }
00285   }
00286 
00287   // Count number of new messages for each folder
00288   QString folderId;
00289   if ( processResult == 1 ) {
00290     folderId = ( type() == "cachedimap" ) ? parent->folder()->idString()
00291                                           : mFolder->idString();
00292   }
00293   else {
00294     folderId = aMsg->parent()->idString();
00295   }
00296   addToNewInFolder( folderId, 1 );
00297 
00298   return true; //Everything's fine - message has been added by filter  }
00299 }
00300 
00301 //-----------------------------------------------------------------------------
00302 void KMAccount::setCheckInterval(int aInterval)
00303 {
00304   if (aInterval <= 0)
00305     mInterval = 0;
00306   else
00307     mInterval = aInterval;
00308   // Don't call installTimer from here! See #117935.
00309 }
00310 
00311 int KMAccount::checkInterval() const
00312 {
00313   if ( mInterval <= 0 )
00314     return mInterval;
00315   return QMAX( mInterval, GlobalSettings::self()->minimumCheckInterval() );
00316 }
00317 
00318 //----------------------------------------------------------------------------
00319 void KMAccount::deleteFolderJobs()
00320 {
00321   mJobList.setAutoDelete(true);
00322   mJobList.clear();
00323   mJobList.setAutoDelete(false);
00324 }
00325 
00326 //----------------------------------------------------------------------------
00327 void KMAccount::ignoreJobsForMessage( KMMessage* msg )
00328 {
00329   //FIXME: remove, make folders handle those
00330   for( QPtrListIterator<FolderJob> it(mJobList); it.current(); ++it ) {
00331     if ( it.current()->msgList().first() == msg) {
00332       FolderJob *job = it.current();
00333       mJobList.remove( job );
00334       delete job;
00335       break;
00336     }
00337   }
00338 }
00339 
00340 //-----------------------------------------------------------------------------
00341 void KMAccount::setCheckExclude(bool aExclude)
00342 {
00343   mExclude = aExclude;
00344 }
00345 
00346 
00347 //-----------------------------------------------------------------------------
00348 void KMAccount::installTimer()
00349 {
00350   if (mInterval <= 0) return;
00351   if(!mTimer)
00352   {
00353     mTimer = new QTimer(0, "mTimer");
00354     connect(mTimer,SIGNAL(timeout()),SLOT(mailCheck()));
00355   }
00356   else
00357   {
00358     mTimer->stop();
00359   }
00360   mTimer->start( checkInterval() * 60000 );
00361 }
00362 
00363 
00364 //-----------------------------------------------------------------------------
00365 void KMAccount::deinstallTimer()
00366 {
00367   delete mTimer;
00368   mTimer = 0;
00369 }
00370 
00371 //-----------------------------------------------------------------------------
00372 bool KMAccount::runPrecommand(const QString &precommand)
00373 {
00374   // Run the pre command if there is one
00375   if ( precommand.isEmpty() )
00376     return true;
00377 
00378   KMPrecommand precommandProcess(precommand, this);
00379 
00380   BroadcastStatus::instance()->setStatusMsg(
00381       i18n("Executing precommand %1").arg(precommand ));
00382 
00383   connect(&precommandProcess, SIGNAL(finished(bool)),
00384           SLOT(precommandExited(bool)));
00385 
00386   kdDebug(5006) << "Running precommand " << precommand << endl;
00387   if (!precommandProcess.start()) return false;
00388 
00389   kapp->eventLoop()->enterLoop();
00390 
00391   return mPrecommandSuccess;
00392 }
00393 
00394 //-----------------------------------------------------------------------------
00395 void KMAccount::precommandExited(bool success)
00396 {
00397   mPrecommandSuccess = success;
00398   kapp->eventLoop()->exitLoop();
00399 }
00400 
00401 //-----------------------------------------------------------------------------
00402 void KMAccount::mailCheck()
00403 {
00404   if (mTimer)
00405     mTimer->stop();
00406 
00407   if ( kmkernel ) {
00408     AccountManager *acctmgr = kmkernel->acctMgr();
00409     if ( acctmgr )
00410       acctmgr->singleCheckMail(this, false);
00411   }
00412 }
00413 
00414 //-----------------------------------------------------------------------------
00415 void KMAccount::sendReceipts()
00416 {
00417   QValueList<KMMessage*>::Iterator it;
00418   for(it = mReceipts.begin(); it != mReceipts.end(); ++it)
00419     kmkernel->msgSender()->send(*it); //might process events
00420   mReceipts.clear();
00421 }
00422 
00423 //-----------------------------------------------------------------------------
00424 QString KMAccount::encryptStr(const QString &aStr)
00425 {
00426   QString result;
00427   for (uint i = 0; i < aStr.length(); i++)
00428     /* yes, no typo. can't encode ' ' or '!' because
00429        they're the unicode BOM. stupid scrambling. stupid. */
00430     result += (aStr[i].unicode() <= 0x21 ) ? aStr[i] :
00431       QChar(0x1001F - aStr[i].unicode());
00432   return result;
00433 }
00434 
00435 //-----------------------------------------------------------------------------
00436 QString KMAccount::importPassword(const QString &aStr)
00437 {
00438   unsigned int i, val;
00439   unsigned int len = aStr.length();
00440   QCString result;
00441   result.resize(len+1);
00442 
00443   for (i=0; i<len; i++)
00444   {
00445     val = aStr[i] - ' ';
00446     val = (255-' ') - val;
00447     result[i] = (char)(val + ' ');
00448   }
00449   result[i] = '\0';
00450 
00451   return encryptStr(result);
00452 }
00453 
00454 void KMAccount::invalidateIMAPFolders()
00455 {
00456   // Default: Don't do anything. The IMAP account will handle it
00457 }
00458 
00459 void KMAccount::pseudoAssign( const KMAccount * a ) {
00460   if ( !a ) return;
00461 
00462   setName( a->name() );
00463   setId( a->id() );
00464   setCheckInterval( a->checkInterval() );
00465   setCheckExclude( a->checkExclude() );
00466   setFolder( a->folder() );
00467   setPrecommand( a->precommand() );
00468   setTrash( a->trash() );
00469   setIdentityId( a->identityId() );
00470 }
00471 
00472 //-----------------------------------------------------------------------------
00473 void KMAccount::checkDone( bool newmail, CheckStatus status )
00474 {
00475     setCheckingMail( false );
00476   // Reset the timeout for automatic mailchecking. The user might have
00477   // triggered the check manually.
00478   if (mTimer)
00479     mTimer->start( checkInterval() * 60000 );
00480   if ( mMailCheckProgressItem ) {
00481     // set mMailCheckProgressItem = 0 before calling setComplete() to prevent
00482     // a race condition
00483     ProgressItem *savedMailCheckProgressItem = mMailCheckProgressItem;
00484     mMailCheckProgressItem = 0;
00485     savedMailCheckProgressItem->setComplete(); // that will delete it
00486   }
00487 
00488   emit newMailsProcessed( mNewInFolder );
00489   emit finishedCheck( newmail, status );
00490   mNewInFolder.clear();
00491 }
00492 
00493 //-----------------------------------------------------------------------------
00494 void KMAccount::addToNewInFolder( QString folderId, int num )
00495 {
00496   if ( mNewInFolder.find( folderId ) == mNewInFolder.end() )
00497     mNewInFolder[folderId] = num;
00498   else
00499     mNewInFolder[folderId] += num;
00500 }