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 <tqeventloop.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 TQString &precommand, TQObject *parent) 00046 : TQObject(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, TQT_SIGNAL(processExited(KProcess *)), 00055 TQT_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 TQString& 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 TQString& 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 TQString 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() : TQString()); 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 TQTimer::singleShot( 0, this, TQT_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 TQFile fileD0( "testdat_xx-kmaccount-0" ); 00243 if( fileD0.open( IO_WriteOnly ) ) { 00244 TQDataStream 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: ")) + TQString::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 TQFile fileD0( "testdat_xx-kmaccount-1" ); 00269 if( fileD0.open( IO_WriteOnly ) ) { 00270 TQDataStream 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 TQString(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 TQString 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 TQMAX( 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( TQPtrListIterator<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 TQTimer(0, "mTimer"); 00354 connect(mTimer,TQT_SIGNAL(timeout()),TQT_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 TQString &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, TQT_SIGNAL(finished(bool)), 00384 TQT_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 TQValueList<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 TQString KMAccount::encryptStr(const TQString &aStr) 00425 { 00426 TQString 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 TQChar(0x1001F - aStr[i].unicode()); 00432 return result; 00433 } 00434 00435 //----------------------------------------------------------------------------- 00436 TQString KMAccount::importPassword(const TQString &aStr) 00437 { 00438 unsigned int i, val; 00439 unsigned int len = aStr.length(); 00440 TQCString 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( TQString folderId, int num ) 00495 { 00496 if ( mNewInFolder.find( folderId ) == mNewInFolder.end() ) 00497 mNewInFolder[folderId] = num; 00498 else 00499 mNewInFolder[folderId] += num; 00500 }