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 #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 
00167 //-----------------------------------------------------------------------------
00168 void KMAccount::writeConfig(KConfig& config)
00169 {
00170   // ID, Name
00171   KAccount::writeConfig(config);
00172 
00173   config.writeEntry("Type", type());
00174   config.writeEntry("Folder", mFolder ? mFolder->idString() : QString::null);
00175   config.writeEntry("check-interval", mInterval);
00176   config.writeEntry("check-exclude", mExclude);
00177   config.writePathEntry("precommand", mPrecommand);
00178   config.writeEntry("trash", mTrash);
00179   if ( mIdentityId && mIdentityId != kmkernel->identityManager()->defaultIdentity().uoid() )
00180     config.writeEntry("identity-id", mIdentityId);
00181   else
00182     config.deleteEntry("identity-id");
00183 }
00184 
00185 
00186 //-----------------------------------------------------------------------------
00187 void KMAccount::sendReceipt(KMMessage* aMsg)
00188 {
00189   KConfig* cfg = KMKernel::config();
00190   bool sendReceipts;
00191 
00192   KConfigGroupSaver saver(cfg, "General");
00193 
00194   sendReceipts = cfg->readBoolEntry("send-receipts", false);
00195   if (!sendReceipts) return;
00196 
00197   KMMessage *newMsg = aMsg->createDeliveryReceipt();
00198   if (newMsg) {
00199     mReceipts.append(newMsg);
00200     QTimer::singleShot( 0, this, SLOT( sendReceipts() ) );
00201   }
00202 }
00203 
00204 
00205 //-----------------------------------------------------------------------------
00206 bool KMAccount::processNewMsg(KMMessage* aMsg)
00207 {
00208   int rc, processResult;
00209 
00210   assert(aMsg != 0);
00211 
00212   // Save this one for readding
00213   KMFolderCachedImap* parent = 0;
00214   if( type() == "cachedimap" )
00215     parent = static_cast<KMFolderCachedImap*>( aMsg->storage() );
00216 
00217   // checks whether we should send delivery receipts
00218   // and sends them.
00219   sendReceipt(aMsg);
00220 
00221   // Set status of new messages that are marked as old to read, otherwise
00222   // the user won't see which messages newly arrived.
00223   // This is only valid for pop accounts and produces wrong stati for imap.
00224   if ( type() != "cachedimap" && type() != "imap" ) {
00225     if ( aMsg->isOld() )
00226       aMsg->setStatus(KMMsgStatusUnread);  // -sanders
00227     //    aMsg->setStatus(KMMsgStatusRead);
00228     else
00229       aMsg->setStatus(KMMsgStatusNew);
00230   }
00231 /*
00232 QFile fileD0( "testdat_xx-kmaccount-0" );
00233 if( fileD0.open( IO_WriteOnly ) ) {
00234     QDataStream ds( &fileD0 );
00235     ds.writeRawBytes( aMsg->asString(), aMsg->asString().length() );
00236     fileD0.close();  // If data is 0 we just create a zero length file.
00237 }
00238 */
00239   // 0==message moved; 1==processing ok, no move; 2==critical error, abort!
00240 
00241   processResult = kmkernel->filterMgr()->process(aMsg,KMFilterMgr::Inbound,true,id());
00242   if (processResult == 2) {
00243     perror("Critical error: Unable to collect mail (out of space?)");
00244     KMessageBox::information(0,(i18n("Critical error: "
00245       "Unable to collect mail: ")) + QString::fromLocal8Bit(strerror(errno)));
00246     return false;
00247   }
00248   else if (processResult == 1)
00249   {
00250     if( type() == "cachedimap" )
00251       ; // already done by caller: parent->addMsgInternal( aMsg, false );
00252     else {
00253       // TODO: Perhaps it would be best, if this if was handled by a virtual
00254       // method, so the if( !dimap ) above could die?
00255       kmkernel->filterMgr()->tempOpenFolder(mFolder);
00256       rc = mFolder->addMsg(aMsg);
00257 /*
00258 QFile fileD0( "testdat_xx-kmaccount-1" );
00259 if( fileD0.open( IO_WriteOnly ) ) {
00260     QDataStream ds( &fileD0 );
00261     ds.writeRawBytes( aMsg->asString(), aMsg->asString().length() );
00262     fileD0.close();  // If data is 0 we just create a zero length file.
00263 }
00264 */
00265       if (rc) {
00266         perror("failed to add message");
00267         KMessageBox::information(0, i18n("Failed to add message:\n") +
00268                                  QString(strerror(rc)));
00269         return false;
00270       }
00271       int count = mFolder->count();
00272       // If count == 1, the message is immediately displayed
00273       if (count != 1) mFolder->unGetMsg(count - 1);
00274     }
00275   }
00276 
00277   // Count number of new messages for each folder
00278   QString folderId;
00279   if ( processResult == 1 ) {
00280     folderId = ( type() == "cachedimap" ) ? parent->folder()->idString()
00281                                           : mFolder->idString();
00282   }
00283   else {
00284     folderId = aMsg->parent()->idString();
00285   }
00286   addToNewInFolder( folderId, 1 );
00287 
00288   return true; //Everything's fine - message has been added by filter  }
00289 }
00290 
00291 //-----------------------------------------------------------------------------
00292 void KMAccount::setCheckInterval(int aInterval)
00293 {
00294   if (aInterval <= 0)
00295     mInterval = 0;
00296   else
00297     mInterval = aInterval;
00298   // Don't call installTimer from here! See #117935.
00299 }
00300 
00301 int KMAccount::checkInterval() const
00302 {
00303   if ( mInterval <= 0 )
00304     return mInterval;
00305   return QMAX( mInterval, GlobalSettings::self()->minimumCheckInterval() );
00306 }
00307 
00308 //----------------------------------------------------------------------------
00309 void KMAccount::deleteFolderJobs()
00310 {
00311   mJobList.setAutoDelete(true);
00312   mJobList.clear();
00313   mJobList.setAutoDelete(false);
00314 }
00315 
00316 //----------------------------------------------------------------------------
00317 void KMAccount::ignoreJobsForMessage( KMMessage* msg )
00318 {
00319   //FIXME: remove, make folders handle those
00320   for( QPtrListIterator<FolderJob> it(mJobList); it.current(); ++it ) {
00321     if ( it.current()->msgList().first() == msg) {
00322       FolderJob *job = it.current();
00323       mJobList.remove( job );
00324       delete job;
00325       break;
00326     }
00327   }
00328 }
00329 
00330 //-----------------------------------------------------------------------------
00331 void KMAccount::setCheckExclude(bool aExclude)
00332 {
00333   mExclude = aExclude;
00334 }
00335 
00336 
00337 //-----------------------------------------------------------------------------
00338 void KMAccount::installTimer()
00339 {
00340   if (mInterval <= 0) return;
00341   if(!mTimer)
00342   {
00343     mTimer = new QTimer(0, "mTimer");
00344     connect(mTimer,SIGNAL(timeout()),SLOT(mailCheck()));
00345   }
00346   else
00347   {
00348     mTimer->stop();
00349   }
00350   mTimer->start( checkInterval() * 60000 );
00351 }
00352 
00353 
00354 //-----------------------------------------------------------------------------
00355 void KMAccount::deinstallTimer()
00356 {
00357   delete mTimer;
00358   mTimer = 0;
00359 }
00360 
00361 //-----------------------------------------------------------------------------
00362 bool KMAccount::runPrecommand(const QString &precommand)
00363 {
00364   // Run the pre command if there is one
00365   if ( precommand.isEmpty() )
00366     return true;
00367 
00368   KMPrecommand precommandProcess(precommand, this);
00369 
00370   BroadcastStatus::instance()->setStatusMsg(
00371       i18n("Executing precommand %1").arg(precommand ));
00372 
00373   connect(&precommandProcess, SIGNAL(finished(bool)),
00374           SLOT(precommandExited(bool)));
00375 
00376   kdDebug(5006) << "Running precommand " << precommand << endl;
00377   if (!precommandProcess.start()) return false;
00378 
00379   kapp->eventLoop()->enterLoop();
00380 
00381   return mPrecommandSuccess;
00382 }
00383 
00384 //-----------------------------------------------------------------------------
00385 void KMAccount::precommandExited(bool success)
00386 {
00387   mPrecommandSuccess = success;
00388   kapp->eventLoop()->exitLoop();
00389 }
00390 
00391 //-----------------------------------------------------------------------------
00392 void KMAccount::mailCheck()
00393 {
00394   if (mTimer)
00395     mTimer->stop();
00396 
00397   if ( kmkernel ) {
00398     AccountManager *acctmgr = kmkernel->acctMgr();
00399     if ( acctmgr )
00400       acctmgr->singleCheckMail(this, false);
00401   }
00402 }
00403 
00404 //-----------------------------------------------------------------------------
00405 void KMAccount::sendReceipts()
00406 {
00407   QValueList<KMMessage*>::Iterator it;
00408   for(it = mReceipts.begin(); it != mReceipts.end(); ++it)
00409     kmkernel->msgSender()->send(*it); //might process events
00410   mReceipts.clear();
00411 }
00412 
00413 //-----------------------------------------------------------------------------
00414 QString KMAccount::encryptStr(const QString &aStr)
00415 {
00416   QString result;
00417   for (uint i = 0; i < aStr.length(); i++)
00418     /* yes, no typo. can't encode ' ' or '!' because
00419        they're the unicode BOM. stupid scrambling. stupid. */
00420     result += (aStr[i].unicode() <= 0x21 ) ? aStr[i] :
00421       QChar(0x1001F - aStr[i].unicode());
00422   return result;
00423 }
00424 
00425 //-----------------------------------------------------------------------------
00426 QString KMAccount::importPassword(const QString &aStr)
00427 {
00428   unsigned int i, val;
00429   unsigned int len = aStr.length();
00430   QCString result;
00431   result.resize(len+1);
00432 
00433   for (i=0; i<len; i++)
00434   {
00435     val = aStr[i] - ' ';
00436     val = (255-' ') - val;
00437     result[i] = (char)(val + ' ');
00438   }
00439   result[i] = '\0';
00440 
00441   return encryptStr(result);
00442 }
00443 
00444 void KMAccount::invalidateIMAPFolders()
00445 {
00446   // Default: Don't do anything. The IMAP account will handle it
00447 }
00448 
00449 void KMAccount::pseudoAssign( const KMAccount * a ) {
00450   if ( !a ) return;
00451 
00452   setName( a->name() );
00453   setId( a->id() );
00454   setCheckInterval( a->checkInterval() );
00455   setCheckExclude( a->checkExclude() );
00456   setFolder( a->folder() );
00457   setPrecommand( a->precommand() );
00458   setTrash( a->trash() );
00459   setIdentityId( a->identityId() );
00460 }
00461 
00462 //-----------------------------------------------------------------------------
00463 void KMAccount::checkDone( bool newmail, CheckStatus status )
00464 {
00465     setCheckingMail( false );
00466   // Reset the timeout for automatic mailchecking. The user might have
00467   // triggered the check manually.
00468   if (mTimer)
00469     mTimer->start( checkInterval() * 60000 );
00470   if ( mMailCheckProgressItem ) {
00471     // set mMailCheckProgressItem = 0 before calling setComplete() to prevent
00472     // a race condition
00473     ProgressItem *savedMailCheckProgressItem = mMailCheckProgressItem;
00474     mMailCheckProgressItem = 0;
00475     savedMailCheckProgressItem->setComplete(); // that will delete it
00476   }
00477 
00478   emit newMailsProcessed( mNewInFolder );
00479   emit finishedCheck( newmail, status );
00480   mNewInFolder.clear();
00481 }
00482 
00483 //-----------------------------------------------------------------------------
00484 void KMAccount::addToNewInFolder( QString folderId, int num )
00485 {
00486   if ( mNewInFolder.find( folderId ) == mNewInFolder.end() )
00487     mNewInFolder[folderId] = num;
00488   else
00489     mNewInFolder[folderId] += num;
00490 }
KDE Home | KDE Accessibility Home | Description of Access Keys