kmail

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 "accountmanager.h"
00032 using KMail::AccountManager;
00033 #include "kmfolder.h"
00034 #include "broadcaststatus.h"
00035 using KPIM::BroadcastStatus;
00036 #include "kmmainwin.h"
00037 #include "kmfolderimap.h"
00038 #include "kmmainwidget.h"
00039 #include "kmmainwin.h"
00040 #include "kmmsgpart.h"
00041 #include "acljobs.h"
00042 #include "kmfoldercachedimap.h"
00043 #include "bodyvisitor.h"
00044 using KMail::BodyVisitor;
00045 #include "imapjob.h"
00046 using KMail::ImapJob;
00047 #include "protocols.h"
00048 #include "progressmanager.h"
00049 using KPIM::ProgressManager;
00050 #include "kmfoldermgr.h"
00051 #include "listjob.h"
00052 
00053 #include <kapplication.h>
00054 #include <kdebug.h>
00055 #include <kconfig.h>
00056 #include <klocale.h>
00057 #include <kmessagebox.h>
00058 using KIO::MetaData;
00059 #include <kio/passdlg.h>
00060 using KIO::PasswordDialog;
00061 #include <kio/scheduler.h>
00062 #include <kio/slave.h>
00063 #include <mimelib/bodypart.h>
00064 #include <mimelib/body.h>
00065 #include <mimelib/headers.h>
00066 #include <mimelib/message.h>
00067 //using KIO::Scheduler; // use FQN below
00068 
00069 #include <qregexp.h>
00070 #include <qstylesheet.h>
00071 
00072 namespace KMail {
00073 
00074   static const unsigned short int imapDefaultPort = 143;
00075 
00076   //
00077   //
00078   // Ctor and Dtor
00079   //
00080   //
00081 
00082   ImapAccountBase::ImapAccountBase( AccountManager * parent, const QString & name, uint id )
00083     : NetworkAccount( parent, name, id ),
00084       mTotal( 0 ),
00085       mCountUnread( 0 ),
00086       mCountLastUnread( 0 ),
00087       mAutoExpunge( true ),
00088       mHiddenFolders( false ),
00089       mOnlySubscribedFolders( false ),
00090       mLoadOnDemand( true ),
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       mCheckingSingleFolder( false ),
00101       mListDirProgressItem( 0 )
00102   {
00103     mPort = imapDefaultPort;
00104     mBodyPartList.setAutoDelete(true);
00105     KIO::Scheduler::connect(SIGNAL(slaveError(KIO::Slave *, int, const QString &)),
00106                             this, SLOT(slotSchedulerSlaveError(KIO::Slave *, int, const QString &)));
00107     KIO::Scheduler::connect(SIGNAL(slaveConnected(KIO::Slave *)),
00108                             this, SLOT(slotSchedulerSlaveConnected(KIO::Slave *)));
00109     connect(&mNoopTimer, SIGNAL(timeout()), SLOT(slotNoopTimeout()));
00110     connect(&mIdleTimer, SIGNAL(timeout()), SLOT(slotIdleTimeout()));
00111   }
00112 
00113   ImapAccountBase::~ImapAccountBase() {
00114     kdWarning( mSlave, 5006 )
00115       << "slave should have been destroyed by subclass!" << endl;
00116   }
00117 
00118   void ImapAccountBase::init() {
00119     mAutoExpunge = true;
00120     mHiddenFolders = false;
00121     mOnlySubscribedFolders = false;
00122     mLoadOnDemand = true;
00123     mListOnlyOpenFolders = false;
00124     mProgressEnabled = false;
00125   }
00126 
00127   void ImapAccountBase::pseudoAssign( const KMAccount * a ) {
00128     NetworkAccount::pseudoAssign( a );
00129 
00130     const ImapAccountBase * i = dynamic_cast<const ImapAccountBase*>( a );
00131     if ( !i ) return;
00132 
00133     setAutoExpunge( i->autoExpunge() );
00134     setHiddenFolders( i->hiddenFolders() );
00135     setOnlySubscribedFolders( i->onlySubscribedFolders() );
00136     setLoadOnDemand( i->loadOnDemand() );
00137     setListOnlyOpenFolders( i->listOnlyOpenFolders() );
00138     setNamespaces( i->namespaces() );
00139     setNamespaceToDelimiter( i->namespaceToDelimiter() );
00140   }
00141 
00142   unsigned short int ImapAccountBase::defaultPort() const {
00143     return imapDefaultPort;
00144   }
00145 
00146   QString ImapAccountBase::protocol() const {
00147     return useSSL() ? IMAP_SSL_PROTOCOL : IMAP_PROTOCOL;
00148   }
00149 
00150   //
00151   //
00152   // Getters and Setters
00153   //
00154   //
00155 
00156   void ImapAccountBase::setAutoExpunge( bool expunge ) {
00157     mAutoExpunge = expunge;
00158   }
00159 
00160   void ImapAccountBase::setHiddenFolders( bool show ) {
00161     mHiddenFolders = show;
00162   }
00163 
00164   void ImapAccountBase::setOnlySubscribedFolders( bool show ) {
00165     mOnlySubscribedFolders = show;
00166   }
00167 
00168   void ImapAccountBase::setLoadOnDemand( bool load ) {
00169     mLoadOnDemand = load;
00170   }
00171 
00172   void ImapAccountBase::setListOnlyOpenFolders( bool only ) {
00173     mListOnlyOpenFolders = only;
00174   }
00175 
00176   //
00177   //
00178   // read/write config
00179   //
00180   //
00181 
00182   void ImapAccountBase::readConfig( /*const*/ KConfig/*Base*/ & config ) {
00183     NetworkAccount::readConfig( config );
00184 
00185     setAutoExpunge( config.readBoolEntry( "auto-expunge", false ) );
00186     setHiddenFolders( config.readBoolEntry( "hidden-folders", false ) );
00187     setOnlySubscribedFolders( config.readBoolEntry( "subscribed-folders", false ) );
00188     setLoadOnDemand( config.readBoolEntry( "loadondemand", false ) );
00189     setListOnlyOpenFolders( config.readBoolEntry( "listOnlyOpenFolders", false ) );
00190     // read namespaces
00191     nsMap map;
00192     QStringList list = config.readListEntry( QString::number( PersonalNS ) );
00193     if ( !list.isEmpty() )
00194       map[PersonalNS] = list.gres( "\"", "" );
00195     list = config.readListEntry( QString::number( OtherUsersNS ) );
00196     if ( !list.isEmpty() )
00197       map[OtherUsersNS] = list.gres( "\"", "" );
00198     list = config.readListEntry( QString::number( SharedNS ) );
00199     if ( !list.isEmpty() )
00200       map[SharedNS] = list.gres( "\"", "" );
00201     setNamespaces( map );
00202     // read namespace - delimiter
00203     namespaceDelim entries = config.entryMap( config.group() );
00204     namespaceDelim namespaceToDelimiter;
00205     for ( namespaceDelim::ConstIterator it = entries.begin(); 
00206           it != entries.end(); ++it ) {
00207       if ( it.key().startsWith( "Namespace:" ) ) {
00208         QString key = it.key().right( it.key().length() - 10 );
00209         namespaceToDelimiter[key] = it.data();
00210       }
00211     }
00212     setNamespaceToDelimiter( namespaceToDelimiter );
00213     mOldPrefix = config.readEntry( "prefix" );
00214     if ( !mOldPrefix.isEmpty() ) {
00215       makeConnection();
00216     }
00217   }
00218 
00219   void ImapAccountBase::writeConfig( KConfig/*Base*/ & config ) /*const*/ {
00220     NetworkAccount::writeConfig( config );
00221 
00222     config.writeEntry( "auto-expunge", autoExpunge() );
00223     config.writeEntry( "hidden-folders", hiddenFolders() );
00224     config.writeEntry( "subscribed-folders", onlySubscribedFolders() );
00225     config.writeEntry( "loadondemand", loadOnDemand() );
00226     config.writeEntry( "listOnlyOpenFolders", listOnlyOpenFolders() );
00227     QString data;
00228     for ( nsMap::Iterator it = mNamespaces.begin(); it != mNamespaces.end(); ++it ) {
00229       if ( !it.data().isEmpty() ) {
00230         data = "\"" + it.data().join("\",\"") + "\"";
00231         config.writeEntry( QString::number( it.key() ), data );
00232       }
00233     }
00234     QString key;
00235     for ( namespaceDelim::ConstIterator it = mNamespaceToDelimiter.begin(); 
00236           it != mNamespaceToDelimiter.end(); ++it ) {
00237       key = "Namespace:" + it.key();
00238       config.writeEntry( key, it.data() );
00239     }
00240   }
00241 
00242   //
00243   //
00244   // Network processing
00245   //
00246   //
00247 
00248   MetaData ImapAccountBase::slaveConfig() const {
00249     MetaData m = NetworkAccount::slaveConfig();
00250 
00251     m.insert( "auth", auth() );
00252     if ( autoExpunge() )
00253       m.insert( "expunge", "auto" );
00254 
00255     return m;
00256   }
00257 
00258   ImapAccountBase::ConnectionState ImapAccountBase::makeConnection() 
00259   {
00260     if ( mSlave && mSlaveConnected ) {
00261       return Connected;
00262     }
00263     if ( mPasswordDialogIsActive ) return Connecting;
00264 
00265     if( mAskAgain || ( ( passwd().isEmpty() || login().isEmpty() ) &&
00266                          auth() != "GSSAPI" ) ) {
00267 
00268       Q_ASSERT( !mSlave ); // disconnected on 'wrong login' error already, or first try
00269       QString log = login();
00270       QString pass = passwd();
00271       // We init "store" to true to indicate that we want to have the
00272       // "keep password" checkbox. Then, we set [Passwords]Keep to
00273       // storePasswd(), so that the checkbox in the dialog will be
00274       // init'ed correctly:
00275       KConfigGroup passwords( KGlobal::config(), "Passwords" );
00276       passwords.writeEntry( "Keep", storePasswd() );
00277       QString msg = i18n("You need to supply a username and a password to "
00278              "access this mailbox.");
00279       mPasswordDialogIsActive = true;
00280       
00281       PasswordDialog dlg( msg, log, true /* store pw */, true, KMKernel::self()->mainWin() );
00282       dlg.setPlainCaption( i18n("Authorization Dialog") );
00283       dlg.addCommentLine( i18n("Account:"), name() );
00284       int ret = dlg.exec();
00285       if (ret != QDialog::Accepted ) {
00286         mPasswordDialogIsActive = false;
00287         mAskAgain = false;
00288         emit connectionResult( KIO::ERR_USER_CANCELED, QString::null );
00289         return Error;
00290       }
00291       mPasswordDialogIsActive = false;
00292       // The user has been given the chance to change login and
00293       // password, so copy both from the dialog:
00294       setPasswd( dlg.password(), dlg.keepPassword() );
00295       setLogin( dlg.username() );
00296       mAskAgain = false;
00297     }
00298     // already waiting for a connection?
00299     if ( mSlave && !mSlaveConnected ) return Connecting;
00300 
00301     mSlaveConnected = false;
00302     mSlave = KIO::Scheduler::getConnectedSlave( getUrl(), slaveConfig() );
00303     if ( !mSlave ) {
00304       KMessageBox::error(0, i18n("Could not start process for %1.")
00305              .arg( getUrl().protocol() ) );
00306       return Error;
00307     }
00308     if ( mSlave->isConnected() ) {
00309       slotSchedulerSlaveConnected( mSlave );
00310       return Connected;
00311     }
00312 
00313     return Connecting;
00314   }
00315 
00316   bool ImapAccountBase::handleJobError( KIO::Job *job, const QString& context, bool abortSync )
00317   {
00318     JobIterator it = findJob( job );
00319     if ( it != jobsEnd() && (*it).progressItem )
00320     {
00321       (*it).progressItem->setComplete();
00322       (*it).progressItem = 0;
00323     }
00324     return handleError( job->error(), job->errorText(), job, context, abortSync );
00325   }
00326 
00327   // Called when we're really all done.
00328   void ImapAccountBase::postProcessNewMail( bool showStatusMsg ) {
00329     setCheckingMail(false);
00330     int newMails = 0;
00331     if ( mCountUnread > 0 && mCountUnread > mCountLastUnread ) {
00332       newMails = mCountUnread  - mCountLastUnread;
00333       mCountLastUnread = mCountUnread;
00334       mCountUnread = 0;
00335       checkDone( true, CheckOK );
00336     } else {
00337       mCountUnread = 0;
00338       checkDone( false, CheckOK );
00339     }
00340     if ( showStatusMsg )
00341       BroadcastStatus::instance()->setStatusMsgTransmissionCompleted(
00342           name(), newMails);
00343   }
00344 
00345   //-----------------------------------------------------------------------------
00346   void ImapAccountBase::changeSubscription( bool subscribe, const QString& imapPath )
00347   {
00348     // change the subscription of the folder
00349     KURL url = getUrl();
00350     url.setPath(imapPath);
00351 
00352     QByteArray packedArgs;
00353     QDataStream stream( packedArgs, IO_WriteOnly);
00354 
00355     if (subscribe)
00356       stream << (int) 'u' << url;
00357     else
00358       stream << (int) 'U' << url;
00359 
00360     // create the KIO-job
00361     if ( makeConnection() != Connected ) 
00362       return;// ## doesn't handle Connecting
00363     KIO::SimpleJob *job = KIO::special(url, packedArgs, FALSE);
00364     KIO::Scheduler::assignJobToSlave(mSlave, job);
00365     jobData jd( url.url(), NULL );
00366     // a bit of a hack to save one slot
00367     if (subscribe) jd.onlySubscribed = true;
00368     else jd.onlySubscribed = false;
00369     insertJob(job, jd);
00370 
00371     connect(job, SIGNAL(result(KIO::Job *)),
00372         SLOT(slotSubscriptionResult(KIO::Job *)));
00373   }
00374 
00375   //-----------------------------------------------------------------------------
00376   void ImapAccountBase::slotSubscriptionResult( KIO::Job * job )
00377   {
00378     // result of a subscription-job
00379     JobIterator it = findJob( job );
00380     if ( it == jobsEnd() ) return;
00381     bool onlySubscribed = (*it).onlySubscribed;
00382     QString path = static_cast<KIO::SimpleJob*>(job)->url().path();
00383     if (job->error())
00384     {
00385       handleJobError( job, i18n( "Error while trying to subscribe to %1:" ).arg( path ) + '\n' );
00386       // ## emit subscriptionChanged here in case anyone needs it to support continue/cancel
00387     }
00388     else
00389     {
00390       emit subscriptionChanged( path, onlySubscribed );
00391       if (mSlave) removeJob(job);
00392     }
00393   }
00394 
00395   //-----------------------------------------------------------------------------
00396   // TODO imapPath can be removed once parent can be a KMFolderImapBase or whatever
00397   void ImapAccountBase::getUserRights( KMFolder* parent, const QString& imapPath )
00398   {
00399     // There isn't much point in asking the server about a user's rights on his own inbox,
00400     // it might not be the effective permissions (at least with Cyrus, one can admin his own inbox,
00401     // even after a SETACL that removes the admin permissions. Other imap servers apparently
00402     // don't even allow removing one's own admin permission, so this code won't hurt either).
00403     if ( imapPath == "/INBOX/" ) {
00404       if ( parent->folderType() == KMFolderTypeImap )
00405         static_cast<KMFolderImap*>( parent->storage() )->setUserRights( ACLJobs::All );
00406       else if ( parent->folderType() == KMFolderTypeCachedImap )
00407         static_cast<KMFolderCachedImap*>( parent->storage() )->setUserRights( ACLJobs::All );
00408       emit receivedUserRights( parent ); // warning, you need to connect first to get that one
00409       return;
00410     }
00411 
00412     KURL url = getUrl();
00413     url.setPath(imapPath);
00414 
00415     ACLJobs::GetUserRightsJob* job = ACLJobs::getUserRights( mSlave, url );
00416 
00417     jobData jd( url.url(), parent );
00418     jd.cancellable = true;
00419     insertJob(job, jd);
00420 
00421     connect(job, SIGNAL(result(KIO::Job *)),
00422             SLOT(slotGetUserRightsResult(KIO::Job *)));
00423   }
00424 
00425   void ImapAccountBase::slotGetUserRightsResult( KIO::Job* _job )
00426   {
00427     ACLJobs::GetUserRightsJob* job = static_cast<ACLJobs::GetUserRightsJob *>( _job );
00428     JobIterator it = findJob( job );
00429     if ( it == jobsEnd() ) return;
00430 
00431     KMFolder* folder = (*it).parent;
00432     if ( job->error() ) {
00433       if ( job->error() == KIO::ERR_UNSUPPORTED_ACTION ) // that's when the imap server doesn't support ACLs
00434           mACLSupport = false;
00435       else
00436         kdWarning(5006) << "slotGetUserRightsResult: " << job->errorString() << endl;
00437     } else {
00438 #ifndef NDEBUG
00439       //kdDebug(5006) << "User Rights: " << ACLJobs::permissionsToString( job->permissions() ) << endl;
00440 #endif
00441       // Store the permissions
00442       if ( folder->folderType() == KMFolderTypeImap )
00443         static_cast<KMFolderImap*>( folder->storage() )->setUserRights( job->permissions() );
00444       else if ( folder->folderType() == KMFolderTypeCachedImap )
00445         static_cast<KMFolderCachedImap*>( folder->storage() )->setUserRights( job->permissions() );
00446     }
00447     if (mSlave) removeJob(job);
00448     emit receivedUserRights( folder );
00449   }
00450 
00451   //-----------------------------------------------------------------------------
00452   void ImapAccountBase::getACL( KMFolder* parent, const QString& imapPath )
00453   {
00454     KURL url = getUrl();
00455     url.setPath(imapPath);
00456 
00457     ACLJobs::GetACLJob* job = ACLJobs::getACL( mSlave, url );
00458     jobData jd( url.url(), parent );
00459     jd.cancellable = true;
00460     insertJob(job, jd);
00461 
00462     connect(job, SIGNAL(result(KIO::Job *)),
00463             SLOT(slotGetACLResult(KIO::Job *)));
00464   }
00465 
00466   void ImapAccountBase::slotGetACLResult( KIO::Job* _job )
00467   {
00468     ACLJobs::GetACLJob* job = static_cast<ACLJobs::GetACLJob *>( _job );
00469     JobIterator it = findJob( job );
00470     if ( it == jobsEnd() ) return;
00471 
00472     KMFolder* folder = (*it).parent;
00473     emit receivedACL( folder, job, job->entries() );
00474     if (mSlave) removeJob(job);
00475   }
00476 
00477   //-----------------------------------------------------------------------------
00478   // Do not remove imapPath, FolderDiaQuotaTab needs to call this with parent==0.
00479   void ImapAccountBase::getStorageQuotaInfo( KMFolder* parent, const QString& imapPath )
00480   {
00481     if ( !mSlave ) return;
00482     KURL url = getUrl();
00483     url.setPath(imapPath);
00484 
00485     QuotaJobs::GetStorageQuotaJob* job = QuotaJobs::getStorageQuota( mSlave, url );
00486     jobData jd( url.url(), parent );
00487     jd.cancellable = true;
00488     insertJob(job, jd);
00489 
00490     connect(job, SIGNAL(result(KIO::Job *)),
00491             SLOT(slotGetStorageQuotaInfoResult(KIO::Job *)));
00492   }
00493 
00494   void ImapAccountBase::slotGetStorageQuotaInfoResult( KIO::Job* _job )
00495   {
00496     QuotaJobs::GetStorageQuotaJob* job = static_cast<QuotaJobs::GetStorageQuotaJob *>( _job );
00497     JobIterator it = findJob( job );
00498     if ( it == jobsEnd() ) return;
00499     if ( job->error() && job->error() == KIO::ERR_UNSUPPORTED_ACTION )
00500       setHasNoQuotaSupport();
00501 
00502     KMFolder* folder = (*it).parent; // can be 0
00503     emit receivedStorageQuotaInfo( folder, job, job->storageQuotaInfo() );
00504     if (mSlave) removeJob(job);
00505   }
00506 
00507   void ImapAccountBase::slotNoopTimeout()
00508   {
00509     if ( mSlave ) {
00510       QByteArray packedArgs;
00511       QDataStream stream( packedArgs, IO_WriteOnly );
00512 
00513       stream << ( int ) 'N';
00514 
00515       KIO::SimpleJob *job = KIO::special( getUrl(), packedArgs, false );
00516       KIO::Scheduler::assignJobToSlave(mSlave, job);
00517       connect( job, SIGNAL(result( KIO::Job * ) ),
00518           this, SLOT( slotSimpleResult( KIO::Job * ) ) );
00519     } else {
00520       /* Stop the timer, we have disconnected. We have to make sure it is
00521          started again when a new slave appears. */
00522       mNoopTimer.stop();
00523     }
00524   }
00525 
00526   void ImapAccountBase::slotIdleTimeout()
00527   {
00528     if ( mSlave ) {
00529       KIO::Scheduler::disconnectSlave(mSlave);
00530       mSlave = 0;
00531       mSlaveConnected = false;
00532       /* As for the noop timer, we need to make sure this one is started
00533          again when a new slave goes up. */
00534       mIdleTimer.stop();
00535     }
00536   }
00537 
00538   void ImapAccountBase::slotAbortRequested( KPIM::ProgressItem* item )
00539   {
00540     if ( item )
00541       item->setComplete();
00542     killAllJobs();
00543   }
00544 
00545 
00546   //-----------------------------------------------------------------------------
00547   void ImapAccountBase::slotSchedulerSlaveError(KIO::Slave *aSlave, int errorCode,
00548       const QString &errorMsg)
00549   {
00550     if (aSlave != mSlave) return;
00551     handleError( errorCode, errorMsg, 0, QString::null, true );
00552     if ( mAskAgain )
00553       makeConnection();
00554     else {
00555       if ( !mSlaveConnected ) {
00556         mSlaveConnectionError = true;
00557         resetConnectionList( this );
00558         if ( mSlave )
00559         {
00560           KIO::Scheduler::disconnectSlave( slave() );
00561           mSlave = 0;
00562         }
00563       }
00564       emit connectionResult( errorCode, errorMsg );
00565     }
00566   }
00567 
00568   //-----------------------------------------------------------------------------
00569   void ImapAccountBase::slotSchedulerSlaveConnected(KIO::Slave *aSlave)
00570   {
00571     if (aSlave != mSlave) return;
00572     mSlaveConnected = true;
00573     mNoopTimer.start( 60000 ); // make sure we start sending noops
00574     emit connectionResult( 0, QString::null ); // success
00575 
00576     if ( mNamespaces.isEmpty() || mNamespaceToDelimiter.isEmpty() ) {
00577       connect( this, SIGNAL( namespacesFetched( const ImapAccountBase::nsDelimMap& ) ),
00578           this, SLOT( slotSaveNamespaces( const ImapAccountBase::nsDelimMap& ) ) );
00579       getNamespaces();
00580     }
00581 
00582     // get capabilities
00583     QByteArray packedArgs;
00584     QDataStream stream( packedArgs, IO_WriteOnly);
00585     stream << (int) 'c';
00586     KIO::SimpleJob *job = KIO::special( getUrl(), packedArgs, false );
00587     KIO::Scheduler::assignJobToSlave( mSlave, job );
00588     connect( job, SIGNAL(infoMessage(KIO::Job*, const QString&)),
00589        SLOT(slotCapabilitiesResult(KIO::Job*, const QString&)) );
00590   }
00591 
00592   //-----------------------------------------------------------------------------
00593   void ImapAccountBase::slotCapabilitiesResult( KIO::Job*, const QString& result )
00594   {
00595     mCapabilities = QStringList::split(' ', result.lower() );
00596     kdDebug(5006) << "capabilities:" << mCapabilities << endl;
00597   }
00598 
00599   //-----------------------------------------------------------------------------
00600   void ImapAccountBase::getNamespaces()
00601   {
00602     disconnect( this, SIGNAL( connectionResult(int, const QString&) ),
00603           this, SLOT( getNamespaces() ) );
00604     if ( makeConnection() != Connected || !mSlave ) {
00605       kdDebug(5006) << "getNamespaces - wait for connection" << endl;
00606       if ( mNamespaces.isEmpty() || mNamespaceToDelimiter.isEmpty() ) {
00607         // when the connection is established slotSchedulerSlaveConnected notifies us
00608       } else {
00609         // getNamespaces was called by someone else
00610         connect( this, SIGNAL( connectionResult(int, const QString&) ),
00611             this, SLOT( getNamespaces() ) );
00612       }
00613       return;
00614     }
00615     
00616     QByteArray packedArgs;
00617     QDataStream stream( packedArgs, IO_WriteOnly);
00618     stream << (int) 'n';
00619     jobData jd;
00620     jd.total = 1; jd.done = 0; jd.cancellable = true;
00621     jd.progressItem = ProgressManager::createProgressItem( 
00622         ProgressManager::getUniqueID(),
00623         i18n("Retrieving Namespaces"),
00624         QString::null, true, useSSL() || useTLS() );
00625     jd.progressItem->setTotalItems( 1 );
00626     connect ( jd.progressItem,
00627         SIGNAL( progressItemCanceled( KPIM::ProgressItem* ) ),
00628         this,
00629         SLOT( slotAbortRequested( KPIM::ProgressItem* ) ) );
00630     KIO::SimpleJob *job = KIO::special( getUrl(), packedArgs, false );
00631     KIO::Scheduler::assignJobToSlave( mSlave, job );
00632     insertJob( job, jd );
00633     connect( job, SIGNAL( infoMessage(KIO::Job*, const QString&) ),
00634         SLOT( slotNamespaceResult(KIO::Job*, const QString&) ) );
00635   }
00636 
00637   //-----------------------------------------------------------------------------
00638   void ImapAccountBase::slotNamespaceResult( KIO::Job* job, const QString& str )
00639   {
00640     JobIterator it = findJob( job );
00641     if ( it == jobsEnd() ) return;
00642 
00643     nsDelimMap map;
00644     namespaceDelim nsDelim;
00645     QStringList ns = QStringList::split( ",", str );
00646     for ( QStringList::Iterator it = ns.begin(); it != ns.end(); ++it ) {
00647       // split, allow empty parts as we can get empty namespaces
00648       QStringList parts = QStringList::split( "=", *it, true );
00649       imapNamespace section = imapNamespace( parts[0].toInt() );
00650       if ( map.contains( section ) ) {
00651         nsDelim = map[section];
00652       } else {
00653         nsDelim.clear();
00654       }
00655       // map namespace to delimiter
00656       nsDelim[parts[1]] = parts[2];
00657       map[section] = nsDelim;
00658     }
00659     removeJob(it);
00660 
00661     kdDebug(5006) << "namespaces fetched" << endl;
00662     emit namespacesFetched( map );
00663   }
00664     
00665   //-----------------------------------------------------------------------------
00666   void ImapAccountBase::slotSaveNamespaces( const ImapAccountBase::nsDelimMap& map )
00667   {
00668     kdDebug(5006) << "slotSaveNamespaces " << name() << endl;
00669     // extract the needed information
00670     mNamespaces.clear();
00671     mNamespaceToDelimiter.clear();
00672     for ( uint i = 0; i < 3; ++i ) {
00673       imapNamespace section = imapNamespace( i );
00674       namespaceDelim ns = map[ section ];
00675       namespaceDelim::ConstIterator it;
00676       QStringList list;
00677       for ( it = ns.begin(); it != ns.end(); ++it ) {
00678         list += it.key();
00679         mNamespaceToDelimiter[ it.key() ] = it.data();
00680       }
00681       if ( !list.isEmpty() ) {
00682         mNamespaces[section] = list;
00683       }
00684     }
00685     // see if we need to migrate an old prefix
00686     if ( !mOldPrefix.isEmpty() ) {
00687       migratePrefix();
00688     }
00689     emit namespacesFetched();
00690   }
00691 
00692   //-----------------------------------------------------------------------------
00693   void ImapAccountBase::migratePrefix()
00694   {
00695     if ( !mOldPrefix.isEmpty() && mOldPrefix != "/" ) {
00696       // strip /
00697       if ( mOldPrefix.startsWith("/") ) {
00698         mOldPrefix = mOldPrefix.right( mOldPrefix.length()-1 );
00699       }
00700       if ( mOldPrefix.endsWith("/") ) {
00701         mOldPrefix = mOldPrefix.left( mOldPrefix.length()-1 );
00702       }
00703       QStringList list = mNamespaces[PersonalNS];
00704       bool done = false;
00705       for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) {
00706         if ( (*it).startsWith( mOldPrefix ) ) {
00707           // should be ok
00708           done = true;
00709           kdDebug(5006) << "migratePrefix - no migration needed" << endl;
00710           break;
00711         }
00712       }
00713       if ( !done ) {
00714         QString msg = i18n("KMail has detected a prefix entry in the "
00715             "configuration of the account \"%1\" which is obsolete with the "
00716             "support of IMAP namespaces.").arg( name() );
00717         if ( list.contains( "" ) ) {
00718           // replace empty entry with the old prefix
00719           list.remove( "" );
00720           list += mOldPrefix;
00721           mNamespaces[PersonalNS] = list;
00722           if ( mNamespaceToDelimiter.contains( "" ) ) {
00723             QString delim = mNamespaceToDelimiter[""];
00724             mNamespaceToDelimiter.remove( "" );
00725             mNamespaceToDelimiter[mOldPrefix] = delim;
00726           }
00727           kdDebug(5006) << "migratePrefix - replaced empty with " << mOldPrefix << endl;
00728           msg += i18n("The configuration was automatically migrated but you should check "
00729               "your account configuration.");
00730         } else if ( list.count() == 1 ) {
00731           // only one entry in the personal namespace so replace it
00732           QString old = list.first();
00733           list.clear();
00734           list += mOldPrefix;
00735           mNamespaces[PersonalNS] = list;
00736           if ( mNamespaceToDelimiter.contains( old ) ) {
00737             QString delim = mNamespaceToDelimiter[old];
00738             mNamespaceToDelimiter.remove( old );
00739             mNamespaceToDelimiter[mOldPrefix] = delim;
00740           }
00741           kdDebug(5006) << "migratePrefix - replaced single with " << mOldPrefix << endl;
00742           msg += i18n("The configuration was automatically migrated but you should check "
00743               "your account configuration.");
00744         } else {
00745           kdDebug(5006) << "migratePrefix - migration failed" << endl;
00746           msg += i18n("It was not possible to migrate your configuration automatically "
00747               "so please check your account configuration.");
00748         }
00749         KMessageBox::information( kmkernel->getKMMainWidget(), msg );
00750       }
00751     } else 
00752     {
00753       kdDebug(5006) << "migratePrefix - no migration needed" << endl;
00754     }
00755     mOldPrefix = "";
00756   }
00757 
00758   //-----------------------------------------------------------------------------
00759   QString ImapAccountBase::namespaceForFolder( FolderStorage* storage )
00760   {
00761     QString path;
00762     if ( storage->folderType() == KMFolderTypeImap ) {
00763       path = static_cast<KMFolderImap*>( storage )->imapPath();
00764     } else if ( storage->folderType() == KMFolderTypeCachedImap ) {
00765       path = static_cast<KMFolderCachedImap*>( storage )->imapPath();
00766     }
00767 
00768     nsMap::Iterator it;
00769     for ( it = mNamespaces.begin(); it != mNamespaces.end(); ++it )
00770     {
00771       QStringList::Iterator strit;
00772       for ( strit = it.data().begin(); strit != it.data().end(); ++strit )
00773       {
00774         QString ns = *strit;
00775         if ( ns.endsWith("/") || ns.endsWith(".") ) {
00776           // strip delimiter for the comparison
00777           ns = ns.left( ns.length()-1 );
00778         }
00779         // first ignore an empty prefix as it would match always
00780         if ( !ns.isEmpty() && path.find( ns ) != -1 ) {
00781           return (*strit);
00782         }
00783       }
00784     }
00785     return QString::null;
00786   }  
00787 
00788   //-----------------------------------------------------------------------------
00789   QString ImapAccountBase::delimiterForNamespace( const QString& prefix )
00790   {
00791     kdDebug(5006) << "delimiterForNamespace " << prefix << endl;
00792     // try to match exactly
00793     if ( mNamespaceToDelimiter.contains(prefix) ) {
00794       return mNamespaceToDelimiter[prefix];
00795     }
00796 
00797     // then try if the prefix is part of a namespace
00798     // exclude empty namespace
00799     for ( namespaceDelim::ConstIterator it = mNamespaceToDelimiter.begin(); 
00800           it != mNamespaceToDelimiter.end(); ++it ) {
00801       // the namespace definition sometimes contains the delimiter
00802       // make sure we also match this version
00803       QString stripped = it.key().left( it.key().length() - 1 );
00804       if ( !it.key().isEmpty() && 
00805           ( prefix.contains( it.key() ) || prefix.contains( stripped ) ) ) {
00806         return it.data();
00807       }
00808     }
00809     // see if we have an empty namespace
00810     // this should always be the case
00811     if ( mNamespaceToDelimiter.contains( "" ) ) {
00812       return mNamespaceToDelimiter[""];
00813     }
00814     // well, we tried
00815     kdDebug(5006) << "delimiterForNamespace - not found" << endl;
00816     return QString::null;
00817   }
00818 
00819   //-----------------------------------------------------------------------------
00820   QString ImapAccountBase::delimiterForFolder( FolderStorage* storage )
00821   {
00822     QString prefix = namespaceForFolder( storage );
00823     QString delim = delimiterForNamespace( prefix );
00824     return delim;
00825   }
00826 
00827   //-----------------------------------------------------------------------------
00828   void ImapAccountBase::slotSimpleResult(KIO::Job * job)
00829   {
00830     JobIterator it = findJob( job );
00831     bool quiet = false;
00832     if (it != mapJobData.end()) {
00833       quiet = (*it).quiet;
00834       if ( !(job->error() && !quiet) ) // the error handler removes in that case
00835         removeJob(it);
00836     }
00837     if (job->error()) {
00838       if (!quiet)
00839         handleJobError(job, QString::null );
00840       else {
00841         if ( job->error() == KIO::ERR_CONNECTION_BROKEN && slave() ) {
00842           // make sure ERR_CONNECTION_BROKEN is properly handled and the slave
00843           // disconnected even when quiet()
00844           KIO::Scheduler::disconnectSlave( slave() );
00845           mSlave = 0;
00846         }
00847         if (job->error() == KIO::ERR_SLAVE_DIED)
00848           slaveDied();
00849       }
00850     }
00851   }
00852 
00853   //-----------------------------------------------------------------------------
00854   bool ImapAccountBase::handlePutError( KIO::Job* job, jobData& jd, KMFolder* folder )
00855   {
00856     Q_ASSERT( !jd.msgList.isEmpty() );
00857     KMMessage* msg = jd.msgList.first();
00858     // Use double-quotes around the subject to keep the sentence readable,
00859     // but don't use double quotes around the sender since from() might return a double-quoted name already
00860     const QString subject = msg->subject().isEmpty() ? i18n( "<unknown>" ) : QString("\"%1\"").arg( msg->subject() );
00861     const QString from = msg->from().isEmpty() ? i18n( "<unknown>" ) : msg->from();
00862     QString myError = "<p><b>" + i18n("Error while uploading message")
00863       + "</b></p><p>"
00864       + 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 ) )
00865       + "</p><p>"
00866       + i18n("The destination folder was %1, which has the URL %2.").arg( QStyleSheet::escape( folder->label() ), QStyleSheet::escape( jd.htmlURL() ) )
00867       + "</p><p>"
00868       + i18n("The error message from the server communication is here:") + "</p>";
00869     return handleJobError( job, myError );
00870   }
00871 
00872   //-----------------------------------------------------------------------------
00873   bool ImapAccountBase::handleError( int errorCode, const QString &errorMsg, KIO::Job* job, const QString& context, bool abortSync )
00874   {
00875     // Copy job's data before a possible killAllJobs
00876     QStringList errors;
00877     if ( job && job->error() != KIO::ERR_SLAVE_DEFINED /*workaround for kdelibs-3.2*/)
00878       errors = job->detailedErrorStrings();
00879 
00880     bool jobsKilled = true;
00881     switch( errorCode ) {
00882     case KIO::ERR_SLAVE_DIED: slaveDied(); killAllJobs( true ); break;
00883     case KIO::ERR_COULD_NOT_LOGIN: // bad password
00884       mAskAgain = true;
00885       // fallthrough intended
00886     case KIO::ERR_CONNECTION_BROKEN:
00887     case KIO::ERR_COULD_NOT_CONNECT:
00888     case KIO::ERR_SERVER_TIMEOUT:
00889       // These mean that we'll have to reconnect on the next attempt, so disconnect and set mSlave to 0.
00890       killAllJobs( true );
00891       break;
00892     case KIO::ERR_USER_CANCELED:
00893       killAllJobs( false );
00894       break;
00895     default:
00896       if ( abortSync )
00897         killAllJobs( false );
00898       else
00899         jobsKilled = false;
00900       break;
00901     }
00902 
00903     // check if we still display an error
00904     if ( !mErrorDialogIsActive && errorCode != KIO::ERR_USER_CANCELED ) {
00905       mErrorDialogIsActive = true;
00906       QString msg = context + '\n' + KIO::buildErrorString( errorCode, errorMsg );
00907       QString caption = i18n("Error");
00908       
00909       if ( jobsKilled || errorCode == KIO::ERR_COULD_NOT_LOGIN ) {
00910         if ( errorCode == KIO::ERR_SERVER_TIMEOUT || errorCode == KIO::ERR_CONNECTION_BROKEN ) {
00911           msg = i18n("The connection to the server %1 was unexpectedly closed or timed out. It will be re-established automatically if possible.").
00912             arg( name() );
00913           KMessageBox::information( kapp->activeWindow(), msg, caption, "kmailConnectionBrokenErrorDialog" );
00914           // Show it in the status bar, in case the user has ticked "don't show again"
00915           if ( errorCode == KIO::ERR_CONNECTION_BROKEN )
00916             KPIM::BroadcastStatus::instance()->setStatusMsg(
00917                 i18n(  "The connection to account %1 was broken." ).arg( name() ) );
00918           else if ( errorCode == KIO::ERR_SERVER_TIMEOUT )
00919             KPIM::BroadcastStatus::instance()->setStatusMsg(
00920                 i18n(  "The connection to account %1 timed out." ).arg( name() ) );
00921         } else {
00922           if ( !errors.isEmpty() )
00923               KMessageBox::detailedError( kapp->activeWindow(), msg, errors.join("\n").prepend("<qt>"), caption );
00924           else
00925               KMessageBox::error( kapp->activeWindow(), msg, caption );
00926           }
00927       }
00928       else { // i.e. we have a chance to continue, ask the user about it
00929         if ( errors.count() >= 3 ) { // there is no detailedWarningContinueCancel... (#86517)
00930           msg = QString( "<qt>") + context + errors[1] + '\n' + errors[2];
00931           caption = errors[0];
00932         }
00933         int ret = KMessageBox::warningContinueCancel( kapp->activeWindow(), msg, caption );
00934         if ( ret == KMessageBox::Cancel ) {
00935           jobsKilled = true;
00936           killAllJobs( false );
00937         }
00938       }
00939       mErrorDialogIsActive = false;
00940     } else {
00941       if ( mErrorDialogIsActive )
00942         kdDebug(5006) << "suppressing error:" << errorMsg << endl;
00943     }
00944     if ( job && !jobsKilled )
00945       removeJob( job );
00946     return !jobsKilled; // jobsKilled==false -> continue==true
00947     }
00948 
00949   //-----------------------------------------------------------------------------
00950   void ImapAccountBase::cancelMailCheck()
00951   {
00952     QMap<KIO::Job*, jobData>::Iterator it = mapJobData.begin();
00953     while ( it != mapJobData.end() ) {
00954       kdDebug(5006) << "cancelMailCheck: job is cancellable: " << (*it).cancellable << endl;
00955       if ( (*it).cancellable ) {
00956         it.key()->kill();
00957         QMap<KIO::Job*, jobData>::Iterator rmit = it;
00958         ++it;
00959         mapJobData.remove( rmit );
00960         // We killed a job -> this kills the slave
00961         mSlave = 0;
00962       } else
00963         ++it;
00964     }
00965 
00966     for( QPtrListIterator<FolderJob> it( mJobList ); it.current(); ++it ) {
00967       if ( it.current()->isCancellable() ) {
00968         FolderJob* job = it.current();
00969         job->setPassiveDestructor( true );
00970         mJobList.remove( job );
00971         delete job;
00972       } else
00973         ++it;
00974     }
00975   }
00976 
00977 
00978   //-----------------------------------------------------------------------------
00979   QString ImapAccountBase::jobData::htmlURL() const
00980   {
00981     KURL u(  url );
00982     return u.htmlURL();
00983   }
00984 
00985   //-----------------------------------------------------------------------------
00986   void ImapAccountBase::processNewMailSingleFolder(KMFolder* folder)
00987   {
00988     mFoldersQueuedForChecking.append(folder);
00989     mCheckingSingleFolder = true;
00990     if ( checkingMail() )
00991     {
00992       disconnect( this, SIGNAL( finishedCheck( bool, CheckStatus ) ),
00993                   this, SLOT( slotCheckQueuedFolders() ) );
00994       connect( this, SIGNAL( finishedCheck( bool, CheckStatus ) ),
00995                this, SLOT( slotCheckQueuedFolders() ) );
00996     } else {
00997       slotCheckQueuedFolders();
00998     }
00999   }
01000 
01001   //-----------------------------------------------------------------------------
01002   void ImapAccountBase::slotCheckQueuedFolders()
01003   {
01004     disconnect( this, SIGNAL( finishedCheck( bool, CheckStatus ) ),
01005                 this, SLOT( slotCheckQueuedFolders() ) );
01006 
01007     QValueList<QGuardedPtr<KMFolder> > mSaveList = mMailCheckFolders;
01008     mMailCheckFolders = mFoldersQueuedForChecking;
01009     if ( kmkernel->acctMgr() )
01010       kmkernel->acctMgr()->singleCheckMail(this, true);
01011     mMailCheckFolders = mSaveList;
01012     mFoldersQueuedForChecking.clear();
01013   }
01014 
01015   //-----------------------------------------------------------------------------
01016   bool ImapAccountBase::checkingMail( KMFolder *folder )
01017   {
01018     if (checkingMail() && mFoldersQueuedForChecking.contains(folder))
01019       return true;
01020     return false;
01021   }
01022 
01023   //-----------------------------------------------------------------------------
01024   void ImapAccountBase::handleBodyStructure( QDataStream & stream, KMMessage * msg,
01025                                              const AttachmentStrategy *as )
01026   {
01027     mBodyPartList.clear();
01028     mCurrentMsg = msg;
01029     // first delete old parts as we construct our own
01030     msg->deleteBodyParts();
01031     // make the parts and fill the mBodyPartList
01032     constructParts( stream, 1, 0, 0, msg->asDwMessage() );
01033     if ( mBodyPartList.count() == 1 ) // we directly set the body later
01034       msg->deleteBodyParts();
01035 
01036     if ( !as )
01037     {
01038       kdWarning(5006) << k_funcinfo << " - found no attachment strategy!" << endl;
01039       return;
01040     }
01041 
01042     // see what parts have to loaded according to attachmentstrategy
01043     BodyVisitor *visitor = BodyVisitorFactory::getVisitor( as );
01044     visitor->visit( mBodyPartList );
01045     QPtrList<KMMessagePart> parts = visitor->partsToLoad();
01046     delete visitor;
01047     QPtrListIterator<KMMessagePart> it( parts );
01048     KMMessagePart *part;
01049     int partsToLoad = 0;
01050     // check how many parts we have to load
01051     while ( (part = it.current()) != 0 )
01052     {
01053       ++it;
01054       if ( part->loadPart() )
01055       {
01056         ++partsToLoad;
01057       }
01058     }
01059     if ( (mBodyPartList.count() * 0.5) < partsToLoad )
01060     {
01061       // more than 50% of the parts have to be loaded anyway so it is faster
01062       // to load the message completely
01063       kdDebug(5006) << "Falling back to normal mode" << endl;
01064       FolderJob *job = msg->parent()->createJob(
01065           msg, FolderJob::tGetMessage, 0, "TEXT" );
01066       job->start();
01067       return;
01068     }
01069     it.toFirst();
01070     while ( (part = it.current()) != 0 )
01071     {
01072       ++it;
01073       kdDebug(5006) << "ImapAccountBase::handleBodyStructure - load " << part->partSpecifier()
01074         << " (" << part->originalContentTypeStr() << ")" << endl;
01075       if ( part->loadHeaders() )
01076       {
01077         kdDebug(5006) << "load HEADER" << endl;
01078         FolderJob *job = msg->parent()->createJob(
01079             msg, FolderJob::tGetMessage, 0, part->partSpecifier()+".MIME" );
01080         job->start();
01081       }
01082       if ( part->loadPart() )
01083       {
01084         kdDebug(5006) << "load Part" << endl;
01085         FolderJob *job = msg->parent()->createJob(
01086             msg, FolderJob::tGetMessage, 0, part->partSpecifier() );
01087         job->start();
01088       }
01089     }
01090   }
01091 
01092   //-----------------------------------------------------------------------------
01093   void ImapAccountBase::constructParts( QDataStream & stream, int count, KMMessagePart* parentKMPart,
01094                                         DwBodyPart * parent, const DwMessage * dwmsg )
01095   {
01096     int children;
01097     for (int i = 0; i < count; i++)
01098     {
01099       stream >> children;
01100       KMMessagePart* part = new KMMessagePart( stream );
01101       part->setParent( parentKMPart );
01102       mBodyPartList.append( part );
01103       kdDebug(5006) << "ImapAccountBase::constructParts - created id " << part->partSpecifier()
01104         << " of type " << part->originalContentTypeStr() << endl;
01105       DwBodyPart *dwpart = mCurrentMsg->createDWBodyPart( part );
01106 
01107       if ( parent )
01108       {
01109         // add to parent body
01110         parent->Body().AddBodyPart( dwpart );
01111         dwpart->Parse();
01112 //        kdDebug(5006) << "constructed dwpart " << dwpart << ",dwmsg " << dwmsg << ",parent " << parent
01113 //          << ",dwparts msg " << dwpart->Body().Message() <<",id "<<dwpart->ObjectId() << endl;
01114       } else if ( part->partSpecifier() != "0" &&
01115                   !part->partSpecifier().endsWith(".HEADER") )
01116       {
01117         // add to message
01118         dwmsg->Body().AddBodyPart( dwpart );
01119         dwpart->Parse();
01120 //        kdDebug(5006) << "constructed dwpart " << dwpart << ",dwmsg " << dwmsg << ",parent " << parent
01121 //          << ",dwparts msg " << dwpart->Body().Message() <<",id "<<dwpart->ObjectId() << endl;
01122       } else
01123         dwpart = 0;
01124 
01125       if ( !parentKMPart )
01126         parentKMPart = part;
01127 
01128       if (children > 0)
01129       {
01130         DwBodyPart* newparent = dwpart;
01131         const DwMessage* newmsg = dwmsg;
01132         if ( part->originalContentTypeStr() == "MESSAGE/RFC822" && dwpart &&
01133              dwpart->Body().Message() )
01134         {
01135           // set the encapsulated message as the new message
01136           newparent = 0;
01137           newmsg = dwpart->Body().Message();
01138         }
01139         KMMessagePart* newParentKMPart = part;
01140         if ( part->partSpecifier().endsWith(".HEADER") ) // we don't want headers as parent
01141           newParentKMPart = parentKMPart;
01142 
01143         constructParts( stream, children, newParentKMPart, newparent, newmsg );
01144       }
01145     }
01146   }
01147 
01148   //-----------------------------------------------------------------------------
01149   void ImapAccountBase::setImapStatus( KMFolder* folder, const QString& path, const QCString& flags )
01150   {
01151      // set the status on the server, the uids are integrated in the path
01152      kdDebug(5006) << "setImapStatus path=" << path << " to: " << flags << endl;
01153      KURL url = getUrl();
01154      url.setPath(path);
01155 
01156      QByteArray packedArgs;
01157      QDataStream stream( packedArgs, IO_WriteOnly);
01158 
01159      stream << (int) 'S' << url << flags;
01160 
01161      if ( makeConnection() != Connected ) 
01162        return; // can't happen with dimap
01163 
01164      KIO::SimpleJob *job = KIO::special(url, packedArgs, FALSE);
01165      KIO::Scheduler::assignJobToSlave(slave(), job);
01166      ImapAccountBase::jobData jd( url.url(), folder );
01167      jd.path = path;
01168      insertJob(job, jd);
01169      connect(job, SIGNAL(result(KIO::Job *)),
01170            SLOT(slotSetStatusResult(KIO::Job *)));
01171   }
01172   //-----------------------------------------------------------------------------
01173   void ImapAccountBase::slotSetStatusResult(KIO::Job * job)
01174   {
01175      ImapAccountBase::JobIterator it = findJob(job);
01176      if ( it == jobsEnd() ) return;
01177      int errorCode = job->error();
01178      KMFolder * const parent = (*it).parent;
01179      const QString path = (*it).path;
01180      if (errorCode && errorCode != KIO::ERR_CANNOT_OPEN_FOR_WRITING)
01181      {
01182        bool cont = handleJobError( job, i18n( "Error while uploading status of messages to server: " ) + '\n' );
01183        emit imapStatusChanged( parent, path, cont );
01184      }
01185      else
01186      {
01187        emit imapStatusChanged( parent, path, true );
01188        removeJob(it);
01189      }
01190   }
01191 
01192   //-----------------------------------------------------------------------------
01193   void ImapAccountBase::setFolder(KMFolder* folder, bool addAccount)
01194   {
01195     if (folder)
01196     {
01197       folder->setSystemLabel(name());
01198       folder->setId(id());
01199     }
01200     NetworkAccount::setFolder(folder, addAccount);
01201   }
01202 
01203   //-----------------------------------------------------------------------------
01204   void ImapAccountBase::removeJob( JobIterator& it )
01205   {
01206     if( (*it).progressItem ) {
01207       (*it).progressItem->setComplete();
01208       (*it).progressItem = 0;
01209     }
01210     mapJobData.remove( it );
01211   }
01212 
01213   //-----------------------------------------------------------------------------
01214   void KMail::ImapAccountBase::removeJob( KIO::Job* job )
01215   {
01216     mapJobData.remove( job );
01217   }
01218 
01219   //-----------------------------------------------------------------------------
01220   KPIM::ProgressItem* ImapAccountBase::listDirProgressItem()
01221   {
01222     if ( !mListDirProgressItem )
01223     {
01224       mListDirProgressItem = ProgressManager::createProgressItem(
01225           "ListDir" + name(),
01226           QStyleSheet::escape( name() ),
01227           i18n("retrieving folders"),
01228           true,
01229           useSSL() || useTLS() );
01230       connect ( mListDirProgressItem,
01231                 SIGNAL( progressItemCanceled( KPIM::ProgressItem* ) ),
01232                 this,
01233                 SLOT( slotAbortRequested( KPIM::ProgressItem* ) ) );
01234       // Start with a guessed value of the old folder count plus 5%. As long
01235       // as the list of folders doesn't constantly change, that should be good
01236       // enough.
01237       unsigned int count = folderCount();
01238       mListDirProgressItem->setTotalItems( count + (unsigned int)(count*0.05) );
01239     }
01240     return mListDirProgressItem;
01241   }
01242 
01243   //-----------------------------------------------------------------------------
01244   unsigned int ImapAccountBase::folderCount() const
01245   {
01246     if ( !rootFolder() || !rootFolder()->folder() || !rootFolder()->folder()->child() )
01247       return 0;
01248     return kmkernel->imapFolderMgr()->folderCount( rootFolder()->folder()->child() );
01249   }
01250 
01251   //------------------------------------------------------------------------------
01252   QString ImapAccountBase::addPathToNamespace( const QString& prefix )
01253   {
01254     QString myPrefix = prefix;
01255     if ( !myPrefix.startsWith( "/" ) ) {
01256       myPrefix = "/" + myPrefix;
01257     }
01258     if ( !myPrefix.endsWith( "/" ) ) {
01259       myPrefix += "/";
01260     }
01261 
01262     return myPrefix;
01263   }
01264 
01265   //------------------------------------------------------------------------------
01266   bool ImapAccountBase::isNamespaceFolder( QString& name )
01267   {
01268     QStringList ns = mNamespaces[OtherUsersNS];
01269     ns += mNamespaces[SharedNS];
01270     ns += mNamespaces[PersonalNS];
01271     QString nameWithDelimiter;
01272     for ( QStringList::Iterator it = ns.begin(); it != ns.end(); ++it )
01273     {
01274       nameWithDelimiter = name + delimiterForNamespace( *it );
01275       if ( *it == name || *it == nameWithDelimiter )
01276         return true;
01277     }
01278     return false;
01279   }
01280 
01281   //------------------------------------------------------------------------------
01282   ImapAccountBase::nsDelimMap ImapAccountBase::namespacesWithDelimiter()
01283   {
01284     nsDelimMap map;
01285     nsMap::ConstIterator it;
01286     for ( uint i = 0; i < 3; ++i )
01287     {
01288       imapNamespace section = imapNamespace( i );
01289       QStringList namespaces = mNamespaces[section];
01290       namespaceDelim nsDelim;
01291       QStringList::Iterator lit;
01292       for ( lit = namespaces.begin(); lit != namespaces.end(); ++lit )
01293       {
01294         nsDelim[*lit] = delimiterForNamespace( *lit );
01295       }
01296       map[section] = nsDelim;
01297     }
01298     return map;
01299   }
01300 
01301   //------------------------------------------------------------------------------
01302   QString ImapAccountBase::createImapPath( const QString& parent, 
01303                                            const QString& folderName )
01304   {
01305     kdDebug(5006) << "createImapPath parent="<<parent<<", folderName="<<folderName<<endl;  
01306     QString newName = parent;
01307     // strip / at the end
01308     if ( newName.endsWith("/") ) {
01309       newName = newName.left( newName.length() - 1 );
01310     }
01311     // add correct delimiter
01312     QString delim = delimiterForNamespace( newName );
01313     // should not happen...
01314     if ( delim.isEmpty() ) {
01315       delim = "/";
01316     }
01317     if ( !newName.isEmpty() && 
01318          !newName.endsWith( delim ) && !folderName.startsWith( delim ) ) {
01319       newName = newName + delim;
01320     }
01321     newName = newName + folderName;
01322     // add / at the end
01323     if ( !newName.endsWith("/") ) {
01324       newName = newName + "/";
01325     }
01326 
01327     return newName;
01328   }
01329 
01330   //------------------------------------------------------------------------------
01331   QString ImapAccountBase::createImapPath( FolderStorage* parent, 
01332                                            const QString& folderName )
01333   {
01334     QString path;
01335     if ( parent->folderType() == KMFolderTypeImap ) {
01336       path = static_cast<KMFolderImap*>( parent )->imapPath();
01337     } else if ( parent->folderType() == KMFolderTypeCachedImap ) {
01338       path = static_cast<KMFolderCachedImap*>( parent )->imapPath();
01339     } else {
01340       // error
01341       return path;
01342     }
01343     
01344     return createImapPath( path, folderName );
01345   }
01346 
01347 } // namespace KMail
01348 
01349 #include "imapaccountbase.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys