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