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