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