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