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