cachedimapjob.cpp
00001 /* -*- mode: C++; c-file-style: "gnu" -*- 00002 * 00003 * This file is part of KMail, the KDE mail client. 00004 * Copyright (c) 2002-2004 Bo Thorsen <bo@sonofthor.dk> 00005 * 2002-2003 Steffen Hansen <hansen@kde.org> 00006 * 2002-2003 Zack Rusin <zack@kde.org> 00007 * 00008 * KMail is free software; you can redistribute it and/or modify it 00009 * under the terms of the GNU General Public License, version 2, as 00010 * published by the Free Software Foundation. 00011 * 00012 * KMail is distributed in the hope that it will be useful, but 00013 * WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU General Public License 00018 * along with this program; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00020 * 00021 * In addition, as a special exception, the copyright holders give 00022 * permission to link the code of this program with any edition of 00023 * the TQt library by Trolltech AS, Norway (or with modified versions 00024 * of TQt that use the same license as TQt), and distribute linked 00025 * combinations including the two. You must obey the GNU General 00026 * Public License in all respects for all of the code used other than 00027 * TQt. If you modify this file, you may extend this exception to 00028 * your version of the file, but you are not obligated to do so. If 00029 * you do not wish to do so, delete this exception statement from 00030 * your version. 00031 */ 00032 00033 #ifdef HAVE_CONFIG_H 00034 #include <config.h> 00035 #endif 00036 00037 #include "cachedimapjob.h" 00038 #include "imapaccountbase.h" 00039 00040 #include "kmfoldermgr.h" 00041 #include "kmfolder.h" 00042 #include "kmfoldercachedimap.h" 00043 #include "kmailicalifaceimpl.h" 00044 #include "kmacctcachedimap.h" 00045 #include "kmmsgdict.h" 00046 #include "maildirjob.h" 00047 #include "scalix.h" 00048 #include "util.h" 00049 00050 #include <kio/scheduler.h> 00051 #include <kio/job.h> 00052 00053 #include <klocale.h> 00054 #include <kdebug.h> 00055 00056 00057 namespace KMail { 00058 00059 // Get messages 00060 CachedImapJob::CachedImapJob( const TQValueList<MsgForDownload>& msgs, 00061 JobType type, KMFolderCachedImap* folder ) 00062 : FolderJob( type ), mFolder( folder ), mMsgsForDownload( msgs ), 00063 mTotalBytes(0), mMsg(0), mParentFolder( 0 ) 00064 { 00065 TQValueList<MsgForDownload>::ConstIterator it = msgs.begin(); 00066 for ( ; it != msgs.end() ; ++it ) 00067 mTotalBytes += (*it).size; 00068 } 00069 00070 // Put messages 00071 CachedImapJob::CachedImapJob( const TQPtrList<KMMessage>& msgs, JobType type, 00072 KMFolderCachedImap* folder ) 00073 : FolderJob( msgs, TQString(), type, folder?folder->folder():0 ), mFolder( folder ), 00074 mTotalBytes( msgs.count() ), // we abuse it as "total number of messages" 00075 mMsg( 0 ), mParentFolder( 0 ) 00076 { 00077 } 00078 00079 CachedImapJob::CachedImapJob( const TQValueList<unsigned long>& msgs, 00080 JobType type, KMFolderCachedImap* folder ) 00081 : FolderJob( TQPtrList<KMMessage>(), TQString(), type, folder?folder->folder():0 ), 00082 mFolder( folder ), mSerNumMsgList( msgs ), mTotalBytes( msgs.count() ), mMsg( 0 ), 00083 mParentFolder ( 0 ) 00084 { 00085 } 00086 00087 // Add sub folders 00088 CachedImapJob::CachedImapJob( const TQValueList<KMFolderCachedImap*>& fList, 00089 JobType type, KMFolderCachedImap* folder ) 00090 : FolderJob( type ), mFolder( folder ), mFolderList( fList ), mMsg( 0 ), 00091 mParentFolder ( 0 ) 00092 { 00093 } 00094 00095 // Rename folder 00096 CachedImapJob::CachedImapJob( const TQString& string1, JobType type, 00097 KMFolderCachedImap* folder ) 00098 : FolderJob( type ), mFolder(folder), mMsg( 0 ), mString( string1 ), 00099 mParentFolder ( 0 ) 00100 { 00101 assert( folder ); 00102 assert( type != tDeleteMessage ); // moved to another ctor 00103 } 00104 00105 // Delete folders or messages 00106 CachedImapJob::CachedImapJob( const TQStringList& foldersOrMsgs, JobType type, 00107 KMFolderCachedImap* folder ) 00108 : FolderJob( type ), mFolder( folder ), mFoldersOrMessages( foldersOrMsgs ), 00109 mMsg( 0 ), mParentFolder( 0 ) 00110 { 00111 assert( folder ); 00112 } 00113 00114 // Other jobs (list messages,expunge folder, check uid validity) 00115 CachedImapJob::CachedImapJob( JobType type, KMFolderCachedImap* folder ) 00116 : FolderJob( type ), mFolder( folder ), mMsg( 0 ), mParentFolder ( 0 ) 00117 { 00118 assert( folder ); 00119 } 00120 00121 CachedImapJob::~CachedImapJob() 00122 { 00123 mAccount->mJobList.remove(this); 00124 } 00125 00126 void CachedImapJob::execute() 00127 { 00128 mSentBytes = 0; 00129 00130 if( !mFolder ) { 00131 if( !mMsgList.isEmpty() ) { 00132 mFolder = static_cast<KMFolderCachedImap*>(mMsgList.first()->storage()); 00133 } 00134 } 00135 assert( mFolder ); 00136 mAccount = mFolder->account(); 00137 assert( mAccount != 0 ); 00138 if( mAccount->makeConnection() != ImapAccountBase::Connected ) { 00139 // No connection to the IMAP server 00140 kdDebug(5006) << "mAccount->makeConnection() failed" << endl; 00141 mPassiveDestructor = true; 00142 delete this; 00143 return; 00144 } else 00145 mPassiveDestructor = false; 00146 00147 // All necessary conditions have been met. Register this job 00148 mAccount->mJobList.append(this); 00149 00156 if ( mAccount->groupwareType() == KMAcctCachedImap::GroupwareScalix ) { 00157 if ( !mAccount->sentCustomLoginCommand() ) { 00158 TQByteArray packedArgs; 00159 TQDataStream stream( packedArgs, IO_WriteOnly ); 00160 00161 const TQString command = TQString( "X-SCALIX-ID " ); 00162 const TQString argument = TQString( "(\"name\" \"Evolution\" \"version\" \"2.10.0\")" ); 00163 00164 stream << (int) 'X' << 'N' << command << argument; 00165 00166 const KURL url = mAccount->getUrl(); 00167 00168 ImapAccountBase::jobData jd( url.url(), mFolder->folder() ); 00169 jd.items << mFolder->label(); // for the err msg 00170 KIO::SimpleJob *simpleJob = KIO::special( url.url(), packedArgs, false ); 00171 KIO::Scheduler::assignJobToSlave(mAccount->slave(), simpleJob); 00172 mAccount->insertJob(simpleJob, jd); 00173 00174 mAccount->setSentCustomLoginCommand( true ); 00175 } 00176 } 00177 00178 switch( mType ) { 00179 case tGetMessage: slotGetNextMessage(); break; 00180 case tPutMessage: slotPutNextMessage(); break; 00181 case tDeleteMessage: slotDeleteNextMessages(); break; 00182 case tExpungeFolder: expungeFolder(); break; 00183 case tAddSubfolders: slotAddNextSubfolder(); break; 00184 case tDeleteFolders: slotDeleteNextFolder(); break; 00185 case tCheckUidValidity: checkUidValidity(); break; 00186 case tRenameFolder: renameFolder(mString); break; 00187 case tListMessages: listMessages(); break; 00188 default: 00189 assert( 0 ); 00190 } 00191 } 00192 00193 void CachedImapJob::listMessages() 00194 { 00195 KURL url = mAccount->getUrl(); 00196 url.setPath( mFolder->imapPath() + ";UID=1:*;SECTION=FLAGS RFC822.SIZE"); 00197 00198 KIO::SimpleJob *job = KIO::get(url, false, false); 00199 KIO::Scheduler::assignJobToSlave( mAccount->slave(), job ); 00200 ImapAccountBase::jobData jd( url.url(), mFolder->folder() ); 00201 jd.cancellable = true; 00202 mAccount->insertJob( job, jd ); 00203 connect( job, TQT_SIGNAL( result(KIO::Job *) ), 00204 this, TQT_SLOT( slotListMessagesResult( KIO::Job* ) ) ); 00205 // send the data directly for KMFolderCachedImap 00206 connect( job, TQT_SIGNAL( data( KIO::Job*, const TQByteArray& ) ), 00207 mFolder, TQT_SLOT( slotGetMessagesData( KIO::Job* , const TQByteArray& ) ) ); 00208 } 00209 00210 void CachedImapJob::slotDeleteNextMessages( KIO::Job* job ) 00211 { 00212 if (job) { 00213 KMAcctCachedImap::JobIterator it = mAccount->findJob(job); 00214 if ( it == mAccount->jobsEnd() ) { // Shouldn't happen 00215 delete this; 00216 return; 00217 } 00218 00219 if( job->error() ) { 00220 mAccount->handleJobError( job, i18n( "Error while deleting messages on the server: " ) + '\n' ); 00221 delete this; 00222 return; 00223 } 00224 mAccount->removeJob(it); 00225 } 00226 00227 if( mFoldersOrMessages.isEmpty() ) { 00228 // No more messages to delete 00229 delete this; 00230 return; 00231 } 00232 00233 TQString uids = mFoldersOrMessages.front(); mFoldersOrMessages.pop_front(); 00234 00235 KURL url = mAccount->getUrl(); 00236 url.setPath( mFolder->imapPath() + 00237 TQString::fromLatin1(";UID=%1").arg(uids) ); 00238 00239 KIO::SimpleJob *simpleJob = KIO::file_delete( url, false ); 00240 KIO::Scheduler::assignJobToSlave( mAccount->slave(), simpleJob ); 00241 ImapAccountBase::jobData jd( url.url(), mFolder->folder() ); 00242 mAccount->insertJob( simpleJob, jd ); 00243 connect( simpleJob, TQT_SIGNAL( result(KIO::Job *) ), 00244 this, TQT_SLOT( slotDeleteNextMessages(KIO::Job *) ) ); 00245 } 00246 00247 void CachedImapJob::expungeFolder() 00248 { 00249 KURL url = mAccount->getUrl(); 00250 // Special URL that means EXPUNGE 00251 url.setPath( mFolder->imapPath() + TQString::fromLatin1(";UID=*") ); 00252 00253 KIO::SimpleJob *job = KIO::file_delete( url, false ); 00254 KIO::Scheduler::assignJobToSlave( mAccount->slave(), job ); 00255 ImapAccountBase::jobData jd( url.url(), mFolder->folder() ); 00256 mAccount->insertJob( job, jd ); 00257 connect( job, TQT_SIGNAL( result(KIO::Job *) ), 00258 this, TQT_SLOT( slotExpungeResult(KIO::Job *) ) ); 00259 } 00260 00261 void CachedImapJob::slotExpungeResult( KIO::Job * job ) 00262 { 00263 KMAcctCachedImap::JobIterator it = mAccount->findJob(job); 00264 if ( it == mAccount->jobsEnd() ) { // Shouldn't happen 00265 delete this; 00266 return; 00267 } 00268 00269 if (job->error()) { 00270 mErrorCode = job->error(); 00271 mAccount->handleJobError( job, i18n( "Error while deleting messages on the server: " ) + '\n' ); 00272 } 00273 else 00274 mAccount->removeJob(it); 00275 00276 delete this; 00277 } 00278 00279 void CachedImapJob::slotGetNextMessage(KIO::Job * job) 00280 { 00281 if (job) { 00282 KMAcctCachedImap::JobIterator it = mAccount->findJob(job); 00283 if ( it == mAccount->jobsEnd() ) { // Shouldn't happen 00284 delete this; 00285 return; 00286 } 00287 00288 if (job->error()) { 00289 mErrorCode = job->error(); 00290 mAccount->handleJobError( job, i18n( "Error while retrieving message on the server: " ) + '\n' ); 00291 delete this; 00292 return; 00293 } 00294 00295 ulong size = 0; 00296 if ((*it).data.size() > 0) { 00297 ulong uid = mMsg->UID(); 00298 size = mMsg->msgSizeServer(); 00299 00300 // Convert CR/LF to LF. 00301 size_t dataSize = (*it).data.size(); 00302 dataSize = Util::crlf2lf( (*it).data.data(), dataSize ); // always <= 00303 (*it).data.resize( dataSize ); 00304 00305 mMsg->setComplete( true ); 00306 mMsg->fromByteArray( (*it).data ); 00307 mMsg->setUID(uid); 00308 mMsg->setMsgSizeServer(size); 00309 mMsg->setTransferInProgress( false ); 00310 int index = 0; 00311 mFolder->addMsgInternal( mMsg, true, &index ); 00312 00313 if ( kmkernel->iCalIface().isResourceFolder( mFolder->folder() ) ) { 00314 mFolder->setStatus( index, KMMsgStatusRead, false ); 00315 } 00316 00317 emit messageRetrieved( mMsg ); 00318 if ( index > 0 ) mFolder->unGetMsg( index ); 00319 } else { 00320 emit messageRetrieved( 0 ); 00321 } 00322 mMsg = 0; 00323 00324 mSentBytes += size; 00325 emit progress( mSentBytes, mTotalBytes ); 00326 mAccount->removeJob(it); 00327 } else 00328 mFolder->quiet( true ); 00329 00330 if( mMsgsForDownload.isEmpty() ) { 00331 mFolder->quiet( false ); 00332 delete this; 00333 return; 00334 } 00335 00336 MsgForDownload mfd = mMsgsForDownload.front(); mMsgsForDownload.pop_front(); 00337 00338 mMsg = new KMMessage; 00339 mMsg->setUID(mfd.uid); 00340 mMsg->setMsgSizeServer(mfd.size); 00341 if( mfd.flags > 0 ) 00342 KMFolderImap::flagsToStatus(mMsg, mfd.flags, true, GlobalSettings::allowLocalFlags() ? mFolder->permanentFlags() : INT_MAX); 00343 KURL url = mAccount->getUrl(); 00344 url.setPath(mFolder->imapPath() + TQString(";UID=%1;SECTION=BODY.PEEK[]").arg(mfd.uid)); 00345 00346 ImapAccountBase::jobData jd( url.url(), mFolder->folder() ); 00347 jd.cancellable = true; 00348 mMsg->setTransferInProgress(true); 00349 KIO::SimpleJob *simpleJob = KIO::get(url, false, false); 00350 KIO::Scheduler::assignJobToSlave(mAccount->slave(), simpleJob); 00351 mAccount->insertJob(simpleJob, jd); 00352 connect(simpleJob, TQT_SIGNAL(processedSize(KIO::Job *, KIO::filesize_t)), 00353 this, TQT_SLOT(slotProcessedSize(KIO::Job *, KIO::filesize_t))); 00354 connect(simpleJob, TQT_SIGNAL(result(KIO::Job *)), 00355 this, TQT_SLOT(slotGetNextMessage(KIO::Job *))); 00356 connect(simpleJob, TQT_SIGNAL(data(KIO::Job *, const TQByteArray &)), 00357 mFolder, TQT_SLOT(slotSimpleData(KIO::Job *, const TQByteArray &))); 00358 } 00359 00360 void CachedImapJob::slotProcessedSize(KIO::Job *, KIO::filesize_t processed) 00361 { 00362 emit progress( mSentBytes + processed, mTotalBytes ); 00363 } 00364 00365 void CachedImapJob::slotPutNextMessage() 00366 { 00367 mMsg = 0; 00368 00369 // First try the message list 00370 if( !mMsgList.isEmpty() ) { 00371 mMsg = mMsgList.first(); 00372 mMsgList.removeFirst(); 00373 } 00374 00375 // Now try the serial number list 00376 while( mMsg == 0 && !mSerNumMsgList.isEmpty() ) { 00377 unsigned long serNum = mSerNumMsgList.first(); 00378 mSerNumMsgList.pop_front(); 00379 00380 // Find the message with this serial number 00381 int i = 0; 00382 KMFolder* aFolder = 0; 00383 KMMsgDict::instance()->getLocation( serNum, &aFolder, &i ); 00384 if( mFolder->folder() != aFolder ) 00385 // This message was moved or something 00386 continue; 00387 mMsg = mFolder->getMsg( i ); 00388 } 00389 00390 if( !mMsg ) { 00391 // No message found for upload 00392 delete this; 00393 return; 00394 } 00395 00396 KURL url = mAccount->getUrl(); 00397 TQString flags = KMFolderImap::statusToFlags( mMsg->status(), mFolder->permanentFlags() ); 00398 url.setPath( mFolder->imapPath() + ";SECTION=" + flags ); 00399 00400 ImapAccountBase::jobData jd( url.url(), mFolder->folder() ); 00401 00402 mMsg->setUID( 0 ); // for the index 00403 TQCString cstr(mMsg->asString()); 00404 int a = cstr.find("\nX-UID: "); 00405 int b = cstr.find('\n', a); 00406 if (a != -1 && b != -1 && cstr.find("\n\n") > a) cstr.remove(a, b-a); 00407 TQCString mData(cstr.length() + cstr.contains('\n')); 00408 unsigned int i = 0; 00409 for( char *ch = cstr.data(); *ch; ch++ ) { 00410 if ( *ch == '\n' ) { 00411 mData.at(i) = '\r'; 00412 i++; 00413 } 00414 mData.at(i) = *ch; i++; 00415 } 00416 jd.data = mData; 00417 jd.msgList.append( mMsg ); 00418 00419 mMsg->setTransferInProgress(true); 00420 KIO::SimpleJob *simpleJob = KIO::put(url, 0, false, false, false); 00421 KIO::Scheduler::assignJobToSlave(mAccount->slave(), simpleJob); 00422 mAccount->insertJob(simpleJob, jd); 00423 connect( simpleJob, TQT_SIGNAL( result(KIO::Job *) ), 00424 TQT_SLOT( slotPutMessageResult(KIO::Job *) ) ); 00425 connect( simpleJob, TQT_SIGNAL( dataReq(KIO::Job *, TQByteArray &) ), 00426 TQT_SLOT( slotPutMessageDataReq(KIO::Job *, TQByteArray &) ) ); 00427 connect( simpleJob, TQT_SIGNAL( data(KIO::Job *, const TQByteArray &) ), 00428 mFolder, TQT_SLOT( slotSimpleData(KIO::Job *, const TQByteArray &) ) ); 00429 connect( simpleJob, TQT_SIGNAL(infoMessage(KIO::Job *, const TQString &)), 00430 TQT_SLOT(slotPutMessageInfoData(KIO::Job *, const TQString &)) ); 00431 00432 } 00433 00434 //----------------------------------------------------------------------------- 00435 // TODO: port to KIO::StoredTransferJob once it's ok to require kdelibs-3.3 00436 void CachedImapJob::slotPutMessageDataReq(KIO::Job *job, TQByteArray &data) 00437 { 00438 KMAcctCachedImap::JobIterator it = mAccount->findJob(job); 00439 if ( it == mAccount->jobsEnd() ) { // Shouldn't happen 00440 delete this; 00441 return; 00442 } 00443 if ((*it).data.size() - (*it).offset > 0x8000) { 00444 data.duplicate((*it).data.data() + (*it).offset, 0x8000); 00445 (*it).offset += 0x8000; 00446 } else if ((*it).data.size() - (*it).offset > 0) { 00447 data.duplicate((*it).data.data() + (*it).offset, 00448 (*it).data.size() - (*it).offset); 00449 (*it).offset = (*it).data.size(); 00450 } else 00451 data.resize(0); 00452 } 00453 00454 //---------------------------------------------------------------------------- 00455 void CachedImapJob::slotPutMessageInfoData( KIO::Job *job, const TQString &data ) 00456 { 00457 KMFolderCachedImap *imapFolder = static_cast<KMFolderCachedImap*>( mDestFolder->storage() ); 00458 if ( imapFolder ) { 00459 KMAcctCachedImap *account = imapFolder->account(); 00460 ImapAccountBase::JobIterator it = account->findJob( job ); 00461 if ( it == account->jobsEnd() ) { 00462 return; 00463 } 00464 00465 if ( data.find( "UID" ) != -1 && mMsg ) { 00466 int uid = ( data.right( data.length() - 4 ) ).toInt(); 00467 kdDebug( 5006 ) << k_funcinfo << "Server told us uid is: " << uid << endl; 00468 mMsg->setUID( uid ); 00469 } 00470 } 00471 } 00472 00473 00474 //----------------------------------------------------------------------------- 00475 void CachedImapJob::slotPutMessageResult(KIO::Job *job) 00476 { 00477 KMAcctCachedImap::JobIterator it = mAccount->findJob(job); 00478 if ( it == mAccount->jobsEnd() ) { // Shouldn't happen 00479 delete this; 00480 return; 00481 } 00482 00483 if ( job->error() ) { 00484 bool cont = mAccount->handlePutError( job, *it, mFolder->folder() ); 00485 if ( !cont ) { 00486 delete this; 00487 } else { 00488 mMsg = 0; 00489 slotPutNextMessage(); 00490 } 00491 return; 00492 } 00493 00494 emit messageStored( mMsg ); 00495 00496 // we abuse those fields, the unit is the number of messages, here 00497 ++mSentBytes; 00498 emit progress( mSentBytes, mTotalBytes ); 00499 00500 int i; 00501 if( ( i = mFolder->find(mMsg) ) != -1 ) { 00502 /* 00503 * If we have acquired a uid during upload the server supports the uidnext 00504 * extension and there is no need to redownload this mail, we already have 00505 * it. Otherwise remove it, it will be redownloaded. 00506 */ 00507 if ( mMsg->UID() == 0 ) { 00508 mFolder->removeMsg(i); 00509 } else { 00510 // When removing+readding, no point in telling the imap resources about it 00511 bool b = kmkernel->iCalIface().isResourceQuiet(); 00512 kmkernel->iCalIface().setResourceQuiet( true ); 00513 00514 mFolder->takeTemporarily( i ); 00515 mFolder->addMsgKeepUID( mMsg ); 00516 mMsg->setTransferInProgress( false ); 00517 00518 kmkernel->iCalIface().setResourceQuiet( b ); 00519 } 00520 } 00521 mMsg = NULL; 00522 mAccount->removeJob( it ); 00523 slotPutNextMessage(); 00524 } 00525 00526 00527 void CachedImapJob::slotAddNextSubfolder( KIO::Job * job ) 00528 { 00529 if (job) { 00530 KMAcctCachedImap::JobIterator it = mAccount->findJob(job); 00531 if ( it == mAccount->jobsEnd() ) { // Shouldn't happen 00532 delete this; 00533 return; 00534 } 00535 00536 // make copy of setting, to reset it before potentially destroying 'it' 00537 bool silentUpload = static_cast<KMFolderCachedImap*>((*it).parent->storage())->silentUpload(); 00538 static_cast<KMFolderCachedImap*>((*it).parent->storage())->setSilentUpload( false ); 00539 00540 if ( job->error() && !silentUpload ) { 00541 TQString myError = "<p><b>" + i18n("Error while uploading folder") 00542 + "</b></p><p>" + i18n("Could not make the folder <b>%1</b> on the server.").arg((*it).items[0]) 00543 + "</p><p>" + i18n("This could be because you do not have permission to do this, or because the folder is already present on the server; the error message from the server communication is here:") + "</p>"; 00544 mAccount->handleJobError( job, myError ); 00545 } 00546 00547 if( job->error() ) { 00548 delete this; 00549 return; 00550 } else { 00551 KMFolderCachedImap* storage = static_cast<KMFolderCachedImap*>( (*it).current->storage() ); 00552 KMFolderCachedImap* parentStorage = static_cast<KMFolderCachedImap*>( (*it).parent->storage() ); 00553 Q_ASSERT( storage ); 00554 Q_ASSERT( parentStorage ); 00555 if ( storage->imapPath().isEmpty() ) { 00556 TQString path = mAccount->createImapPath( parentStorage->imapPath(), storage->folder()->name() ); 00557 if ( !storage->imapPathForCreation().isEmpty() ) 00558 path = storage->imapPathForCreation(); 00559 storage->setImapPath( path ); 00560 storage->writeConfig(); 00561 } 00562 } 00563 mAccount->removeJob( it ); 00564 } 00565 00566 if (mFolderList.isEmpty()) { 00567 // No more folders to add 00568 delete this; 00569 return; 00570 } 00571 00572 KMFolderCachedImap *folder = mFolderList.front(); 00573 mFolderList.pop_front(); 00574 KURL url = mAccount->getUrl(); 00575 TQString path = mAccount->createImapPath( mFolder->imapPath(), 00576 folder->folder()->name() ); 00577 if ( !folder->imapPathForCreation().isEmpty() ) { 00578 // the folder knows it's namespace 00579 path = folder->imapPathForCreation(); 00580 } 00581 url.setPath( path ); 00582 00583 if ( mAccount->groupwareType() != KMAcctCachedImap::GroupwareScalix ) { 00584 // Associate the jobData with the parent folder, not with the child 00585 // This is necessary in case of an error while creating the subfolder, 00586 // so that folderComplete is called on the parent (and the sync resetted). 00587 ImapAccountBase::jobData jd( url.url(), mFolder->folder() ); 00588 jd.items << folder->label(); // for the err msg 00589 jd.current = folder->folder(); 00590 KIO::SimpleJob *simpleJob = KIO::mkdir(url); 00591 KIO::Scheduler::assignJobToSlave(mAccount->slave(), simpleJob); 00592 mAccount->insertJob(simpleJob, jd); 00593 connect( simpleJob, TQT_SIGNAL(result(KIO::Job *)), 00594 this, TQT_SLOT(slotAddNextSubfolder(KIO::Job *)) ); 00595 } else { 00596 TQByteArray packedArgs; 00597 TQDataStream stream( packedArgs, IO_WriteOnly ); 00598 00599 const TQString command = TQString( "X-CREATE-SPECIAL" ); 00600 const TQString argument = TQString( "%1 %2" ).arg( Scalix::Utils::contentsTypeToScalixId( folder->contentsType() ) ) 00601 .arg( path ); 00602 00603 stream << (int) 'X' << 'N' << command << argument; 00604 00605 ImapAccountBase::jobData jd( url.url(), mFolder->folder() ); 00606 jd.items << folder->label(); // for the err msg 00607 jd.current = folder->folder(); 00608 KIO::SimpleJob *simpleJob = KIO::special( url.url(), packedArgs, false ); 00609 KIO::Scheduler::assignJobToSlave(mAccount->slave(), simpleJob); 00610 mAccount->insertJob(simpleJob, jd); 00611 connect( simpleJob, TQT_SIGNAL(result(KIO::Job *)), 00612 this, TQT_SLOT(slotAddNextSubfolder(KIO::Job *)) ); 00613 } 00614 } 00615 00616 00617 void CachedImapJob::slotDeleteNextFolder( KIO::Job *job ) 00618 { 00619 if (job) { 00620 KMAcctCachedImap::JobIterator it = mAccount->findJob(job); 00621 if ( it == mAccount->jobsEnd() ) { // Shouldn't happen 00622 delete this; 00623 return; 00624 } 00625 00626 mAccount->removeDeletedFolder( (*it).path ); 00627 00628 if( job->error() ) { 00629 mAccount->handleJobError( job, i18n( "Error while deleting folder %1 on the server: " ).arg( (*it).path ) + '\n' ); 00630 delete this; 00631 return; 00632 } 00633 mAccount->removeJob(it); 00634 } 00635 00636 if( mFoldersOrMessages.isEmpty() ) { 00637 // No more folders to delete 00638 delete this; 00639 return; 00640 } 00641 00642 TQString folderPath = mFoldersOrMessages.front(); 00643 mFoldersOrMessages.pop_front(); 00644 KURL url = mAccount->getUrl(); 00645 url.setPath(folderPath); 00646 ImapAccountBase::jobData jd( url.url(), mFolder->folder() ); 00647 jd.path = url.path(); 00648 KIO::SimpleJob *simpleJob = KIO::file_delete(url, false); 00649 KIO::Scheduler::assignJobToSlave(mAccount->slave(), simpleJob); 00650 mAccount->insertJob(simpleJob, jd); 00651 connect( simpleJob, TQT_SIGNAL( result(KIO::Job *) ), 00652 TQT_SLOT( slotDeleteNextFolder(KIO::Job *) ) ); 00653 } 00654 00655 void CachedImapJob::checkUidValidity() 00656 { 00657 KURL url = mAccount->getUrl(); 00658 url.setPath( mFolder->imapPath() + ";UID=0:0" ); 00659 00660 ImapAccountBase::jobData jd( url.url(), mFolder->folder() ); 00661 jd.cancellable = true; 00662 00663 KIO::SimpleJob *job = KIO::get( url, false, false ); 00664 KIO::Scheduler::assignJobToSlave( mAccount->slave(), job ); 00665 mAccount->insertJob( job, jd ); 00666 connect( job, TQT_SIGNAL(result(KIO::Job *)), 00667 TQT_SLOT(slotCheckUidValidityResult(KIO::Job *)) ); 00668 connect( job, TQT_SIGNAL(data(KIO::Job *, const TQByteArray &)), 00669 mFolder, TQT_SLOT(slotSimpleData(KIO::Job *, const TQByteArray &))); 00670 } 00671 00672 void CachedImapJob::slotCheckUidValidityResult(KIO::Job * job) 00673 { 00674 KMAcctCachedImap::JobIterator it = mAccount->findJob(job); 00675 if ( it == mAccount->jobsEnd() ) { // Shouldn't happen 00676 delete this; 00677 return; 00678 } 00679 00680 if( job->error() ) { 00681 mErrorCode = job->error(); 00682 mAccount->handleJobError( job, i18n( "Error while reading folder %1 on the server: " ).arg( (*it).parent->label() ) + '\n' ); 00683 delete this; 00684 return; 00685 } 00686 00687 // Check the uidValidity 00688 TQCString cstr((*it).data.data(), (*it).data.size() + 1); 00689 int a = cstr.find("X-uidValidity: "); 00690 if (a < 0) { 00691 // Something is seriously rotten here! 00692 // TODO: Tell the user that he has a problem 00693 kdDebug(5006) << "No uidvalidity available for folder " 00694 << mFolder->name() << endl; 00695 } 00696 else { 00697 int b = cstr.find("\r\n", a); 00698 if ( (b - a - 15) >= 0 ) { 00699 TQString uidv = cstr.mid(a + 15, b - a - 15); 00700 // kdDebug(5006) << "New uidv = " << uidv << ", old uidv = " 00701 // << mFolder->uidValidity() << endl; 00702 if( !mFolder->uidValidity().isEmpty() && mFolder->uidValidity() != uidv ) { 00703 // kdDebug(5006) << "Expunging the mailbox " << mFolder->name() 00704 // << "!" << endl; 00705 mFolder->expunge(); 00706 mFolder->setLastUid( 0 ); 00707 mFolder->clearUidMap(); 00708 } 00709 } else 00710 kdDebug(5006) << "No uidvalidity available for folder " 00711 << mFolder->name() << endl; 00712 } 00713 00714 a = cstr.find( "X-PermanentFlags: " ); 00715 if ( a < 0 ) { 00716 kdDebug(5006) << "no PERMANENTFLAGS response? assumming custom flags are not available" << endl; 00717 } else { 00718 int b = cstr.find( "\r\n", a ); 00719 if ( (b - a - 18) >= 0 ) { 00720 int flags = cstr.mid( a + 18, b - a - 18 ).toInt(); 00721 emit permanentFlags( flags ); 00722 } else { 00723 kdDebug(5006) << "PERMANENTFLAGS response broken, assumming custom flags are not available" << endl; 00724 } 00725 } 00726 00727 mAccount->removeJob(it); 00728 delete this; 00729 } 00730 00731 00732 void CachedImapJob::renameFolder( const TQString &newName ) 00733 { 00734 mNewName = newName; 00735 00736 // Set the source URL 00737 KURL urlSrc = mAccount->getUrl(); 00738 mOldImapPath = mFolder->imapPath(); 00739 urlSrc.setPath( mOldImapPath ); 00740 00741 // Set the destination URL - this is a bit trickier 00742 KURL urlDst = mAccount->getUrl(); 00743 mNewImapPath = mFolder->imapPath(); 00744 // Destination url = old imappath - oldname + new name 00745 mNewImapPath.truncate( mNewImapPath.length() - mFolder->folder()->name().length() - 1); 00746 mNewImapPath += newName + '/'; 00747 urlDst.setPath( mNewImapPath ); 00748 00749 ImapAccountBase::jobData jd( newName, mFolder->folder() ); 00750 jd.path = mNewImapPath; 00751 00752 KIO::SimpleJob *simpleJob = KIO::rename( urlSrc, urlDst, false ); 00753 KIO::Scheduler::assignJobToSlave( mAccount->slave(), simpleJob ); 00754 mAccount->insertJob( simpleJob, jd ); 00755 connect( simpleJob, TQT_SIGNAL(result(KIO::Job *)), 00756 TQT_SLOT(slotRenameFolderResult(KIO::Job *)) ); 00757 } 00758 00759 static void renameChildFolders( KMFolderDir* dir, const TQString& oldPath, 00760 const TQString& newPath ) 00761 { 00762 if( dir ) { 00763 KMFolderNode *node = dir->first(); 00764 while( node ) { 00765 if( !node->isDir() ) { 00766 KMFolderCachedImap* imapFolder = 00767 static_cast<KMFolderCachedImap*>(static_cast<KMFolder*>(node)->storage()); 00768 if ( !imapFolder->imapPath().isEmpty() ) 00769 // Only rename folders that have been accepted by the server 00770 if( imapFolder->imapPath().find( oldPath ) == 0 ) { 00771 TQString p = imapFolder->imapPath(); 00772 p = p.mid( oldPath.length() ); 00773 p.prepend( newPath ); 00774 imapFolder->setImapPath( p ); 00775 renameChildFolders( imapFolder->folder()->child(), oldPath, newPath ); 00776 } 00777 } 00778 node = dir->next(); 00779 } 00780 } 00781 } 00782 00783 void CachedImapJob::revertLabelChange() 00784 { 00785 TQMap<TQString, KMAcctCachedImap::RenamedFolder>::ConstIterator renit = mAccount->renamedFolders().find( mFolder->imapPath() ); 00786 Q_ASSERT( renit != mAccount->renamedFolders().end() ); 00787 if ( renit != mAccount->renamedFolders().end() ) { 00788 mFolder->folder()->setLabel( (*renit).mOldLabel ); 00789 mAccount->removeRenamedFolder( mFolder->imapPath() ); 00790 kmkernel->dimapFolderMgr()->contentsChanged(); 00791 } 00792 } 00793 00794 void CachedImapJob::renameOnDisk() 00795 { 00796 TQString oldName = mFolder->name(); 00797 TQString oldPath = mFolder->imapPath(); 00798 mAccount->removeRenamedFolder( oldPath ); 00799 mFolder->setImapPath( mNewImapPath ); 00800 mFolder->FolderStorage::rename( mNewName ); 00801 00802 if( oldPath.endsWith( "/" ) ) oldPath.truncate( oldPath.length() -1 ); 00803 TQString newPath = mFolder->imapPath(); 00804 if( newPath.endsWith( "/" ) ) newPath.truncate( newPath.length() -1 ); 00805 renameChildFolders( mFolder->folder()->child(), oldPath, newPath ); 00806 kmkernel->dimapFolderMgr()->contentsChanged(); 00807 } 00808 00809 void CachedImapJob::slotSubscribtionChange1Failed( const TQString &errorMessage ) 00810 { 00811 KMessageBox::sorry( 0, i18n( "Error while trying to subscribe to the renamed folder %1.\n" 00812 "Renaming itself was successful, but the renamed folder might disappear " 00813 "from the folder list after the next sync since it is unsubscribed on the server.\n" 00814 "You can try to manually subscribe to the folder yourself.\n\n" 00815 "%2" ) 00816 .arg( mFolder->label() ).arg( errorMessage ) ); 00817 delete this; 00818 } 00819 00820 void CachedImapJob::slotSubscribtionChange2Failed( const TQString &errorMessage ) 00821 { 00822 kdWarning(5006) << k_funcinfo << errorMessage << endl; 00823 // Ignore this error, not something user-visible anyway 00824 delete this; 00825 } 00826 00827 void CachedImapJob::slotSubscribtionChange1Done( const TQString&, bool ) 00828 { 00829 disconnect( mAccount, TQT_SIGNAL( subscriptionChanged( const TQString&, bool ) ), 00830 this, TQT_SLOT( slotSubscribtionChange1Done( const TQString&, bool ) ) ); 00831 connect( mAccount, TQT_SIGNAL( subscriptionChanged( const TQString&, bool ) ), 00832 this, TQT_SLOT( slotSubscribtionChange2Done( const TQString&, bool ) ) ); 00833 disconnect( mAccount, TQT_SIGNAL( subscriptionChangeFailed( const TQString& ) ), 00834 this, TQT_SLOT( slotSubscribtionChange1Failed( const TQString& ) ) ); 00835 connect( mAccount, TQT_SIGNAL( subscriptionChangeFailed( const TQString& ) ), 00836 this, TQT_SLOT( slotSubscribtionChange2Failed( const TQString& ) ) ); 00837 00838 mAccount->changeSubscription( false, mOldImapPath, true /* quiet */ ); 00839 } 00840 00841 void CachedImapJob::slotSubscribtionChange2Done( const TQString&, bool ) 00842 { 00843 // Finally done with everything! 00844 delete this; 00845 } 00846 00847 void CachedImapJob::slotRenameFolderResult( KIO::Job *job ) 00848 { 00849 KMAcctCachedImap::JobIterator it = mAccount->findJob(job); 00850 if ( it == mAccount->jobsEnd() ) { // Shouldn't happen 00851 delete this; 00852 return; 00853 } 00854 00855 if( job->error() ) { 00856 revertLabelChange(); 00857 const TQString errorMessage = i18n( "Error while trying to rename folder %1" ).arg( mFolder->label() ); 00858 mAccount->handleJobError( job, errorMessage ); 00859 delete this; 00860 } else { 00861 00862 mAccount->removeJob( it ); 00863 renameOnDisk(); 00864 00865 // Okay, the folder seems to be renamed on the server and on disk. 00866 // Now unsubscribe from the old folder name and subscribe to the new folder name, 00867 // so that the folder doesn't suddenly disappear after renaming it 00868 connect( mAccount, TQT_SIGNAL( subscriptionChangeFailed( const TQString& ) ), 00869 this, TQT_SLOT( slotSubscribtionChange1Failed( const TQString& ) ) ); 00870 connect( mAccount, TQT_SIGNAL( subscriptionChanged( const TQString&, bool ) ), 00871 this, TQT_SLOT( slotSubscribtionChange1Done( const TQString&, bool ) ) ); 00872 mAccount->changeSubscription( true, mNewImapPath, true /* quiet */ ); 00873 } 00874 } 00875 00876 void CachedImapJob::slotListMessagesResult( KIO::Job * job ) 00877 { 00878 KMAcctCachedImap::JobIterator it = mAccount->findJob(job); 00879 if ( it == mAccount->jobsEnd() ) { // Shouldn't happen 00880 delete this; 00881 return; 00882 } 00883 00884 if (job->error()) { 00885 mErrorCode = job->error(); 00886 mAccount->handleJobError( job, i18n( "Error while deleting messages on the server: " ) + '\n' ); 00887 } 00888 else 00889 mAccount->removeJob(it); 00890 00891 delete this; 00892 } 00893 00894 //----------------------------------------------------------------------------- 00895 void CachedImapJob::setParentFolder( const KMFolderCachedImap* parent ) 00896 { 00897 mParentFolder = const_cast<KMFolderCachedImap*>( parent ); 00898 } 00899 00900 } 00901 00902 #include "cachedimapjob.moc"