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