kmail

kmaccount.cpp

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