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"