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