00001
00032 #ifdef HAVE_CONFIG_H
00033 #include <config.h>
00034 #endif
00035
00036 #include <errno.h>
00037
00038 #include <qvaluevector.h>
00039
00040 #include "kmkernel.h"
00041 #include "kmfoldercachedimap.h"
00042 #include "undostack.h"
00043 #include "kmfoldermgr.h"
00044 #include "kmacctcachedimap.h"
00045 #include "accountmanager.h"
00046 using KMail::AccountManager;
00047 #include "kmailicalifaceimpl.h"
00048 #include "kmfolder.h"
00049 #include "kmglobal.h"
00050 #include "acljobs.h"
00051 #include "broadcaststatus.h"
00052 using KPIM::BroadcastStatus;
00053 #include "progressmanager.h"
00054
00055 using KMail::CachedImapJob;
00056 #include "imapaccountbase.h"
00057 using KMail::ImapAccountBase;
00058 #include "listjob.h"
00059 using KMail::ListJob;
00060
00061 #include "kmfolderseldlg.h"
00062 #include "kmcommands.h"
00063 #include "kmmainwidget.h"
00064
00065 #include <kapplication.h>
00066 #include <kmessagebox.h>
00067 #include <klocale.h>
00068 #include <kdebug.h>
00069 #include <kconfig.h>
00070 #include <kio/global.h>
00071 #include <kio/scheduler.h>
00072 #include <qbuffer.h>
00073 #include <qbuttongroup.h>
00074 #include <qcombobox.h>
00075 #include <qfile.h>
00076 #include <qhbox.h>
00077 #include <qlabel.h>
00078 #include <qlayout.h>
00079 #include <qradiobutton.h>
00080 #include <qvaluelist.h>
00081 #include "annotationjobs.h"
00082 #include "quotajobs.h"
00083 using namespace KMail;
00084 #include <globalsettings.h>
00085
00086 #define UIDCACHE_VERSION 1
00087 #define MAIL_LOSS_DEBUGGING 0
00088
00089 static QString incidencesForToString( KMFolderCachedImap::IncidencesFor r ) {
00090 switch (r) {
00091 case KMFolderCachedImap::IncForNobody: return "nobody";
00092 case KMFolderCachedImap::IncForAdmins: return "admins";
00093 case KMFolderCachedImap::IncForReaders: return "readers";
00094 }
00095 return QString::null;
00096 }
00097
00098 static KMFolderCachedImap::IncidencesFor incidencesForFromString( const QString& str ) {
00099 if ( str == "nobody" ) return KMFolderCachedImap::IncForNobody;
00100 if ( str == "admins" ) return KMFolderCachedImap::IncForAdmins;
00101 if ( str == "readers" ) return KMFolderCachedImap::IncForReaders;
00102 return KMFolderCachedImap::IncForAdmins;
00103 }
00104
00105 DImapTroubleShootDialog::DImapTroubleShootDialog( QWidget* parent,
00106 const char* name )
00107 : KDialogBase( Plain, i18n( "Troubleshooting IMAP Cache" ),
00108 Ok | Cancel, Cancel, parent, name, true ),
00109 rc( None )
00110 {
00111 QFrame* page = plainPage();
00112 QVBoxLayout *topLayout = new QVBoxLayout( page, 0 );
00113
00114 QString txt = i18n( "<p><b>Troubleshooting the IMAP cache.</b></p>"
00115 "<p>If you have problems with synchronizing an IMAP "
00116 "folder, you should first try rebuilding the index "
00117 "file. This will take some time to rebuild, but will "
00118 "not cause any problems.</p><p>If that is not enough, "
00119 "you can try refreshing the IMAP cache. If you do this, "
00120 "you will loose all your local changes for this folder "
00121 "and all its subfolders.</p>",
00122 "<p><b>Troubleshooting the IMAP cache.</b></p>"
00123 "<p>If you have problems with synchronizing an IMAP "
00124 "folder, you should first try rebuilding the index "
00125 "file. This will take some time to rebuild, but will "
00126 "not cause any problems.</p><p>If that is not enough, "
00127 "you can try refreshing the IMAP cache. If you do this, "
00128 "you will lose all your local changes for this folder "
00129 "and all its subfolders.</p>" );
00130 topLayout->addWidget( new QLabel( txt, page ) );
00131
00132 QButtonGroup *group = new QButtonGroup( 0 );
00133
00134 mIndexButton = new QRadioButton( page );
00135 mIndexButton->setText( i18n( "Rebuild &Index" ) );
00136 group->insert( mIndexButton );
00137 topLayout->addWidget( mIndexButton );
00138
00139 QHBox *hbox = new QHBox( page );
00140 QLabel *scopeLabel = new QLabel( i18n( "Scope:" ), hbox );
00141 scopeLabel->setEnabled( false );
00142 mIndexScope = new QComboBox( hbox );
00143 mIndexScope->insertItem( i18n( "Only current folder" ) );
00144 mIndexScope->insertItem( i18n( "Current folder and all subfolders" ) );
00145 mIndexScope->insertItem( i18n( "All folders of this account" ) );
00146 mIndexScope->setEnabled( false );
00147 topLayout->addWidget( hbox );
00148
00149 mCacheButton = new QRadioButton( page );
00150 mCacheButton->setText( i18n( "Refresh &Cache" ) );
00151 group->insert( mCacheButton );
00152 topLayout->addWidget( mCacheButton );
00153
00154 enableButtonSeparator( true );
00155
00156 connect ( mIndexButton, SIGNAL(toggled(bool)), mIndexScope, SLOT(setEnabled(bool)) );
00157 connect ( mIndexButton, SIGNAL(toggled(bool)), scopeLabel, SLOT(setEnabled(bool)) );
00158
00159 connect( this, SIGNAL( okClicked () ), this, SLOT( slotDone() ) );
00160 }
00161
00162 int DImapTroubleShootDialog::run()
00163 {
00164 DImapTroubleShootDialog d;
00165 d.exec();
00166 return d.rc;
00167 }
00168
00169 void DImapTroubleShootDialog::slotDone()
00170 {
00171 rc = None;
00172 if ( mIndexButton->isOn() )
00173 rc = mIndexScope->currentItem();
00174 else if ( mCacheButton->isOn() )
00175 rc = RefreshCache;
00176 done( Ok );
00177 }
00178
00179 KMFolderCachedImap::KMFolderCachedImap( KMFolder* folder, const char* aName )
00180 : KMFolderMaildir( folder, aName ),
00181 mSyncState( SYNC_STATE_INITIAL ), mContentState( imapNoInformation ),
00182 mSubfolderState( imapNoInformation ),
00183 mIncidencesFor( IncForAdmins ),
00184 mIsSelected( false ),
00185 mCheckFlags( true ), mReadOnly( false ), mAccount( NULL ), uidMapDirty( true ),
00186 uidWriteTimer( -1 ), mLastUid( 0 ), mTentativeHighestUid( 0 ),
00187 mFoundAnIMAPDigest( false ),
00188 mUserRights( 0 ), mOldUserRights( 0 ), mSilentUpload( false ),
00189
00190 mFolderRemoved( false ),
00191 mRecurse( true ),
00192 mStatusChangedLocally( false ), mAnnotationFolderTypeChanged( false ),
00193 mIncidencesForChanged( false ), mPersonalNamespacesCheckDone( true ),
00194 mQuotaInfo(), mAlarmsBlocked( false ),
00195 mRescueCommandCount( 0 ),
00196 mPermanentFlags( 31 )
00197 {
00198 setUidValidity("");
00199
00200 if ( readUidCache() == -1 ) {
00201 if ( QFile::exists( uidCacheLocation() ) ) {
00202 KMessageBox::error( 0,
00203 i18n( "The UID cache file for folder %1 could not be read. There "
00204 "could be a problem with file system permission, or it is corrupted."
00205 ).arg( folder->prettyURL() ) );
00206
00207
00208 unlink( QFile::encodeName( uidCacheLocation() ) );
00209 }
00210 }
00211
00212 mProgress = 0;
00213 }
00214
00215 KMFolderCachedImap::~KMFolderCachedImap()
00216 {
00217 if (kmkernel->undoStack()) kmkernel->undoStack()->folderDestroyed( folder() );
00218 }
00219
00220 void KMFolderCachedImap::reallyDoClose( const char* owner )
00221 {
00222 if( !mFolderRemoved ) {
00223 writeUidCache();
00224 }
00225 KMFolderMaildir::reallyDoClose( owner );
00226 }
00227
00228 void KMFolderCachedImap::initializeFrom( KMFolderCachedImap* parent )
00229 {
00230 setAccount( parent->account() );
00231
00232
00233 mAccount->removeDeletedFolder( imapPath() );
00234 setUserRights( parent->userRights() );
00235 }
00236
00237 void KMFolderCachedImap::readConfig()
00238 {
00239 KConfig* config = KMKernel::config();
00240 KConfigGroupSaver saver( config, "Folder-" + folder()->idString() );
00241 if( mImapPath.isEmpty() ) mImapPath = config->readEntry( "ImapPath" );
00242 if( QString( name() ).upper() == "INBOX" && mImapPath == "/INBOX/" )
00243 {
00244 folder()->setLabel( i18n( "inbox" ) );
00245
00246 folder()->setSystemFolder( true );
00247 }
00248 mNoContent = config->readBoolEntry( "NoContent", false );
00249 mReadOnly = config->readBoolEntry( "ReadOnly", false );
00250 if ( !config->readEntry( "FolderAttributes" ).isEmpty() )
00251 mFolderAttributes = config->readEntry( "FolderAttributes" );
00252
00253 if ( mAnnotationFolderType != "FROMSERVER" ) {
00254 mAnnotationFolderType = config->readEntry( "Annotation-FolderType" );
00255
00256 if ( !mAnnotationFolderType.isEmpty() && !mAnnotationFolderType.startsWith( "mail" ) )
00257 kmkernel->iCalIface().setStorageFormat( folder(), KMailICalIfaceImpl::StorageXML );
00258
00259
00260 }
00261 mIncidencesFor = incidencesForFromString( config->readEntry( "IncidencesFor" ) );
00262 mAlarmsBlocked = config->readBoolEntry( "AlarmsBlocked", false );
00263
00264
00265
00266 mUserRights = config->readNumEntry( "UserRights", 0 );
00267 mOldUserRights = mUserRights;
00268
00269 int storageQuotaUsage = config->readNumEntry( "StorageQuotaUsage", -1 );
00270 int storageQuotaLimit = config->readNumEntry( "StorageQuotaLimit", -1 );
00271 QString storageQuotaRoot = config->readEntry( "StorageQuotaRoot", QString::null );
00272 if ( !storageQuotaRoot.isNull() ) {
00273 mQuotaInfo.setName( "STORAGE" );
00274 mQuotaInfo.setRoot( storageQuotaRoot );
00275
00276 if ( storageQuotaUsage > -1 )
00277 mQuotaInfo.setCurrent( storageQuotaUsage );
00278 if ( storageQuotaLimit > -1 )
00279 mQuotaInfo.setMax( storageQuotaLimit );
00280 }
00281
00282 KMFolderMaildir::readConfig();
00283
00284 mStatusChangedLocally =
00285 config->readBoolEntry( "StatusChangedLocally", false );
00286
00287 mAnnotationFolderTypeChanged = config->readBoolEntry( "AnnotationFolderTypeChanged", false );
00288 mIncidencesForChanged = config->readBoolEntry( "IncidencesForChanged", false );
00289 if ( mImapPath.isEmpty() ) {
00290 mImapPathCreation = config->readEntry("ImapPathCreation");
00291 }
00292
00293 QStringList uids = config->readListEntry( "UIDSDeletedSinceLastSync" );
00294 #if MAIL_LOSS_DEBUGGING
00295 kdDebug( 5006 ) << "READING IN UIDSDeletedSinceLastSync: " << folder()->prettyURL() << endl << uids << endl;
00296 #endif
00297 for ( QStringList::iterator it = uids.begin(); it != uids.end(); it++ ) {
00298 mDeletedUIDsSinceLastSync.insert( (*it).toULong(), 0);
00299 }
00300 }
00301
00302 void KMFolderCachedImap::writeConfig()
00303 {
00304 KConfigGroup configGroup( KMKernel::config(), "Folder-" + folder()->idString() );
00305 configGroup.writeEntry( "ImapPath", mImapPath );
00306 configGroup.writeEntry( "NoContent", mNoContent );
00307 configGroup.writeEntry( "ReadOnly", mReadOnly );
00308 configGroup.writeEntry( "FolderAttributes", mFolderAttributes );
00309 configGroup.writeEntry( "StatusChangedLocally", mStatusChangedLocally );
00310 if ( !mImapPathCreation.isEmpty() ) {
00311 if ( mImapPath.isEmpty() ) {
00312 configGroup.writeEntry( "ImapPathCreation", mImapPathCreation );
00313 } else {
00314 configGroup.deleteEntry( "ImapPathCreation" );
00315 }
00316 }
00317 if ( !mDeletedUIDsSinceLastSync.isEmpty() ) {
00318 QValueList<ulong> uids = mDeletedUIDsSinceLastSync.keys();
00319 QStringList uidstrings;
00320 for( QValueList<ulong>::iterator it = uids.begin(); it != uids.end(); it++ ) {
00321 uidstrings.append( QString::number( (*it) ) );
00322 }
00323 configGroup.writeEntry( "UIDSDeletedSinceLastSync", uidstrings );
00324 #if MAIL_LOSS_DEBUGGING
00325 kdDebug( 5006 ) << "WRITING OUT UIDSDeletedSinceLastSync in: " << folder( )->prettyURL( ) << endl << uidstrings << endl;
00326 #endif
00327 } else {
00328 configGroup.deleteEntry( "UIDSDeletedSinceLastSync" );
00329 }
00330 writeConfigKeysWhichShouldNotGetOverwrittenByReadConfig();
00331 KMFolderMaildir::writeConfig();
00332 }
00333
00334 void KMFolderCachedImap::writeConfigKeysWhichShouldNotGetOverwrittenByReadConfig()
00335 {
00336 KConfigGroup configGroup( KMKernel::config(), "Folder-" + folder()->idString() );
00337 if ( !folder()->noContent() )
00338 {
00339 configGroup.writeEntry( "AnnotationFolderTypeChanged", mAnnotationFolderTypeChanged );
00340 configGroup.writeEntry( "Annotation-FolderType", mAnnotationFolderType );
00341 configGroup.writeEntry( "IncidencesForChanged", mIncidencesForChanged );
00342 configGroup.writeEntry( "IncidencesFor", incidencesForToString( mIncidencesFor ) );
00343 configGroup.writeEntry( "AlarmsBlocked", mAlarmsBlocked );
00344 configGroup.writeEntry( "UserRights", mUserRights );
00345
00346 configGroup.deleteEntry( "StorageQuotaUsage");
00347 configGroup.deleteEntry( "StorageQuotaRoot");
00348 configGroup.deleteEntry( "StorageQuotaLimit");
00349
00350 if ( mQuotaInfo.isValid() ) {
00351 if ( mQuotaInfo.current().isValid() ) {
00352 configGroup.writeEntry( "StorageQuotaUsage", mQuotaInfo.current().toInt() );
00353 }
00354 if ( mQuotaInfo.max().isValid() ) {
00355 configGroup.writeEntry( "StorageQuotaLimit", mQuotaInfo.max().toInt() );
00356 }
00357 configGroup.writeEntry( "StorageQuotaRoot", mQuotaInfo.root() );
00358 }
00359 }
00360 }
00361
00362 int KMFolderCachedImap::create()
00363 {
00364 int rc = KMFolderMaildir::create();
00365
00366 readConfig();
00367 mUnreadMsgs = -1;
00368 return rc;
00369 }
00370
00371 void KMFolderCachedImap::remove()
00372 {
00373 mFolderRemoved = true;
00374
00375 QString part1 = folder()->path() + "/." + dotEscape(name());
00376 QString uidCacheFile = part1 + ".uidcache";
00377
00378
00379 if( QFile::exists(uidCacheFile) )
00380 unlink( QFile::encodeName( uidCacheFile ) );
00381
00382 FolderStorage::remove();
00383 }
00384
00385 QString KMFolderCachedImap::uidCacheLocation() const
00386 {
00387 QString sLocation(folder()->path());
00388 if (!sLocation.isEmpty()) sLocation += '/';
00389 return sLocation + '.' + dotEscape(fileName()) + ".uidcache";
00390 }
00391
00392 int KMFolderCachedImap::readUidCache()
00393 {
00394 QFile uidcache( uidCacheLocation() );
00395 if( uidcache.open( IO_ReadOnly ) ) {
00396 char buf[1024];
00397 int len = uidcache.readLine( buf, sizeof(buf) );
00398 if( len > 0 ) {
00399 int cacheVersion;
00400 sscanf( buf, "# KMail-UidCache V%d\n", &cacheVersion );
00401 if( cacheVersion == UIDCACHE_VERSION ) {
00402 len = uidcache.readLine( buf, sizeof(buf) );
00403 if( len > 0 ) {
00404 setUidValidity( QString::fromLocal8Bit(buf).stripWhiteSpace() );
00405 len = uidcache.readLine( buf, sizeof(buf) );
00406 if( len > 0 ) {
00407 #if MAIL_LOSS_DEBUGGING
00408 kdDebug(5006) << "Reading in last uid from cache: " << QString::fromLocal8Bit(buf).stripWhiteSpace() << " in " << folder()->prettyURL() << endl;
00409 #endif
00410
00411 setLastUid( QString::fromLocal8Bit(buf).stripWhiteSpace().toULong() );
00412 return 0;
00413 }
00414 }
00415 }
00416 }
00417 }
00418 return -1;
00419 }
00420
00421 int KMFolderCachedImap::writeUidCache()
00422 {
00423 if( uidValidity().isEmpty() || uidValidity() == "INVALID" ) {
00424
00425 if( QFile::exists( uidCacheLocation() ) )
00426 return unlink( QFile::encodeName( uidCacheLocation() ) );
00427 return 0;
00428 }
00429 #if MAIL_LOSS_DEBUGGING
00430 kdDebug(5006) << "Writing out UID cache lastuid: " << lastUid() << " in: " << folder()->prettyURL() << endl;
00431 #endif
00432 QFile uidcache( uidCacheLocation() );
00433 if( uidcache.open( IO_WriteOnly ) ) {
00434 QTextStream str( &uidcache );
00435 str << "# KMail-UidCache V" << UIDCACHE_VERSION << endl;
00436 str << uidValidity() << endl;
00437 str << lastUid() << endl;
00438 uidcache.flush();
00439 if ( uidcache.status() == IO_Ok ) {
00440 fsync( uidcache.handle() );
00441 uidcache.close();
00442 if ( uidcache.status() == IO_Ok )
00443 return 0;
00444 }
00445 }
00446 KMessageBox::error( 0,
00447 i18n( "The UID cache file for folder %1 could not be written. There "
00448 "could be a problem with file system permission." ).arg( folder()->prettyURL() ) );
00449
00450 return -1;
00451 }
00452
00453 void KMFolderCachedImap::reloadUidMap()
00454 {
00455
00456 uidMap.clear();
00457 open("reloadUdi");
00458 for( int i = 0; i < count(); ++i ) {
00459 KMMsgBase *msg = getMsgBase( i );
00460 if( !msg ) continue;
00461 ulong uid = msg->UID();
00462
00463 uidMap.insert( uid, i );
00464 }
00465 close("reloadUdi");
00466 uidMapDirty = false;
00467 }
00468
00469
00470 KMMessage* KMFolderCachedImap::take(int idx)
00471 {
00472 uidMapDirty = true;
00473 rememberDeletion( idx );
00474 return KMFolderMaildir::take(idx);
00475 }
00476
00477
00478 int KMFolderCachedImap::addMsgInternal( KMMessage* msg, bool newMail,
00479 int* index_return )
00480 {
00481
00482 ulong uid = msg->UID();
00483 if( uid != 0 ) {
00484 uidMapDirty = true;
00485 }
00486
00487 KMFolderOpener openThis(folder(), "KMFolderCachedImap::addMsgInternal");
00488 int rc = openThis.openResult();
00489 if ( rc ) {
00490 kdDebug(5006) << k_funcinfo << "open: " << rc << " of folder: " << label() << endl;
00491 return rc;
00492 }
00493
00494
00495 rc = KMFolderMaildir::addMsg(msg, index_return);
00496
00497 if( newMail && ( imapPath() == "/INBOX/" || ( !GlobalSettings::self()->filterOnlyDIMAPInbox()
00498 && (userRights() <= 0 || userRights() & ACLJobs::Administer )
00499 && (contentsType() == ContentsTypeMail || GlobalSettings::self()->filterGroupwareFolders()) ) ) )
00500
00501 mAccount->processNewMsg( msg );
00502
00503 return rc;
00504 }
00505
00506
00507 int KMFolderCachedImap::addMsg(KMMessage* msg, int* index_return)
00508 {
00509 if ( !canAddMsgNow( msg, index_return ) ) return 0;
00510
00511 int rc = KMFolderMaildir::addMsgInternal(msg, index_return, true );
00512 return rc;
00513 }
00514
00515 void KMFolderCachedImap::rememberDeletion( int idx )
00516 {
00517 KMMsgBase *msg = getMsgBase( idx );
00518 assert(msg);
00519 long uid = msg->UID();
00520 assert(uid>=0);
00521 mDeletedUIDsSinceLastSync.insert(uid, 0);
00522 kdDebug(5006) << "Explicit delete of UID " << uid << " at index: " << idx << " in " << folder()->prettyURL() << endl;
00523 }
00524
00525
00526 void KMFolderCachedImap::removeMsg(int idx, bool imapQuiet)
00527 {
00528 uidMapDirty = true;
00529 rememberDeletion( idx );
00530
00531 KMFolderMaildir::removeMsg(idx,imapQuiet);
00532 }
00533
00534 bool KMFolderCachedImap::canRemoveFolder() const {
00535
00536 if( folder() && folder()->child() && folder()->child()->count() > 0 )
00537 return false;
00538
00539 #if 0
00540
00541 return KMFolderMaildir::canRemoveFolder();
00542 #endif
00543 return true;
00544 }
00545
00546
00547 int KMFolderCachedImap::rename( const QString& aName,
00548 KMFolderDir* )
00549 {
00550 QString oldName = mAccount->renamedFolder( imapPath() );
00551 if ( oldName.isEmpty() ) oldName = name();
00552 if ( aName == oldName )
00553
00554 return 0;
00555
00556 if( account() == 0 || imapPath().isEmpty() ) {
00557 QString err = i18n("You must synchronize with the server before renaming IMAP folders.");
00558 KMessageBox::error( 0, err );
00559 return -1;
00560 }
00561
00562
00563
00564
00565
00566
00567 if ( name() != aName )
00568 mAccount->addRenamedFolder( imapPath(), folder()->label(), aName );
00569 else
00570 mAccount->removeRenamedFolder( imapPath() );
00571
00572 folder()->setLabel( aName );
00573 emit nameChanged();
00574
00575 return 0;
00576 }
00577
00578 KMFolder* KMFolderCachedImap::trashFolder() const
00579 {
00580 QString trashStr = account()->trash();
00581 return kmkernel->dimapFolderMgr()->findIdString( trashStr );
00582 }
00583
00584 void KMFolderCachedImap::setLastUid( ulong uid )
00585 {
00586 #if MAIL_LOSS_DEBUGGING
00587 kdDebug(5006) << "Setting mLastUid to: " << uid << " in " << folder()->prettyURL() << endl;
00588 #endif
00589 mLastUid = uid;
00590 if( uidWriteTimer == -1 )
00591
00592 uidWriteTimer = startTimer( 60000 );
00593 }
00594
00595 void KMFolderCachedImap::timerEvent( QTimerEvent* )
00596 {
00597 killTimer( uidWriteTimer );
00598 uidWriteTimer = -1;
00599 if ( writeUidCache() == -1 )
00600 unlink( QFile::encodeName( uidCacheLocation() ) );
00601 }
00602
00603 ulong KMFolderCachedImap::lastUid()
00604 {
00605 return mLastUid;
00606 }
00607
00608 KMMsgBase* KMFolderCachedImap::findByUID( ulong uid )
00609 {
00610 bool mapReloaded = false;
00611 if( uidMapDirty ) {
00612 reloadUidMap();
00613 mapReloaded = true;
00614 }
00615
00616 QMap<ulong,int>::Iterator it = uidMap.find( uid );
00617 if( it != uidMap.end() ) {
00618 KMMsgBase *msg = getMsgBase( *it );
00619 #if MAIL_LOSS_DEBUGGING
00620 kdDebug(5006) << "Folder: " << folder()->prettyURL() << endl;
00621 kdDebug(5006) << "UID " << uid << " is supposed to be in the map" << endl;
00622 kdDebug(5006) << "UID's index is to be " << *it << endl;
00623 kdDebug(5006) << "There is a message there? " << (msg != 0) << endl;
00624 if ( msg ) {
00625 kdDebug(5006) << "Its UID is: " << msg->UID() << endl;
00626 }
00627 #endif
00628
00629 if( msg && msg->UID() == uid )
00630 return msg;
00631 kdDebug(5006) << "########## Didn't find uid: " << uid << "in cache athough it's supposed to be there!" << endl;
00632 } else {
00633 #if MAIL_LOSS_DEBUGGING
00634 kdDebug(5006) << "Didn't find uid: " << uid << "in cache!" << endl;
00635 #endif
00636 }
00637
00638
00639
00640 return 0;
00641
00642 reloadUidMap();
00643 it = uidMap.find( uid );
00644 if( it != uidMap.end() )
00645
00646 return getMsgBase( *it );
00647 #if MAIL_LOSS_DEBUGGING
00648 else
00649 kdDebug(5006) << "Reloaded, but stil didn't find uid: " << uid << endl;
00650 #endif
00651
00652 return 0;
00653 }
00654
00655
00656
00657 KMAcctCachedImap *KMFolderCachedImap::account() const
00658 {
00659 if( (KMAcctCachedImap *)mAccount == 0 && kmkernel && kmkernel->acctMgr() ) {
00660
00661 mAccount = static_cast<KMAcctCachedImap *>( kmkernel->acctMgr()->findByName( name() ) );
00662 }
00663
00664 return mAccount;
00665 }
00666
00667 void KMFolderCachedImap::slotTroubleshoot()
00668 {
00669 const int rc = DImapTroubleShootDialog::run();
00670
00671 if( rc == DImapTroubleShootDialog::RefreshCache ) {
00672
00673 if( !account() ) {
00674 KMessageBox::sorry( 0, i18n("No account setup for this folder.\n"
00675 "Please try running a sync before this.") );
00676 return;
00677 }
00678 QString str = i18n("Are you sure you want to refresh the IMAP cache of "
00679 "the folder %1 and all its subfolders?\nThis will "
00680 "remove all changes you have done locally to your "
00681 "folders.").arg( label() );
00682 QString s1 = i18n("Refresh IMAP Cache");
00683 QString s2 = i18n("&Refresh");
00684 if( KMessageBox::warningContinueCancel( 0, str, s1, s2 ) ==
00685 KMessageBox::Continue )
00686 account()->invalidateIMAPFolders( this );
00687 } else {
00688
00689 switch ( rc ) {
00690 case DImapTroubleShootDialog::ReindexAll:
00691 {
00692 KMFolderCachedImap *rootStorage = dynamic_cast<KMFolderCachedImap*>( account()->rootFolder() );
00693 if ( rootStorage )
00694 rootStorage->createIndexFromContentsRecursive();
00695 break;
00696 }
00697 case DImapTroubleShootDialog::ReindexCurrent:
00698 createIndexFromContents();
00699 break;
00700 case DImapTroubleShootDialog::ReindexRecursive:
00701 createIndexFromContentsRecursive();
00702 break;
00703 default:
00704 return;
00705 }
00706 KMessageBox::information( 0, i18n( "The index of this folder has been "
00707 "recreated." ) );
00708 writeIndex();
00709 kmkernel->getKMMainWidget()->folderSelected();
00710 }
00711 }
00712
00713 void KMFolderCachedImap::serverSync( bool recurse )
00714 {
00715 if( mSyncState != SYNC_STATE_INITIAL ) {
00716 if( KMessageBox::warningYesNo( 0, i18n("Folder %1 is not in initial sync state (state was %2). Do you want to reset it to initial sync state and sync anyway?" ).arg( imapPath() ).arg( mSyncState ), QString::null, i18n("Reset && Sync"), KStdGuiItem::cancel() ) == KMessageBox::Yes ) {
00717 mSyncState = SYNC_STATE_INITIAL;
00718 } else return;
00719 }
00720
00721 mRecurse = recurse;
00722 assert( account() );
00723
00724 ProgressItem *progressItem = mAccount->mailCheckProgressItem();
00725 if ( progressItem ) {
00726 progressItem->reset();
00727 progressItem->setTotalItems( 100 );
00728 }
00729 mProgress = 0;
00730
00731 #if 0
00732 if( mHoldSyncs ) {
00733
00734 account()->mailCheckProgressItem()->setProgress( 100 );
00735 mProgress = 100;
00736 newState( mProgress, i18n("Synchronization skipped"));
00737 mSyncState = SYNC_STATE_INITIAL;
00738 emit folderComplete( this, true );
00739 return;
00740 }
00741 #endif
00742 mTentativeHighestUid = 0;
00743
00744 serverSyncInternal();
00745 }
00746
00747 QString KMFolderCachedImap::state2String( int state ) const
00748 {
00749 switch( state ) {
00750 case SYNC_STATE_INITIAL: return "SYNC_STATE_INITIAL";
00751 case SYNC_STATE_GET_USERRIGHTS: return "SYNC_STATE_GET_USERRIGHTS";
00752 case SYNC_STATE_PUT_MESSAGES: return "SYNC_STATE_PUT_MESSAGES";
00753 case SYNC_STATE_UPLOAD_FLAGS: return "SYNC_STATE_UPLOAD_FLAGS";
00754 case SYNC_STATE_CREATE_SUBFOLDERS: return "SYNC_STATE_CREATE_SUBFOLDERS";
00755 case SYNC_STATE_LIST_SUBFOLDERS: return "SYNC_STATE_LIST_SUBFOLDERS";
00756 case SYNC_STATE_LIST_NAMESPACES: return "SYNC_STATE_LIST_NAMESPACES";
00757 case SYNC_STATE_LIST_SUBFOLDERS2: return "SYNC_STATE_LIST_SUBFOLDERS2";
00758 case SYNC_STATE_DELETE_SUBFOLDERS: return "SYNC_STATE_DELETE_SUBFOLDERS";
00759 case SYNC_STATE_LIST_MESSAGES: return "SYNC_STATE_LIST_MESSAGES";
00760 case SYNC_STATE_DELETE_MESSAGES: return "SYNC_STATE_DELETE_MESSAGES";
00761 case SYNC_STATE_GET_MESSAGES: return "SYNC_STATE_GET_MESSAGES";
00762 case SYNC_STATE_EXPUNGE_MESSAGES: return "SYNC_STATE_EXPUNGE_MESSAGES";
00763 case SYNC_STATE_HANDLE_INBOX: return "SYNC_STATE_HANDLE_INBOX";
00764 case SYNC_STATE_TEST_ANNOTATIONS: return "SYNC_STATE_TEST_ANNOTATIONS";
00765 case SYNC_STATE_GET_ANNOTATIONS: return "SYNC_STATE_GET_ANNOTATIONS";
00766 case SYNC_STATE_SET_ANNOTATIONS: return "SYNC_STATE_SET_ANNOTATIONS";
00767 case SYNC_STATE_GET_ACLS: return "SYNC_STATE_GET_ACLS";
00768 case SYNC_STATE_SET_ACLS: return "SYNC_STATE_SET_ACLS";
00769 case SYNC_STATE_GET_QUOTA: return "SYNC_STATE_GET_QUOTA";
00770 case SYNC_STATE_FIND_SUBFOLDERS: return "SYNC_STATE_FIND_SUBFOLDERS";
00771 case SYNC_STATE_SYNC_SUBFOLDERS: return "SYNC_STATE_SYNC_SUBFOLDERS";
00772 case SYNC_STATE_RENAME_FOLDER: return "SYNC_STATE_RENAME_FOLDER";
00773 case SYNC_STATE_CHECK_UIDVALIDITY: return "SYNC_STATE_CHECK_UIDVALIDITY";
00774 default: return "Unknown state";
00775 }
00776 }
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807
00808
00809 void KMFolderCachedImap::serverSyncInternal()
00810 {
00811
00812
00813
00814 if( kmkernel->mailCheckAborted() ) {
00815 resetSyncState();
00816 emit folderComplete( this, false );
00817 return;
00818 }
00819
00820
00821 switch( mSyncState ) {
00822 case SYNC_STATE_INITIAL:
00823 {
00824 mProgress = 0;
00825 foldersForDeletionOnServer.clear();
00826 newState( mProgress, i18n("Synchronizing"));
00827
00828 open("cachedimap");
00829 if ( !noContent() )
00830 mAccount->addLastUnreadMsgCount( this, countUnread() );
00831
00832
00833 ImapAccountBase::ConnectionState cs = mAccount->makeConnection();
00834 if ( cs == ImapAccountBase::Error ) {
00835
00836
00837
00838 newState( mProgress, i18n( "Error connecting to server %1" ).arg( mAccount->host() ) );
00839 close("cachedimap");
00840 emit folderComplete(this, false);
00841 break;
00842 } else if ( cs == ImapAccountBase::Connecting ) {
00843 mAccount->setAnnotationCheckPassed( false );
00844
00845 newState( mProgress, i18n("Connecting to %1").arg( mAccount->host() ) );
00846
00847 connect( mAccount, SIGNAL( connectionResult(int, const QString&) ),
00848 this, SLOT( slotConnectionResult(int, const QString&) ) );
00849 break;
00850 } else {
00851
00852
00853 mSyncState = SYNC_STATE_GET_USERRIGHTS;
00854
00855 }
00856 }
00857
00858
00859 case SYNC_STATE_GET_USERRIGHTS:
00860
00861
00862 mSyncState = SYNC_STATE_RENAME_FOLDER;
00863
00864 if( !noContent() && mAccount->hasACLSupport() ) {
00865
00866 mOldUserRights = mUserRights;
00867 newState( mProgress, i18n("Checking permissions"));
00868 connect( mAccount, SIGNAL( receivedUserRights( KMFolder* ) ),
00869 this, SLOT( slotReceivedUserRights( KMFolder* ) ) );
00870 mAccount->getUserRights( folder(), imapPath() );
00871 break;
00872 }
00873
00874 case SYNC_STATE_RENAME_FOLDER:
00875 {
00876 mSyncState = SYNC_STATE_CHECK_UIDVALIDITY;
00877
00878 bool isResourceFolder = kmkernel->iCalIface().isStandardResourceFolder( folder() );
00879 QString newName = mAccount->renamedFolder( imapPath() );
00880 if ( !newName.isEmpty() && !folder()->isSystemFolder() && !isResourceFolder ) {
00881 newState( mProgress, i18n("Renaming folder") );
00882 CachedImapJob *job = new CachedImapJob( newName, CachedImapJob::tRenameFolder, this );
00883 connect( job, SIGNAL( result(KMail::FolderJob *) ), this, SLOT( slotIncreaseProgress() ) );
00884 connect( job, SIGNAL( finished() ), this, SLOT( serverSyncInternal() ) );
00885 job->start();
00886 break;
00887 }
00888 }
00889
00890 case SYNC_STATE_CHECK_UIDVALIDITY:
00891 mSyncState = SYNC_STATE_CREATE_SUBFOLDERS;
00892 if( !noContent() ) {
00893 checkUidValidity();
00894 break;
00895 }
00896
00897
00898 case SYNC_STATE_CREATE_SUBFOLDERS:
00899 mSyncState = SYNC_STATE_PUT_MESSAGES;
00900 createNewFolders();
00901 break;
00902
00903 case SYNC_STATE_PUT_MESSAGES:
00904 mSyncState = SYNC_STATE_UPLOAD_FLAGS;
00905 if( !noContent() ) {
00906 uploadNewMessages();
00907 break;
00908 }
00909
00910 case SYNC_STATE_UPLOAD_FLAGS:
00911 mSyncState = SYNC_STATE_LIST_NAMESPACES;
00912 if( !noContent() ) {
00913
00914 if( uidMapDirty )
00915 reloadUidMap();
00916
00917
00918 if ( mUserRights <= 0 || ( mUserRights & (KMail::ACLJobs::WriteFlags ) ) ) {
00919 if ( mStatusChangedLocally ) {
00920 uploadFlags();
00921 break;
00922 } else {
00923
00924 }
00925 } else if ( mUserRights & KMail::ACLJobs::WriteSeenFlag ) {
00926 if ( mStatusChangedLocally ) {
00927 uploadSeenFlags();
00928 break;
00929 }
00930 }
00931 }
00932
00933
00934 case SYNC_STATE_LIST_NAMESPACES:
00935 if ( this == mAccount->rootFolder() ) {
00936 listNamespaces();
00937 break;
00938 }
00939 mSyncState = SYNC_STATE_LIST_SUBFOLDERS;
00940
00941
00942 case SYNC_STATE_LIST_SUBFOLDERS:
00943 newState( mProgress, i18n("Retrieving folderlist"));
00944 mSyncState = SYNC_STATE_LIST_SUBFOLDERS2;
00945 if( !listDirectory() ) {
00946 mSyncState = SYNC_STATE_INITIAL;
00947 KMessageBox::error(0, i18n("Error while retrieving the folderlist"));
00948 }
00949 break;
00950
00951 case SYNC_STATE_LIST_SUBFOLDERS2:
00952 mSyncState = SYNC_STATE_DELETE_SUBFOLDERS;
00953 mProgress += 10;
00954 newState( mProgress, i18n("Retrieving subfolders"));
00955 listDirectory2();
00956 break;
00957
00958 case SYNC_STATE_DELETE_SUBFOLDERS:
00959 mSyncState = SYNC_STATE_LIST_MESSAGES;
00960 if( !foldersForDeletionOnServer.isEmpty() ) {
00961 newState( mProgress, i18n("Deleting folders from server"));
00962 CachedImapJob* job = new CachedImapJob( foldersForDeletionOnServer,
00963 CachedImapJob::tDeleteFolders, this );
00964 connect( job, SIGNAL( result(KMail::FolderJob *) ), this, SLOT( slotIncreaseProgress() ) );
00965 connect( job, SIGNAL( finished() ), this, SLOT( slotFolderDeletionOnServerFinished() ) );
00966 job->start();
00967 break;
00968 }
00969
00970
00971
00972
00973 case SYNC_STATE_LIST_MESSAGES:
00974 mSyncState = SYNC_STATE_DELETE_MESSAGES;
00975 if( !noContent() ) {
00976 newState( mProgress, i18n("Retrieving message list"));
00977 listMessages();
00978 break;
00979 }
00980
00981
00982 case SYNC_STATE_DELETE_MESSAGES:
00983 mSyncState = SYNC_STATE_EXPUNGE_MESSAGES;
00984 if( !noContent() ) {
00985 if( deleteMessages() ) {
00986
00987 } else {
00988
00989 newState( mProgress, i18n("No messages to delete..."));
00990 mSyncState = SYNC_STATE_GET_MESSAGES;
00991 serverSyncInternal();
00992 }
00993 break;
00994 }
00995
00996
00997 case SYNC_STATE_EXPUNGE_MESSAGES:
00998 mSyncState = SYNC_STATE_GET_MESSAGES;
00999 if( !noContent() ) {
01000 newState( mProgress, i18n("Expunging deleted messages"));
01001 CachedImapJob *job = new CachedImapJob( QString::null,
01002 CachedImapJob::tExpungeFolder, this );
01003 connect( job, SIGNAL( result(KMail::FolderJob *) ), this, SLOT( slotIncreaseProgress() ) );
01004 connect( job, SIGNAL( finished() ), this, SLOT( serverSyncInternal() ) );
01005 job->start();
01006 break;
01007 }
01008
01009
01010 case SYNC_STATE_GET_MESSAGES:
01011 mSyncState = SYNC_STATE_HANDLE_INBOX;
01012 if( !noContent() ) {
01013 if( !mMsgsForDownload.isEmpty() ) {
01014 newState( mProgress, i18n("Retrieving new messages"));
01015 CachedImapJob *job = new CachedImapJob( mMsgsForDownload,
01016 CachedImapJob::tGetMessage,
01017 this );
01018 connect( job, SIGNAL( progress(unsigned long, unsigned long) ),
01019 this, SLOT( slotProgress(unsigned long, unsigned long) ) );
01020 connect( job, SIGNAL( finished() ), this, SLOT( slotUpdateLastUid() ) );
01021 connect( job, SIGNAL( finished() ), this, SLOT( serverSyncInternal() ) );
01022 job->start();
01023 mMsgsForDownload.clear();
01024 break;
01025 } else {
01026 newState( mProgress, i18n("No new messages from server"));
01027
01028
01029
01030
01031
01032 slotUpdateLastUid();
01033 if( mLastUid == 0 && uidWriteTimer == -1 ) {
01034
01035 if ( writeUidCache() == -1 ) {
01036 resetSyncState();
01037 emit folderComplete( this, false );
01038 return;
01039 }
01040 }
01041 }
01042 }
01043
01044
01045
01046 case SYNC_STATE_HANDLE_INBOX:
01047
01048 mProgress = 95;
01049 mSyncState = SYNC_STATE_TEST_ANNOTATIONS;
01050
01051 #define KOLAB_FOLDERTEST "/vendor/kolab/folder-test"
01052 case SYNC_STATE_TEST_ANNOTATIONS:
01053 mSyncState = SYNC_STATE_GET_ANNOTATIONS;
01054
01055 if( !mAccount->annotationCheckPassed() &&
01056 ( mUserRights <= 0 || ( mUserRights & ACLJobs::Administer ) )
01057 && !imapPath().isEmpty() && imapPath() != "/" ) {
01058 kdDebug(5006) << "Setting test attribute on folder: "<< folder()->prettyURL() << endl;
01059 newState( mProgress, i18n("Checking annotation support"));
01060
01061 KURL url = mAccount->getUrl();
01062 url.setPath( imapPath() );
01063 KMail::AnnotationList annotations;
01064
01065 KMail::AnnotationAttribute attr( KOLAB_FOLDERTEST, "value.shared", "true" );
01066 annotations.append( attr );
01067
01068 kdDebug(5006) << "Setting test attribute to "<< url << endl;
01069 KIO::Job* job = AnnotationJobs::multiSetAnnotation( mAccount->slave(),
01070 url, annotations );
01071 ImapAccountBase::jobData jd( url.url(), folder() );
01072 jd.cancellable = true;
01073 mAccount->insertJob(job, jd);
01074 connect(job, SIGNAL(result(KIO::Job *)),
01075 SLOT(slotTestAnnotationResult(KIO::Job *)));
01076 break;
01077 }
01078
01079 case SYNC_STATE_GET_ANNOTATIONS: {
01080 #define KOLAB_FOLDERTYPE "/vendor/kolab/folder-type"
01081 #define KOLAB_INCIDENCESFOR "/vendor/kolab/incidences-for"
01082
01083 mSyncState = SYNC_STATE_SET_ANNOTATIONS;
01084
01085 bool needToGetInitialAnnotations = false;
01086 if ( !noContent() ) {
01087
01088 if ( mAnnotationFolderType == "FROMSERVER" ) {
01089 needToGetInitialAnnotations = true;
01090 mAnnotationFolderType = QString::null;
01091 } else {
01092 updateAnnotationFolderType();
01093 }
01094 }
01095
01096
01097
01098 if ( !noContent() && mAccount->hasAnnotationSupport() &&
01099 ( kmkernel->iCalIface().isEnabled() || needToGetInitialAnnotations ) ) {
01100 QStringList annotations;
01101 if ( !mAnnotationFolderTypeChanged || mAnnotationFolderType.isEmpty() )
01102 annotations << KOLAB_FOLDERTYPE;
01103 if ( !mIncidencesForChanged )
01104 annotations << KOLAB_INCIDENCESFOR;
01105 if ( !annotations.isEmpty() ) {
01106 newState( mProgress, i18n("Retrieving annotations"));
01107 KURL url = mAccount->getUrl();
01108 url.setPath( imapPath() );
01109 AnnotationJobs::MultiGetAnnotationJob* job =
01110 AnnotationJobs::multiGetAnnotation( mAccount->slave(), url, annotations );
01111 ImapAccountBase::jobData jd( url.url(), folder() );
01112 jd.cancellable = true;
01113 mAccount->insertJob(job, jd);
01114
01115 connect( job, SIGNAL(annotationResult(const QString&, const QString&, bool)),
01116 SLOT(slotAnnotationResult(const QString&, const QString&, bool)) );
01117 connect( job, SIGNAL(result(KIO::Job *)),
01118 SLOT(slotGetAnnotationResult(KIO::Job *)) );
01119 break;
01120 }
01121 }
01122 }
01123 case SYNC_STATE_SET_ANNOTATIONS:
01124
01125 mSyncState = SYNC_STATE_SET_ACLS;
01126 if ( !noContent() && mAccount->hasAnnotationSupport() &&
01127 ( mUserRights <= 0 || ( mUserRights & ACLJobs::Administer ) ) ) {
01128 newState( mProgress, i18n("Setting annotations"));
01129 KURL url = mAccount->getUrl();
01130 url.setPath( imapPath() );
01131 KMail::AnnotationList annotations;
01132 if ( mAnnotationFolderTypeChanged && !mAnnotationFolderType.isEmpty() ) {
01133 KMail::AnnotationAttribute attr( KOLAB_FOLDERTYPE, "value.shared", mAnnotationFolderType );
01134 annotations.append( attr );
01135 kdDebug(5006) << "Setting folder-type annotation for " << label() << " to " << mAnnotationFolderType << endl;
01136 }
01137 if ( mIncidencesForChanged ) {
01138 const QString val = incidencesForToString( mIncidencesFor );
01139 KMail::AnnotationAttribute attr( KOLAB_INCIDENCESFOR, "value.shared", val );
01140 annotations.append( attr );
01141 kdDebug(5006) << "Setting incidences-for annotation for " << label() << " to " << val << endl;
01142 }
01143 if ( !annotations.isEmpty() ) {
01144 KIO::Job* job =
01145 AnnotationJobs::multiSetAnnotation( mAccount->slave(), url, annotations );
01146 ImapAccountBase::jobData jd( url.url(), folder() );
01147 jd.cancellable = true;
01148 mAccount->insertJob(job, jd);
01149
01150 connect(job, SIGNAL(annotationChanged( const QString&, const QString&, const QString& ) ),
01151 SLOT( slotAnnotationChanged( const QString&, const QString&, const QString& ) ));
01152 connect(job, SIGNAL(result(KIO::Job *)),
01153 SLOT(slotSetAnnotationResult(KIO::Job *)));
01154 break;
01155 }
01156 }
01157
01158 case SYNC_STATE_SET_ACLS:
01159 mSyncState = SYNC_STATE_GET_ACLS;
01160
01161 if( !noContent() && mAccount->hasACLSupport() &&
01162 ( mUserRights <= 0 || ( mUserRights & ACLJobs::Administer ) ) ) {
01163 bool hasChangedACLs = false;
01164 ACLList::ConstIterator it = mACLList.begin();
01165 for ( ; it != mACLList.end() && !hasChangedACLs; ++it ) {
01166 hasChangedACLs = (*it).changed;
01167 }
01168 if ( hasChangedACLs ) {
01169 newState( mProgress, i18n("Setting permissions"));
01170 KURL url = mAccount->getUrl();
01171 url.setPath( imapPath() );
01172 KIO::Job* job = KMail::ACLJobs::multiSetACL( mAccount->slave(), url, mACLList );
01173 ImapAccountBase::jobData jd( url.url(), folder() );
01174 mAccount->insertJob(job, jd);
01175
01176 connect(job, SIGNAL(result(KIO::Job *)),
01177 SLOT(slotMultiSetACLResult(KIO::Job *)));
01178 connect(job, SIGNAL(aclChanged( const QString&, int )),
01179 SLOT(slotACLChanged( const QString&, int )) );
01180 break;
01181 }
01182 }
01183
01184 case SYNC_STATE_GET_ACLS:
01185 mSyncState = SYNC_STATE_GET_QUOTA;
01186
01187 if( !noContent() && mAccount->hasACLSupport() ) {
01188 newState( mProgress, i18n( "Retrieving permissions" ) );
01189 mAccount->getACL( folder(), mImapPath );
01190 connect( mAccount, SIGNAL(receivedACL( KMFolder*, KIO::Job*, const KMail::ACLList& )),
01191 this, SLOT(slotReceivedACL( KMFolder*, KIO::Job*, const KMail::ACLList& )) );
01192 break;
01193 }
01194 case SYNC_STATE_GET_QUOTA:
01195
01196 mSyncState = SYNC_STATE_FIND_SUBFOLDERS;
01197 if( !noContent() && mAccount->hasQuotaSupport() ) {
01198 newState( mProgress, i18n("Getting quota information"));
01199 KURL url = mAccount->getUrl();
01200 url.setPath( imapPath() );
01201 KIO::Job* job = KMail::QuotaJobs::getStorageQuota( mAccount->slave(), url );
01202 ImapAccountBase::jobData jd( url.url(), folder() );
01203 mAccount->insertJob(job, jd);
01204 connect( job, SIGNAL( storageQuotaResult( const QuotaInfo& ) ),
01205 SLOT( slotStorageQuotaResult( const QuotaInfo& ) ) );
01206 connect( job, SIGNAL(result(KIO::Job *)),
01207 SLOT(slotQuotaResult(KIO::Job *)) );
01208 break;
01209 }
01210 case SYNC_STATE_FIND_SUBFOLDERS:
01211 {
01212 mProgress = 98;
01213 newState( mProgress, i18n("Updating cache file"));
01214
01215 mSyncState = SYNC_STATE_SYNC_SUBFOLDERS;
01216 mSubfoldersForSync.clear();
01217 mCurrentSubfolder = 0;
01218 if( folder() && folder()->child() ) {
01219 KMFolderNode *node = folder()->child()->first();
01220 while( node ) {
01221 if( !node->isDir() ) {
01222 KMFolderCachedImap* storage = static_cast<KMFolderCachedImap*>(static_cast<KMFolder*>(node)->storage());
01223
01224 if ( !storage->imapPath().isEmpty()
01225
01226 && !foldersForDeletionOnServer.contains( storage->imapPath() ) ) {
01227 mSubfoldersForSync << storage;
01228 } else {
01229 kdDebug(5006) << "Do not add " << storage->label()
01230 << " to synclist" << endl;
01231 }
01232 }
01233 node = folder()->child()->next();
01234 }
01235 }
01236
01237
01238 mProgress = 100;
01239 newState( mProgress, i18n("Synchronization done"));
01240 KURL url = mAccount->getUrl();
01241 url.setPath( imapPath() );
01242 kmkernel->iCalIface().folderSynced( folder(), url );
01243 }
01244
01245 if ( !mRecurse )
01246 mSubfoldersForSync.clear();
01247
01248
01249 case SYNC_STATE_SYNC_SUBFOLDERS:
01250 {
01251 if( mCurrentSubfolder ) {
01252 disconnect( mCurrentSubfolder, SIGNAL( folderComplete(KMFolderCachedImap*, bool) ),
01253 this, SLOT( slotSubFolderComplete(KMFolderCachedImap*, bool) ) );
01254 mCurrentSubfolder = 0;
01255 }
01256
01257 if( mSubfoldersForSync.isEmpty() ) {
01258 mSyncState = SYNC_STATE_INITIAL;
01259 mAccount->addUnreadMsgCount( this, countUnread() );
01260 close("cachedimap");
01261 emit folderComplete( this, true );
01262 } else {
01263 mCurrentSubfolder = mSubfoldersForSync.front();
01264 mSubfoldersForSync.pop_front();
01265 connect( mCurrentSubfolder, SIGNAL( folderComplete(KMFolderCachedImap*, bool) ),
01266 this, SLOT( slotSubFolderComplete(KMFolderCachedImap*, bool) ) );
01267
01268
01269 assert( !mCurrentSubfolder->imapPath().isEmpty() );
01270 mCurrentSubfolder->setAccount( account() );
01271 bool recurse = mCurrentSubfolder->noChildren() ? false : true;
01272 mCurrentSubfolder->serverSync( recurse );
01273 }
01274 }
01275 break;
01276
01277 default:
01278 kdDebug(5006) << "KMFolderCachedImap::serverSyncInternal() WARNING: no such state "
01279 << mSyncState << endl;
01280 }
01281 }
01282
01283
01284
01285
01286 void KMFolderCachedImap::slotConnectionResult( int errorCode, const QString& errorMsg )
01287 {
01288 disconnect( mAccount, SIGNAL( connectionResult(int, const QString&) ),
01289 this, SLOT( slotConnectionResult(int, const QString&) ) );
01290 if ( !errorCode ) {
01291
01292 mSyncState = SYNC_STATE_GET_USERRIGHTS;
01293 mProgress += 5;
01294 serverSyncInternal();
01295 } else {
01296
01297 newState( mProgress, KIO::buildErrorString( errorCode, errorMsg ));
01298 emit folderComplete(this, false);
01299 }
01300 }
01301
01302
01303 QValueList<unsigned long> KMFolderCachedImap::findNewMessages()
01304 {
01305 QValueList<unsigned long> result;
01306 for( int i = 0; i < count(); ++i ) {
01307 KMMsgBase *msg = getMsgBase( i );
01308 if( !msg ) continue;
01309 if ( msg->UID() == 0 )
01310 result.append( msg->getMsgSerNum() );
01311 }
01312 return result;
01313 }
01314
01315
01316 void KMFolderCachedImap::uploadNewMessages()
01317 {
01318 QValueList<unsigned long> newMsgs = findNewMessages();
01319 if( !newMsgs.isEmpty() ) {
01320 if ( mUserRights <= 0 || ( mUserRights & ( KMail::ACLJobs::Insert ) ) ) {
01321 newState( mProgress, i18n("Uploading messages to server"));
01322 CachedImapJob *job = new CachedImapJob( newMsgs, CachedImapJob::tPutMessage, this );
01323 connect( job, SIGNAL( progress( unsigned long, unsigned long) ),
01324 this, SLOT( slotPutProgress(unsigned long, unsigned long) ) );
01325 connect( job, SIGNAL( finished() ), this, SLOT( serverSyncInternal() ) );
01326 job->start();
01327 return;
01328 } else {
01329 KMCommand *command = rescueUnsyncedMessages();
01330 connect( command, SIGNAL( completed( KMCommand * ) ),
01331 this, SLOT( serverSyncInternal() ) );
01332 }
01333 } else {
01334 if ( mUserRights != mOldUserRights && (mOldUserRights & KMail::ACLJobs::Insert)
01335 && !(mUserRights & KMail::ACLJobs::Insert) ) {
01336
01337 KMessageBox::information( 0, i18n("<p>Your access rights to folder <b>%1</b> have been restricted, "
01338 "it will no longer be possible to add messages to this folder.</p>").arg( folder()->prettyURL() ),
01339 i18n("Acces rights revoked"), "KMailACLRevocationNotification" );
01340 }
01341 }
01342 newState( mProgress, i18n("No messages to upload to server"));
01343 serverSyncInternal();
01344 }
01345
01346
01347 void KMFolderCachedImap::slotPutProgress( unsigned long done, unsigned long total )
01348 {
01349
01350 int progressSpan = 10;
01351 newState( mProgress + (progressSpan * done) / total, QString::null );
01352 if ( done == total )
01353 mProgress += progressSpan;
01354 }
01355
01356
01357 void KMFolderCachedImap::uploadFlags()
01358 {
01359 if ( !uidMap.isEmpty() ) {
01360 mStatusFlagsJobs = 0;
01361 newState( mProgress, i18n("Uploading status of messages to server"));
01362
01363
01364 QMap< QString, QStringList > groups;
01365
01366 for( int i = 0; i < count(); ++i ) {
01367 KMMsgBase* msg = getMsgBase( i );
01368 if( !msg || msg->UID() == 0 )
01369
01370 continue;
01371
01372 QString flags = KMFolderImap::statusToFlags(msg->status(), mPermanentFlags);
01373
01374 QString uid;
01375 uid.setNum( msg->UID() );
01376 groups[flags].append(uid);
01377 }
01378 QMapIterator< QString, QStringList > dit;
01379 for( dit = groups.begin(); dit != groups.end(); ++dit ) {
01380 QCString flags = dit.key().latin1();
01381 QStringList sets = KMFolderImap::makeSets( (*dit), true );
01382 mStatusFlagsJobs += sets.count();
01383
01384 for( QStringList::Iterator slit = sets.begin(); slit != sets.end(); ++slit ) {
01385 QString imappath = imapPath() + ";UID=" + ( *slit );
01386 mAccount->setImapStatus(folder(), imappath, flags);
01387 }
01388 }
01389
01390
01391 if ( mStatusFlagsJobs ) {
01392 connect( mAccount, SIGNAL( imapStatusChanged(KMFolder*, const QString&, bool) ),
01393 this, SLOT( slotImapStatusChanged(KMFolder*, const QString&, bool) ) );
01394 return;
01395 }
01396 }
01397 newState( mProgress, i18n("No messages to upload to server"));
01398 serverSyncInternal();
01399 }
01400
01401 void KMFolderCachedImap::uploadSeenFlags()
01402 {
01403 if ( !uidMap.isEmpty() ) {
01404 mStatusFlagsJobs = 0;
01405 newState( mProgress, i18n("Uploading status of messages to server"));
01406
01407 QValueList<ulong> seenUids, unseenUids;
01408 for( int i = 0; i < count(); ++i ) {
01409 KMMsgBase* msg = getMsgBase( i );
01410 if( !msg || msg->UID() == 0 )
01411
01412 continue;
01413
01414 if ( msg->status() & KMMsgStatusOld || msg->status() & KMMsgStatusRead )
01415 seenUids.append( msg->UID() );
01416 else
01417 unseenUids.append( msg->UID() );
01418 }
01419 if ( !seenUids.isEmpty() ) {
01420 QStringList sets = KMFolderImap::makeSets( seenUids, true );
01421 mStatusFlagsJobs += sets.count();
01422 for( QStringList::Iterator it = sets.begin(); it != sets.end(); ++it ) {
01423 QString imappath = imapPath() + ";UID=" + ( *it );
01424 mAccount->setImapSeenStatus( folder(), imappath, true );
01425 }
01426 }
01427 if ( !unseenUids.isEmpty() ) {
01428 QStringList sets = KMFolderImap::makeSets( unseenUids, true );
01429 mStatusFlagsJobs += sets.count();
01430 for( QStringList::Iterator it = sets.begin(); it != sets.end(); ++it ) {
01431 QString imappath = imapPath() + ";UID=" + ( *it );
01432 mAccount->setImapSeenStatus( folder(), imappath, false );
01433 }
01434 }
01435
01436 if ( mStatusFlagsJobs ) {
01437 connect( mAccount, SIGNAL( imapStatusChanged(KMFolder*, const QString&, bool) ),
01438 this, SLOT( slotImapStatusChanged(KMFolder*, const QString&, bool) ) );
01439 return;
01440 }
01441 }
01442 newState( mProgress, i18n("No messages to upload to server"));
01443 serverSyncInternal();
01444 }
01445
01446 void KMFolderCachedImap::slotImapStatusChanged(KMFolder* folder, const QString&, bool cont)
01447 {
01448 if ( mSyncState == SYNC_STATE_INITIAL ){
01449
01450 return;
01451 }
01452
01453 if ( folder->storage() == this ) {
01454 --mStatusFlagsJobs;
01455 if ( mStatusFlagsJobs == 0 || !cont )
01456 disconnect( mAccount, SIGNAL( imapStatusChanged(KMFolder*, const QString&, bool) ),
01457 this, SLOT( slotImapStatusChanged(KMFolder*, const QString&, bool) ) );
01458 if ( mStatusFlagsJobs == 0 && cont ) {
01459 mProgress += 5;
01460 serverSyncInternal();
01461
01462 }
01463 }
01464 }
01465
01466
01467 void KMFolderCachedImap::setStatus( int idx, KMMsgStatus status, bool toggle)
01468 {
01469 KMFolderMaildir::setStatus( idx, status, toggle );
01470 mStatusChangedLocally = true;
01471 }
01472
01473 void KMFolderCachedImap::setStatus(QValueList<int>& ids, KMMsgStatus status, bool toggle)
01474 {
01475 KMFolderMaildir::setStatus(ids, status, toggle);
01476 mStatusChangedLocally = true;
01477 }
01478
01479
01480 void KMFolderCachedImap::createNewFolders()
01481 {
01482 QValueList<KMFolderCachedImap*> newFolders = findNewFolders();
01483
01484 if( !newFolders.isEmpty() ) {
01485 newState( mProgress, i18n("Creating subfolders on server"));
01486 CachedImapJob *job = new CachedImapJob( newFolders, CachedImapJob::tAddSubfolders, this );
01487 connect( job, SIGNAL( result(KMail::FolderJob *) ), this, SLOT( slotIncreaseProgress() ) );
01488 connect( job, SIGNAL( finished() ), this, SLOT( serverSyncInternal() ) );
01489 job->start();
01490 } else {
01491 serverSyncInternal();
01492 }
01493 }
01494
01495 QValueList<KMFolderCachedImap*> KMFolderCachedImap::findNewFolders()
01496 {
01497 QValueList<KMFolderCachedImap*> newFolders;
01498 if( folder() && folder()->child() ) {
01499 KMFolderNode *node = folder()->child()->first();
01500 while( node ) {
01501 if( !node->isDir() ) {
01502 if( static_cast<KMFolder*>(node)->folderType() != KMFolderTypeCachedImap ) {
01503 kdError(5006) << "KMFolderCachedImap::findNewFolders(): ARGH!!! "
01504 << node->name() << " is not an IMAP folder\n";
01505 node = folder()->child()->next();
01506 assert(0);
01507 }
01508 KMFolderCachedImap* folder = static_cast<KMFolderCachedImap*>(static_cast<KMFolder*>(node)->storage());
01509 if( folder->imapPath().isEmpty() ) {
01510 newFolders << folder;
01511 }
01512 }
01513 node = folder()->child()->next();
01514 }
01515 }
01516 return newFolders;
01517 }
01518
01519 bool KMFolderCachedImap::deleteMessages()
01520 {
01521
01522 QPtrList<KMMessage> msgsForDeletion;
01523
01524
01525
01526
01527
01528 QStringList uids;
01529 QMap<ulong,int>::const_iterator it = uidMap.constBegin();
01530 for( ; it != uidMap.end(); it++ ) {
01531 ulong uid ( it.key() );
01532 if( uid!=0 && !uidsOnServer.find( uid ) ) {
01533 uids << QString::number( uid );
01534 msgsForDeletion.append( getMsg( *it ) );
01535 }
01536 }
01537
01538 if( !msgsForDeletion.isEmpty() ) {
01539 #if MAIL_LOSS_DEBUGGING
01540 if ( KMessageBox::warningYesNo(
01541 0, i18n( "<qt><p>Mails on the server in folder <b>%1</b> were deleted. "
01542 "Do you want to delete them locally?<br>UIDs: %2</p></qt>" )
01543 .arg( folder()->prettyURL() ).arg( uids.join(",") ) ) == KMessageBox::Yes )
01544 #endif
01545 removeMsg( msgsForDeletion );
01546 }
01547
01548 if ( mUserRights > 0 && !( mUserRights & KMail::ACLJobs::Delete ) )
01549 return false;
01550
01551
01552 if( !uidsForDeletionOnServer.isEmpty() ) {
01553 newState( mProgress, i18n("Deleting removed messages from server"));
01554 QStringList sets = KMFolderImap::makeSets( uidsForDeletionOnServer, true );
01555 uidsForDeletionOnServer.clear();
01556 kdDebug(5006) << "Deleting " << sets.count() << " sets of messages from server folder " << imapPath() << endl;
01557 CachedImapJob *job = new CachedImapJob( sets, CachedImapJob::tDeleteMessage, this );
01558 connect( job, SIGNAL( result(KMail::FolderJob *) ),
01559 this, SLOT( slotDeleteMessagesResult(KMail::FolderJob *) ) );
01560 job->start();
01561 return true;
01562 } else {
01563 return false;
01564 }
01565 }
01566
01567 void KMFolderCachedImap::slotDeleteMessagesResult( KMail::FolderJob* job )
01568 {
01569 if ( job->error() ) {
01570
01571 mSyncState = SYNC_STATE_GET_MESSAGES;
01572 } else {
01573
01574 mDeletedUIDsSinceLastSync.clear();
01575 }
01576 mProgress += 10;
01577 serverSyncInternal();
01578 }
01579
01580 void KMFolderCachedImap::checkUidValidity() {
01581
01582
01583 if( imapPath().isEmpty() || imapPath() == "/" )
01584
01585 serverSyncInternal();
01586 else {
01587 newState( mProgress, i18n("Checking folder validity"));
01588 CachedImapJob *job = new CachedImapJob( FolderJob::tCheckUidValidity, this );
01589 connect( job, SIGNAL(permanentFlags(int)), SLOT(slotPermanentFlags(int)) );
01590 connect( job, SIGNAL( result( KMail::FolderJob* ) ),
01591 this, SLOT( slotCheckUidValidityResult( KMail::FolderJob* ) ) );
01592 job->start();
01593 }
01594 }
01595
01596 void KMFolderCachedImap::slotCheckUidValidityResult( KMail::FolderJob* job )
01597 {
01598 if ( job->error() ) {
01599
01600
01601 mSyncState = SYNC_STATE_HANDLE_INBOX;
01602 }
01603 mProgress += 5;
01604 serverSyncInternal();
01605 }
01606
01607 void KMFolderCachedImap::slotPermanentFlags(int flags)
01608 {
01609 mPermanentFlags = flags;
01610 }
01611
01612
01613
01614 void KMFolderCachedImap::listMessages() {
01615 bool groupwareOnly = GlobalSettings::self()->showOnlyGroupwareFoldersForGroupwareAccount()
01616 && GlobalSettings::self()->theIMAPResourceAccount() == (int)mAccount->id()
01617 && folder()->isSystemFolder()
01618 && mImapPath == "/INBOX/";
01619
01620
01621 if( imapPath() == "/" || groupwareOnly ) {
01622 serverSyncInternal();
01623 return;
01624 }
01625
01626 if( !mAccount->slave() ) {
01627 resetSyncState();
01628 emit folderComplete( this, false );
01629 return;
01630 }
01631 uidsOnServer.clear();
01632 uidsOnServer.resize( count() * 2 );
01633 uidsForDeletionOnServer.clear();
01634 mMsgsForDownload.clear();
01635 mUidsForDownload.clear();
01636
01637 mFoundAnIMAPDigest = false;
01638
01639 CachedImapJob* job = new CachedImapJob( FolderJob::tListMessages, this );
01640 connect( job, SIGNAL( result(KMail::FolderJob *) ),
01641 this, SLOT( slotGetLastMessagesResult(KMail::FolderJob *) ) );
01642 job->start();
01643 }
01644
01645 void KMFolderCachedImap::slotGetLastMessagesResult(KMail::FolderJob *job)
01646 {
01647 getMessagesResult(job, true);
01648 }
01649
01650
01651 void KMFolderCachedImap::slotGetMessagesData(KIO::Job * job, const QByteArray & data)
01652 {
01653 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
01654 if ( it == mAccount->jobsEnd() ) {
01655 kdDebug(5006) << "could not find job!?!?!" << endl;
01656
01657
01658
01659 mSyncState = SYNC_STATE_HANDLE_INBOX;
01660 serverSyncInternal();
01661 return;
01662 }
01663 (*it).cdata += QCString(data, data.size() + 1);
01664 int pos = (*it).cdata.find("\r\n--IMAPDIGEST");
01665 if (pos > 0) {
01666 int a = (*it).cdata.find("\r\nX-uidValidity:");
01667 if (a != -1) {
01668 int b = (*it).cdata.find("\r\n", a + 17);
01669 setUidValidity((*it).cdata.mid(a + 17, b - a - 17));
01670 }
01671 a = (*it).cdata.find("\r\nX-Access:");
01672
01673
01674
01675
01676
01677 if (a != -1 && mUserRights == -1 ) {
01678 int b = (*it).cdata.find("\r\n", a + 12);
01679 const QString access = (*it).cdata.mid(a + 12, b - a - 12);
01680 setReadOnly( access == "Read only" );
01681 }
01682 (*it).cdata.remove(0, pos);
01683 mFoundAnIMAPDigest = true;
01684 }
01685 pos = (*it).cdata.find("\r\n--IMAPDIGEST", 1);
01686
01687 if ( uidsOnServer.size() == 0 )
01688 uidsOnServer.resize( KMail::nextPrime( 2000 ) );
01689 const int v = 42;
01690 while (pos >= 0) {
01691
01692
01693
01694
01695
01696
01697
01698
01699
01700 const QCString& entry( (*it).cdata );
01701 const int indexOfUID = entry.find("X-UID", 16);
01702 const int startOfUIDValue = indexOfUID + 7;
01703 const int indexOfLength = entry.find("X-Length", startOfUIDValue );
01704 const int startOfLengthValue = indexOfLength + 10;
01705 const int indexOfFlags = entry.find("X-Flags", startOfLengthValue );
01706 const int startOfFlagsValue = indexOfFlags + 9;
01707
01708 const int flags = entry.mid( startOfFlagsValue, entry.find( '\r', startOfFlagsValue ) - startOfFlagsValue ).toInt();
01709 const ulong size = entry.mid( startOfLengthValue, entry.find( '\r', startOfLengthValue ) - startOfLengthValue ).toULong();
01710 const ulong uid = entry.mid( startOfUIDValue, entry.find( '\r', startOfUIDValue ) - startOfUIDValue ).toULong();
01711
01712 const bool deleted = ( flags & 8 );
01713 if ( !deleted ) {
01714 if( uid != 0 ) {
01715 if ( uidsOnServer.count() == uidsOnServer.size() ) {
01716 uidsOnServer.resize( KMail::nextPrime( uidsOnServer.size() * 2 ) );
01717
01718 }
01719 uidsOnServer.insert( uid, &v );
01720 }
01721 bool redownload = false;
01722 if ( uid <= lastUid() ) {
01723
01724
01725
01726
01727
01728
01729
01730
01731
01732
01733 KMMsgBase *existingMessage = findByUID(uid);
01734 if( !existingMessage ) {
01735 #if MAIL_LOSS_DEBUGGING
01736 kdDebug(5006) << "Looking at uid " << uid << " high water is: " << lastUid() << " we should delete it" << endl;
01737 #endif
01738
01739 if ( mDeletedUIDsSinceLastSync.contains(uid) ) {
01740 if ( mUserRights <= 0 || ( mUserRights & KMail::ACLJobs::Delete ) ) {
01741 #if MAIL_LOSS_DEBUGGING
01742 kdDebug(5006) << "message with uid " << uid << " is gone from local cache. Must be deleted on server!!!" << endl;
01743 #endif
01744 uidsForDeletionOnServer << uid;
01745 } else {
01746 redownload = true;
01747 }
01748 } else {
01749 kdDebug(5006) << "WARNING: ####### " << endl;
01750 kdDebug(5006) << "Message locally missing but not deleted in folder: " << folder()->prettyURL() << endl;
01751 kdDebug(5006) << "The missing UID: " << uid << ". It will be redownloaded " << endl;
01752 redownload = true;
01753 }
01754
01755 } else {
01756
01757
01758
01759 if ( !mReadOnly || !GlobalSettings::allowLocalFlags() ) {
01760
01761 KMFolderImap::flagsToStatus( existingMessage, flags, false, mReadOnly ? INT_MAX : mPermanentFlags );
01762 } else if ( mUserRights & KMail::ACLJobs::WriteSeenFlag ) {
01763 KMFolderImap::seenFlagToStatus( existingMessage, flags );
01764 }
01765 }
01766
01767 }
01768 if ( uid > lastUid() || redownload ) {
01769 #if MAIL_LOSS_DEBUGGING
01770 kdDebug(5006) << "Looking at uid " << uid << " high water is: " << lastUid() << " we should download it" << endl;
01771 #endif
01772
01773
01774 if ( !uidMap.contains( uid ) ) {
01775 mMsgsForDownload << KMail::CachedImapJob::MsgForDownload(uid, flags, size);
01776 if( imapPath() == "/INBOX/" )
01777 mUidsForDownload << uid;
01778 }
01779
01780 if ( uid > mTentativeHighestUid ) {
01781 #if MAIL_LOSS_DEBUGGING
01782 kdDebug(5006) << "Setting the tentative highest UID to: " << uid << endl;
01783 #endif
01784 mTentativeHighestUid = uid;
01785 }
01786 }
01787 }
01788 (*it).cdata.remove(0, pos);
01789 (*it).done++;
01790 pos = (*it).cdata.find("\r\n--IMAPDIGEST", 1);
01791 }
01792 }
01793
01794 void KMFolderCachedImap::getMessagesResult( KMail::FolderJob *job, bool lastSet )
01795 {
01796 mProgress += 10;
01797 if ( !job->error() && !mFoundAnIMAPDigest ) {
01798 kdWarning(5006) << "######## Folderlisting did not complete, but there was no error! "
01799 "Aborting sync of folder: " << folder()->prettyURL() << endl;
01800 #if MAIL_LOSS_DEBUGGING
01801 kmkernel->emergencyExit( i18n("Folder listing failed in interesting ways." ) );
01802 #endif
01803 }
01804 if( job->error() ) {
01805 mContentState = imapNoInformation;
01806 mSyncState = SYNC_STATE_HANDLE_INBOX;
01807 } else {
01808 if( lastSet ) {
01809 mContentState = imapFinished;
01810 mStatusChangedLocally = false;
01811 }
01812 }
01813 serverSyncInternal();
01814 }
01815
01816 void KMFolderCachedImap::slotProgress(unsigned long done, unsigned long total)
01817 {
01818 int progressSpan = 100 - 5 - mProgress;
01819
01820
01821
01822 newState( mProgress + (progressSpan * done) / total, QString::null );
01823 }
01824
01825 void KMFolderCachedImap::setAccount(KMAcctCachedImap *aAccount)
01826 {
01827 assert( aAccount->isA("KMAcctCachedImap") );
01828 mAccount = aAccount;
01829 if( imapPath()=="/" ) aAccount->setFolder( folder() );
01830
01831
01832 QString newName = mAccount->renamedFolder( imapPath() );
01833 if ( !newName.isEmpty() )
01834 folder()->setLabel( newName );
01835
01836 if( !folder() || !folder()->child() || !folder()->child()->count() ) return;
01837 for( KMFolderNode* node = folder()->child()->first(); node;
01838 node = folder()->child()->next() )
01839 if (!node->isDir())
01840 static_cast<KMFolderCachedImap*>(static_cast<KMFolder*>(node)->storage())->setAccount(aAccount);
01841 }
01842
01843 void KMFolderCachedImap::listNamespaces()
01844 {
01845 ImapAccountBase::ListType type = ImapAccountBase::List;
01846 if ( mAccount->onlySubscribedFolders() )
01847 type = ImapAccountBase::ListSubscribed;
01848
01849 kdDebug(5006) << "listNamespaces " << mNamespacesToList << endl;
01850 if ( mNamespacesToList.isEmpty() ) {
01851 mSyncState = SYNC_STATE_DELETE_SUBFOLDERS;
01852 mPersonalNamespacesCheckDone = true;
01853
01854 QStringList ns = mAccount->namespaces()[ImapAccountBase::OtherUsersNS];
01855 ns += mAccount->namespaces()[ImapAccountBase::SharedNS];
01856 mNamespacesToCheck = ns.count();
01857 for ( QStringList::Iterator it = ns.begin(); it != ns.end(); ++it )
01858 {
01859 if ( (*it).isEmpty() ) {
01860
01861 --mNamespacesToCheck;
01862 continue;
01863 }
01864 KMail::ListJob* job = new KMail::ListJob( mAccount, type, this, mAccount->addPathToNamespace( *it ) );
01865 job->setHonorLocalSubscription( true );
01866 connect( job, SIGNAL(receivedFolders(const QStringList&, const QStringList&,
01867 const QStringList&, const QStringList&, const ImapAccountBase::jobData&)),
01868 this, SLOT(slotCheckNamespace(const QStringList&, const QStringList&,
01869 const QStringList&, const QStringList&, const ImapAccountBase::jobData&)));
01870 job->start();
01871 }
01872 if ( mNamespacesToCheck == 0 ) {
01873 serverSyncInternal();
01874 }
01875 return;
01876 }
01877 mPersonalNamespacesCheckDone = false;
01878
01879 QString ns = mNamespacesToList.front();
01880 mNamespacesToList.pop_front();
01881
01882 mSyncState = SYNC_STATE_LIST_SUBFOLDERS2;
01883 newState( mProgress, i18n("Retrieving folders for namespace %1").arg(ns));
01884 KMail::ListJob* job = new KMail::ListJob( mAccount, type, this,
01885 mAccount->addPathToNamespace( ns ) );
01886 job->setNamespace( ns );
01887 job->setHonorLocalSubscription( true );
01888 connect( job, SIGNAL(receivedFolders(const QStringList&, const QStringList&,
01889 const QStringList&, const QStringList&, const ImapAccountBase::jobData&)),
01890 this, SLOT(slotListResult(const QStringList&, const QStringList&,
01891 const QStringList&, const QStringList&, const ImapAccountBase::jobData&)));
01892 job->start();
01893 }
01894
01895 void KMFolderCachedImap::slotCheckNamespace( const QStringList& subfolderNames,
01896 const QStringList& subfolderPaths,
01897 const QStringList& subfolderMimeTypes,
01898 const QStringList& subfolderAttributes,
01899 const ImapAccountBase::jobData& jobData )
01900 {
01901 Q_UNUSED( subfolderPaths );
01902 Q_UNUSED( subfolderMimeTypes );
01903 Q_UNUSED( subfolderAttributes );
01904 --mNamespacesToCheck;
01905 kdDebug(5006) << "slotCheckNamespace " << subfolderNames << ",remain=" <<
01906 mNamespacesToCheck << endl;
01907
01908
01909
01910 QString name = jobData.path.mid( 1, jobData.path.length()-2 );
01911 name.remove( mAccount->delimiterForNamespace( name ) );
01912 if ( name.isEmpty() ) {
01913
01914 kdWarning(5006) << "slotCheckNamespace: ignoring empty folder!" << endl;
01915 return;
01916 }
01917
01918 folder()->createChildFolder();
01919 KMFolderNode *node = 0;
01920 for ( node = folder()->child()->first(); node;
01921 node = folder()->child()->next())
01922 {
01923 if ( !node->isDir() && node->name() == name )
01924 break;
01925 }
01926 if ( !subfolderNames.isEmpty() ) {
01927 if ( node ) {
01928
01929 kdDebug(5006) << "found namespace folder " << name << endl;
01930 } else
01931 {
01932
01933 kdDebug(5006) << "create namespace folder " << name << endl;
01934 KMFolder* newFolder = folder()->child()->createFolder( name, false,
01935 KMFolderTypeCachedImap );
01936 if ( newFolder ) {
01937 KMFolderCachedImap *f = static_cast<KMFolderCachedImap*>( newFolder->storage() );
01938 f->setImapPath( mAccount->addPathToNamespace( name ) );
01939 f->setNoContent( true );
01940 f->setAccount( mAccount );
01941 f->close("cachedimap");
01942 kmkernel->dimapFolderMgr()->contentsChanged();
01943 }
01944 }
01945 } else {
01946 if ( node ) {
01947 kdDebug(5006) << "delete namespace folder " << name << endl;
01948 KMFolder* fld = static_cast<KMFolder*>(node);
01949 kmkernel->dimapFolderMgr()->remove( fld );
01950 }
01951 }
01952
01953 if ( mNamespacesToCheck == 0 ) {
01954
01955 serverSyncInternal();
01956 }
01957 }
01958
01959
01960
01961 bool KMFolderCachedImap::listDirectory()
01962 {
01963 if( !mAccount->slave() ) {
01964 resetSyncState();
01965 emit folderComplete( this, false );
01966 return false;
01967 }
01968 mSubfolderState = imapInProgress;
01969
01970
01971 ImapAccountBase::ListType type = ImapAccountBase::List;
01972 if ( mAccount->onlySubscribedFolders() )
01973 type = ImapAccountBase::ListSubscribed;
01974 KMail::ListJob* job = new KMail::ListJob( mAccount, type, this );
01975 job->setHonorLocalSubscription( true );
01976 connect( job, SIGNAL(receivedFolders(const QStringList&, const QStringList&,
01977 const QStringList&, const QStringList&, const ImapAccountBase::jobData&)),
01978 this, SLOT(slotListResult(const QStringList&, const QStringList&,
01979 const QStringList&, const QStringList&, const ImapAccountBase::jobData&)));
01980 job->start();
01981
01982 return true;
01983 }
01984
01985 void KMFolderCachedImap::slotListResult( const QStringList& folderNames,
01986 const QStringList& folderPaths,
01987 const QStringList& folderMimeTypes,
01988 const QStringList& folderAttributes,
01989 const ImapAccountBase::jobData& jobData )
01990 {
01991 Q_UNUSED( jobData );
01992
01993
01994 mSubfolderNames = folderNames;
01995 mSubfolderPaths = folderPaths;
01996 mSubfolderMimeTypes = folderMimeTypes;
01997 mSubfolderState = imapFinished;
01998 mSubfolderAttributes = folderAttributes;
01999 kdDebug(5006) << "##### setting subfolder attributes: " << mSubfolderAttributes << endl;
02000
02001 folder()->createChildFolder();
02002 KMFolderNode *node = folder()->child()->first();
02003 bool root = ( this == mAccount->rootFolder() );
02004
02005 QPtrList<KMFolder> toRemove;
02006 bool emptyList = ( root && mSubfolderNames.empty() );
02007 if ( !emptyList ) {
02008 while (node) {
02009 if (!node->isDir() ) {
02010 KMFolderCachedImap *f = static_cast<KMFolderCachedImap*>(static_cast<KMFolder*>(node)->storage());
02011
02012 if ( mSubfolderNames.findIndex(node->name()) == -1 ) {
02013 QString name = node->name();
02014
02015
02016 bool isInNamespace = ( jobData.curNamespace.isEmpty() ||
02017 jobData.curNamespace == mAccount->namespaceForFolder( f ) );
02018
02019 bool ignore = root && ( f->imapPath() == "/INBOX/" ||
02020 mAccount->isNamespaceFolder( name ) || !isInNamespace );
02021
02022
02023 if( !f->imapPath().isEmpty() && !ignore ) {
02024
02025
02026 toRemove.append( f->folder() );
02027 kdDebug(5006) << node->name() << " isn't on the server. It has an imapPath -> delete it locally" << endl;
02028 }
02029 } else {
02030
02031
02035 int index = mSubfolderNames.findIndex( node->name() );
02036 f->mFolderAttributes = folderAttributes[ index ];
02037 }
02038 } else {
02039
02040 }
02041 node = folder()->child()->next();
02042 }
02043 }
02044
02045 for ( KMFolder* doomed=toRemove.first(); doomed; doomed = toRemove.next() ) {
02046 rescueUnsyncedMessagesAndDeleteFolder( doomed );
02047 }
02048
02049 mProgress += 5;
02050
02051
02052 slotRescueDone( 0 );
02053 }
02054
02055
02056 void KMFolderCachedImap::listDirectory2()
02057 {
02058 QString path = folder()->path();
02059 kmkernel->dimapFolderMgr()->quiet(true);
02060
02061 bool root = ( this == mAccount->rootFolder() );
02062 if ( root && !mAccount->hasInbox() )
02063 {
02064 KMFolderCachedImap *f = 0;
02065 KMFolderNode *node;
02066
02067 for (node = folder()->child()->first(); node; node = folder()->child()->next())
02068 if (!node->isDir() && node->name() == "INBOX") break;
02069 if (node) {
02070 f = static_cast<KMFolderCachedImap*>(static_cast<KMFolder*>(node)->storage());
02071 } else {
02072 KMFolder* newFolder = folder()->child()->createFolder("INBOX", true, KMFolderTypeCachedImap);
02073 if ( newFolder ) {
02074 f = static_cast<KMFolderCachedImap*>(newFolder->storage());
02075 }
02076 }
02077 if ( f ) {
02078 f->setAccount( mAccount );
02079 f->setImapPath( "/INBOX/" );
02080 f->folder()->setLabel( i18n("inbox") );
02081 }
02082 if (!node) {
02083 if ( f )
02084 f->close("cachedimap");
02085 kmkernel->dimapFolderMgr()->contentsChanged();
02086 }
02087
02088 mAccount->setHasInbox( true );
02089 }
02090
02091 if ( root && !mSubfolderNames.isEmpty() ) {
02092 KMFolderCachedImap* parent =
02093 findParent( mSubfolderPaths.first(), mSubfolderNames.first() );
02094 if ( parent ) {
02095 kdDebug(5006) << "KMFolderCachedImap::listDirectory2 - pass listing to "
02096 << parent->label() << endl;
02097 mSubfolderNames.clear();
02098 }
02099 }
02100
02101
02102 QValueVector<int> foldersNewOnServer;
02103 for (uint i = 0; i < mSubfolderNames.count(); i++) {
02104
02105
02106 KMFolderCachedImap *f = 0;
02107 KMFolderNode *node = 0;
02108 for (node = folder()->child()->first(); node;
02109 node = folder()->child()->next())
02110 if (!node->isDir() && node->name() == mSubfolderNames[i]) break;
02111
02112 if (!node) {
02113
02114
02115 QString subfolderPath = mSubfolderPaths[i];
02116
02117
02118
02119 bool locallyDeleted = mAccount->isDeletedFolder( subfolderPath );
02120
02121
02122
02123 if ( !locallyDeleted && mAccount->isPreviouslyDeletedFolder( subfolderPath ) ) {
02124 locallyDeleted = KMessageBox::warningYesNo(
02125 0, i18n( "<qt><p>It seems that the folder <b>%1</b> was deleted. Do you want to delete it from the server?</p></qt>" ).arg( mSubfolderNames[i] ), QString::null, KStdGuiItem::del(), KStdGuiItem::cancel() ) == KMessageBox::Yes;
02126 }
02127
02128 if ( locallyDeleted ) {
02129 kdDebug(5006) << subfolderPath << " was deleted locally => delete on server." << endl;
02130 foldersForDeletionOnServer += mAccount->deletedFolderPaths( subfolderPath );
02131 } else {
02132 kdDebug(5006) << subfolderPath << " is a new folder on the server => create local cache" << endl;
02133 foldersNewOnServer.append( i );
02134 }
02135 } else {
02136 if( static_cast<KMFolder*>(node)->folderType() == KMFolderTypeCachedImap )
02137 f = dynamic_cast<KMFolderCachedImap*>(static_cast<KMFolder*>(node)->storage());
02138 if( f ) {
02139
02140
02141
02142 f->setAccount(mAccount);
02143 f->setNoContent(mSubfolderMimeTypes[i] == "inode/directory");
02144 f->setNoChildren(mSubfolderMimeTypes[i] == "message/digest");
02145 f->setImapPath(mSubfolderPaths[i]);
02146 }
02147 }
02148 }
02149
02150
02151
02152
02153
02154
02155
02156
02157
02158
02159
02160 if ( GlobalSettings::self()->showOnlyGroupwareFoldersForGroupwareAccount()
02161 && GlobalSettings::self()->theIMAPResourceAccount() == (int)mAccount->id()
02162 && mAccount->hasAnnotationSupport()
02163 && GlobalSettings::self()->theIMAPResourceEnabled()
02164 && !foldersNewOnServer.isEmpty() ) {
02165
02166 QStringList paths;
02167 for ( uint i = 0; i < foldersNewOnServer.count(); ++i )
02168 paths << mSubfolderPaths[ foldersNewOnServer[i] ];
02169
02170 AnnotationJobs::MultiUrlGetAnnotationJob* job =
02171 AnnotationJobs::multiUrlGetAnnotation( mAccount->slave(), mAccount->getUrl(), paths, KOLAB_FOLDERTYPE );
02172 ImapAccountBase::jobData jd( QString::null, folder() );
02173 jd.cancellable = true;
02174 mAccount->insertJob(job, jd);
02175 connect( job, SIGNAL(result(KIO::Job *)),
02176 SLOT(slotMultiUrlGetAnnotationResult(KIO::Job *)) );
02177
02178 } else {
02179 createFoldersNewOnServerAndFinishListing( foldersNewOnServer );
02180 }
02181 }
02182
02183 void KMFolderCachedImap::createFoldersNewOnServerAndFinishListing( const QValueVector<int> foldersNewOnServer )
02184 {
02185 for ( uint i = 0; i < foldersNewOnServer.count(); ++i ) {
02186 int idx = foldersNewOnServer[i];
02187 KMFolder* newFolder = folder()->child()->createFolder( mSubfolderNames[idx], false, KMFolderTypeCachedImap);
02188 if (newFolder) {
02189 KMFolderCachedImap *f = dynamic_cast<KMFolderCachedImap*>(newFolder->storage());
02190 kdDebug(5006) << " ####### Locally creating folder " << mSubfolderNames[idx] <<endl;
02191 f->close("cachedimap");
02192 f->setAccount(mAccount);
02193 f->mAnnotationFolderType = "FROMSERVER";
02194 f->setNoContent(mSubfolderMimeTypes[idx] == "inode/directory");
02195 f->setNoChildren(mSubfolderMimeTypes[idx] == "message/digest");
02196 f->setImapPath(mSubfolderPaths[idx]);
02197 f->mFolderAttributes = mSubfolderAttributes[idx];
02198 kdDebug(5006) << " ####### Attributes: " << f->mFolderAttributes <<endl;
02199
02200 kmkernel->dimapFolderMgr()->contentsChanged();
02201 } else {
02202 kdDebug(5006) << "can't create folder " << mSubfolderNames[idx] <<endl;
02203 }
02204 }
02205
02206 kmkernel->dimapFolderMgr()->quiet(false);
02207 emit listComplete(this);
02208 if ( !mPersonalNamespacesCheckDone ) {
02209
02210 mSyncState = SYNC_STATE_LIST_NAMESPACES;
02211 }
02212 serverSyncInternal();
02213 }
02214
02215
02216 KMFolderCachedImap* KMFolderCachedImap::findParent( const QString& path,
02217 const QString& name )
02218 {
02219 QString parent = path.left( path.length() - name.length() - 2 );
02220 if ( parent.length() > 1 )
02221 {
02222
02223 parent = parent.right( parent.length() - 1 );
02224 if ( parent != label() )
02225 {
02226 KMFolderNode *node = folder()->child()->first();
02227
02228 while ( node )
02229 {
02230 if ( node->name() == parent )
02231 {
02232 KMFolder* fld = static_cast<KMFolder*>(node);
02233 KMFolderCachedImap* imapFld =
02234 static_cast<KMFolderCachedImap*>( fld->storage() );
02235 return imapFld;
02236 }
02237 node = folder()->child()->next();
02238 }
02239 }
02240 }
02241 return 0;
02242 }
02243
02244 void KMFolderCachedImap::slotSubFolderComplete(KMFolderCachedImap* sub, bool success)
02245 {
02246 Q_UNUSED(sub);
02247
02248 if ( success ) {
02249 serverSyncInternal();
02250 }
02251 else
02252 {
02253
02254 if ( mCurrentSubfolder ) {
02255 Q_ASSERT( sub == mCurrentSubfolder );
02256 disconnect( mCurrentSubfolder, SIGNAL( folderComplete(KMFolderCachedImap*, bool) ),
02257 this, SLOT( slotSubFolderComplete(KMFolderCachedImap*, bool) ) );
02258 mCurrentSubfolder = 0;
02259 }
02260
02261 mSubfoldersForSync.clear();
02262 mSyncState = SYNC_STATE_INITIAL;
02263 close("cachedimap");
02264 emit folderComplete( this, false );
02265 }
02266 }
02267
02268 void KMFolderCachedImap::slotSimpleData(KIO::Job * job, const QByteArray & data)
02269 {
02270 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
02271 if (it == mAccount->jobsEnd()) return;
02272 QBuffer buff((*it).data);
02273 buff.open(IO_WriteOnly | IO_Append);
02274 buff.writeBlock(data.data(), data.size());
02275 buff.close();
02276 }
02277
02278 FolderJob*
02279 KMFolderCachedImap::doCreateJob( KMMessage *msg, FolderJob::JobType jt, KMFolder *folder,
02280 QString, const AttachmentStrategy* ) const
02281 {
02282 QPtrList<KMMessage> msgList;
02283 msgList.append( msg );
02284 CachedImapJob *job = new CachedImapJob( msgList, jt, folder? static_cast<KMFolderCachedImap*>( folder->storage() ):0 );
02285 job->setParentFolder( this );
02286 return job;
02287 }
02288
02289 FolderJob*
02290 KMFolderCachedImap::doCreateJob( QPtrList<KMMessage>& msgList, const QString& sets,
02291 FolderJob::JobType jt, KMFolder *folder ) const
02292 {
02293
02294 Q_UNUSED( sets );
02295 CachedImapJob *job = new CachedImapJob( msgList, jt, folder? static_cast<KMFolderCachedImap*>( folder->storage() ):0 );
02296 job->setParentFolder( this );
02297 return job;
02298 }
02299
02300 void
02301 KMFolderCachedImap::setUserRights( unsigned int userRights )
02302 {
02303 mUserRights = userRights;
02304 writeConfigKeysWhichShouldNotGetOverwrittenByReadConfig();
02305 }
02306
02307 void
02308 KMFolderCachedImap::slotReceivedUserRights( KMFolder* folder )
02309 {
02310 if ( folder->storage() == this ) {
02311 disconnect( mAccount, SIGNAL( receivedUserRights( KMFolder* ) ),
02312 this, SLOT( slotReceivedUserRights( KMFolder* ) ) );
02313 if ( mUserRights == 0 )
02314 mUserRights = -1;
02315 else
02316 setReadOnly( ( mUserRights & KMail::ACLJobs::Insert ) == 0 );
02317 mProgress += 5;
02318 serverSyncInternal();
02319 }
02320 }
02321
02322 void
02323 KMFolderCachedImap::setReadOnly( bool readOnly )
02324 {
02325 if ( readOnly != mReadOnly ) {
02326 mReadOnly = readOnly;
02327 emit readOnlyChanged( folder() );
02328 }
02329 }
02330
02331 void
02332 KMFolderCachedImap::slotReceivedACL( KMFolder* folder, KIO::Job*, const KMail::ACLList& aclList )
02333 {
02334 if ( folder->storage() == this ) {
02335 disconnect( mAccount, SIGNAL(receivedACL( KMFolder*, KIO::Job*, const KMail::ACLList& )),
02336 this, SLOT(slotReceivedACL( KMFolder*, KIO::Job*, const KMail::ACLList& )) );
02337 mACLList = aclList;
02338 serverSyncInternal();
02339 }
02340 }
02341
02342 void
02343 KMFolderCachedImap::slotStorageQuotaResult( const QuotaInfo& info )
02344 {
02345 setQuotaInfo( info );
02346 }
02347
02348 void KMFolderCachedImap::setQuotaInfo( const QuotaInfo & info )
02349 {
02350 if ( info != mQuotaInfo ) {
02351 mQuotaInfo = info;
02352 writeConfigKeysWhichShouldNotGetOverwrittenByReadConfig();
02353 emit folderSizeChanged();
02354 }
02355 }
02356
02357 void
02358 KMFolderCachedImap::setACLList( const ACLList& arr )
02359 {
02360 mACLList = arr;
02361 }
02362
02363 void
02364 KMFolderCachedImap::slotMultiSetACLResult(KIO::Job *job)
02365 {
02366 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
02367 if ( it == mAccount->jobsEnd() ) return;
02368 if ( (*it).parent != folder() ) return;
02369
02370 if ( job->error() )
02371
02372
02373 job->showErrorDialog();
02374 else
02375 kmkernel->iCalIface().addFolderChange( folder(), KMailICalIfaceImpl::ACL );
02376
02377 if (mAccount->slave()) mAccount->removeJob(job);
02378 serverSyncInternal();
02379 }
02380
02381 void
02382 KMFolderCachedImap::slotACLChanged( const QString& userId, int permissions )
02383 {
02384
02385
02386 for( ACLList::Iterator it = mACLList.begin(); it != mACLList.end(); ++it ) {
02387 if ( (*it).userId == userId && (*it).permissions == permissions ) {
02388 if ( permissions == -1 )
02389 mACLList.erase( it );
02390 else
02391 (*it).changed = false;
02392 return;
02393 }
02394 }
02395 }
02396
02397
02398 void KMFolderCachedImap::resetSyncState()
02399 {
02400 if ( mSyncState == SYNC_STATE_INITIAL ) return;
02401 mSubfoldersForSync.clear();
02402 mSyncState = SYNC_STATE_INITIAL;
02403 close("cachedimap");
02404
02405 KPIM::ProgressItem *progressItem = mAccount->mailCheckProgressItem();
02406 QString str = i18n("Aborted");
02407 if (progressItem)
02408 progressItem->setStatus( str );
02409 emit statusMsg( str );
02410 }
02411
02412 void KMFolderCachedImap::slotIncreaseProgress()
02413 {
02414 mProgress += 5;
02415 }
02416
02417 void KMFolderCachedImap::newState( int progress, const QString& syncStatus )
02418 {
02419
02420 KPIM::ProgressItem *progressItem = mAccount->mailCheckProgressItem();
02421 if( progressItem )
02422 progressItem->setCompletedItems( progress );
02423 if ( !syncStatus.isEmpty() ) {
02424 QString str;
02425
02426 if ( mAccount->imapFolder() == this )
02427 str = syncStatus;
02428 else
02429 str = QString( "%1: %2" ).arg( label() ).arg( syncStatus );
02430 if( progressItem )
02431 progressItem->setStatus( str );
02432 emit statusMsg( str );
02433 }
02434 if( progressItem )
02435 progressItem->updateProgress();
02436 }
02437
02438 void KMFolderCachedImap::setSubfolderState( imapState state )
02439 {
02440 mSubfolderState = state;
02441 if ( state == imapNoInformation && folder()->child() )
02442 {
02443
02444 KMFolderNode* node;
02445 QPtrListIterator<KMFolderNode> it( *folder()->child() );
02446 for ( ; (node = it.current()); )
02447 {
02448 ++it;
02449 if (node->isDir()) continue;
02450 KMFolder *folder = static_cast<KMFolder*>(node);
02451 static_cast<KMFolderCachedImap*>(folder->storage())->setSubfolderState( state );
02452 }
02453 }
02454 }
02455
02456 void KMFolderCachedImap::setImapPath(const QString &path)
02457 {
02458 mImapPath = path;
02459 }
02460
02461
02462
02463
02464
02465
02466 void KMFolderCachedImap::updateAnnotationFolderType()
02467 {
02468 QString oldType = mAnnotationFolderType;
02469 QString oldSubType;
02470 int dot = oldType.find( '.' );
02471 if ( dot != -1 ) {
02472 oldType.truncate( dot );
02473 oldSubType = mAnnotationFolderType.mid( dot + 1 );
02474 }
02475
02476 QString newType, newSubType;
02477
02478 if ( kmkernel->iCalIface().storageFormat( folder() ) == KMailICalIfaceImpl::StorageXML ) {
02479 newType = KMailICalIfaceImpl::annotationForContentsType( mContentsType );
02480 if ( kmkernel->iCalIface().isStandardResourceFolder( folder() ) )
02481 newSubType = "default";
02482 else
02483 newSubType = oldSubType;
02484 }
02485
02486
02487 if ( newType != oldType || newSubType != oldSubType ) {
02488 mAnnotationFolderType = newType + ( newSubType.isEmpty() ? QString::null : "."+newSubType );
02489 mAnnotationFolderTypeChanged = true;
02490 kdDebug(5006) << mImapPath << ": updateAnnotationFolderType: '" << mAnnotationFolderType << "', was (" << oldType << " " << oldSubType << ") => mAnnotationFolderTypeChanged set to TRUE" << endl;
02491 }
02492
02493 writeConfigKeysWhichShouldNotGetOverwrittenByReadConfig();
02494 }
02495
02496 void KMFolderCachedImap::setIncidencesFor( IncidencesFor incfor )
02497 {
02498 if ( mIncidencesFor != incfor ) {
02499 mIncidencesFor = incfor;
02500 mIncidencesForChanged = true;
02501 }
02502 }
02503
02504 void KMFolderCachedImap::slotAnnotationResult(const QString& entry, const QString& value, bool found)
02505 {
02506 if ( entry == KOLAB_FOLDERTYPE ) {
02507
02508
02509
02510
02511
02512 if ( found ) {
02513 QString type = value;
02514 QString subtype;
02515 int dot = value.find( '.' );
02516 if ( dot != -1 ) {
02517 type.truncate( dot );
02518 subtype = value.mid( dot + 1 );
02519 }
02520 bool foundKnownType = false;
02521 for ( uint i = 0 ; i <= ContentsTypeLast; ++i ) {
02522 FolderContentsType contentsType = static_cast<KMail::FolderContentsType>( i );
02523 if ( type == KMailICalIfaceImpl::annotationForContentsType( contentsType ) ) {
02524
02525
02526 if ( contentsType != ContentsTypeMail )
02527 kmkernel->iCalIface().setStorageFormat( folder(), KMailICalIfaceImpl::StorageXML );
02528 mAnnotationFolderType = value;
02529 if ( folder()->parent()->owner()->idString() != GlobalSettings::self()->theIMAPResourceFolderParent()
02530 && GlobalSettings::self()->theIMAPResourceEnabled()
02531 && subtype == "default" ) {
02532
02533
02534 mAnnotationFolderType = type;
02535 kdDebug(5006) << mImapPath << ": slotGetAnnotationResult: parent folder is " << folder()->parent()->owner()->idString() << " => truncating annotation to " << value << endl;
02536 }
02537 setContentsType( contentsType );
02538 mAnnotationFolderTypeChanged = false;
02539 foundKnownType = true;
02540
02541
02542
02543
02544
02545 if ( contentsType != ContentsTypeMail )
02546 markUnreadAsRead();
02547
02548
02549 writeConfigKeysWhichShouldNotGetOverwrittenByReadConfig();
02550 break;
02551 }
02552 }
02553 if ( !foundKnownType && !mReadOnly ) {
02554
02555
02556 mAnnotationFolderTypeChanged = true;
02557 }
02558
02559 }
02560 else if ( !mReadOnly ) {
02561
02562
02563 mAnnotationFolderTypeChanged = true;
02564 }
02565 } else if ( entry == KOLAB_INCIDENCESFOR ) {
02566 if ( found ) {
02567 mIncidencesFor = incidencesForFromString( value );
02568 Q_ASSERT( mIncidencesForChanged == false );
02569 }
02570 }
02571 }
02572
02573 void KMFolderCachedImap::slotGetAnnotationResult( KIO::Job* job )
02574 {
02575 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
02576 Q_ASSERT( it != mAccount->jobsEnd() );
02577 if ( it == mAccount->jobsEnd() ) return;
02578 Q_ASSERT( (*it).parent == folder() );
02579 if ( (*it).parent != folder() ) return;
02580
02581 AnnotationJobs::GetAnnotationJob* annjob = static_cast<AnnotationJobs::GetAnnotationJob *>( job );
02582 if ( annjob->error() ) {
02583 if ( job->error() == KIO::ERR_UNSUPPORTED_ACTION ) {
02584
02585 if ( GlobalSettings::self()->theIMAPResourceStorageFormat() == GlobalSettings::EnumTheIMAPResourceStorageFormat::XML
02586 && (uint)GlobalSettings::self()->theIMAPResourceAccount() == mAccount->id() )
02587 KMessageBox::error( 0, i18n( "The IMAP server %1 does not have support for IMAP annotations. The XML storage cannot be used on this server; please re-configure KMail differently." ).arg( mAccount->host() ) );
02588 mAccount->setHasNoAnnotationSupport();
02589 }
02590 else
02591 kdWarning(5006) << "slotGetAnnotationResult: " << job->errorString() << endl;
02592 }
02593
02594 if (mAccount->slave()) mAccount->removeJob(job);
02595 mProgress += 2;
02596 serverSyncInternal();
02597 }
02598
02599 void KMFolderCachedImap::slotMultiUrlGetAnnotationResult( KIO::Job* job )
02600 {
02601 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
02602 Q_ASSERT( it != mAccount->jobsEnd() );
02603 if ( it == mAccount->jobsEnd() ) return;
02604 Q_ASSERT( (*it).parent == folder() );
02605 if ( (*it).parent != folder() ) return;
02606
02607 QValueVector<int> folders;
02608 AnnotationJobs::MultiUrlGetAnnotationJob* annjob
02609 = static_cast<AnnotationJobs::MultiUrlGetAnnotationJob *>( job );
02610 if ( annjob->error() ) {
02611 if ( job->error() == KIO::ERR_UNSUPPORTED_ACTION ) {
02612
02613 if ( GlobalSettings::self()->theIMAPResourceStorageFormat() == GlobalSettings::EnumTheIMAPResourceStorageFormat::XML
02614 && (uint)GlobalSettings::self()->theIMAPResourceAccount() == mAccount->id() )
02615 KMessageBox::error( 0, i18n( "The IMAP server %1 doesn't have support for imap annotations. The XML storage cannot be used on this server, please re-configure KMail differently" ).arg( mAccount->host() ) );
02616 mAccount->setHasNoAnnotationSupport();
02617 }
02618 else
02619 kdWarning(5006) << "slotGetMultiUrlAnnotationResult: " << job->errorString() << endl;
02620 } else {
02621
02622 QMap<QString, QString> annotations = annjob->annotations();
02623 QMap<QString, QString>::Iterator it = annotations.begin();
02624 for ( ; it != annotations.end(); ++it ) {
02625 const QString folderPath = it.key();
02626 const QString annotation = it.data();
02627 kdDebug(5006) << k_funcinfo << "Folder: " << folderPath << " has type: " << annotation << endl;
02628
02629 QString type(annotation);
02630 int dot = annotation.find( '.' );
02631 if ( dot != -1 ) type.truncate( dot );
02632 type = type.simplifyWhiteSpace();
02633
02634 const int idx = mSubfolderPaths.findIndex( folderPath );
02635 const bool isNoContent = mSubfolderMimeTypes[idx] == "inode/directory";
02636 if ( ( isNoContent && type.isEmpty() )
02637 || ( !type.isEmpty() && type != KMailICalIfaceImpl::annotationForContentsType( ContentsTypeMail ) ) ) {
02638 folders.append( idx );
02639 kdDebug(5006) << k_funcinfo << " subscribing to: " << folderPath << endl;
02640 } else {
02641 kdDebug(5006) << k_funcinfo << " automatically unsubscribing from: " << folderPath << endl;
02642 mAccount->changeLocalSubscription( folderPath, false );
02643 }
02644 }
02645 }
02646
02647 if (mAccount->slave()) mAccount->removeJob(job);
02648 createFoldersNewOnServerAndFinishListing( folders );
02649 }
02650
02651 void KMFolderCachedImap::slotQuotaResult( KIO::Job* job )
02652 {
02653 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
02654 Q_ASSERT( it != mAccount->jobsEnd() );
02655 if ( it == mAccount->jobsEnd() ) return;
02656 Q_ASSERT( (*it).parent == folder() );
02657 if ( (*it).parent != folder() ) return;
02658
02659 QuotaJobs::GetStorageQuotaJob* quotajob = static_cast<QuotaJobs::GetStorageQuotaJob *>( job );
02660 QuotaInfo empty;
02661 if ( quotajob->error() ) {
02662 if ( job->error() == KIO::ERR_UNSUPPORTED_ACTION ) {
02663
02664 mAccount->setHasNoQuotaSupport();
02665 setQuotaInfo( empty );
02666 }
02667 else
02668 kdWarning(5006) << "slotGetQuotaResult: " << job->errorString() << endl;
02669 }
02670
02671 if (mAccount->slave()) mAccount->removeJob(job);
02672 mProgress += 2;
02673 serverSyncInternal();
02674 }
02675
02676 void
02677 KMFolderCachedImap::slotAnnotationChanged( const QString& entry, const QString& attribute, const QString& value )
02678 {
02679 Q_UNUSED( attribute );
02680 Q_UNUSED( value );
02681
02682 if ( entry == KOLAB_FOLDERTYPE )
02683 mAnnotationFolderTypeChanged = false;
02684 else if ( entry == KOLAB_INCIDENCESFOR ) {
02685 mIncidencesForChanged = false;
02686
02687
02688 kmkernel->iCalIface().addFolderChange( folder(), KMailICalIfaceImpl::ACL );
02689 }
02690 }
02691
02692 void KMFolderCachedImap::slotTestAnnotationResult(KIO::Job *job)
02693 {
02694 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
02695 Q_ASSERT( it != mAccount->jobsEnd() );
02696 if ( it == mAccount->jobsEnd() ) return;
02697 Q_ASSERT( (*it).parent == folder() );
02698 if ( (*it).parent != folder() ) return;
02699
02700 mAccount->setAnnotationCheckPassed( true );
02701 if ( job->error() ) {
02702 kdDebug(5006) << "Test Annotation was not passed, disabling annotation support" << endl;
02703 mAccount->setHasNoAnnotationSupport( );
02704 } else {
02705 kdDebug(5006) << "Test Annotation was passed OK" << endl;
02706 }
02707 if (mAccount->slave()) mAccount->removeJob(job);
02708 serverSyncInternal();
02709 }
02710
02711 void
02712 KMFolderCachedImap::slotSetAnnotationResult(KIO::Job *job)
02713 {
02714 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
02715 if ( it == mAccount->jobsEnd() ) return;
02716 if ( (*it).parent != folder() ) return;
02717
02718 bool cont = true;
02719 if ( job->error() ) {
02720
02721 if ( job->error() == KIO::ERR_UNSUPPORTED_ACTION && contentsType() == ContentsTypeMail )
02722 if (mAccount->slave()) mAccount->removeJob(job);
02723 else
02724 cont = mAccount->handleJobError( job, i18n( "Error while setting annotation: " ) + '\n' );
02725 } else {
02726 if (mAccount->slave()) mAccount->removeJob(job);
02727 }
02728 if ( cont )
02729 serverSyncInternal();
02730 }
02731
02732 void KMFolderCachedImap::slotUpdateLastUid()
02733 {
02734 if( mTentativeHighestUid != 0 ) {
02735
02736
02737
02738
02739
02740
02741
02742
02743 bool sane = false;
02744
02745 for (int i=0;i<count(); i++ ) {
02746 ulong uid = getMsgBase(i)->UID();
02747 if ( uid > mTentativeHighestUid && uid > lastUid() ) {
02748 kdWarning(5006) << "DANGER: Either the server listed a wrong highest uid, "
02749 "or we parsed it wrong. Send email to adam@kde.org, please, and include this log." << endl;
02750 kdWarning(5006) << "uid: " << uid << " mTentativeHighestUid: " << mTentativeHighestUid << endl;
02751 assert( false );
02752 break;
02753 } else if ( uid == mTentativeHighestUid || lastUid() ) {
02754
02755 sane = true;
02756 } else {
02757
02758 }
02759 }
02760 if (sane) {
02761 #if MAIL_LOSS_DEBUGGING
02762 kdDebug(5006) << "Tentative highest UID test was sane, writing out: " << mTentativeHighestUid << endl;
02763 #endif
02764 setLastUid( mTentativeHighestUid );
02765 }
02766 }
02767 mTentativeHighestUid = 0;
02768 }
02769
02770 bool KMFolderCachedImap::isMoveable() const
02771 {
02772 return ( hasChildren() == HasNoChildren &&
02773 !folder()->isSystemFolder() ) ? true : false;
02774 }
02775
02776 void KMFolderCachedImap::slotFolderDeletionOnServerFinished()
02777 {
02778 for ( QStringList::const_iterator it = foldersForDeletionOnServer.constBegin();
02779 it != foldersForDeletionOnServer.constEnd(); ++it ) {
02780 KURL url( mAccount->getUrl() );
02781 url.setPath( *it );
02782 kmkernel->iCalIface().folderDeletedOnServer( url );
02783 }
02784 serverSyncInternal();
02785 }
02786
02787 int KMFolderCachedImap::createIndexFromContentsRecursive()
02788 {
02789 if ( !folder() || !folder()->child() )
02790 return 0;
02791
02792 KMFolderNode *node = 0;
02793 for( QPtrListIterator<KMFolderNode> it( *folder()->child() ); (node = it.current()); ++it ) {
02794 if( !node->isDir() ) {
02795 KMFolderCachedImap* storage = static_cast<KMFolderCachedImap*>(static_cast<KMFolder*>(node)->storage());
02796 kdDebug() << k_funcinfo << "Re-indexing: " << storage->folder()->label() << endl;
02797 int rv = storage->createIndexFromContentsRecursive();
02798 if ( rv > 0 )
02799 return rv;
02800 }
02801 }
02802
02803 return createIndexFromContents();
02804 }
02805
02806 void KMFolderCachedImap::setAlarmsBlocked( bool blocked )
02807 {
02808 mAlarmsBlocked = blocked;
02809 }
02810
02811 bool KMFolderCachedImap::alarmsBlocked() const
02812 {
02813 return mAlarmsBlocked;
02814 }
02815
02816 bool KMFolderCachedImap::isCloseToQuota() const
02817 {
02818 bool closeToQuota = false;
02819 if ( mQuotaInfo.isValid() && mQuotaInfo.max().toInt() > 0 ) {
02820 const int ratio = mQuotaInfo.current().toInt() * 100 / mQuotaInfo.max().toInt();
02821
02822 closeToQuota = ( ratio > 0 && ratio >= GlobalSettings::closeToQuotaThreshold() );
02823 }
02824
02825 return closeToQuota;
02826 }
02827
02828 KMCommand* KMFolderCachedImap::rescueUnsyncedMessages()
02829 {
02830 QValueList<unsigned long> newMsgs = findNewMessages();
02831 kdDebug() << k_funcinfo << newMsgs << " of " << count() << endl;
02832 if ( newMsgs.isEmpty() )
02833 return 0;
02834 KMFolder *dest = 0;
02835 bool manualMove = true;
02836 while ( GlobalSettings::autoLostFoundMove() ) {
02837
02838 KMFolder *inboxFolder = kmkernel->findFolderById( QString(".%1.directory/INBOX").arg( account()->id() ) );
02839 if ( !inboxFolder ) {
02840 kdWarning(5006) << k_funcinfo << "inbox not found!" << endl;
02841 break;
02842 }
02843 KMFolderDir *inboxDir = inboxFolder->child();
02844 if ( !inboxDir && !inboxFolder->storage() )
02845 break;
02846 assert( inboxFolder->storage()->folderType() == KMFolderTypeCachedImap );
02847
02848
02849 KMFolderNode *node;
02850 KMFolder *lfFolder = 0;
02851 if ( !(node = inboxDir->hasNamedFolder( i18n("lost+found") )) ) {
02852 kdDebug(5006) << k_funcinfo << "creating lost+found folder" << endl;
02853 KMFolder* folder = kmkernel->dimapFolderMgr()->createFolder(
02854 i18n("lost+found"), false, KMFolderTypeCachedImap, inboxDir );
02855 if ( !folder || !folder->storage() )
02856 break;
02857 static_cast<KMFolderCachedImap*>( folder->storage() )->initializeFrom(
02858 static_cast<KMFolderCachedImap*>( inboxFolder->storage() ) );
02859 folder->storage()->setContentsType( KMail::ContentsTypeMail );
02860 folder->storage()->writeConfig();
02861 lfFolder = folder;
02862 } else {
02863 kdDebug(5006) << k_funcinfo << "found lost+found folder" << endl;
02864 lfFolder = dynamic_cast<KMFolder*>( node );
02865 }
02866 if ( !lfFolder || !lfFolder->createChildFolder() || !lfFolder->storage() )
02867 break;
02868
02869
02870 QDate today = QDate::currentDate();
02871 QString baseName = folder()->label() + "-" + QString::number( today.year() )
02872 + (today.month() < 10 ? "0" : "" ) + QString::number( today.month() )
02873 + (today.day() < 10 ? "0" : "" ) + QString::number( today.day() );
02874 QString name = baseName;
02875 int suffix = 0;
02876 while ( (node = lfFolder->child()->hasNamedFolder( name )) ) {
02877 ++suffix;
02878 name = baseName + '-' + QString::number( suffix );
02879 }
02880 kdDebug(5006) << k_funcinfo << "creating lost+found folder " << name << endl;
02881 dest = kmkernel->dimapFolderMgr()->createFolder( name, false, KMFolderTypeCachedImap, lfFolder->child() );
02882 if ( !dest || !dest->storage() )
02883 break;
02884 static_cast<KMFolderCachedImap*>( dest->storage() )->initializeFrom(
02885 static_cast<KMFolderCachedImap*>( lfFolder->storage() ) );
02886 dest->storage()->setContentsType( contentsType() );
02887 dest->storage()->writeConfig();
02888
02889 KMessageBox::sorry( 0, i18n("<p>There are new messages in folder <b>%1</b>, which "
02890 "have not been uploaded to the server yet, but the folder has been deleted "
02891 "on the server or you do not "
02892 "have sufficient access rights on the folder to upload them.</p>"
02893 "<p>All affected messages will therefore be moved to <b>%2</b> "
02894 "to avoid data loss.</p>").arg( folder()->prettyURL() ).arg( dest->prettyURL() ),
02895 i18n("Insufficient access rights") );
02896 manualMove = false;
02897 break;
02898 }
02899
02900 if ( manualMove ) {
02901 const QString msg ( i18n( "<p>There are new messages in this folder (%1), which "
02902 "have not been uploaded to the server yet, but the folder has been deleted "
02903 "on the server or you do not "
02904 "have sufficient access rights on the folder now to upload them. "
02905 "Please contact your administrator to allow upload of new messages "
02906 "to you, or move them out of this folder.</p> "
02907 "<p>Do you want to move these messages to another folder now?</p>").arg( folder()->prettyURL() ) );
02908 if ( KMessageBox::warningYesNo( 0, msg, QString::null, i18n("Move"), i18n("Do Not Move") ) == KMessageBox::Yes ) {
02909 KMail::KMFolderSelDlg dlg( kmkernel->getKMMainWidget(),
02910 i18n("Move Messages to Folder"), true );
02911 if ( dlg.exec() ) {
02912 dest = dlg.folder();
02913 }
02914 }
02915 }
02916 if ( dest ) {
02917 QPtrList<KMMsgBase> msgs;
02918 for( int i = 0; i < count(); ++i ) {
02919 KMMsgBase *msg = getMsgBase( i );
02920 if( !msg ) continue;
02921 if ( msg->UID() == 0 )
02922 msgs.append( msg );
02923 }
02924 KMCommand *command = new KMMoveCommand( dest, msgs );
02925 command->start();
02926 return command;
02927 }
02928 return 0;
02929 }
02930
02931 void KMFolderCachedImap::rescueUnsyncedMessagesAndDeleteFolder( KMFolder *folder, bool root )
02932 {
02933 kdDebug() << k_funcinfo << folder << " " << root << endl;
02934 if ( root )
02935 mToBeDeletedAfterRescue.append( folder );
02936 folder->open("cachedimap");
02937 KMFolderCachedImap* storage = dynamic_cast<KMFolderCachedImap*>( folder->storage() );
02938 if ( storage ) {
02939 KMCommand *command = storage->rescueUnsyncedMessages();
02940 if ( command ) {
02941 connect( command, SIGNAL(completed(KMCommand*)),
02942 SLOT(slotRescueDone(KMCommand*)) );
02943 ++mRescueCommandCount;
02944 } else {
02945
02946
02947 folder->close("cachedimap");
02948 }
02949 }
02950 if ( folder->child() ) {
02951 KMFolderNode *node = folder->child()->first();
02952 while (node) {
02953 if (!node->isDir() ) {
02954 KMFolder *subFolder = static_cast<KMFolder*>( node );
02955 rescueUnsyncedMessagesAndDeleteFolder( subFolder, false );
02956 }
02957 node = folder->child()->next();
02958 }
02959 }
02960 }
02961
02962 void KMFolderCachedImap::slotRescueDone(KMCommand * command)
02963 {
02964
02965 if ( command )
02966 --mRescueCommandCount;
02967 if ( mRescueCommandCount > 0 )
02968 return;
02969 for ( QValueList<KMFolder*>::ConstIterator it = mToBeDeletedAfterRescue.constBegin();
02970 it != mToBeDeletedAfterRescue.constEnd(); ++it ) {
02971 kmkernel->dimapFolderMgr()->remove( *it );
02972 }
02973 mToBeDeletedAfterRescue.clear();
02974 serverSyncInternal();
02975 }
02976
02977 #include "kmfoldercachedimap.moc"