00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #ifdef HAVE_CONFIG_H
00034 #include <config.h>
00035 #endif
00036
00037 #include "cachedimapjob.h"
00038
00039 #include "kmfoldermgr.h"
00040 #include "kmfoldercachedimap.h"
00041 #include "kmacctcachedimap.h"
00042 #include "kmmsgdict.h"
00043
00044 #include <kio/scheduler.h>
00045 #include <kio/job.h>
00046
00047 #include <kmessagebox.h>
00048 #include <klocale.h>
00049 #include <kdebug.h>
00050
00051
00052 namespace KMail {
00053
00054
00055 CachedImapJob::CachedImapJob( const QValueList<MsgForDownload>& msgs,
00056 JobType type, KMFolderCachedImap* folder )
00057 : FolderJob( type ), mFolder( folder ), mMsgsForDownload( msgs ),
00058 mTotalBytes(0), mMsg(0)
00059 {
00060 QValueList<MsgForDownload>::ConstIterator it = msgs.begin();
00061 for ( ; it != msgs.end() ; ++it )
00062 mTotalBytes += (*it).size;
00063 }
00064
00065
00066 CachedImapJob::CachedImapJob( const QPtrList<KMMessage>& msgs, JobType type,
00067 KMFolderCachedImap* folder )
00068 : FolderJob( msgs, QString::null, type, folder ), mFolder( folder ),
00069 mTotalBytes( 0 ), mMsg( 0 )
00070 {
00071 }
00072
00073 CachedImapJob::CachedImapJob( const QValueList<unsigned long>& msgs,
00074 JobType type, KMFolderCachedImap* folder )
00075 : FolderJob( QPtrList<KMMessage>(), QString::null, type, folder ),
00076 mFolder( folder ), mSerNumMsgList( msgs ), mTotalBytes( 0 ), mMsg( 0 )
00077 {
00078 }
00079
00080 CachedImapJob::CachedImapJob( const QValueList<KMFolderCachedImap*>& fList,
00081 JobType type, KMFolderCachedImap* folder )
00082 : FolderJob( type ), mFolder( folder ), mFolderList( fList ), mMsg( 0 )
00083 {
00084 }
00085
00086 CachedImapJob::CachedImapJob( const QString& uids, JobType type,
00087 KMFolderCachedImap* folder )
00088 : FolderJob( type ), mFolder(folder), mMsg( 0 ), mString( uids )
00089 {
00090 assert( folder );
00091 }
00092
00093 CachedImapJob::CachedImapJob( const QStringList& folderpaths, JobType type,
00094 KMFolderCachedImap* folder )
00095 : FolderJob( type ), mFolder( folder ), mFolderPathList( folderpaths ),
00096 mMsg( 0 )
00097 {
00098 assert( folder );
00099 }
00100
00101 CachedImapJob::CachedImapJob( JobType type, KMFolderCachedImap* folder )
00102 : FolderJob( type ), mFolder( folder ), mMsg( 0 )
00103 {
00104 assert( folder );
00105 }
00106
00107 CachedImapJob::~CachedImapJob()
00108 {
00109 mAccount->displayProgress();
00110 mAccount->mJobList.remove(this);
00111 }
00112
00113 void CachedImapJob::init()
00114 {
00115 mSentBytes = 0;
00116
00117 if( !mFolder ) {
00118 if( !mMsgList.isEmpty() ) {
00119 mFolder = static_cast<KMFolderCachedImap*>(mMsgList.first()->parent());
00120 }
00121 }
00122 assert( mFolder );
00123 mAccount = mFolder->account();
00124 assert( mAccount != 0 );
00125 if( mAccount->makeConnection() != ImapAccountBase::Connected ) {
00126
00127 kdDebug(5006) << "mAccount->makeConnection() failed" << endl;
00128 mPassiveDestructor = true;
00129 delete this;
00130 return;
00131 } else
00132 mPassiveDestructor = false;
00133
00134
00135 mAccount->mJobList.append(this);
00136
00137 switch( mType ) {
00138 case tGetMessage: slotGetNextMessage(); break;
00139 case tPutMessage: slotPutNextMessage(); break;
00140 case tDeleteMessage: deleteMessages(mString); break;
00141 case tExpungeFolder: expungeFolder(); break;
00142 case tAddSubfolders: slotAddNextSubfolder(); break;
00143 case tDeleteFolders: slotDeleteNextFolder(); break;
00144 case tCheckUidValidity: checkUidValidity(); break;
00145 case tRenameFolder: renameFolder(mString); break;
00146 default:
00147 assert( 0 );
00148 }
00149 }
00150
00151 void CachedImapJob::deleteMessages( const QString& uids )
00152 {
00153 KURL url = mAccount->getUrl();
00154 url.setPath( mFolder->imapPath() +
00155 QString::fromLatin1(";UID=%1").arg(uids) );
00156
00157 KIO::SimpleJob *job = KIO::file_delete( url, false );
00158 KIO::Scheduler::assignJobToSlave( mAccount->slave(), job );
00159 ImapAccountBase::jobData jd( url.url(), mFolder );
00160 mAccount->insertJob( job, jd );
00161 connect( job, SIGNAL( result(KIO::Job *) ),
00162 this, SLOT( slotDeleteResult(KIO::Job *) ) );
00163 }
00164
00165 void CachedImapJob::expungeFolder()
00166 {
00167 KURL url = mAccount->getUrl();
00168
00169 url.setPath( mFolder->imapPath() + QString::fromLatin1(";UID=*") );
00170
00171 KIO::SimpleJob *job = KIO::file_delete( url, false );
00172 KIO::Scheduler::assignJobToSlave( mAccount->slave(), job );
00173 ImapAccountBase::jobData jd( url.url(), mFolder );
00174 mAccount->insertJob( job, jd );
00175 connect( job, SIGNAL( result(KIO::Job *) ),
00176 this, SLOT( slotDeleteResult(KIO::Job *) ) );
00177 }
00178
00179 void CachedImapJob::slotDeleteResult( KIO::Job * job )
00180 {
00181 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
00182 if ( it == mAccount->jobsEnd() ) {
00183 delete this;
00184 return;
00185 }
00186 mAccount->removeJob(it);
00187
00188 if (job->error())
00189 mAccount->slotSlaveError( mAccount->slave(), job->error(),
00190 job->errorText() );
00191
00192 delete this;
00193 }
00194
00195 void CachedImapJob::slotGetNextMessage(KIO::Job * job)
00196 {
00197 if (job) {
00198 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
00199 if ( it == mAccount->jobsEnd() ) {
00200 delete this;
00201 return;
00202 }
00203
00204 if (job->error()) {
00205 mAccount->removeJob(it);
00206 mAccount->slotSlaveError( mAccount->slave(), job->error(),
00207 job->errorText() );
00208 delete this;
00209 return;
00210 }
00211
00212 ulong size = 0;
00213 if ((*it).data.size() > 0) {
00214 QString uid = mMsg->headerField("X-UID");
00215 size = mMsg->headerField("X-Length").toULong();
00216 mMsg->fromByteArray( (*it).data );
00217 mMsg->setHeaderField("X-UID",uid);
00218 mMsg->setTransferInProgress( false );
00219 mMsg->setComplete( true );
00220 mFolder->addMsgInternal( mMsg, true );
00221 emit messageRetrieved( mMsg );
00222 } else {
00223 emit messageRetrieved( 0 );
00224 }
00225 mMsg = 0;
00226
00227 mSentBytes += size;
00228 emit progress( mSentBytes, mTotalBytes );
00229 mAccount->removeJob(it);
00230 }
00231
00232 if( mMsgsForDownload.isEmpty() ) {
00233 delete this;
00234 return;
00235 }
00236
00237 MsgForDownload mfd = mMsgsForDownload.front(); mMsgsForDownload.pop_front();
00238
00239 mMsg = new KMMessage;
00240 mMsg->setHeaderField("X-UID",QString::number(mfd.uid));
00241 mMsg->setHeaderField("X-Length",QString::number(mfd.size));
00242 if( mfd.flags > 0 )
00243 KMFolderCachedImap::flagsToStatus(mMsg, mfd.flags);
00244 KURL url = mAccount->getUrl();
00245 url.setPath(mFolder->imapPath() + QString(";UID=%1;SECTION=FLAGS BODY.PEEK[]").arg(mfd.uid));
00246
00247 ImapAccountBase::jobData jd( url.url(), mFolder );
00248 mMsg->setTransferInProgress(true);
00249 KIO::SimpleJob *simpleJob = KIO::get(url, false, false);
00250 KIO::Scheduler::assignJobToSlave(mAccount->slave(), simpleJob);
00251 mAccount->insertJob(simpleJob, jd);
00252 connect(simpleJob, SIGNAL(processedSize(KIO::Job *, KIO::filesize_t)),
00253 this, SLOT(slotProcessedSize(KIO::Job *, KIO::filesize_t)));
00254 connect(simpleJob, SIGNAL(result(KIO::Job *)),
00255 this, SLOT(slotGetNextMessage(KIO::Job *)));
00256 connect(simpleJob, SIGNAL(data(KIO::Job *, const QByteArray &)),
00257 mFolder, SLOT(slotSimpleData(KIO::Job *, const QByteArray &)));
00258 }
00259
00260 void CachedImapJob::slotProcessedSize(KIO::Job *, KIO::filesize_t processed)
00261 {
00262 emit progress( mSentBytes + processed, mTotalBytes );
00263 }
00264
00265 void CachedImapJob::slotPutNextMessage()
00266 {
00267 mMsg = 0;
00268
00269
00270 if( !mMsgList.isEmpty() ) {
00271 mMsg = mMsgList.first();
00272 mMsgList.removeFirst();
00273 }
00274
00275
00276 while( mMsg == 0 && !mSerNumMsgList.isEmpty() ) {
00277 unsigned long serNum = mSerNumMsgList.first();
00278 mSerNumMsgList.pop_front();
00279
00280
00281 int i = 0;
00282 KMFolder* aFolder = 0;
00283 kmkernel->msgDict()->getLocation( serNum, &aFolder, &i );
00284 if( mFolder != aFolder )
00285
00286 continue;
00287 mMsg = mFolder->getMsg( i );
00288 }
00289
00290 if( !mMsg ) {
00291
00292 delete this;
00293 return;
00294 }
00295
00296 KURL url = mAccount->getUrl();
00297 QString flags = KMFolderImap::statusToFlags( mMsg->status() );
00298 url.setPath( mFolder->imapPath() + ";SECTION=" + flags );
00299
00300 ImapAccountBase::jobData jd( url.url(), mFolder );
00301
00302 QCString cstr(mMsg->asString());
00303 int a = cstr.find("\nX-UID: ");
00304 int b = cstr.find('\n', a);
00305 if (a != -1 && b != -1 && cstr.find("\n\n") > a) cstr.remove(a, b-a);
00306 mData.resize(cstr.length() + cstr.contains('\n'));
00307 unsigned int i = 0;
00308 for( char *ch = cstr.data(); *ch; ch++ ) {
00309 if ( *ch == '\n' ) {
00310 mData.at(i) = '\r';
00311 i++;
00312 }
00313 mData.at(i) = *ch; i++;
00314 }
00315 jd.data = mData;
00316
00317 mMsg->setTransferInProgress(true);
00318 KIO::SimpleJob *simpleJob = KIO::put(url, 0, false, false, false);
00319 KIO::Scheduler::assignJobToSlave(mAccount->slave(), simpleJob);
00320 mAccount->insertJob(simpleJob, jd);
00321 connect( simpleJob, SIGNAL( result(KIO::Job *) ),
00322 SLOT( slotPutMessageResult(KIO::Job *) ) );
00323 connect( simpleJob, SIGNAL( dataReq(KIO::Job *, QByteArray &) ),
00324 SLOT( slotPutMessageDataReq(KIO::Job *, QByteArray &) ) );
00325 connect( simpleJob, SIGNAL( data(KIO::Job *, const QByteArray &) ),
00326 mFolder, SLOT( slotSimpleData(KIO::Job *, const QByteArray &) ) );
00327 }
00328
00329
00330 void CachedImapJob::slotPutMessageDataReq(KIO::Job *job, QByteArray &data)
00331 {
00332 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
00333 if ( it == mAccount->jobsEnd() ) {
00334 delete this;
00335 return;
00336 }
00337 if ((*it).data.size() - (*it).offset > 0x8000) {
00338 data.duplicate((*it).data.data() + (*it).offset, 0x8000);
00339 (*it).offset += 0x8000;
00340 } else if ((*it).data.size() - (*it).offset > 0) {
00341 data.duplicate((*it).data.data() + (*it).offset,
00342 (*it).data.size() - (*it).offset);
00343 (*it).offset = (*it).data.size();
00344 } else
00345 data.resize(0);
00346 }
00347
00348
00349
00350 void CachedImapJob::slotPutMessageResult(KIO::Job *job)
00351 {
00352 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
00353 if ( it == mAccount->jobsEnd() ) {
00354 delete this;
00355 return;
00356 }
00357
00358 if ( job->error() ) {
00359 QStringList errors = job->detailedErrorStrings();
00360 QString myError = "<qt><p><b>" + i18n("Error while uploading message")
00361 + "</b></p><p>" + i18n("Could not upload the message %1 on the server from folder %2 with URL %3.").arg((*it).items[0]).arg(mFolder->name()).arg((*it).htmlURL())
00362 + "</p><p>" + i18n("This could be because you don't have permission to do this. The error message from the server communication is here:") + "</p>";
00363 KMessageBox::error( 0, myError + errors[1] + '\n' + errors[2], errors[0] );
00364 mAccount->removeJob(it);
00365 delete this;
00366 return;
00367 }
00368
00369 emit messageStored( mMsg );
00370 int i;
00371 if( ( i = mFolder->find(mMsg) ) != -1 ) {
00372 mFolder->removeMsg(i);
00373 }
00374 mMsg = NULL;
00375 mAccount->removeJob( it );
00376 slotPutNextMessage();
00377 }
00378
00379
00380 void CachedImapJob::slotAddNextSubfolder( KIO::Job * job )
00381 {
00382 if (job) {
00383 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
00384 if ( it == mAccount->jobsEnd() ) {
00385 delete this;
00386 return;
00387 }
00388
00389 if ( job->error() &&
00390 !static_cast<KMFolderCachedImap*>((*it).parent)->silentUpload() ) {
00391 QStringList errors = job->detailedErrorStrings();
00392 QString myError = "<qt><p><b>" + i18n("Error while uploading folder")
00393 + "</b></p><p>" + i18n("Could not make the folder %1 on the server.").arg((*it).items[0])
00394 + "</p><p>" + i18n("This could be because you don't 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>";
00395 KMessageBox::error( 0, myError + errors[1] + '\n' + errors[2],
00396 errors[0] );
00397 }
00398 static_cast<KMFolderCachedImap*>((*it).parent)->setSilentUpload( false );
00399 mAccount->removeJob( it );
00400
00401 if( job->error() ) {
00402 delete this;
00403 return;
00404 }
00405 }
00406
00407 if (mFolderList.isEmpty()) {
00408
00409 delete this;
00410 return;
00411 }
00412
00413 KMFolderCachedImap *folder = mFolderList.front();
00414 mFolderList.pop_front();
00415 KURL url = mAccount->getUrl();
00416 url.setPath(mFolder->imapPath() + folder->name());
00417
00418 ImapAccountBase::jobData jd( url.url(), folder );
00419 KIO::SimpleJob *simpleJob = KIO::mkdir(url);
00420 KIO::Scheduler::assignJobToSlave(mAccount->slave(), simpleJob);
00421 mAccount->insertJob(simpleJob, jd);
00422 connect( simpleJob, SIGNAL(result(KIO::Job *)),
00423 this, SLOT(slotAddNextSubfolder(KIO::Job *)) );
00424 }
00425
00426
00427 void CachedImapJob::slotDeleteNextFolder( KIO::Job *job )
00428 {
00429 if (job) {
00430 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
00431 if ( it == mAccount->jobsEnd() ) {
00432 delete this;
00433 return;
00434 }
00435 mAccount->removeJob(it);
00436
00437 if( job->error() ) {
00438 job->showErrorDialog( 0L );
00439 delete this;
00440 return;
00441 }
00442 }
00443
00444 if( mFolderPathList.isEmpty() ) {
00445
00446 delete this;
00447 return;
00448 }
00449
00450 QString folderPath = mFolderPathList.front(); mFolderPathList.pop_front();
00451 KURL url = mAccount->getUrl();
00452 url.setPath(folderPath);
00453 ImapAccountBase::jobData jd( url.url(), mFolder );
00454 KIO::SimpleJob *simpleJob = KIO::file_delete(url, false);
00455 KIO::Scheduler::assignJobToSlave(mAccount->slave(), simpleJob);
00456 mAccount->insertJob(simpleJob, jd);
00457 connect( simpleJob, SIGNAL( result(KIO::Job *) ),
00458 SLOT( slotDeleteNextFolder(KIO::Job *) ) );
00459 }
00460
00461 void CachedImapJob::checkUidValidity()
00462 {
00463 KURL url = mAccount->getUrl();
00464 url.setPath( mFolder->imapPath() + ";UID=0:0" );
00465
00466 ImapAccountBase::jobData jd( url.url(), mFolder );
00467
00468 KIO::SimpleJob *job = KIO::get( url, false, false );
00469 KIO::Scheduler::assignJobToSlave( mAccount->slave(), job );
00470 mAccount->insertJob( job, jd );
00471 connect( job, SIGNAL(result(KIO::Job *)),
00472 SLOT(slotCheckUidValidityResult(KIO::Job *)) );
00473 connect( job, SIGNAL(data(KIO::Job *, const QByteArray &)),
00474 mFolder, SLOT(slotSimpleData(KIO::Job *, const QByteArray &)));
00475 }
00476
00477 void CachedImapJob::slotCheckUidValidityResult(KIO::Job * job)
00478 {
00479 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
00480 if ( it == mAccount->jobsEnd() ) {
00481 delete this;
00482 return;
00483 }
00484
00485 if( job->error() ) {
00486 mAccount->removeJob(it);
00487 job->showErrorDialog( 0 );
00488 delete this;
00489 return;
00490 }
00491
00492
00493 QCString cstr((*it).data.data(), (*it).data.size() + 1);
00494 int a = cstr.find("X-uidValidity: ");
00495 if (a < 0) {
00496
00497
00498 kdDebug(5006) << "No uidvalidity available for folder "
00499 << mFolder->name() << endl;
00500 return;
00501 }
00502 int b = cstr.find("\r\n", a);
00503 if ( (b - a - 15) >= 0 ) {
00504 QString uidv = cstr.mid(a + 15, b - a - 15);
00505
00506
00507 if( !mFolder->uidValidity().isEmpty() && mFolder->uidValidity() != uidv ) {
00508
00509
00510 mFolder->expunge();
00511 mFolder->setLastUid( 0 );
00512 }
00513 } else
00514 kdDebug(5006) << "No uidvalidity available for folder "
00515 << mFolder->name() << endl;
00516
00517 mAccount->removeJob(it);
00518 delete this;
00519 }
00520
00521
00522 void CachedImapJob::renameFolder( const QString &newName )
00523 {
00524
00525 KURL urlSrc = mAccount->getUrl();
00526 urlSrc.setPath( mFolder->imapPath() );
00527
00528
00529 KURL urlDst = mAccount->getUrl();
00530 QString imapPath( mFolder->imapPath() );
00531
00532 imapPath.truncate( imapPath.length() - mFolder->name().length() - 1);
00533 imapPath += newName + '/';
00534 urlDst.setPath( imapPath );
00535
00536 ImapAccountBase::jobData jd( newName, mFolder );
00537 jd.path = imapPath;
00538
00539 KIO::SimpleJob *simpleJob = KIO::rename( urlSrc, urlDst, false );
00540 KIO::Scheduler::assignJobToSlave( mAccount->slave(), simpleJob );
00541 mAccount->insertJob( simpleJob, jd );
00542 connect( simpleJob, SIGNAL(result(KIO::Job *)),
00543 SLOT(slotRenameFolderResult(KIO::Job *)) );
00544 }
00545
00546 static void renameChildFolders( KMFolderDir* dir, const QString& oldPath,
00547 const QString& newPath )
00548 {
00549 if( dir ) {
00550 KMFolderNode *node = dir->first();
00551 while( node ) {
00552 if( !node->isDir() ) {
00553 KMFolderCachedImap* imapFolder =
00554 static_cast<KMFolderCachedImap*>(node);
00555 if ( !imapFolder->imapPath().isEmpty() )
00556
00557 if( imapFolder->imapPath().find( oldPath ) == 0 ) {
00558 QString p = imapFolder->imapPath();
00559 p = p.mid( oldPath.length() );
00560 p.prepend( newPath );
00561 imapFolder->setImapPath( p );
00562 renameChildFolders( imapFolder->child(), oldPath, newPath );
00563 }
00564 }
00565 node = dir->next();
00566 }
00567 }
00568 }
00569
00570 void CachedImapJob::slotRenameFolderResult( KIO::Job *job )
00571 {
00572 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
00573 if ( it == mAccount->jobsEnd() ) {
00574 delete this;
00575 return;
00576 }
00577
00578 if( job->error() ) {
00579 job->showErrorDialog( 0 );
00580 } else {
00581
00582
00583 QString oldName = mFolder->name();
00584 QString oldPath = mFolder->imapPath();
00585 mFolder->setImapPath( (*it).path );
00586 mFolder->KMFolder::rename( (*it).url );
00587
00588 if( oldPath.endsWith( "/" ) ) oldPath.truncate( oldPath.length() -1 );
00589 QString newPath = mFolder->imapPath();
00590 if( newPath.endsWith( "/" ) ) newPath.truncate( newPath.length() -1 );
00591 renameChildFolders( mFolder->child(), oldPath, newPath );
00592 kmkernel->dimapFolderMgr()->contentsChanged();
00593 }
00594
00595 mAccount->removeJob(it);
00596 delete this;
00597 }
00598
00599 void CachedImapJob::execute()
00600 {
00601 init();
00602 }
00603
00604 void CachedImapJob::expireMessages()
00605 {
00606
00607 }
00608
00609 }
00610
00611 #include "cachedimapjob.moc"