kmail Library API Documentation

kmfoldercachedimap.cpp

00001 00021 #ifdef HAVE_CONFIG_H 00022 #include <config.h> 00023 #endif 00024 00025 #include <errno.h> 00026 00027 #include "kmkernel.h" 00028 #include "kmfoldercachedimap.h" 00029 #include "undostack.h" 00030 #include "kmfoldermgr.h" 00031 #include "kmmessage.h" 00032 #include "kmacctcachedimap.h" 00033 #include "kmacctmgr.h" 00034 #include "imapprogressdialog.h" 00035 #include "kmgroupware.h" 00036 #include "kmailicalifaceimpl.h" 00037 00038 using KMail::CachedImapJob; 00039 using KMail::ImapAccountBase; 00040 00041 #include <kapplication.h> 00042 #include <kmessagebox.h> 00043 #include <klocale.h> 00044 #include <kdebug.h> 00045 #include <kconfig.h> 00046 #include <kio/global.h> 00047 #include <kio/scheduler.h> 00048 #include <qbuffer.h> 00049 #include <qfile.h> 00050 #include <qlabel.h> 00051 #include <qlayout.h> 00052 #include <qvaluelist.h> 00053 00054 #define UIDCACHE_VERSION 1 00055 00056 00057 DImapTroubleShootDialog::DImapTroubleShootDialog( QWidget* parent, 00058 const char* name ) 00059 : KDialogBase( Plain, i18n( "Troubleshooting the IMAP cache" ), 00060 Cancel | User1 | User2, Cancel, parent, name, true ), 00061 rc( Cancel ) 00062 { 00063 QFrame* page = plainPage(); 00064 QVBoxLayout *topLayout = new QVBoxLayout( page, 0 ); 00065 QString txt = i18n( "<p><b>Troubleshooting the IMAP cache.</b></p>" 00066 "<p>If you have problems with synchronizing an IMAP " 00067 "folder, you should first try rebuilding the index " 00068 "file. This will take some time to rebuild, but will " 00069 "not cause any problems.</p><p>If that is not enough, " 00070 "you can try refreshing the IMAP cache. If you do this, " 00071 "you will loose all your local changes for this folder " 00072 "and all it's subfolders.</p>" ); 00073 topLayout->addWidget( new QLabel( txt, page ) ); 00074 enableButtonSeparator( true ); 00075 00076 setButtonText( User1, i18n( "Refresh &Cache" ) ); 00077 setButtonText( User2, i18n( "Rebuild &Index" ) ); 00078 00079 connect( this, SIGNAL( user1Clicked () ), this, SLOT( slotRebuildCache() ) ); 00080 connect( this, SIGNAL( user2Clicked () ), this, SLOT( slotRebuildIndex() ) ); 00081 } 00082 00083 int DImapTroubleShootDialog::run() 00084 { 00085 DImapTroubleShootDialog d; 00086 d.exec(); 00087 return d.rc; 00088 } 00089 00090 void DImapTroubleShootDialog::slotRebuildCache() 00091 { 00092 rc = User1; 00093 done( User1 ); 00094 } 00095 00096 void DImapTroubleShootDialog::slotRebuildIndex() 00097 { 00098 rc = User2; 00099 done( User2 ); 00100 } 00101 00102 00103 KMFolderCachedImap::KMFolderCachedImap( KMFolderDir* aParent, 00104 const QString& aName ) 00105 : KMFolderMaildir( aParent, aName ), 00106 mSyncState( SYNC_STATE_INITIAL ), mContentState( imapNoInformation ), 00107 mSubfolderState( imapNoInformation ), mIsSelected( false ), 00108 mCheckFlags( true ), mAccount( NULL ), uidMapDirty( true ), 00109 mLastUid( 0 ), uidWriteTimer( -1 ), 00110 mIsConnected( false ), mFolderRemoved( false ), mResync( false ), 00111 mSuppressDialog( false ), mHoldSyncs( false ), mRemoveRightAway( false ) 00112 { 00113 KConfig* config = KMKernel::config(); 00114 KConfigGroupSaver saver(config, "Folder-" + idString()); 00115 if (mImapPath.isEmpty()) mImapPath = config->readEntry("ImapPath"); 00116 if (aName == "INBOX" && mImapPath == "/INBOX/") 00117 { 00118 //mLabel = i18n("inbox"); 00119 } 00120 mIsSystemFolder = false; 00121 mNoContent = config->readBoolEntry("NoContent", FALSE); 00122 mReadOnly = config->readBoolEntry("ReadOnly", FALSE); 00123 00124 connect( this, SIGNAL( listMessagesComplete() ), 00125 this, SLOT( serverSyncInternal() ) ); 00126 00127 setUidValidity(""); 00128 mLastUid=0; 00129 readUidCache(); 00130 00131 mProgress = 0; 00132 } 00133 00134 KMFolderCachedImap::~KMFolderCachedImap() 00135 { 00136 if( !mFolderRemoved ) { 00137 // Only write configuration when the folder haven't been deleted 00138 KConfig* config = KMKernel::config(); 00139 KConfigGroupSaver saver(config, "Folder-" + idString()); 00140 config->writeEntry("ImapPath", mImapPath); 00141 config->writeEntry("NoContent", mNoContent); 00142 config->writeEntry("ReadOnly", mReadOnly); 00143 00144 writeUidCache(); 00145 } 00146 00147 if (kmkernel->undoStack()) kmkernel->undoStack()->folderDestroyed(this); 00148 } 00149 00150 int KMFolderCachedImap::remove() 00151 { 00152 mFolderRemoved = true; 00153 int rc = KMFolderMaildir::remove(); 00154 00155 if( mRemoveRightAway ) { 00156 // This is the account folder of an account that was just removed 00157 // When this happens, be sure to delete all traces of the cache 00158 QString part1 = path() + "/." + dotEscape(name()); 00159 QString uidCacheFile = part1 + ".uidcache"; 00160 if( QFile::exists(uidCacheFile) ) 00161 unlink( QFile::encodeName( uidCacheFile ) ); 00162 KIO::del( KURL( part1 + ".directory" ) ); 00163 } else { 00164 // Don't remove the uidcache file here, since presence of that is how 00165 // we figure out if a directory present on the server have been deleted 00166 // from the cache or if it's new on the server. The file is removed 00167 // during the sync 00168 } 00169 00170 return rc; 00171 } 00172 00173 QString KMFolderCachedImap::uidCacheLocation() const 00174 { 00175 QString sLocation(path()); 00176 if (!sLocation.isEmpty()) sLocation += '/'; 00177 return sLocation + '.' + dotEscape(fileName()) + ".uidcache"; 00178 } 00179 00180 int KMFolderCachedImap::readUidCache() 00181 { 00182 QFile uidcache( uidCacheLocation() ); 00183 if( uidcache.open( IO_ReadOnly ) ) { 00184 char buf[1024]; 00185 int len = uidcache.readLine( buf, sizeof(buf) ); 00186 if( len > 0 ) { 00187 int cacheVersion; 00188 sscanf( buf, "# KMail-UidCache V%d\n", &cacheVersion ); 00189 if( cacheVersion == UIDCACHE_VERSION ) { 00190 len = uidcache.readLine( buf, sizeof(buf) ); 00191 if( len > 0 ) { 00192 setUidValidity( QString::fromLocal8Bit( buf).stripWhiteSpace() ); 00193 len = uidcache.readLine( buf, sizeof(buf) ); 00194 if( len > 0 ) { 00195 mLastUid = 00196 QString::fromLocal8Bit( buf).stripWhiteSpace().toULong(); 00197 return 0; 00198 } 00199 } 00200 } 00201 } 00202 } 00203 return -1; 00204 } 00205 00206 int KMFolderCachedImap::writeUidCache() 00207 { 00208 if( lastUid() == 0 || uidValidity().isEmpty() ) 00209 // No info from the server yet 00210 return 0; 00211 00212 QFile uidcache( uidCacheLocation() ); 00213 if( uidcache.open( IO_WriteOnly ) ) { 00214 QTextStream str( &uidcache ); 00215 str << "# KMail-UidCache V" << UIDCACHE_VERSION << endl; 00216 str << uidValidity() << endl; 00217 str << lastUid() << endl; 00218 uidcache.flush(); 00219 fsync( uidcache.handle() ); /* this is probably overkill */ 00220 uidcache.close(); 00221 return 0; 00222 } else { 00223 return errno; /* does QFile set errno? */ 00224 } 00225 } 00226 00227 void KMFolderCachedImap::reloadUidMap() 00228 { 00229 uidMap.clear(); 00230 open(); 00231 for( int i = 0; i < count(); ++i ) { 00232 bool unget = !isMessage(i); 00233 bool ok; 00234 KMMessage *msg = getMsg(i); 00235 if( !msg ) continue; 00236 ulong uid = msg->headerField("X-UID").toULong(&ok); 00237 if (unget) unGetMsg(i); 00238 if( ok ) { 00239 uidMap.insert( uid, i ); 00240 if( uid > mLastUid ) setLastUid( uid ); 00241 } 00242 } 00243 close(); 00244 uidMapDirty = false; 00245 } 00246 00247 /* Reimplemented from KMFolderMaildir */ 00248 KMMessage* KMFolderCachedImap::take(int idx) 00249 { 00250 uidMapDirty = true; 00251 return KMFolderMaildir::take(idx); 00252 } 00253 00254 // Add a message without clearing it's X-UID field. 00255 int KMFolderCachedImap::addMsgInternal( KMMessage* msg, bool newMail, 00256 int* index_return ) 00257 { 00258 // Possible optimization: Only dirty if not filtered below 00259 bool ok; 00260 ulong uid = msg->headerField("X-UID").toULong( &ok ); 00261 if( ok ) { 00262 uidMapDirty = true; 00263 if( uid > mLastUid ) 00264 setLastUid( uid ); 00265 } 00266 00267 // Add the message 00268 int rc = KMFolderMaildir::addMsg(msg, index_return); 00269 00270 if( newMail && imapPath() == "/INBOX/" ) 00271 // This is a new message. Filter it 00272 mAccount->processNewMsg( msg ); 00273 00274 return rc; 00275 } 00276 00277 /* Reimplemented from KMFolderMaildir */ 00278 int KMFolderCachedImap::addMsg(KMMessage* msg, int* index_return) 00279 { 00280 // Strip the IMAP UID 00281 msg->removeHeaderField( "X-UID" ); 00282 00283 // Add it to storage 00284 return addMsgInternal( msg, false, index_return ); 00285 } 00286 00287 00288 /* Reimplemented from KMFolderMaildir */ 00289 void KMFolderCachedImap::removeMsg(int idx, bool imapQuiet) 00290 { 00291 uidMapDirty = true; 00292 00293 // Remove it from disk 00294 KMFolderMaildir::removeMsg(idx,imapQuiet); 00295 00296 kmkernel->dimapFolderMgr()->contentsChanged(); 00297 } 00298 00299 bool KMFolderCachedImap::canRemoveFolder() const { 00300 // If this has subfolders it can't be removed 00301 if( child() != 0 && child()->count() > 0 ) 00302 return false; 00303 00304 #if 0 00305 // No special condition here, so let base class decide 00306 return KMFolderMaildir::canRemoveFolder(); 00307 #endif 00308 return true; 00309 } 00310 00311 /* Reimplemented from KMFolderDir */ 00312 int KMFolderCachedImap::rename( const QString& aName, 00313 KMFolderDir* /*aParent*/ ) 00314 { 00315 if ( aName == name() ) 00316 // Stupid user trying to rename it to it's old name :) 00317 return 0; 00318 00319 if( mSyncState != SYNC_STATE_INITIAL ) { 00320 KMessageBox::error( 0, i18n("You can't rename a folder when a sync is in progress") ); 00321 return -1; 00322 } 00323 00324 if( account() == 0 ) { 00325 QString err = i18n("You must synchronize with the server before renaming IMAP folders."); 00326 KMessageBox::error( 0, err ); 00327 return -1; 00328 } 00329 00330 CachedImapJob *job = new CachedImapJob( aName, CachedImapJob::tRenameFolder, this ); 00331 job->start(); 00332 return 0; 00333 } 00334 00335 void KMFolderCachedImap::setLastUid( ulong uid ) 00336 { 00337 mLastUid = uid; 00338 if( uidWriteTimer == -1 ) 00339 // Write in one minute 00340 uidWriteTimer = startTimer( 60000 ); 00341 } 00342 00343 void KMFolderCachedImap::timerEvent( QTimerEvent* ) 00344 { 00345 killTimer( uidWriteTimer ); 00346 uidWriteTimer = -1; 00347 writeUidCache(); 00348 } 00349 00350 ulong KMFolderCachedImap::lastUid() 00351 { 00352 return mLastUid; 00353 } 00354 00355 KMMessage* KMFolderCachedImap::findByUID( ulong uid ) 00356 { 00357 bool mapReloaded = false; 00358 if( uidMapDirty ) { 00359 reloadUidMap(); 00360 mapReloaded = true; 00361 } 00362 00363 QMap<ulong,int>::Iterator it = uidMap.find( uid ); 00364 if( it != uidMap.end() ) { 00365 bool unget = !isMessage(count() - 1); 00366 KMMessage* msg = getMsg( *it ); 00367 if( msg && msg->headerField("X-UID").toULong() == uid ) 00368 return msg; 00369 else if( unget ) 00370 unGetMsg( *it ); 00371 } 00372 00373 // Not found by now 00374 if( mapReloaded ) 00375 // Not here then 00376 return 0; 00377 00378 // There could be a problem in the maps. Rebuild them and try again 00379 reloadUidMap(); 00380 it = uidMap.find( uid ); 00381 if( it != uidMap.end() ) 00382 // Since the uid map is just rebuilt, no need for the sanity check 00383 return getMsg( *it ); 00384 00385 // Then it's not here 00386 return 0; 00387 } 00388 00389 // This finds and sets the proper account for this folder if it has 00390 // not been done 00391 KMAcctCachedImap *KMFolderCachedImap::account() 00392 { 00393 if( (KMAcctCachedImap *)mAccount == 0 ) { 00394 // Find the account 00395 mAccount = static_cast<KMAcctCachedImap *>( kmkernel->acctMgr()->find( name() ) ); 00396 } 00397 00398 return mAccount; 00399 } 00400 00401 void KMFolderCachedImap::slotTroubleshoot() 00402 { 00403 const int rc = DImapTroubleShootDialog::run(); 00404 00405 if( rc == KDialogBase::User1 ) { 00406 // Refresh cache 00407 if( !account() ) { 00408 KMessageBox::sorry( 0, i18n("No account setup for this folder.\n" 00409 "Please try running a sync before this.") ); 00410 return; 00411 } 00412 QString str = i18n("Are you sure you want to refresh the IMAP cache of " 00413 "the folder %1 and all it's subfolders?\nThis will " 00414 "remove all changes you have done locally to your " 00415 "folders").arg( name() ); 00416 QString s1 = i18n("Refresh IMAP Cache"); 00417 QString s2 = i18n("&Refresh"); 00418 if( KMessageBox::warningContinueCancel( 0, str, s1, s2 ) == 00419 KMessageBox::Continue ) 00420 account()->invalidateIMAPFolders( this ); 00421 } else if( rc == KDialogBase::User2 ) { 00422 // Rebuild index file 00423 createIndexFromContents(); 00424 KMessageBox::information( 0, i18n( "The index of this folder has been " 00425 "recreated." ) ); 00426 } 00427 } 00428 00429 void KMFolderCachedImap::processNewMail() 00430 { 00431 if( account() ) 00432 account()->processNewMail( this, true ); 00433 } 00434 00435 void KMFolderCachedImap::serverSync( bool suppressDialog ) 00436 { 00437 if( mSyncState != SYNC_STATE_INITIAL ) { 00438 if( KMessageBox::warningYesNo( 0, i18n("Folder %1 is not in initial sync state (state was %2). Do you want to reset\nit to initial sync state and sync anyway?" ).arg( imapPath() ).arg( mSyncState ) ) == KMessageBox::Yes ) { 00439 mSyncState = SYNC_STATE_INITIAL; 00440 } else return; 00441 } 00442 00443 assert( account() ); 00444 00445 // Connect to the imap progress dialog 00446 mSuppressDialog = suppressDialog; 00447 if( mIsConnected != mAccount->isProgressDialogEnabled() && 00448 suppressDialog ) 00449 { 00450 if( !mIsConnected ) 00451 connect( this, SIGNAL( newState( const QString&, int, const QString& ) ), 00452 account()->imapProgressDialog(), 00453 SLOT( syncState( const QString&, int, const QString& ) ) ); 00454 else 00455 disconnect( this, SIGNAL( newState( const QString&, int, const QString& ) ), 00456 account()->imapProgressDialog(), 00457 SLOT( syncState( const QString&, int, const QString& ) ) ); 00458 mIsConnected = mAccount->isProgressDialogEnabled(); 00459 } 00460 00461 if( mHoldSyncs ) { 00462 // All done for this folder. 00463 mProgress = 100; // all done 00464 emit newState( name(), mProgress, i18n("Synchronization skipped")); 00465 mAccount->displayProgress(); 00466 mSyncState = SYNC_STATE_INITIAL; 00467 emit statusMsg( i18n("%1: Synchronization done").arg(name()) ); 00468 emit folderComplete( this, true ); 00469 return; 00470 } 00471 00472 mResync = false; 00473 serverSyncInternal(); 00474 } 00475 00476 QString KMFolderCachedImap::state2String( int state ) const 00477 { 00478 switch( state ) { 00479 case SYNC_STATE_INITIAL: return "SYNC_STATE_INITIAL"; 00480 case SYNC_STATE_PUT_MESSAGES: return "SYNC_STATE_PUT_MESSAGES"; 00481 case SYNC_STATE_CREATE_SUBFOLDERS: return "SYNC_STATE_CREATE_SUBFOLDERS"; 00482 case SYNC_STATE_LIST_SUBFOLDERS: return "SYNC_STATE_LIST_SUBFOLDERS"; 00483 case SYNC_STATE_LIST_SUBFOLDERS2: return "SYNC_STATE_LIST_SUBFOLDERS2"; 00484 case SYNC_STATE_DELETE_SUBFOLDERS: return "SYNC_STATE_DELETE_SUBFOLDERS"; 00485 case SYNC_STATE_LIST_MESSAGES: return "SYNC_STATE_LIST_MESSAGES"; 00486 case SYNC_STATE_DELETE_MESSAGES: return "SYNC_STATE_DELETE_MESSAGES"; 00487 case SYNC_STATE_GET_MESSAGES: return "SYNC_STATE_GET_MESSAGES"; 00488 case SYNC_STATE_FIND_SUBFOLDERS: return "SYNC_STATE_FIND_SUBFOLDERS"; 00489 case SYNC_STATE_SYNC_SUBFOLDERS: return "SYNC_STATE_SYNC_SUBFOLDERS"; 00490 case SYNC_STATE_EXPUNGE_MESSAGES: return "SYNC_STATE_EXPUNGE_MESSAGES"; 00491 case SYNC_STATE_HANDLE_INBOX: return "SYNC_STATE_HANDLE_INBOX"; 00492 case SYNC_STATE_CHECK_UIDVALIDITY: return "SYNC_STATE_CHECK_UIDVALIDITY"; 00493 default: return "Unknown state"; 00494 } 00495 } 00496 00497 00498 // While the server synchronization is running, mSyncState will hold 00499 // the state that should be executed next 00500 void KMFolderCachedImap::serverSyncInternal() 00501 { 00502 switch( mSyncState ) { 00503 case SYNC_STATE_INITIAL: 00504 { 00505 mProgress = 0; 00506 emit statusMsg( i18n("%1: Synchronizing").arg(name()) ); 00507 emit newState( name(), mProgress, i18n("Synchronizing")); 00508 00509 open(); 00510 00511 kdDebug(5006) << k_funcinfo << " making connection" << endl; 00512 // Connect to the server (i.e. prepare the slave) 00513 ImapAccountBase::ConnectionState cs = mAccount->makeConnection(); 00514 if ( cs == ImapAccountBase::Error ) { 00515 // Cancelled by user, or slave can't start 00516 kdDebug(5006) << "makeConnection said Error, aborting." << endl; 00517 // We stop here. We're already in SYNC_STATE_INITIAL for the next time. 00518 emit folderComplete(this, FALSE); 00519 break; 00520 } else if ( cs == ImapAccountBase::Connecting ) 00521 { 00522 kdDebug(5006) << "makeConnection said Connecting, waiting for signal." 00523 << endl; 00524 // We'll wait for the connectionResult signal from the account. 00525 connect( mAccount, SIGNAL( connectionResult(int) ), 00526 this, SLOT( slotConnectionResult(int) ) ); 00527 break; 00528 } else // Connected 00529 { 00530 kdDebug(5006) << "makeConnection said Connected, proceeding." << endl; 00531 mSyncState = SYNC_STATE_CHECK_UIDVALIDITY; 00532 // Fall through to next state 00533 } 00534 } 00535 case SYNC_STATE_CHECK_UIDVALIDITY: 00536 emit syncRunning( this, true ); 00537 mSyncState = SYNC_STATE_CREATE_SUBFOLDERS; 00538 if( !noContent() ) { 00539 // TODO (Bo): How can we obtain the UID validity on a noContent folder? 00540 // TODO (Bo): Is it perhaps not necessary to do so? 00541 checkUidValidity(); 00542 break; 00543 } 00544 // Else carry on 00545 00546 case SYNC_STATE_CREATE_SUBFOLDERS: 00547 mSyncState = SYNC_STATE_PUT_MESSAGES; 00548 createNewFolders(); 00549 break; 00550 00551 case SYNC_STATE_PUT_MESSAGES: 00552 mSyncState = SYNC_STATE_LIST_SUBFOLDERS; 00553 if( !noContent() ) { 00554 uploadNewMessages(); 00555 break; 00556 } 00557 // Else carry on 00558 00559 case SYNC_STATE_LIST_SUBFOLDERS: 00560 mSyncState = SYNC_STATE_LIST_SUBFOLDERS2; 00561 mProgress += 10; 00562 emit statusMsg( i18n("%1: Retrieving folderlist").arg(name()) ); 00563 emit newState( name(), mProgress, i18n("Retrieving folderlist")); 00564 if( !listDirectory() ) { 00565 mSyncState = SYNC_STATE_INITIAL; 00566 KMessageBox::error(0, i18n("Error during listDirectory()")); 00567 } 00568 break; 00569 00570 case SYNC_STATE_LIST_SUBFOLDERS2: 00571 mSyncState = SYNC_STATE_DELETE_SUBFOLDERS; 00572 mProgress += 10; 00573 emit newState( name(), mProgress, i18n("Retrieving subfolders")); 00574 listDirectory2(); 00575 break; 00576 00577 case SYNC_STATE_DELETE_SUBFOLDERS: 00578 mSyncState = SYNC_STATE_LIST_MESSAGES; 00579 emit syncState( SYNC_STATE_DELETE_SUBFOLDERS, foldersForDeletionOnServer.count() ); 00580 if( !foldersForDeletionOnServer.isEmpty() ) { 00581 emit statusMsg( i18n("%1: Deleting folders %2 from server").arg(name()) 00582 .arg( foldersForDeletionOnServer.join(", ") ) ); 00583 emit newState( name(), mProgress, i18n("Deleting folders from server")); 00584 CachedImapJob* job = new CachedImapJob( foldersForDeletionOnServer, 00585 CachedImapJob::tDeleteFolders, this ); 00586 connect( job, SIGNAL( finished() ), this, SLOT( serverSyncInternal() ) ); 00587 job->start(); 00588 break; 00589 } else 00590 emit newState( name(), mProgress, i18n("No folders to delete from server")); 00591 // Carry on 00592 00593 case SYNC_STATE_LIST_MESSAGES: 00594 mSyncState = SYNC_STATE_DELETE_MESSAGES; 00595 mProgress += 10; 00596 if( !noContent() ) { 00597 emit statusMsg( i18n("%1: Retrieving messagelist").arg(name()) ); 00598 emit newState( name(), mProgress, i18n("Retrieving messagelist")); 00599 // emit syncState( SYNC_STATE_LIST_MESSAGES, foldersForDeletionOnServer.count() ); 00600 listMessages(); 00601 break; 00602 } 00603 // Else carry on 00604 00605 case SYNC_STATE_DELETE_MESSAGES: 00606 mSyncState = SYNC_STATE_EXPUNGE_MESSAGES; 00607 if( !noContent() ) { 00608 if( deleteMessages() ) { 00609 // Fine, we will continue with the next state 00610 } else { 00611 // No messages to delete, skip to GET_MESSAGES 00612 emit newState( name(), mProgress, i18n("No messages to delete...")); 00613 mSyncState = SYNC_STATE_GET_MESSAGES; 00614 serverSyncInternal(); 00615 } 00616 break; 00617 } 00618 // Else carry on 00619 00620 case SYNC_STATE_EXPUNGE_MESSAGES: 00621 mSyncState = SYNC_STATE_GET_MESSAGES; 00622 if( !noContent() ) { 00623 mProgress += 10; 00624 emit statusMsg( i18n("%1: Expunging deleted messages").arg(name()) ); 00625 emit newState( name(), mProgress, i18n("Expunging deleted messages")); 00626 CachedImapJob *job = new CachedImapJob( QString::null, 00627 CachedImapJob::tExpungeFolder, this ); 00628 connect( job, SIGNAL( finished() ), this, SLOT( serverSyncInternal() ) ); 00629 job->start(); 00630 break; 00631 } 00632 // Else carry on 00633 00634 case SYNC_STATE_GET_MESSAGES: 00635 mSyncState = SYNC_STATE_HANDLE_INBOX; 00636 if( !noContent() ) { 00637 //emit syncState( SYNC_STATE_GET_MESSAGES, mMsgsForDownload.count() ); 00638 if( !mMsgsForDownload.isEmpty() ) { 00639 emit statusMsg( i18n("%1: Retrieving new messages").arg(name()) ); 00640 emit newState( name(), mProgress, i18n("Retrieving new messages")); 00641 CachedImapJob *job = new CachedImapJob( mMsgsForDownload, 00642 CachedImapJob::tGetMessage, 00643 this ); 00644 connect( job, SIGNAL( progress(unsigned long, unsigned long) ), 00645 this, SLOT( slotProgress(unsigned long, unsigned long) ) ); 00646 connect( job, SIGNAL( finished() ), this, SLOT( serverSyncInternal() ) ); 00647 job->start(); 00648 mMsgsForDownload.clear(); 00649 break; 00650 } else { 00651 emit newState( name(), mProgress, i18n("No new messages from server")); 00652 } 00653 } 00654 // Else carry on 00655 00656 case SYNC_STATE_HANDLE_INBOX: 00657 // Wrap up the 'download emails' stage (which has a 20% span) 00658 mProgress += 20; 00659 //kdDebug() << name() << ": +20 -> " << mProgress << "%" << endl; 00660 00661 if( mResync ) { 00662 // Some conflict have been resolved, so restart the sync 00663 mResync = false; 00664 mSyncState = SYNC_STATE_INITIAL; 00665 serverSyncInternal(); 00666 break; 00667 } else 00668 // Continue with the subfolders 00669 mSyncState = SYNC_STATE_FIND_SUBFOLDERS; 00670 00671 case SYNC_STATE_FIND_SUBFOLDERS: 00672 { 00673 emit newState( name(), mProgress, i18n("Updating cache file")); 00674 00675 mSyncState = SYNC_STATE_SYNC_SUBFOLDERS; 00676 mSubfoldersForSync.clear(); 00677 mCurrentSubfolder = 0; 00678 if( child() ) { 00679 KMFolderNode *node = child()->first(); 00680 while( node ) { 00681 if( !node->isDir() ) { 00682 if ( !static_cast<KMFolderCachedImap*>(node)->imapPath().isEmpty() ) 00683 // Only sync folders that have been accepted by the server 00684 mSubfoldersForSync << static_cast<KMFolderCachedImap*>(node); 00685 } 00686 node = child()->next(); 00687 } 00688 } 00689 } 00690 00691 // All done for this folder. 00692 mProgress = 100; // all done 00693 emit newState( name(), mProgress, i18n("Synchronization done")); 00694 emit syncRunning( this, false ); 00695 mAccount->displayProgress(); 00696 // Carry on 00697 00698 case SYNC_STATE_SYNC_SUBFOLDERS: 00699 { 00700 if( mCurrentSubfolder ) { 00701 disconnect( mCurrentSubfolder, SIGNAL( folderComplete(KMFolderCachedImap*, bool) ), 00702 this, SLOT( serverSyncInternal() ) ); 00703 mCurrentSubfolder = 0; 00704 } 00705 00706 if( mSubfoldersForSync.isEmpty() ) { 00707 mSyncState = SYNC_STATE_INITIAL; 00708 emit statusMsg( i18n("%1: Synchronization done").arg(name()) ); 00709 emit folderComplete( this, TRUE ); 00710 close(); 00711 } else { 00712 mCurrentSubfolder = mSubfoldersForSync.front(); 00713 mSubfoldersForSync.pop_front(); 00714 connect( mCurrentSubfolder, SIGNAL( folderComplete(KMFolderCachedImap*, bool) ), 00715 this, SLOT( serverSyncInternal() ) ); 00716 00717 // kdDebug(5006) << "Sync'ing subfolder " << mCurrentSubfolder->imapPath() << endl; 00718 assert( !mCurrentSubfolder->imapPath().isEmpty() ); 00719 mCurrentSubfolder->setAccount( account() ); 00720 mCurrentSubfolder->serverSync( mSuppressDialog ); 00721 } 00722 } 00723 break; 00724 00725 default: 00726 kdDebug(5006) << "KMFolderCachedImap::serverSyncInternal() WARNING: no such state " 00727 << mSyncState << endl; 00728 } 00729 } 00730 00731 /* Connected to the imap account's connectionResult signal. 00732 Emitted when the slave connected or failed to connect. 00733 */ 00734 void KMFolderCachedImap::slotConnectionResult( int errorCode ) 00735 { 00736 kdDebug(5006) << k_funcinfo << errorCode << endl; 00737 disconnect( mAccount, SIGNAL( connectionResult(int) ), 00738 this, SLOT( slotConnectionResult(int) ) ); 00739 if ( !errorCode ) { 00740 // Success 00741 mSyncState = SYNC_STATE_CHECK_UIDVALIDITY; 00742 serverSyncInternal(); 00743 } else { 00744 // Error (error message already shown by the account) 00745 emit folderComplete(this, FALSE); 00746 } 00747 } 00748 00749 /* find new messages (messages without a UID) */ 00750 QValueList<unsigned long> KMFolderCachedImap::findNewMessages() 00751 { 00752 QValueList<unsigned long> result; 00753 for( int i = 0; i < count(); ++i ) { 00754 bool unget = !isMessage(i); 00755 KMMessage *msg = getMsg(i); 00756 if( !msg ) continue; /* what goes on if getMsg() returns 0? */ 00757 if( msg->headerField("X-UID").isEmpty() ) { 00758 result.append( msg->getMsgSerNum() ); 00759 } else { 00760 if (unget) unGetMsg(i); 00761 } 00762 } 00763 return result; 00764 } 00765 00766 /* Upload new messages to server */ 00767 void KMFolderCachedImap::uploadNewMessages() 00768 { 00769 QValueList<unsigned long> newMsgs = findNewMessages(); 00770 emit syncState( SYNC_STATE_PUT_MESSAGES, newMsgs.count() ); 00771 mProgress += 10; 00772 //kdDebug() << name() << ": +10 (uploadNewMessages) -> " << mProgress << "%" << endl; 00773 if( !newMsgs.isEmpty() ) { 00774 emit statusMsg( i18n("%1: Uploading messages to server").arg(name()) ); 00775 00776 emit newState( name(), mProgress, i18n("Uploading messages to server")); 00777 CachedImapJob *job = new CachedImapJob( newMsgs, CachedImapJob::tPutMessage, this ); 00778 connect( job, SIGNAL( finished() ), this, SLOT( serverSyncInternal() ) ); 00779 job->start(); 00780 } else { 00781 emit newState( name(), mProgress, i18n("No messages to upload to server")); 00782 00783 serverSyncInternal(); 00784 } 00785 } 00786 00787 /* Upload new folders to server */ 00788 void KMFolderCachedImap::createNewFolders() 00789 { 00790 QValueList<KMFolderCachedImap*> newFolders = findNewFolders(); 00791 //emit syncState( SYNC_STATE_CREATE_SUBFOLDERS, newFolders.count() ); 00792 mProgress += 10; 00793 //kdDebug() << name() << ": +10 (createNewFolders) -> " << mProgress << "%" << endl; 00794 if( !newFolders.isEmpty() ) { 00795 emit statusMsg( i18n("%1: Creating subfolders on server").arg(name()) ); 00796 emit newState( name(), mProgress, i18n("Creating subfolders on server")); 00797 CachedImapJob *job = new CachedImapJob( newFolders, CachedImapJob::tAddSubfolders, this ); 00798 connect( job, SIGNAL( finished() ), this, SLOT( serverSyncInternal() ) ); 00799 job->start(); 00800 } else { 00801 serverSyncInternal(); 00802 } 00803 } 00804 00805 QValueList<KMFolderCachedImap*> KMFolderCachedImap::findNewFolders() 00806 { 00807 QValueList<KMFolderCachedImap*> newFolders; 00808 if( child() ) { 00809 KMFolderNode *node = child()->first(); 00810 while( node ) { 00811 if( !node->isDir() ) { 00812 if( !node->isA("KMFolderCachedImap") ) { 00813 kdDebug(5006) << "KMFolderCachedImap::findNewFolders(): ARGH!!! " 00814 << node->name() << " is not an IMAP folder. It is a " 00815 << node->className() << endl; 00816 node = child()->next(); 00817 assert(0); 00818 } 00819 KMFolderCachedImap* folder = static_cast<KMFolderCachedImap*>(node); 00820 if( folder->imapPath().isEmpty() ) newFolders << folder; 00821 } 00822 node = child()->next(); 00823 } 00824 } 00825 return newFolders; 00826 } 00827 00828 bool KMFolderCachedImap::deleteMessages() 00829 { 00830 /* Delete messages from cache that are gone from the server */ 00831 QPtrList<KMMessage> msgsForDeletion; 00832 00833 // It is not possible to just go over all indices and remove 00834 // them one by one because the index list can get resized under 00835 // us. So use msg pointers instead 00836 for( int i = 0; i < count(); ++i ) { 00837 bool unget = !isMessage(i); 00838 KMMessage *msg = getMsg(i); 00839 if( !msg ) continue; 00840 bool ok; 00841 ulong uid = msg->headerField( "X-UID" ).toULong( &ok ); 00842 if( ok && !uidsOnServer.contains( uid ) ) 00843 msgsForDeletion.append( msg ); 00844 else 00845 if (unget) unGetMsg(i); 00846 } 00847 00848 if( !msgsForDeletion.isEmpty() ) { 00849 emit statusMsg( i18n("%1: Deleting removed messages from cache").arg(name()) ); 00850 removeMsg( msgsForDeletion ); 00851 } 00852 00853 mProgress += 10; 00854 //kdDebug() << name() << ": +10 (deleteMessages) -> " << mProgress << "%" << endl; 00855 emit newState( name(), mProgress, i18n("Deleting removed messages from server")); 00856 00857 /* Delete messages from the server that we dont have anymore */ 00858 if( !uidsForDeletionOnServer.isEmpty() ) { 00859 emit statusMsg( i18n("%1: Deleting removed messages from server").arg(name()) ); 00860 QStringList sets = makeSets( uidsForDeletionOnServer, true ); 00861 uidsForDeletionOnServer.clear(); 00862 if( sets.count() > 1 ) { 00863 // Rerun the sync until the messages are all deleted 00864 mResync = true; 00865 } 00866 //kdDebug(5006) << "Deleting " << sets.front() << " from sever folder " << imapPath() << endl; 00867 CachedImapJob *job = new CachedImapJob( sets.front(), CachedImapJob::tDeleteMessage, 00868 this ); 00869 connect( job, SIGNAL( finished() ), this, SLOT( serverSyncInternal() ) ); 00870 job->start(); 00871 return true; 00872 } else { 00873 return false; 00874 } 00875 } 00876 00877 void KMFolderCachedImap::checkUidValidity() { 00878 // IMAP root folders don't seem to have a UID validity setting. 00879 // Also, don't try the uid validity on new folders 00880 if( imapPath().isEmpty() || imapPath() == "/" ) 00881 // Just proceed 00882 serverSyncInternal(); 00883 else { 00884 mProgress += 10; 00885 //kdDebug() << name() << ": +10 (checkUidValidity) -> " << mProgress << "%" << endl; 00886 emit newState( name(), mProgress, i18n("Checking folder validity")); 00887 emit statusMsg( i18n("%1: Checking folder validity").arg(name()) ); 00888 CachedImapJob *job = new CachedImapJob( FolderJob::tCheckUidValidity, this ); 00889 connect( job, SIGNAL( finished() ), this, SLOT( serverSyncInternal() ) ); 00890 job->start(); 00891 } 00892 } 00893 00894 /* This will only list the messages in a folder. 00895 No directory listing done*/ 00896 void KMFolderCachedImap::listMessages() { 00897 if( imapPath() == "/" ) { 00898 // Don't list messages on the root folder 00899 serverSyncInternal(); 00900 return; 00901 } 00902 00903 if( mAccount->makeConnection() != ImapAccountBase::Connected ) { 00904 emit listMessagesComplete(); 00905 emit folderComplete( this, false ); 00906 return; 00907 } 00908 uidsOnServer.clear(); 00909 uidsForDeletionOnServer.clear(); 00910 mMsgsForDownload.clear(); 00911 mUidsForDownload.clear(); 00912 KURL url = mAccount->getUrl(); 00913 url.setPath(imapPath() + ";UID=1:*;SECTION=ENVELOPE"); 00914 KMAcctCachedImap::jobData jd( url.url(), this ); 00915 00916 KIO::SimpleJob *newJob = KIO::get(url, FALSE, FALSE); 00917 KIO::Scheduler::assignJobToSlave(mAccount->slave(), newJob); 00918 mAccount->insertJob(newJob, jd); 00919 00920 connect( newJob, SIGNAL( result( KIO::Job* ) ), 00921 this, SLOT( slotGetLastMessagesResult( KIO::Job* ) ) ); 00922 connect( newJob, SIGNAL( data( KIO::Job*, const QByteArray& ) ), 00923 this, SLOT( slotGetMessagesData( KIO::Job* , const QByteArray& ) ) ); 00924 } 00925 00926 void KMFolderCachedImap::slotGetLastMessagesResult(KIO::Job * job) 00927 { 00928 getMessagesResult(job, true); 00929 } 00930 00931 00932 //----------------------------------------------------------------------------- 00933 void KMFolderCachedImap::slotGetMessagesResult(KIO::Job * job) 00934 { 00935 getMessagesResult(job, false); 00936 } 00937 00938 // All this should be moved to CachedImapJob obviously... 00939 void KMFolderCachedImap::slotGetMessagesData(KIO::Job * job, const QByteArray & data) 00940 { 00941 KMAcctCachedImap::JobIterator it = mAccount->findJob(job); 00942 if ( it == mAccount->jobsEnd() ) { // Shouldn't happen 00943 kdDebug(5006) << "could not find job!?!?!" << endl; 00944 serverSyncInternal(); /* HACK^W Fix: we should at least try to keep going */ 00945 return; 00946 } 00947 (*it).cdata += QCString(data, data.size() + 1); 00948 int pos = (*it).cdata.find("\r\n--IMAPDIGEST"); 00949 if (pos > 0) { 00950 int p = (*it).cdata.find("\r\nX-uidValidity:"); 00951 if (p != -1) 00952 setUidValidity((*it).cdata.mid(p + 17, (*it).cdata.find("\r\n", p+1) - p - 17)); 00953 (*it).cdata.remove(0, pos); 00954 } 00955 pos = (*it).cdata.find("\r\n--IMAPDIGEST", 1); 00956 00957 int flags; 00958 while (pos >= 0) { 00959 KMMessage *msg = new KMMessage; 00960 msg->fromString((*it).cdata.mid(16, pos - 16)); 00961 flags = msg->headerField("X-Flags").toInt(); 00962 bool ok; 00963 ulong uid = msg->headerField("X-UID").toULong(&ok); 00964 if( ok ) uidsOnServer.append( uid ); 00965 if ( /*flags & 8 ||*/ uid <= lastUid()) { 00966 // kdDebug(5006) << "KMFolderCachedImap::slotGetMessagesData() : folder "<<name()<<" already has msg="<<msg->headerField("Subject") << ", UID="<<uid << ", lastUid = " << mLastUid << endl; 00967 /* If this message UID is not present locally, then it must 00968 have been deleted by the user, so we delete it on the 00969 server also. 00970 */ 00971 KMMsgBase *existingMessage = findByUID(uid); 00972 if( !existingMessage ) { 00973 // kdDebug(5006) << "message with uid " << uid << " is gone from local cache. Must be deleted on server!!!" << endl; 00974 uidsForDeletionOnServer << uid; 00975 } else { 00976 /* The message is OK, update flags */ 00977 flagsToStatus( existingMessage, flags ); 00978 } 00979 delete msg; 00980 } else { 00981 ulong size = msg->headerField("X-Length").toULong(); 00982 mMsgsForDownload << KMail::CachedImapJob::MsgForDownload(uid, flags, size); 00983 if( imapPath() == "/INBOX/" ) 00984 mUidsForDownload << uid; 00985 00986 delete msg; 00987 } 00988 (*it).cdata.remove(0, pos); 00989 (*it).done++; 00990 pos = (*it).cdata.find("\r\n--IMAPDIGEST", 1); 00991 mAccount->displayProgress(); 00992 } 00993 } 00994 00995 void KMFolderCachedImap::getMessagesResult( KIO::Job * job, bool lastSet ) 00996 { 00997 00998 KMAcctCachedImap::JobIterator it = mAccount->findJob(job); 00999 if ( it == mAccount->jobsEnd() ) { // Shouldn't happen 01000 kdDebug(5006) << "could not find job!?!?!" << endl; 01001 serverSyncInternal(); /* HACK^W Fix: we should at least try to keep going */ 01002 return; 01003 } 01004 01005 if( job->error() ) { 01006 mAccount->slotSlaveError( mAccount->slave(), job->error(), 01007 job->errorText() ); 01008 mContentState = imapNoInformation; 01009 emit folderComplete(this, FALSE); 01010 } else if (lastSet) mContentState = imapFinished; 01011 mAccount->removeJob(it); 01012 if( lastSet ) 01013 emit listMessagesComplete(); 01014 } 01015 01016 void KMFolderCachedImap::slotProgress(unsigned long done, unsigned long total) 01017 { 01018 //kdDebug() << "KMFolderCachedImap::slotProgress done=" << done << " total=" << total << "=> progress=" << mProgress + ( 20 * done ) / total << endl; 01019 // Progress info while retrieving new emails 01020 // (going from mProgress to mProgress+20) 01021 emit newState( name(), mProgress + (20 * done) / total, QString::null); 01022 } 01023 01024 //----------------------------------------------------------------------------- 01025 void KMFolderCachedImap::flagsToStatus(KMMsgBase *msg, int flags, bool newMsg) 01026 { 01027 if (flags & 4) 01028 msg->setStatus( KMMsgStatusFlag ); 01029 if (flags & 2) 01030 msg->setStatus( KMMsgStatusReplied ); 01031 if (flags & 1) 01032 msg->setStatus( KMMsgStatusOld ); 01033 01034 if (msg->isOfUnknownStatus()) { 01035 if (newMsg) 01036 msg->setStatus( KMMsgStatusNew ); 01037 else 01038 msg->setStatus( KMMsgStatusUnread ); 01039 } 01040 } 01041 01042 01043 void KMFolderCachedImap::setAccount(KMAcctCachedImap *aAccount) 01044 { 01045 assert( aAccount->isA("KMAcctCachedImap") ); 01046 mAccount = aAccount; 01047 if( imapPath()=="/" ) aAccount->setFolder(this); 01048 01049 if( !mChild || mChild->count() == 0) return; 01050 for( KMFolderNode* node = mChild->first(); node; node = mChild->next() ) 01051 if (!node->isDir()) 01052 static_cast<KMFolderCachedImap*>(node)->setAccount(aAccount); 01053 } 01054 01055 01056 // This synchronizes the subfolders with the server 01057 bool KMFolderCachedImap::listDirectory() 01058 { 01059 mSubfolderState = imapInProgress; 01060 KURL url = mAccount->getUrl(); 01061 url.setPath(imapPath() + ";TYPE=" 01062 + (mAccount->onlySubscribedFolders() ? "LSUB" : "LIST")); 01063 KMAcctCachedImap::jobData jd( url.url(), this ); 01064 mSubfolderNames.clear(); 01065 mSubfolderPaths.clear(); 01066 mSubfolderMimeTypes.clear(); 01067 01068 if( mAccount->makeConnection() != ImapAccountBase::Connected ) { 01069 emit folderComplete( this, false ); 01070 return false; 01071 } 01072 01073 KIO::SimpleJob *job = KIO::listDir(url, FALSE); 01074 KIO::Scheduler::assignJobToSlave(mAccount->slave(), job); 01075 mAccount->insertJob(job, jd); 01076 connect(job, SIGNAL(result(KIO::Job *)), 01077 this, SLOT(slotListResult(KIO::Job *))); 01078 connect(job, SIGNAL(entries(KIO::Job *, const KIO::UDSEntryList &)), 01079 this, SLOT(slotListEntries(KIO::Job *, const KIO::UDSEntryList &))); 01080 01081 return TRUE; 01082 } 01083 01084 void KMFolderCachedImap::slotListResult(KIO::Job * job) 01085 { 01086 KMAcctCachedImap::JobIterator it = mAccount->findJob(job); 01087 if( it == mAccount->jobsEnd() ) { // Shouldn't happen 01088 kdDebug(5006) << "could not find job!?!?!" << endl; 01089 serverSyncInternal(); /* HACK^W Fix: we should at least try to keep going */ 01090 return; 01091 } 01092 01093 if( job->error() ) { 01094 kdDebug(5006) << "listDirectory() - slotListResult: Job error\n"; 01095 mAccount->slotSlaveError( mAccount->slave(), job->error(), job->errorText() ); 01096 } 01097 01098 mSubfolderState = imapFinished; 01099 mAccount->removeJob(it); 01100 01101 if (!job->error()) { 01102 kmkernel->dimapFolderMgr()->quiet(TRUE); 01103 createChildFolder(); 01104 01105 // Find all subfolders present on disk but not on the server 01106 KMFolderCachedImap *folder; 01107 KMFolderNode *node = mChild->first(); 01108 QPtrList<KMFolder> toRemove; 01109 while (node) { 01110 if (!node->isDir() ) { 01111 if( mSubfolderNames.findIndex(node->name()) == -1) { 01112 // This subfolder isn't present on the server 01113 kdDebug(5006) << node->name() << " isn't on the server." << endl; 01114 folder = static_cast<KMFolderCachedImap*>(node); 01115 if( !folder->uidValidity().isEmpty() ) { 01116 // The folder have a uidValidity setting, so it has been on the 01117 // server before. Delete it locally. 01118 toRemove.append( folder ); 01119 } 01120 } 01121 } 01122 node = mChild->next(); 01123 } 01124 // Remove all folders 01125 for ( KMFolder* doomed=toRemove.first(); doomed; doomed = toRemove.next() ) 01126 kmkernel->dimapFolderMgr()->remove( doomed ); 01127 01128 mAccount->displayProgress(); 01129 serverSyncInternal(); 01130 } 01131 } 01132 01133 01134 void KMFolderCachedImap::listDirectory2() { 01135 foldersForDeletionOnServer.clear(); 01136 01137 // Find all subfolders present on server but not on disk 01138 for (uint i = 0; i < mSubfolderNames.count(); i++) { 01139 KMFolderCachedImap *folder = 0; 01140 01141 // Find the subdir, if already present 01142 KMFolderNode *node; 01143 for (node = mChild->first(); node; node = mChild->next()) 01144 if (!node->isDir() && node->name() == mSubfolderNames[i]) break; 01145 01146 if (!node) { 01147 // This folder is not present here 01148 QString part1 = path() + "/." + dotEscape(name()) + ".directory/." 01149 + dotEscape(mSubfolderNames[i]); 01150 QString uidCacheFile = part1 + ".uidcache"; 01151 if( QFile::exists(uidCacheFile) ) { 01152 // This is an old folder that is deleted locally - delete it on the server 01153 unlink( QFile::encodeName( uidCacheFile ) ); 01154 foldersForDeletionOnServer << mSubfolderPaths[i]; 01155 // Make sure all trace of the dir is gone 01156 KIO::del( KURL( part1 + ".directory" ) ); 01157 } else { 01158 // This is a new folder, create the local cache 01159 folder = static_cast<KMFolderCachedImap*> 01160 (mChild->createFolder(mSubfolderNames[i], false, KMFolderTypeCachedImap)); 01161 if (folder) { 01162 folder->close(); 01163 folder->setAccount(mAccount); 01164 kmkernel->dimapFolderMgr()->contentsChanged(); 01165 } else { 01166 kdDebug(5006) << "can't create folder " << mSubfolderNames[i] <<endl; 01167 } 01168 } 01169 } else { 01170 // kdDebug(5006) << "node " << node->name() << " is a " << node->className() << endl; 01171 if( node->isA("KMFolderCachedImap") ) 01172 folder = static_cast<KMFolderCachedImap*>(node); 01173 } 01174 01175 if( folder && folder->imapPath().isEmpty() ) { 01176 // kdDebug(5006) << "folder("<<folder->name()<<")->imapPath()=" << folder->imapPath() 01177 // << "\nAssigning new imapPath " << mSubfolderPaths[i] << endl; 01178 // Write folder settings 01179 folder->setAccount(mAccount); 01180 folder->setNoContent(mSubfolderMimeTypes[i] == "inode/directory"); 01181 folder->setImapPath(mSubfolderPaths[i]); 01182 } 01183 } 01184 01185 kmkernel->dimapFolderMgr()->quiet(FALSE); 01186 emit listComplete(this); 01187 serverSyncInternal(); 01188 } 01189 01190 01191 //----------------------------------------------------------------------------- 01192 void KMFolderCachedImap::slotListEntries(KIO::Job * job, const KIO::UDSEntryList & uds) 01193 { 01194 // kdDebug(5006) << "KMFolderCachedImap::slotListEntries("<<name()<<")" << endl; 01195 KMAcctCachedImap::JobIterator it = mAccount->findJob(job); 01196 if (it == mAccount->jobsEnd()) return; 01197 01198 QString name; 01199 KURL url; 01200 QString mimeType; 01201 for (KIO::UDSEntryList::ConstIterator udsIt = uds.begin(); 01202 udsIt != uds.end(); udsIt++) 01203 { 01204 // kdDebug(5006) << "slotListEntries start" << endl; 01205 mimeType = QString::null; 01206 01207 // Find the info on this subfolder 01208 for (KIO::UDSEntry::ConstIterator eIt = (*udsIt).begin(); 01209 eIt != (*udsIt).end(); eIt++) 01210 { 01211 //kdDebug(5006) << "slotListEntries got type " << (*eIt).m_uds << " str " << (*eIt).m_str << endl; 01212 if ((*eIt).m_uds == KIO::UDS_NAME) 01213 name = (*eIt).m_str; 01214 else if ((*eIt).m_uds == KIO::UDS_URL) 01215 url = KURL((*eIt).m_str, 106); // utf-8 01216 else if ((*eIt).m_uds == KIO::UDS_MIME_TYPE) 01217 mimeType = (*eIt).m_str; 01218 } 01219 01220 // kdDebug(5006) << "slotListEntries end. mimetype = " << mimeType 01221 // << ", name = " << name << ", path = " << url.path() << endl; 01222 01223 // If this was a subfolder, add it to the list 01224 if ((mimeType == "inode/directory" || mimeType == "message/digest" 01225 || mimeType == "message/directory") 01226 && name != ".." && (mAccount->hiddenFolders() || name.at(0) != '.')) 01227 { 01228 // Some servers send _lots_ of duplicates 01229 if (mSubfolderNames.findIndex(name) == -1) { 01230 mSubfolderNames.append(name); 01231 mSubfolderPaths.append(url.path()); 01232 mSubfolderMimeTypes.append(mimeType); 01233 } 01234 } 01235 } 01236 } 01237 01238 void KMFolderCachedImap::slotSimpleData(KIO::Job * job, const QByteArray & data) 01239 { 01240 KMAcctCachedImap::JobIterator it = mAccount->findJob(job); 01241 if (it == mAccount->jobsEnd()) return; 01242 QBuffer buff((*it).data); 01243 buff.open(IO_WriteOnly | IO_Append); 01244 buff.writeBlock(data.data(), data.size()); 01245 buff.close(); 01246 } 01247 01248 01249 QStringList KMFolderCachedImap::makeSets(QStringList& uids, bool sort) 01250 { 01251 QValueList<ulong> tmp; 01252 for ( QStringList::Iterator it = uids.begin(); it != uids.end(); ++it ) 01253 tmp.append( (*it).toInt() ); 01254 return makeSets(tmp, sort); 01255 } 01256 01257 QStringList KMFolderCachedImap::makeSets(QValueList<ulong>& uids, bool sort) 01258 { 01259 QStringList sets; 01260 QString set; 01261 01262 if (uids.size() == 1) 01263 { 01264 sets.append(QString::number(uids.first())); 01265 return sets; 01266 } 01267 01268 if (sort) qHeapSort(uids); 01269 01270 ulong last = 0; 01271 // needed to make a uid like 124 instead of 124:124 01272 bool inserted = false; 01273 /* iterate over uids and build sets like 120:122,124,126:150 */ 01274 for ( QValueList<ulong>::Iterator it = uids.begin(); it != uids.end(); ++it ) 01275 { 01276 if (it == uids.begin() || set.isEmpty()) { 01277 set = QString::number(*it); 01278 inserted = true; 01279 } else 01280 { 01281 if (last+1 != *it) 01282 { 01283 // end this range 01284 if (inserted) 01285 set += ',' + QString::number(*it); 01286 else 01287 set += ':' + QString::number(last) + ',' + QString::number(*it); 01288 inserted = true; 01289 if (set.length() > 100) 01290 { 01291 // just in case the server has a problem with longer lines.. 01292 sets.append(set); 01293 set = ""; 01294 } 01295 } else { 01296 inserted = false; 01297 } 01298 } 01299 last = *it; 01300 } 01301 // last element 01302 if (!inserted) 01303 set += ':' + QString::number(uids.last()); 01304 01305 if (!set.isEmpty()) sets.append(set); 01306 01307 return sets; 01308 } 01309 01310 FolderJob* 01311 KMFolderCachedImap::doCreateJob( KMMessage *msg, FolderJob::JobType jt, KMFolder *folder, 01312 QString, const AttachmentStrategy* ) const 01313 { 01314 QPtrList<KMMessage> msgList; 01315 msgList.append( msg ); 01316 CachedImapJob *job = new CachedImapJob( msgList, jt, static_cast<KMFolderCachedImap*>( folder ) ); 01317 return job; 01318 } 01319 01320 FolderJob* 01321 KMFolderCachedImap::doCreateJob( QPtrList<KMMessage>& msgList, const QString& sets, 01322 FolderJob::JobType jt, KMFolder *folder ) const 01323 { 01324 //FIXME: how to handle sets here? 01325 Q_UNUSED( sets ); 01326 CachedImapJob *job = new CachedImapJob( msgList, jt, static_cast<KMFolderCachedImap*>( folder ) ); 01327 return job; 01328 } 01329 01330 #include "kmfoldercachedimap.moc"
KDE Logo
This file is part of the documentation for kmail Library Version 3.2.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Jul 28 23:58:00 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003