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
#ifdef HAVE_CONFIG_H
00033
#include <config.h>
00034
#endif
00035
00036
#include "imapjob.h"
00037
#include "kmfolderimap.h"
00038
#include "kmfolder.h"
00039
#include "kmmsgpart.h"
00040
#include "progressmanager.h"
00041
using KPIM::ProgressManager;
00042
00043
#include <kio/scheduler.h>
00044
#include <kdebug.h>
00045
#include <klocale.h>
00046
#include <mimelib/body.h>
00047
#include <mimelib/bodypart.h>
00048
#include <mimelib/string.h>
00049
00050
00051
namespace KMail {
00052
00053
00054 ImapJob::ImapJob( KMMessage *msg, JobType jt, KMFolderImap* folder,
00055
QString partSpecifier,
const AttachmentStrategy *as )
00056 : FolderJob( msg, jt, folder? folder->folder() : 0, partSpecifier ),
00057 mAttachmentStrategy( as ), mParentProgressItem(0)
00058 {
00059 }
00060
00061
00062 ImapJob::ImapJob(
QPtrList<KMMessage>& msgList,
QString sets, JobType jt,
00063 KMFolderImap* folder )
00064 : FolderJob( msgList, sets, jt, folder? folder->folder() : 0 ),
00065 mAttachmentStrategy ( 0 ), mParentProgressItem(0)
00066 {
00067 }
00068
00069
void ImapJob::init( JobType jt,
QString sets, KMFolderImap* folder,
00070
QPtrList<KMMessage>& msgList )
00071 {
00072 mJob = 0;
00073
00074 assert(jt == tGetMessage || folder);
00075 KMMessage* msg = msgList.first();
00076
00077
if ( !msg ) {
00078 deleteLater();
00079
return;
00080 }
00081 mType = jt;
00082 mDestFolder = folder? folder->folder() : 0;
00083
00084
if (folder) {
00085 folder->open();
00086 }
00087
KMFolder *msg_parent = msg->parent();
00088
if (msg_parent) {
00089
if (!folder || folder!= msg_parent->
storage()) {
00090 msg_parent->
open();
00091 }
00092 }
00093 mSrcFolder = msg_parent;
00094
00095
00096
00097
00098 KMAcctImap *account;
00099
if (folder) {
00100 account = folder->account();
00101 }
else {
00102 account = static_cast<KMFolderImap*>(msg_parent->storage())->account();
00103 }
00104
if ( !account ||
00105 account->makeConnection() == ImapAccountBase::Error ) {
00106 deleteLater();
00107
return;
00108 }
00109 account->mJobList.append(
this );
00110
if ( jt == tPutMessage )
00111 {
00112
00113 KURL url = account->getUrl();
00114
QString flags = KMFolderImap::statusToFlags( msg->status() );
00115 url.setPath( folder->imapPath() +
";SECTION=" + flags );
00116 ImapAccountBase::jobData jd;
00117 jd.parent = 0; jd.offset = 0; jd.done = 0;
00118 jd.total = msg->msgSizeServer();
00119 jd.msgList.append(msg);
00120
QCString cstr( msg->asString() );
00121
int a = cstr.find(
"\nX-UID: ");
00122
int b = cstr.find(
'\n', a);
00123
if (a != -1 && b != -1 && cstr.find(
"\n\n") > a) cstr.remove(a, b-a);
00124 mData.resize( cstr.length() + cstr.contains(
"\n" ) - cstr.contains(
"\r\n" ) );
00125
unsigned int i = 0;
00126
char prevChar =
'\0';
00127
00128
for (
char *ch = cstr.data(); *ch; ch++ )
00129 {
00130
if ( *ch ==
'\n' && (prevChar !=
'\r') ) {
00131 mData.at( i ) =
'\r';
00132 i++;
00133 }
00134 mData.at( i ) = *ch;
00135 prevChar = *ch;
00136 i++;
00137 }
00138 jd.data = mData;
00139 jd.progressItem = ProgressManager::createProgressItem(
00140 mParentProgressItem,
00141
"ImapJobUploading"+ProgressManager::getUniqueID(),
00142 i18n(
"Uploading message data"),
00143 i18n(
"Destination folder: ") + mDestFolder->prettyURL(),
00144
true,
00145 account->useSSL() || account->useTLS() );
00146 jd.progressItem->setTotalItems( jd.total );
00147 connect ( jd.progressItem, SIGNAL( progressItemCanceled( ProgressItem* ) ),
00148 account, SLOT( slotAbortRequested( ProgressItem* ) ) );
00149 KIO::SimpleJob *simpleJob = KIO::put( url, 0, FALSE, FALSE, FALSE );
00150 KIO::Scheduler::assignJobToSlave( account->slave(), simpleJob );
00151 mJob = simpleJob;
00152 account->insertJob( mJob, jd );
00153 connect( mJob, SIGNAL(result(KIO::Job *)),
00154 SLOT(slotPutMessageResult(KIO::Job *)) );
00155 connect( mJob, SIGNAL(dataReq(KIO::Job *,
QByteArray &)),
00156 SLOT(slotPutMessageDataReq(KIO::Job *,
QByteArray &)) );
00157 connect( mJob, SIGNAL(infoMessage(KIO::Job *,
const QString &)),
00158 SLOT(slotPutMessageInfoData(KIO::Job *,
const QString &)) );
00159 connect( mJob, SIGNAL(processedSize(KIO::Job *, KIO::filesize_t)),
00160 SLOT(slotProcessedSize(KIO::Job *, KIO::filesize_t)));
00161 }
00162
else if ( jt == tCopyMessage || jt == tMoveMessage )
00163 {
00164 KURL url = account->getUrl();
00165 KURL destUrl = account->getUrl();
00166 destUrl.setPath(folder->imapPath());
00167 KMFolderImap *imapDestFolder = static_cast<KMFolderImap*>(msg_parent->storage());
00168 url.setPath( imapDestFolder->imapPath() +
";UID=" + sets );
00169 ImapAccountBase::jobData jd;
00170 jd.parent = 0; jd.offset = 0;
00171 jd.total = 1; jd.done = 0;
00172 jd.msgList = msgList;
00173
00174
QByteArray packedArgs;
00175
QDataStream stream( packedArgs, IO_WriteOnly );
00176
00177 stream << (
int)
'C' << url << destUrl;
00178 jd.progressItem = ProgressManager::createProgressItem(
00179 mParentProgressItem,
00180
"ImapJobCopyMove"+ProgressManager::getUniqueID(),
00181 i18n(
"Server operation"),
00182 i18n(
"Source folder: ") + msg_parent->prettyURL()
00183 +
" - destination folder: " + mDestFolder->prettyURL(),
00184
true,
00185 account->useSSL() || account->useTLS() );
00186 jd.progressItem->setTotalItems( jd.total );
00187 connect ( jd.progressItem, SIGNAL( progressItemCanceled( ProgressItem* ) ),
00188 account, SLOT( slotAbortRequested( ProgressItem* ) ) );
00189 KIO::SimpleJob *simpleJob = KIO::special( url, packedArgs, FALSE );
00190 KIO::Scheduler::assignJobToSlave( account->slave(), simpleJob );
00191 mJob = simpleJob;
00192 account->insertJob( mJob, jd );
00193 connect( mJob, SIGNAL(result(KIO::Job *)),
00194 SLOT(slotCopyMessageResult(KIO::Job *)) );
00195
if ( jt == tMoveMessage )
00196 {
00197 connect( mJob, SIGNAL(infoMessage(KIO::Job *,
const QString &)),
00198 SLOT(slotCopyMessageInfoData(KIO::Job *,
const QString &)) );
00199 }
00200 }
00201
else {
00202 slotGetNextMessage();
00203 }
00204 }
00205
00206
00207
00208 ImapJob::~ImapJob()
00209 {
00210
if ( mDestFolder )
00211 {
00212 KMAcctImap *account = static_cast<KMFolderImap*>(mDestFolder->storage())->account();
00213
if ( account && mJob ) {
00214 ImapAccountBase::JobIterator it = account->findJob( mJob );
00215
if ( it != account->jobsEnd() ) {
00216
if( (*it).progressItem ) {
00217 (*it).progressItem->setComplete();
00218 (*it).progressItem = 0;
00219 }
00220
if ( !(*it).msgList.isEmpty() ) {
00221
for (
QPtrListIterator<KMMessage> mit( (*it).msgList ); mit.current(); ++mit )
00222 mit.current()->setTransferInProgress(
false );
00223 }
00224 }
00225 account->removeJob( mJob );
00226 }
00227 account->mJobList.remove(
this );
00228 mDestFolder->close();
00229 }
00230
00231
if ( mSrcFolder ) {
00232
if (!mDestFolder || mDestFolder != mSrcFolder) {
00233
if (! (mSrcFolder->folderType() == KMFolderTypeImap) )
return;
00234 KMAcctImap *account = static_cast<KMFolderImap*>(mSrcFolder->storage())->account();
00235
if ( account && mJob ) {
00236 ImapAccountBase::JobIterator it = account->findJob( mJob );
00237
if ( it != account->jobsEnd() ) {
00238
if( (*it).progressItem ) {
00239 (*it).progressItem->setComplete();
00240 (*it).progressItem = 0;
00241 }
00242
if ( !(*it).msgList.isEmpty() ) {
00243
for (
QPtrListIterator<KMMessage> mit( (*it).msgList ); mit.current(); ++mit )
00244 mit.current()->setTransferInProgress(
false );
00245 }
00246 }
00247 account->removeJob( mJob );
00248 }
00249 account->mJobList.remove(
this );
00250 }
00251 mSrcFolder->close();
00252 }
00253 }
00254
00255
00256
00257
void ImapJob::slotGetNextMessage()
00258 {
00259 KMMessage *msg = mMsgList.first();
00260 KMFolderImap *msgParent = static_cast<KMFolderImap*>(msg->storage());
00261 KMAcctImap *account = msgParent->account();
00262
if ( msg->UID() == 0 )
00263 {
00264 emit messageRetrieved( msg );
00265 account->mJobList.remove(
this );
00266 deleteLater();
00267
return;
00268 }
00269 KURL url = account->getUrl();
00270
QString path = msgParent->imapPath() +
";UID=" + QString::number(msg->UID());
00271 ImapAccountBase::jobData jd;
00272 jd.parent = 0; jd.offset = 0;
00273 jd.total = 1; jd.done = 0;
00274 jd.msgList.append( msg );
00275
if ( !mPartSpecifier.isEmpty() )
00276 {
00277
if ( mPartSpecifier.find (
"STRUCTURE", 0,
false) != -1 ) {
00278 path +=
";SECTION=STRUCTURE";
00279 }
else if ( mPartSpecifier ==
"HEADER" ) {
00280 path +=
";SECTION=HEADER";
00281 }
else {
00282 path +=
";SECTION=BODY.PEEK[" + mPartSpecifier +
"]";
00283 DwBodyPart * part = msg->findDwBodyPart( msg->getFirstDwBodyPart(), mPartSpecifier );
00284
if (part)
00285 jd.total = part->BodySize();
00286 }
00287 }
else {
00288 path +=
";SECTION=BODY.PEEK[]";
00289
if (msg->msgSizeServer() > 0)
00290 jd.total = msg->msgSizeServer();
00291 }
00292 url.setPath( path );
00293
00294
00295 msg->setTransferInProgress(
true );
00296 jd.progressItem = ProgressManager::createProgressItem(
00297 mParentProgressItem,
00298
"ImapJobDownloading"+ProgressManager::getUniqueID(),
00299 i18n(
"Downloading message data"),
00300 i18n(
"Message with subject: ") + msg->subject(),
00301
true,
00302 account->useSSL() || account->useTLS() );
00303 connect ( jd.progressItem, SIGNAL( progressItemCanceled( ProgressItem* ) ),
00304 account, SLOT( slotAbortRequested( ProgressItem* ) ) );
00305 jd.progressItem->setTotalItems( jd.total );
00306
00307 KIO::SimpleJob *simpleJob = KIO::get( url, FALSE, FALSE );
00308 KIO::Scheduler::assignJobToSlave( account->slave(), simpleJob );
00309 mJob = simpleJob;
00310 account->insertJob( mJob, jd );
00311
if ( mPartSpecifier.find(
"STRUCTURE", 0,
false ) != -1 )
00312 {
00313 connect( mJob, SIGNAL(result(KIO::Job *)),
00314
this, SLOT(slotGetBodyStructureResult(KIO::Job *)) );
00315 }
else {
00316 connect( mJob, SIGNAL(result(KIO::Job *)),
00317
this, SLOT(slotGetMessageResult(KIO::Job *)) );
00318 }
00319 connect( mJob, SIGNAL(data(KIO::Job *,
const QByteArray &)),
00320 msgParent, SLOT(slotSimpleData(KIO::Job *,
const QByteArray &)) );
00321
if ( jd.total > 1 )
00322 {
00323 connect(mJob, SIGNAL(processedSize(KIO::Job *, KIO::filesize_t)),
00324
this, SLOT(slotProcessedSize(KIO::Job *, KIO::filesize_t)));
00325 }
00326 }
00327
00328
00329
00330
void ImapJob::slotGetMessageResult( KIO::Job * job )
00331 {
00332 KMMessage *msg = mMsgList.first();
00333
if (!msg || !msg->parent() || !job) {
00334 deleteLater();
00335
return;
00336 }
00337 KMFolderImap* parent = static_cast<KMFolderImap*>(msg->storage());
00338
if (msg->transferInProgress())
00339 msg->setTransferInProgress(
false );
00340 KMAcctImap *account = parent->account();
00341
if ( !account ) {
00342 deleteLater();
00343
return;
00344 }
00345 ImapAccountBase::JobIterator it = account->findJob( job );
00346
if ( it == account->jobsEnd() )
return;
00347
00348
bool gotData =
true;
00349
if (job->error())
00350 {
00351
QString errorStr = i18n(
"Error while retrieving messages from the server." );
00352 account->handleJobError( job, errorStr );
00353
if ( (*it).progressItem )
00354 (*it).progressItem->setStatus( errorStr );
00355
return;
00356 }
else {
00357
if ((*it).data.size() > 0)
00358 {
00359 kdDebug(5006) <<
"ImapJob::slotGetMessageResult - retrieved part " << mPartSpecifier << endl;
00360
if ( mPartSpecifier.isEmpty() ||
00361 mPartSpecifier ==
"HEADER" )
00362 {
00363 uint size = msg->msgSizeServer();
00364
if ( size > 0 && mPartSpecifier.isEmpty() )
00365 (*it).done = size;
00366 ulong uid = msg->UID();
00367
00368
if ( mPartSpecifier.isEmpty() )
00369 msg->setComplete(
true );
00370
else
00371 msg->setReadyToShow(
false );
00372
00373 msg->fromByteArray( (*it).data );
00374
00375 msg->setUID(uid);
00376
if ( size > 0 && msg->msgSizeServer() == 0 )
00377 msg->setMsgSizeServer(size);
00378
00379 }
else {
00380
00381 msg->updateBodyPart( mPartSpecifier, (*it).data );
00382 msg->setReadyToShow(
true );
00383
00384
00385
if (msg->attachmentState() != KMMsgHasAttachment)
00386 msg->updateAttachmentState();
00387 }
00388 }
else {
00389 kdDebug(5006) <<
"ImapJob::slotGetMessageResult - got no data for " << mPartSpecifier << endl;
00390 gotData =
false;
00391 msg->setReadyToShow(
true );
00392
00393 msg->notify();
00394 }
00395 }
00396
if (account->slave()) {
00397 account->removeJob(it);
00398 account->mJobList.remove(
this);
00399 }
00400
00401
00402
if ( mPartSpecifier.isEmpty() ||
00403 mPartSpecifier ==
"HEADER" )
00404 {
00405
if ( gotData )
00406 emit messageRetrieved(msg);
00407
else
00408 {
00409
00410
00411 parent->ignoreJobsForMessage( msg );
00412
int idx = parent->find( msg );
00413
if (idx != -1) parent->removeMsg( idx,
true );
00414 emit messageRetrieved( 0 );
00415 }
00416 }
else {
00417 emit messageUpdated(msg, mPartSpecifier);
00418 }
00419 deleteLater();
00420 }
00421
00422
00423
void ImapJob::slotGetBodyStructureResult( KIO::Job * job )
00424 {
00425 KMMessage *msg = mMsgList.first();
00426
if (!msg || !msg->parent() || !job) {
00427 deleteLater();
00428
return;
00429 }
00430 KMFolderImap* parent = static_cast<KMFolderImap*>(msg->storage());
00431
if (msg->transferInProgress())
00432 msg->setTransferInProgress(
false );
00433 KMAcctImap *account = parent->account();
00434
if ( !account ) {
00435 deleteLater();
00436
return;
00437 }
00438 ImapAccountBase::JobIterator it = account->findJob( job );
00439
if ( it == account->jobsEnd() )
return;
00440
00441
00442
if (job->error())
00443 {
00444 account->handleJobError( job, i18n(
"Error while retrieving information on the structure of a message." ) );
00445
return;
00446 }
else {
00447
if ((*it).data.size() > 0)
00448 {
00449
QDataStream stream( (*it).data, IO_ReadOnly );
00450 account->handleBodyStructure(stream, msg, mAttachmentStrategy);
00451 }
00452 }
00453
if (account->slave()) {
00454 account->removeJob(it);
00455 account->mJobList.remove(
this);
00456 }
00457 deleteLater();
00458 }
00459
00460
00461
void ImapJob::slotPutMessageDataReq( KIO::Job *job,
QByteArray &data )
00462 {
00463 KMAcctImap *account = static_cast<KMFolderImap*>(mDestFolder->storage())->account();
00464 ImapAccountBase::JobIterator it = account->findJob( job );
00465
if ( it == account->jobsEnd() )
return;
00466
00467
if ((*it).data.size() - (*it).offset > 0x8000)
00468 {
00469 data.duplicate((*it).data.data() + (*it).offset, 0x8000);
00470 (*it).offset += 0x8000;
00471 }
00472
else if ((*it).data.size() - (*it).offset > 0)
00473 {
00474 data.duplicate((*it).data.data() + (*it).offset, (*it).data.size() - (*it).offset);
00475 (*it).offset = (*it).data.size();
00476 }
else data.resize(0);
00477 }
00478
00479
00480
00481
void ImapJob::slotPutMessageResult( KIO::Job *job )
00482 {
00483 KMMessage *msg = mMsgList.first();
00484 KMAcctImap *account = static_cast<KMFolderImap*>(mDestFolder->storage())->account();
00485 ImapAccountBase::JobIterator it = account->findJob( job );
00486
if ( it == account->jobsEnd() )
return;
00487
if (job->error())
00488 {
00489 account->handlePutError( job, *it, mDestFolder );
00490
if ( (*it).progressItem )
00491 (*it).progressItem->setStatus(
"Uploading message data failed.");
00492
return;
00493 }
else {
00494
if ( !(*it).msgList.isEmpty() )
00495 {
00496 emit messageStored((*it).msgList.last());
00497 (*it).msgList.removeLast();
00498 }
else if (msg)
00499 {
00500 emit messageStored(msg);
00501 }
00502 msg = 0;
00503
if ( (*it).progressItem )
00504 (*it).progressItem->setStatus(
"Uploading message data completed.");
00505 }
00506
if (account->slave()) {
00507 account->removeJob(it);
00508 account->mJobList.remove(
this);
00509 }
00510 deleteLater();
00511 }
00512
00513
00514
void ImapJob::slotCopyMessageInfoData(KIO::Job * job,
const QString & data)
00515 {
00516 KMFolderImap * imapFolder = static_cast<KMFolderImap*>(mDestFolder->storage());
00517 KMAcctImap *account = imapFolder->account();
00518 ImapAccountBase::JobIterator it = account->findJob( job );
00519
if ( it == account->jobsEnd() )
return;
00520
00521
if (data.find(
"UID") != -1)
00522 {
00523
00524
QString oldUid = data.section(
' ', 1, 1);
00525
QString newUid = data.section(
' ', 2, 2);
00526
00527
00528
QValueList<ulong> olduids = KMFolderImap::splitSets(oldUid);
00529
QValueList<ulong> newuids = KMFolderImap::splitSets(newUid);
00530
00531
int index = -1;
00532
if ( !(*it).msgList.isEmpty() )
00533 {
00534 KMMessage * msg;
00535
for ( msg = (*it).msgList.first(); msg; msg = (*it).msgList.next() )
00536 {
00537 ulong uid = msg->UID();
00538 index = olduids.findIndex(uid);
00539
if (index > -1)
00540 {
00541
00542
const ulong * sernum = (ulong *)msg->getMsgSerNum();
00543 imapFolder->insertUidSerNumEntry(newuids[index], sernum);
00544 }
00545 }
00546 }
else if (mMsgList.first()) {
00547 ulong uid = mMsgList.first()->UID();
00548 index = olduids.findIndex(uid);
00549
if (index > -1)
00550 {
00551
00552
const ulong * sernum = (ulong *)mMsgList.first()->getMsgSerNum();
00553 imapFolder->insertUidSerNumEntry(newuids[index], sernum);
00554 }
00555 }
00556 }
00557 }
00558
00559
00560
void ImapJob::slotPutMessageInfoData(KIO::Job *job,
const QString &data)
00561 {
00562 KMFolderImap * imapFolder = static_cast<KMFolderImap*>(mDestFolder->storage());
00563 KMAcctImap *account = imapFolder->account();
00564 ImapAccountBase::JobIterator it = account->findJob( job );
00565
if ( it == account->jobsEnd() )
return;
00566
00567
if (data.find(
"UID") != -1)
00568 {
00569 ulong uid = (data.right(data.length()-4)).toInt();
00570
00571
if ( !(*it).msgList.isEmpty() )
00572 {
00573
const ulong * sernum = (ulong *)(*it).msgList.last()->getMsgSerNum();
00574 imapFolder->insertUidSerNumEntry(uid, sernum);
00575 }
else if (mMsgList.first())
00576 {
00577
const ulong * sernum = (ulong *)mMsgList.first()->getMsgSerNum();
00578 imapFolder->insertUidSerNumEntry(uid, sernum);
00579 }
00580 }
00581 }
00582
00583
00584
00585
void ImapJob::slotCopyMessageResult( KIO::Job *job )
00586 {
00587 KMAcctImap *account = static_cast<KMFolderImap*>(mDestFolder->storage())->account();
00588 ImapAccountBase::JobIterator it = account->findJob( job );
00589
if ( it == account->jobsEnd() )
return;
00590
00591
if (job->error())
00592 {
00593 account->handleJobError( job, i18n(
"Error while copying messages.") );
00594
return;
00595 }
else {
00596
if ( !(*it).msgList.isEmpty() )
00597 {
00598 emit messageCopied((*it).msgList);
00599 }
else if (mMsgList.first()) {
00600 emit messageCopied(mMsgList.first());
00601 }
00602 }
00603
if (account->slave()) {
00604 account->removeJob(it);
00605 account->mJobList.remove(
this);
00606 }
00607 deleteLater();
00608 }
00609
00610
00611
void ImapJob::execute()
00612 {
00613 init( mType, mSets, mDestFolder?
00614 dynamic_cast<KMFolderImap*>( mDestFolder->storage() ):0, mMsgList );
00615 }
00616
00617
00618
void ImapJob::setParentFolder(
const KMFolderImap* parent )
00619 {
00620 mParentFolder = const_cast<KMFolderImap*>( parent );
00621 }
00622
00623
00624
void ImapJob::slotProcessedSize(KIO::Job * job, KIO::filesize_t processed)
00625 {
00626 KMMessage *msg = mMsgList.first();
00627
if (!msg || !job) {
00628
return;
00629 }
00630 KMFolderImap* parent = 0;
00631
if ( msg->parent() && msg->parent()->folderType() == KMFolderTypeImap )
00632 parent = static_cast<KMFolderImap*>(msg->parent()->storage());
00633
else if (mDestFolder)
00634 parent = static_cast<KMFolderImap*>(mDestFolder->storage());
00635
if (!parent)
return;
00636 KMAcctImap *account = parent->account();
00637
if ( !account )
return;
00638 ImapAccountBase::JobIterator it = account->findJob( job );
00639
if ( it == account->jobsEnd() )
return;
00640 (*it).done = processed;
00641
if ( (*it).progressItem ) {
00642 (*it).progressItem->setCompletedItems( processed );
00643 (*it).progressItem->updateProgress();
00644 }
00645 emit progress( (*it).done, (*it).total );
00646 }
00647
00648 }
00649
00650
#include "imapjob.moc"