kmail Library API Documentation

imapaccountbase.cpp

00001 00024 #ifdef HAVE_CONFIG_H 00025 #include <config.h> 00026 #endif 00027 00028 #include "imapaccountbase.h" 00029 using KMail::SieveConfig; 00030 00031 #include "kmacctmgr.h" 00032 #include "kmfolder.h" 00033 #include "broadcaststatus.h" 00034 using KPIM::BroadcastStatus; 00035 #include "kmmainwin.h" 00036 #include "kmfolderimap.h" 00037 #include "kmmainwidget.h" 00038 #include "kmmainwin.h" 00039 #include "kmmsgpart.h" 00040 #include "acljobs.h" 00041 #include "kmfoldercachedimap.h" 00042 #include "bodyvisitor.h" 00043 using KMail::BodyVisitor; 00044 #include "imapjob.h" 00045 using KMail::ImapJob; 00046 #include "protocols.h" 00047 #include "progressmanager.h" 00048 using KPIM::ProgressManager; 00049 #include "kmfoldermgr.h" 00050 00051 #include <kapplication.h> 00052 #include <kdebug.h> 00053 #include <kconfig.h> 00054 #include <klocale.h> 00055 #include <kmessagebox.h> 00056 using KIO::MetaData; 00057 #include <kio/passdlg.h> 00058 using KIO::PasswordDialog; 00059 #include <kio/scheduler.h> 00060 #include <kio/slave.h> 00061 #include <mimelib/bodypart.h> 00062 #include <mimelib/body.h> 00063 #include <mimelib/headers.h> 00064 #include <mimelib/message.h> 00065 //using KIO::Scheduler; // use FQN below 00066 00067 #include <qregexp.h> 00068 #include <qstylesheet.h> 00069 00070 namespace KMail { 00071 00072 static const unsigned short int imapDefaultPort = 143; 00073 00074 // 00075 // 00076 // Ctor and Dtor 00077 // 00078 // 00079 00080 ImapAccountBase::ImapAccountBase( KMAcctMgr * parent, const QString & name, uint id ) 00081 : NetworkAccount( parent, name, id ), 00082 mPrefix( "/" ), 00083 mTotal( 0 ), 00084 mCountUnread( 0 ), 00085 mCountLastUnread( 0 ), 00086 mAutoExpunge( true ), 00087 mHiddenFolders( false ), 00088 mOnlySubscribedFolders( false ), 00089 mLoadOnDemand( true ), 00090 mListOnlyOpenFolders( false ), 00091 mProgressEnabled( false ), 00092 mErrorDialogIsActive( false ), 00093 mPasswordDialogIsActive( false ), 00094 mACLSupport( true ), 00095 mSlaveConnected( false ), 00096 mListDirProgressItem( 0 ) 00097 { 00098 mPort = imapDefaultPort; 00099 mBodyPartList.setAutoDelete(true); 00100 KIO::Scheduler::connect(SIGNAL(slaveError(KIO::Slave *, int, const QString &)), 00101 this, SLOT(slotSchedulerSlaveError(KIO::Slave *, int, const QString &))); 00102 KIO::Scheduler::connect(SIGNAL(slaveConnected(KIO::Slave *)), 00103 this, SLOT(slotSchedulerSlaveConnected(KIO::Slave *))); 00104 connect(&mNoopTimer, SIGNAL(timeout()), SLOT(slotNoopTimeout())); 00105 connect(&mIdleTimer, SIGNAL(timeout()), SLOT(slotIdleTimeout())); 00106 } 00107 00108 ImapAccountBase::~ImapAccountBase() { 00109 kdWarning( mSlave, 5006 ) 00110 << "slave should have been destroyed by subclass!" << endl; 00111 } 00112 00113 void ImapAccountBase::init() { 00114 mPrefix = '/'; 00115 mAutoExpunge = true; 00116 mHiddenFolders = false; 00117 mOnlySubscribedFolders = false; 00118 mLoadOnDemand = true; 00119 mListOnlyOpenFolders = false; 00120 mProgressEnabled = false; 00121 } 00122 00123 void ImapAccountBase::pseudoAssign( const KMAccount * a ) { 00124 NetworkAccount::pseudoAssign( a ); 00125 00126 const ImapAccountBase * i = dynamic_cast<const ImapAccountBase*>( a ); 00127 if ( !i ) return; 00128 00129 setPrefix( i->prefix() ); 00130 setAutoExpunge( i->autoExpunge() ); 00131 setHiddenFolders( i->hiddenFolders() ); 00132 setOnlySubscribedFolders( i->onlySubscribedFolders() ); 00133 setLoadOnDemand( i->loadOnDemand() ); 00134 setListOnlyOpenFolders( i->listOnlyOpenFolders() ); 00135 } 00136 00137 unsigned short int ImapAccountBase::defaultPort() const { 00138 return imapDefaultPort; 00139 } 00140 00141 QString ImapAccountBase::protocol() const { 00142 return useSSL() ? IMAP_SSL_PROTOCOL : IMAP_PROTOCOL; 00143 } 00144 00145 // 00146 // 00147 // Getters and Setters 00148 // 00149 // 00150 00151 void ImapAccountBase::setPrefix( const QString & prefix ) { 00152 mPrefix = prefix; 00153 mPrefix.remove( QRegExp( "[%*\"]" ) ); 00154 if ( mPrefix.isEmpty() || mPrefix[0] != '/' ) 00155 mPrefix.prepend( '/' ); 00156 if ( mPrefix[ mPrefix.length() - 1 ] != '/' ) 00157 mPrefix += '/'; 00158 #if 1 00159 setPrefixHook(); // ### needed while KMFolderCachedImap exists 00160 #else 00161 if ( mFolder ) mFolder->setImapPath( mPrefix ); 00162 #endif 00163 } 00164 00165 void ImapAccountBase::setAutoExpunge( bool expunge ) { 00166 mAutoExpunge = expunge; 00167 } 00168 00169 void ImapAccountBase::setHiddenFolders( bool show ) { 00170 mHiddenFolders = show; 00171 } 00172 00173 void ImapAccountBase::setOnlySubscribedFolders( bool show ) { 00174 mOnlySubscribedFolders = show; 00175 } 00176 00177 void ImapAccountBase::setLoadOnDemand( bool load ) { 00178 mLoadOnDemand = load; 00179 } 00180 00181 void ImapAccountBase::setListOnlyOpenFolders( bool only ) { 00182 mListOnlyOpenFolders = only; 00183 } 00184 00185 // 00186 // 00187 // read/write config 00188 // 00189 // 00190 00191 void ImapAccountBase::readConfig( /*const*/ KConfig/*Base*/ & config ) { 00192 NetworkAccount::readConfig( config ); 00193 00194 setPrefix( config.readEntry( "prefix", "/" ) ); 00195 setAutoExpunge( config.readBoolEntry( "auto-expunge", false ) ); 00196 setHiddenFolders( config.readBoolEntry( "hidden-folders", false ) ); 00197 setOnlySubscribedFolders( config.readBoolEntry( "subscribed-folders", false ) ); 00198 setLoadOnDemand( config.readBoolEntry( "loadondemand", false ) ); 00199 setListOnlyOpenFolders( config.readBoolEntry( "listOnlyOpenFolders", false ) ); 00200 } 00201 00202 void ImapAccountBase::writeConfig( KConfig/*Base*/ & config ) /*const*/ { 00203 NetworkAccount::writeConfig( config ); 00204 00205 config.writeEntry( "prefix", prefix() ); 00206 config.writeEntry( "auto-expunge", autoExpunge() ); 00207 config.writeEntry( "hidden-folders", hiddenFolders() ); 00208 config.writeEntry( "subscribed-folders", onlySubscribedFolders() ); 00209 config.writeEntry( "loadondemand", loadOnDemand() ); 00210 config.writeEntry( "listOnlyOpenFolders", listOnlyOpenFolders() ); 00211 } 00212 00213 // 00214 // 00215 // Network processing 00216 // 00217 // 00218 00219 MetaData ImapAccountBase::slaveConfig() const { 00220 MetaData m = NetworkAccount::slaveConfig(); 00221 00222 m.insert( "auth", auth() ); 00223 if ( autoExpunge() ) 00224 m.insert( "expunge", "auto" ); 00225 00226 return m; 00227 } 00228 00229 ImapAccountBase::ConnectionState ImapAccountBase::makeConnection() { 00230 00231 if ( mSlave && mSlaveConnected ) return Connected; 00232 if ( mPasswordDialogIsActive ) return Connecting; 00233 00234 if( mAskAgain || passwd().isEmpty() || login().isEmpty() ) { 00235 Q_ASSERT( !mSlave ); // disconnected on 'wrong login' error already, or first try 00236 QString log = login(); 00237 QString pass = passwd(); 00238 // We init "store" to true to indicate that we want to have the 00239 // "keep password" checkbox. Then, we set [Passwords]Keep to 00240 // storePasswd(), so that the checkbox in the dialog will be 00241 // init'ed correctly: 00242 bool store = true; 00243 KConfigGroup passwords( KGlobal::config(), "Passwords" ); 00244 passwords.writeEntry( "Keep", storePasswd() ); 00245 QString msg = i18n("You need to supply a username and a password to " 00246 "access this mailbox."); 00247 mPasswordDialogIsActive = true; 00248 if ( PasswordDialog::getNameAndPassword( log, pass, &store, msg, false, 00249 QString::null, name(), 00250 i18n("Account:") ) 00251 != QDialog::Accepted ) { 00252 mPasswordDialogIsActive = false; 00253 mAskAgain = false; 00254 emit connectionResult( KIO::ERR_USER_CANCELED, QString::null ); 00255 return Error; 00256 } 00257 mPasswordDialogIsActive = false; 00258 // The user has been given the chance to change login and 00259 // password, so copy both from the dialog: 00260 setPasswd( pass, store ); 00261 setLogin( log ); 00262 mAskAgain = false; 00263 } 00264 // already waiting for a connection? 00265 if ( mSlave && !mSlaveConnected ) return Connecting; 00266 00267 mSlaveConnected = false; 00268 mSlave = KIO::Scheduler::getConnectedSlave( getUrl(), slaveConfig() ); 00269 if ( !mSlave ) { 00270 KMessageBox::error(0, i18n("Could not start process for %1.") 00271 .arg( getUrl().protocol() ) ); 00272 return Error; 00273 } 00274 if ( mSlave->isConnected() ) { 00275 mSlaveConnected = true; 00276 return Connected; 00277 } 00278 00279 return Connecting; 00280 } 00281 00282 bool ImapAccountBase::handleJobError( KIO::Job *job, const QString& context, bool abortSync ) 00283 { 00284 return handleError( job->error(), job->errorText(), job, context, abortSync ); 00285 } 00286 00287 // Called when we're really all done. 00288 void ImapAccountBase::postProcessNewMail() { 00289 setCheckingMail(false); 00290 int newMails = 0; 00291 if ( mCountUnread > 0 && mCountUnread > mCountLastUnread ) { 00292 newMails = mCountUnread - mCountLastUnread; 00293 mCountLastUnread = mCountUnread; 00294 mCountUnread = 0; 00295 checkDone( true, CheckOK ); 00296 } else { 00297 mCountUnread = 0; 00298 checkDone( false, CheckOK ); 00299 } 00300 BroadcastStatus::instance()->setStatusMsgTransmissionCompleted( 00301 name(), newMails); 00302 } 00303 00304 //----------------------------------------------------------------------------- 00305 void ImapAccountBase::changeSubscription( bool subscribe, QString imapPath ) 00306 { 00307 // change the subscription of the folder 00308 KURL url = getUrl(); 00309 url.setPath(imapPath); 00310 00311 QByteArray packedArgs; 00312 QDataStream stream( packedArgs, IO_WriteOnly); 00313 00314 if (subscribe) 00315 stream << (int) 'u' << url; 00316 else 00317 stream << (int) 'U' << url; 00318 00319 // create the KIO-job 00320 if (makeConnection() != Connected) // ## doesn't handle Connecting 00321 return; 00322 KIO::SimpleJob *job = KIO::special(url, packedArgs, FALSE); 00323 KIO::Scheduler::assignJobToSlave(mSlave, job); 00324 jobData jd( url.url(), NULL ); 00325 // a bit of a hack to save one slot 00326 if (subscribe) jd.onlySubscribed = true; 00327 else jd.onlySubscribed = false; 00328 insertJob(job, jd); 00329 00330 connect(job, SIGNAL(result(KIO::Job *)), 00331 SLOT(slotSubscriptionResult(KIO::Job *))); 00332 } 00333 00334 //----------------------------------------------------------------------------- 00335 void ImapAccountBase::slotSubscriptionResult( KIO::Job * job ) 00336 { 00337 // result of a subscription-job 00338 JobIterator it = findJob( job ); 00339 if ( it == jobsEnd() ) return; 00340 bool onlySubscribed = (*it).onlySubscribed; 00341 QString path = static_cast<KIO::SimpleJob*>(job)->url().path(); 00342 if (job->error()) 00343 { 00344 handleJobError( job, i18n( "Error while trying to subscribe to %1:" ).arg( path ) + '\n' ); 00345 // ## emit subscriptionChanged here in case anyone needs it to support continue/cancel 00346 } 00347 else 00348 { 00349 emit subscriptionChanged( path, onlySubscribed ); 00350 if (mSlave) removeJob(job); 00351 } 00352 } 00353 00354 //----------------------------------------------------------------------------- 00355 // TODO imapPath can be removed once parent can be a KMFolderImapBase or whatever 00356 void ImapAccountBase::getUserRights( KMFolder* parent, const QString& imapPath ) 00357 { 00358 // There isn't much point in asking the server about a user's rights on his own inbox, 00359 // it might not be the effective permissions (at least with Cyrus, one can admin his own inbox, 00360 // even after a SETACL that removes the admin permissions. Other imap servers apparently 00361 // don't even allow removing one's own admin permission, so this code won't hurt either). 00362 if ( imapPath == "/INBOX/" ) { 00363 if ( parent->folderType() == KMFolderTypeImap ) 00364 static_cast<KMFolderImap*>( parent->storage() )->setUserRights( ACLJobs::All ); 00365 else if ( parent->folderType() == KMFolderTypeCachedImap ) 00366 static_cast<KMFolderCachedImap*>( parent->storage() )->setUserRights( ACLJobs::All ); 00367 emit receivedUserRights( parent ); // warning, you need to connect first to get that one 00368 return; 00369 } 00370 00371 KURL url = getUrl(); 00372 url.setPath(imapPath); 00373 00374 ACLJobs::GetUserRightsJob* job = ACLJobs::getUserRights( mSlave, url ); 00375 00376 jobData jd( url.url(), parent ); 00377 jd.cancellable = true; 00378 insertJob(job, jd); 00379 00380 connect(job, SIGNAL(result(KIO::Job *)), 00381 SLOT(slotGetUserRightsResult(KIO::Job *))); 00382 } 00383 00384 void ImapAccountBase::slotGetUserRightsResult( KIO::Job* _job ) 00385 { 00386 ACLJobs::GetUserRightsJob* job = static_cast<ACLJobs::GetUserRightsJob *>( _job ); 00387 JobIterator it = findJob( job ); 00388 if ( it == jobsEnd() ) return; 00389 00390 KMFolder* folder = (*it).parent; 00391 if ( job->error() ) { 00392 if ( job->error() == KIO::ERR_UNSUPPORTED_ACTION ) // that's when the imap server doesn't support ACLs 00393 mACLSupport = false; 00394 else 00395 kdWarning(5006) << "slotGetUserRightsResult: " << job->errorString() << endl; 00396 } else { 00397 #ifndef NDEBUG 00398 //kdDebug(5006) << "User Rights: " << ACLJobs::permissionsToString( job->permissions() ) << endl; 00399 #endif 00400 // Store the permissions 00401 if ( folder->folderType() == KMFolderTypeImap ) 00402 static_cast<KMFolderImap*>( folder->storage() )->setUserRights( job->permissions() ); 00403 else if ( folder->folderType() == KMFolderTypeCachedImap ) 00404 static_cast<KMFolderCachedImap*>( folder->storage() )->setUserRights( job->permissions() ); 00405 } 00406 if (mSlave) removeJob(job); 00407 emit receivedUserRights( folder ); 00408 } 00409 00410 //----------------------------------------------------------------------------- 00411 void ImapAccountBase::getACL( KMFolder* parent, const QString& imapPath ) 00412 { 00413 KURL url = getUrl(); 00414 url.setPath(imapPath); 00415 00416 ACLJobs::GetACLJob* job = ACLJobs::getACL( mSlave, url ); 00417 jobData jd( url.url(), parent ); 00418 jd.cancellable = true; 00419 insertJob(job, jd); 00420 00421 connect(job, SIGNAL(result(KIO::Job *)), 00422 SLOT(slotGetACLResult(KIO::Job *))); 00423 } 00424 00425 void ImapAccountBase::slotGetACLResult( KIO::Job* _job ) 00426 { 00427 ACLJobs::GetACLJob* job = static_cast<ACLJobs::GetACLJob *>( _job ); 00428 JobIterator it = findJob( job ); 00429 if ( it == jobsEnd() ) return; 00430 00431 KMFolder* folder = (*it).parent; 00432 emit receivedACL( folder, job, job->entries() ); 00433 if (mSlave) removeJob(job); 00434 } 00435 00436 00437 void ImapAccountBase::slotNoopTimeout() 00438 { 00439 if ( mSlave ) { 00440 QByteArray packedArgs; 00441 QDataStream stream( packedArgs, IO_WriteOnly ); 00442 00443 stream << ( int ) 'N'; 00444 00445 KIO::SimpleJob *job = KIO::special( getUrl(), packedArgs, false ); 00446 KIO::Scheduler::assignJobToSlave(mSlave, job); 00447 connect( job, SIGNAL(result( KIO::Job * ) ), 00448 this, SLOT( slotSimpleResult( KIO::Job * ) ) ); 00449 } else { 00450 /* Stop the timer, we have disconnected. We have to make sure it is 00451 started again when a new slave appears. */ 00452 mNoopTimer.stop(); 00453 } 00454 } 00455 00456 void ImapAccountBase::slotIdleTimeout() 00457 { 00458 if ( mSlave ) { 00459 KIO::Scheduler::disconnectSlave(mSlave); 00460 mSlave = 0; 00461 mSlaveConnected = false; 00462 /* As for the noop timer, we need to make sure this one is started 00463 again when a new slave goes up. */ 00464 mIdleTimer.stop(); 00465 } 00466 } 00467 00468 void ImapAccountBase::slotAbortRequested( KPIM::ProgressItem* item ) 00469 { 00470 if ( item ) 00471 item->setComplete(); 00472 killAllJobs(); 00473 } 00474 00475 00476 //----------------------------------------------------------------------------- 00477 void ImapAccountBase::slotSchedulerSlaveError(KIO::Slave *aSlave, int errorCode, 00478 const QString &errorMsg) 00479 { 00480 if (aSlave != mSlave) return; 00481 handleError( errorCode, errorMsg, 0, QString::null, true ); 00482 if ( mAskAgain ) 00483 makeConnection(); 00484 else 00485 emit connectionResult( errorCode, errorMsg ); 00486 } 00487 00488 //----------------------------------------------------------------------------- 00489 void ImapAccountBase::slotSchedulerSlaveConnected(KIO::Slave *aSlave) 00490 { 00491 if (aSlave != mSlave) return; 00492 mSlaveConnected = true; 00493 emit connectionResult( 0, QString::null ); // success 00494 } 00495 00496 //----------------------------------------------------------------------------- 00497 void ImapAccountBase::slotSimpleResult(KIO::Job * job) 00498 { 00499 JobIterator it = findJob( job ); 00500 bool quiet = false; 00501 if (it != mapJobData.end()) { 00502 quiet = (*it).quiet; 00503 if ( !(job->error() && !quiet) ) // the error handler removes in that case 00504 removeJob(it); 00505 } 00506 if (job->error()) { 00507 if (!quiet) 00508 handleJobError(job, QString::null ); 00509 else { 00510 if ( job->error() == KIO::ERR_CONNECTION_BROKEN && slave() ) { 00511 // make sure ERR_CONNECTION_BROKEN is properly handled and the slave 00512 // disconnected even when quiet() 00513 KIO::Scheduler::disconnectSlave( slave() ); 00514 mSlave = 0; 00515 } 00516 if (job->error() == KIO::ERR_SLAVE_DIED) 00517 slaveDied(); 00518 } 00519 } 00520 } 00521 00522 //----------------------------------------------------------------------------- 00523 bool ImapAccountBase::handlePutError( KIO::Job* job, jobData& jd, KMFolder* folder ) 00524 { 00525 Q_ASSERT( !jd.msgList.isEmpty() ); 00526 KMMessage* msg = jd.msgList.first(); 00527 // Use double-quotes around the subject to keep the sentence readable, 00528 // but don't use double quotes around the sender since from() might return a double-quoted name already 00529 const QString subject = msg->subject().isEmpty() ? i18n( "<unknown>" ) : QString("\"%1\"").arg( msg->subject() ); 00530 const QString from = msg->from().isEmpty() ? i18n( "<unknown>" ) : msg->from(); 00531 QString myError = "<p><b>" + i18n("Error while uploading message") 00532 + "</b></p><p>" 00533 + i18n("Could not upload the message dated %1 from %2 with subject %3 on the server.").arg( msg->dateStr(), QStyleSheet::escape( from ), QStyleSheet::escape( subject ) ) 00534 + "</p><p>" 00535 + i18n("The destination folder was %1, which has the URL %2.").arg( QStyleSheet::escape( folder->label() ), QStyleSheet::escape( jd.htmlURL() ) ) 00536 + "</p><p>" 00537 + i18n("The error message from the server communication is here:") + "</p>"; 00538 return handleJobError( job, myError ); 00539 } 00540 00541 //----------------------------------------------------------------------------- 00542 bool ImapAccountBase::handleError( int errorCode, const QString &errorMsg, KIO::Job* job, const QString& context, bool abortSync ) 00543 { 00544 // Copy job's data before a possible killAllJobs 00545 QStringList errors; 00546 if ( job && job->error() != KIO::ERR_SLAVE_DEFINED /*workaround for kdelibs-3.2*/) 00547 errors = job->detailedErrorStrings(); 00548 00549 bool jobsKilled = true; 00550 switch( errorCode ) { 00551 case KIO::ERR_SLAVE_DIED: slaveDied(); killAllJobs( true ); break; 00552 case KIO::ERR_COULD_NOT_LOGIN: // bad password 00553 mAskAgain = true; 00554 // fallthrough intended 00555 case KIO::ERR_CONNECTION_BROKEN: 00556 case KIO::ERR_COULD_NOT_CONNECT: 00557 // These mean that we'll have to reconnect on the next attempt, so disconnect and set mSlave to 0. 00558 killAllJobs( true ); 00559 break; 00560 case KIO::ERR_USER_CANCELED: 00561 killAllJobs( false ); 00562 break; 00563 default: 00564 if ( abortSync ) 00565 killAllJobs( false ); 00566 else 00567 jobsKilled = false; 00568 break; 00569 } 00570 00571 // check if we still display an error 00572 if ( !mErrorDialogIsActive && errorCode != KIO::ERR_USER_CANCELED ) 00573 { 00574 mErrorDialogIsActive = true; 00575 QString msg; 00576 QString caption; 00577 if ( errors.count() >= 3 ) { 00578 msg = QString( "<qt>") + context + errors[1] + '\n' + errors[2]; 00579 caption = errors[0]; 00580 } else { 00581 msg = context + '\n' + KIO::buildErrorString( errorCode, errorMsg ); 00582 caption = i18n("Error"); 00583 } 00584 00585 if ( jobsKilled || errorCode == KIO::ERR_COULD_NOT_LOGIN ) 00586 KMessageBox::error( kapp->activeWindow(), msg, caption ); 00587 else // i.e. we have a chance to continue, ask the user about it 00588 { 00589 int ret = KMessageBox::warningContinueCancel( kapp->activeWindow(), msg, caption ); 00590 if ( ret == KMessageBox::Cancel ) { 00591 jobsKilled = true; 00592 killAllJobs( false ); 00593 } 00594 } 00595 mErrorDialogIsActive = false; 00596 } else 00597 kdDebug(5006) << "suppressing error:" << errorMsg << endl; 00598 00599 if ( job && !jobsKilled ) 00600 removeJob( job ); 00601 return !jobsKilled; // jobsKilled==false -> continue==true 00602 } 00603 00604 //----------------------------------------------------------------------------- 00605 void ImapAccountBase::cancelMailCheck() 00606 { 00607 QMap<KIO::Job*, jobData>::Iterator it = mapJobData.begin(); 00608 while ( it != mapJobData.end() ) { 00609 kdDebug(5006) << "cancelMailCheck: job is cancellable: " << (*it).cancellable << endl; 00610 if ( (*it).cancellable ) { 00611 it.key()->kill(); 00612 QMap<KIO::Job*, jobData>::Iterator rmit = it; 00613 ++it; 00614 mapJobData.remove( rmit ); 00615 // We killed a job -> this kills the slave 00616 mSlave = 0; 00617 } else 00618 ++it; 00619 } 00620 00621 for( QPtrListIterator<FolderJob> it( mJobList ); it.current(); ++it ) { 00622 if ( it.current()->isCancellable() ) { 00623 FolderJob* job = it.current(); 00624 job->setPassiveDestructor( true ); 00625 mJobList.remove( job ); 00626 delete job; 00627 } else 00628 ++it; 00629 } 00630 } 00631 00632 00633 //----------------------------------------------------------------------------- 00634 QString ImapAccountBase::jobData::htmlURL() const 00635 { 00636 KURL u( url ); 00637 return u.htmlURL(); 00638 } 00639 00640 //----------------------------------------------------------------------------- 00641 void ImapAccountBase::processNewMailSingleFolder(KMFolder* folder) 00642 { 00643 mFoldersQueuedForChecking.append(folder); 00644 if ( checkingMail() ) 00645 { 00646 disconnect( this, SIGNAL( finishedCheck( bool, CheckStatus ) ), 00647 this, SLOT( slotCheckQueuedFolders() ) ); 00648 connect( this, SIGNAL( finishedCheck( bool, CheckStatus ) ), 00649 this, SLOT( slotCheckQueuedFolders() ) ); 00650 } else { 00651 slotCheckQueuedFolders(); 00652 } 00653 } 00654 00655 //----------------------------------------------------------------------------- 00656 void ImapAccountBase::slotCheckQueuedFolders() 00657 { 00658 disconnect( this, SIGNAL( finishedCheck( bool, CheckStatus ) ), 00659 this, SLOT( slotCheckQueuedFolders() ) ); 00660 00661 QValueList<QGuardedPtr<KMFolder> > mSaveList = mMailCheckFolders; 00662 mMailCheckFolders = mFoldersQueuedForChecking; 00663 kmkernel->acctMgr()->singleCheckMail(this, true); 00664 mMailCheckFolders = mSaveList; 00665 mFoldersQueuedForChecking.clear(); 00666 } 00667 00668 //----------------------------------------------------------------------------- 00669 bool ImapAccountBase::checkingMail( KMFolder *folder ) 00670 { 00671 if (checkingMail() && mFoldersQueuedForChecking.contains(folder)) 00672 return true; 00673 return false; 00674 } 00675 00676 //----------------------------------------------------------------------------- 00677 void ImapAccountBase::handleBodyStructure( QDataStream & stream, KMMessage * msg, 00678 const AttachmentStrategy *as ) 00679 { 00680 mBodyPartList.clear(); 00681 mCurrentMsg = msg; 00682 // make the parts and fill the mBodyPartList 00683 constructParts( stream, 1, 0, 0, msg->asDwMessage() ); 00684 if ( mBodyPartList.count() == 1 ) // we directly set the body later 00685 msg->deleteBodyParts(); 00686 00687 if ( !as ) 00688 { 00689 kdWarning(5006) << "ImapAccountBase::handleBodyStructure - found no attachment strategy!" << endl; 00690 return; 00691 } 00692 00693 // download parts according to attachmentstrategy 00694 BodyVisitor *visitor = BodyVisitorFactory::getVisitor( as ); 00695 visitor->visit( mBodyPartList ); 00696 QPtrList<KMMessagePart> parts = visitor->partsToLoad(); 00697 QPtrListIterator<KMMessagePart> it( parts ); 00698 KMMessagePart *part; 00699 while ( (part = it.current()) != 0 ) 00700 { 00701 ++it; 00702 kdDebug(5006) << "ImapAccountBase::handleBodyStructure - load " << part->partSpecifier() 00703 << " (" << part->originalContentTypeStr() << ")" << endl; 00704 if ( part->loadHeaders() ) 00705 { 00706 kdDebug(5006) << "load HEADER" << endl; 00707 FolderJob *job = msg->parent()->createJob( 00708 msg, FolderJob::tGetMessage, 0, part->partSpecifier()+".MIME" ); 00709 job->start(); 00710 } 00711 if ( part->loadPart() ) 00712 { 00713 kdDebug(5006) << "load Part" << endl; 00714 FolderJob *job = msg->parent()->createJob( 00715 msg, FolderJob::tGetMessage, 0, part->partSpecifier() ); 00716 job->start(); 00717 } 00718 } 00719 delete visitor; 00720 } 00721 00722 //----------------------------------------------------------------------------- 00723 void ImapAccountBase::constructParts( QDataStream & stream, int count, KMMessagePart* parentKMPart, 00724 DwBodyPart * parent, const DwMessage * dwmsg ) 00725 { 00726 int children; 00727 for (int i = 0; i < count; i++) 00728 { 00729 stream >> children; 00730 KMMessagePart* part = new KMMessagePart( stream ); 00731 part->setParent( parentKMPart ); 00732 mBodyPartList.append( part ); 00733 kdDebug(5006) << "ImapAccountBase::constructParts - created id " << part->partSpecifier() 00734 << " of type " << part->originalContentTypeStr() << endl; 00735 DwBodyPart *dwpart = mCurrentMsg->createDWBodyPart( part ); 00736 dwpart->Parse(); // also creates an encapsulated DwMessage if necessary 00737 00738 // kdDebug(5006) << "constructed dwpart " << dwpart << ",dwmsg " << dwmsg << ",parent " << parent 00739 // << ",dwparts msg " << dwpart->Body().Message() << endl; 00740 00741 if ( parent ) 00742 { 00743 // add to parent body 00744 parent->Body().AddBodyPart( dwpart ); 00745 } else if ( part->partSpecifier() != "0" && 00746 !part->partSpecifier().endsWith(".HEADER") ) 00747 { 00748 // add to message 00749 dwmsg->Body().AddBodyPart( dwpart ); 00750 } else 00751 dwpart = 0; 00752 00753 if ( !parentKMPart ) 00754 parentKMPart = part; 00755 00756 if (children > 0) 00757 { 00758 DwBodyPart* newparent = dwpart; 00759 const DwMessage* newmsg = dwmsg; 00760 if ( part->originalContentTypeStr() == "MESSAGE/RFC822" && 00761 dwpart->Body().Message() ) 00762 { 00763 // set the encapsulated message as new parent message 00764 newparent = 0; 00765 newmsg = dwpart->Body().Message(); 00766 } 00767 KMMessagePart* newParentKMPart = part; 00768 if ( part->partSpecifier().endsWith(".HEADER") ) // we don't want headers as parent 00769 newParentKMPart = parentKMPart; 00770 00771 constructParts( stream, children, newParentKMPart, newparent, newmsg ); 00772 } 00773 } 00774 } 00775 00776 //----------------------------------------------------------------------------- 00777 void ImapAccountBase::setImapStatus( KMFolder* folder, const QString& path, const QCString& flags ) 00778 { 00779 // set the status on the server, the uids are integrated in the path 00780 kdDebug(5006) << "setImapStatus path=" << path << " to: " << flags << endl; 00781 KURL url = getUrl(); 00782 url.setPath(path); 00783 00784 QByteArray packedArgs; 00785 QDataStream stream( packedArgs, IO_WriteOnly); 00786 00787 stream << (int) 'S' << url << flags; 00788 00789 if ( makeConnection() != ImapAccountBase::Connected ) 00790 return; // can't happen with dimap 00791 00792 KIO::SimpleJob *job = KIO::special(url, packedArgs, FALSE); 00793 KIO::Scheduler::assignJobToSlave(slave(), job); 00794 ImapAccountBase::jobData jd( url.url(), folder ); 00795 jd.path = path; 00796 insertJob(job, jd); 00797 connect(job, SIGNAL(result(KIO::Job *)), 00798 SLOT(slotSetStatusResult(KIO::Job *))); 00799 } 00800 //----------------------------------------------------------------------------- 00801 void ImapAccountBase::slotSetStatusResult(KIO::Job * job) 00802 { 00803 ImapAccountBase::JobIterator it = findJob(job); 00804 if ( it == jobsEnd() ) return; 00805 int errorCode = job->error(); 00806 if (errorCode && errorCode != KIO::ERR_CANNOT_OPEN_FOR_WRITING) 00807 { 00808 bool cont = handleJobError( job, i18n( "Error while uploading status of messages to server: " ) + '\n' ); 00809 emit imapStatusChanged( (*it).parent, (*it).path, cont ); 00810 } 00811 else 00812 { 00813 emit imapStatusChanged( (*it).parent, (*it).path, true ); 00814 removeJob(it); 00815 } 00816 } 00817 00818 //----------------------------------------------------------------------------- 00819 void ImapAccountBase::setFolder(KMFolder* folder, bool addAccount) 00820 { 00821 if (folder) 00822 { 00823 folder->setSystemLabel(name()); 00824 folder->setId(id()); 00825 } 00826 NetworkAccount::setFolder(folder, addAccount); 00827 } 00828 00829 //----------------------------------------------------------------------------- 00830 void ImapAccountBase::removeJob( JobIterator& it ) 00831 { 00832 if( (*it).progressItem ) { 00833 (*it).progressItem->setComplete(); 00834 (*it).progressItem = 0; 00835 } 00836 mapJobData.remove( it ); 00837 } 00838 00839 //----------------------------------------------------------------------------- 00840 KPIM::ProgressItem* ImapAccountBase::listDirProgressItem() 00841 { 00842 if ( !mListDirProgressItem ) 00843 { 00844 mListDirProgressItem = ProgressManager::createProgressItem( 00845 "ListDir" + name(), 00846 name(), 00847 i18n("retrieving folders"), 00848 true, 00849 useSSL() || useTLS() ); 00850 connect ( mListDirProgressItem, 00851 SIGNAL( progressItemCanceled( ProgressItem* ) ), 00852 this, 00853 SLOT( slotAbortRequested( ProgressItem* ) ) ); 00854 // Start with a guessed value of the old folder count plus 5%. As long 00855 // as the list of folders doesn't constantly change, that should be good 00856 // enough. 00857 unsigned int count = folderCount(); 00858 mListDirProgressItem->setTotalItems( count + (unsigned int)(count*0.05) ); 00859 } 00860 return mListDirProgressItem; 00861 } 00862 00863 unsigned int ImapAccountBase::folderCount() const 00864 { 00865 if ( !rootFolder() || !rootFolder()->folder() || !rootFolder()->folder()->child() ) 00866 return 0; 00867 return kmkernel->imapFolderMgr()->folderCount( rootFolder()->folder()->child() ); 00868 } 00869 00870 } // namespace KMail 00871 00872 #include "imapaccountbase.moc"
KDE Logo
This file is part of the documentation for kmail Library Version 3.3.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Fri Aug 27 12:52:17 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003