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