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
00374 size_t dataSize = (*it).data.size();
00375 dataSize =
FolderStorage::crlf2lf( (*it).data.data(), dataSize );
00376 (*it).data.resize( dataSize );
00377
00378 msg->fromByteArray( (*it).data );
00379
00380 msg->setUID(uid);
00381
if ( size > 0 && msg->msgSizeServer() == 0 )
00382 msg->setMsgSizeServer(size);
00383
00384 }
else {
00385
00386 msg->updateBodyPart( mPartSpecifier, (*it).data );
00387 msg->setReadyToShow(
true );
00388
00389
00390
if (msg->attachmentState() != KMMsgHasAttachment)
00391 msg->updateAttachmentState();
00392 }
00393 }
else {
00394 kdDebug(5006) <<
"ImapJob::slotGetMessageResult - got no data for " << mPartSpecifier << endl;
00395 gotData =
false;
00396 msg->setReadyToShow(
true );
00397
00398 msg->notify();
00399 }
00400 }
00401
if (account->slave()) {
00402 account->removeJob(it);
00403 account->mJobList.remove(
this);
00404 }
00405
00406
00407
if ( mPartSpecifier.isEmpty() ||
00408 mPartSpecifier ==
"HEADER" )
00409 {
00410
if ( gotData )
00411 emit messageRetrieved(msg);
00412
else
00413 {
00414
00415
00416 parent->ignoreJobsForMessage( msg );
00417
int idx = parent->find( msg );
00418
if (idx != -1) parent->removeMsg( idx,
true );
00419 emit messageRetrieved( 0 );
00420 }
00421 }
else {
00422 emit messageUpdated(msg, mPartSpecifier);
00423 }
00424 deleteLater();
00425 }
00426
00427
00428
void ImapJob::slotGetBodyStructureResult( KIO::Job * job )
00429 {
00430 KMMessage *msg = mMsgList.first();
00431
if (!msg || !msg->parent() || !job) {
00432 deleteLater();
00433
return;
00434 }
00435 KMFolderImap* parent = static_cast<KMFolderImap*>(msg->storage());
00436
if (msg->transferInProgress())
00437 msg->setTransferInProgress(
false );
00438 KMAcctImap *account = parent->account();
00439
if ( !account ) {
00440 deleteLater();
00441
return;
00442 }
00443 ImapAccountBase::JobIterator it = account->findJob( job );
00444
if ( it == account->jobsEnd() )
return;
00445
00446
00447
if (job->error())
00448 {
00449 account->handleJobError( job, i18n(
"Error while retrieving information on the structure of a message." ) );
00450
return;
00451 }
else {
00452
if ((*it).data.size() > 0)
00453 {
00454
QDataStream stream( (*it).data, IO_ReadOnly );
00455 account->handleBodyStructure(stream, msg, mAttachmentStrategy);
00456 }
00457 }
00458
if (account->slave()) {
00459 account->removeJob(it);
00460 account->mJobList.remove(
this);
00461 }
00462 deleteLater();
00463 }
00464
00465
00466
void ImapJob::slotPutMessageDataReq( KIO::Job *job,
QByteArray &data )
00467 {
00468 KMAcctImap *account = static_cast<KMFolderImap*>(mDestFolder->storage())->account();
00469 ImapAccountBase::JobIterator it = account->findJob( job );
00470
if ( it == account->jobsEnd() )
return;
00471
00472
if ((*it).data.size() - (*it).offset > 0x8000)
00473 {
00474 data.duplicate((*it).data.data() + (*it).offset, 0x8000);
00475 (*it).offset += 0x8000;
00476 }
00477
else if ((*it).data.size() - (*it).offset > 0)
00478 {
00479 data.duplicate((*it).data.data() + (*it).offset, (*it).data.size() - (*it).offset);
00480 (*it).offset = (*it).data.size();
00481 }
else data.resize(0);
00482 }
00483
00484
00485
00486
void ImapJob::slotPutMessageResult( KIO::Job *job )
00487 {
00488 KMMessage *msg = mMsgList.first();
00489 KMAcctImap *account = static_cast<KMFolderImap*>(mDestFolder->storage())->account();
00490 ImapAccountBase::JobIterator it = account->findJob( job );
00491
if ( it == account->jobsEnd() )
return;
00492
if (job->error())
00493 {
00494 account->handlePutError( job, *it, mDestFolder );
00495
if ( (*it).progressItem )
00496 (*it).progressItem->setStatus(
"Uploading message data failed.");
00497
return;
00498 }
else {
00499
if ( !(*it).msgList.isEmpty() )
00500 {
00501 emit messageStored((*it).msgList.last());
00502 (*it).msgList.removeLast();
00503 }
else if (msg)
00504 {
00505 emit messageStored(msg);
00506 }
00507 msg = 0;
00508
if ( (*it).progressItem )
00509 (*it).progressItem->setStatus(
"Uploading message data completed.");
00510 }
00511
if (account->slave()) {
00512 account->removeJob(it);
00513 account->mJobList.remove(
this);
00514 }
00515 deleteLater();
00516 }
00517
00518
00519
void ImapJob::slotCopyMessageInfoData(KIO::Job * job,
const QString & data)
00520 {
00521 KMFolderImap * imapFolder = static_cast<KMFolderImap*>(mDestFolder->storage());
00522 KMAcctImap *account = imapFolder->account();
00523 ImapAccountBase::JobIterator it = account->findJob( job );
00524
if ( it == account->jobsEnd() )
return;
00525
00526
if (data.find(
"UID") != -1)
00527 {
00528
00529
QString oldUid = data.section(
' ', 1, 1);
00530
QString newUid = data.section(
' ', 2, 2);
00531
00532
00533
QValueList<ulong> olduids = KMFolderImap::splitSets(oldUid);
00534
QValueList<ulong> newuids = KMFolderImap::splitSets(newUid);
00535
00536
int index = -1;
00537
if ( !(*it).msgList.isEmpty() )
00538 {
00539 KMMessage * msg;
00540
for ( msg = (*it).msgList.first(); msg; msg = (*it).msgList.next() )
00541 {
00542 ulong uid = msg->UID();
00543 index = olduids.findIndex(uid);
00544
if (index > -1)
00545 {
00546
00547
const ulong * sernum = (ulong *)msg->getMsgSerNum();
00548 imapFolder->insertUidSerNumEntry(newuids[index], sernum);
00549 }
00550 }
00551 }
else if (mMsgList.first()) {
00552 ulong uid = mMsgList.first()->UID();
00553 index = olduids.findIndex(uid);
00554
if (index > -1)
00555 {
00556
00557
const ulong * sernum = (ulong *)mMsgList.first()->getMsgSerNum();
00558 imapFolder->insertUidSerNumEntry(newuids[index], sernum);
00559 }
00560 }
00561 }
00562 }
00563
00564
00565
void ImapJob::slotPutMessageInfoData(KIO::Job *job,
const QString &data)
00566 {
00567 KMFolderImap * imapFolder = static_cast<KMFolderImap*>(mDestFolder->storage());
00568 KMAcctImap *account = imapFolder->account();
00569 ImapAccountBase::JobIterator it = account->findJob( job );
00570
if ( it == account->jobsEnd() )
return;
00571
00572
if (data.find(
"UID") != -1)
00573 {
00574 ulong uid = (data.right(data.length()-4)).toInt();
00575
00576
if ( !(*it).msgList.isEmpty() )
00577 {
00578
const ulong * sernum = (ulong *)(*it).msgList.last()->getMsgSerNum();
00579 imapFolder->insertUidSerNumEntry(uid, sernum);
00580 }
else if (mMsgList.first())
00581 {
00582
const ulong * sernum = (ulong *)mMsgList.first()->getMsgSerNum();
00583 imapFolder->insertUidSerNumEntry(uid, sernum);
00584 }
00585 }
00586 }
00587
00588
00589
00590
void ImapJob::slotCopyMessageResult( KIO::Job *job )
00591 {
00592 KMAcctImap *account = static_cast<KMFolderImap*>(mDestFolder->storage())->account();
00593 ImapAccountBase::JobIterator it = account->findJob( job );
00594
if ( it == account->jobsEnd() )
return;
00595
00596
if (job->error())
00597 {
00598 account->handleJobError( job, i18n(
"Error while copying messages.") );
00599
return;
00600 }
else {
00601
if ( !(*it).msgList.isEmpty() )
00602 {
00603 emit messageCopied((*it).msgList);
00604 }
else if (mMsgList.first()) {
00605 emit messageCopied(mMsgList.first());
00606 }
00607 }
00608
if (account->slave()) {
00609 account->removeJob(it);
00610 account->mJobList.remove(
this);
00611 }
00612 deleteLater();
00613 }
00614
00615
00616
void ImapJob::execute()
00617 {
00618 init( mType, mSets, mDestFolder?
00619 dynamic_cast<KMFolderImap*>( mDestFolder->storage() ):0, mMsgList );
00620 }
00621
00622
00623
void ImapJob::setParentFolder(
const KMFolderImap* parent )
00624 {
00625 mParentFolder = const_cast<KMFolderImap*>( parent );
00626 }
00627
00628
00629
void ImapJob::slotProcessedSize(KIO::Job * job, KIO::filesize_t processed)
00630 {
00631 KMMessage *msg = mMsgList.first();
00632
if (!msg || !job) {
00633
return;
00634 }
00635 KMFolderImap* parent = 0;
00636
if ( msg->parent() && msg->parent()->folderType() == KMFolderTypeImap )
00637 parent = static_cast<KMFolderImap*>(msg->parent()->storage());
00638
else if (mDestFolder)
00639 parent = static_cast<KMFolderImap*>(mDestFolder->storage());
00640
if (!parent)
return;
00641 KMAcctImap *account = parent->account();
00642
if ( !account )
return;
00643 ImapAccountBase::JobIterator it = account->findJob( job );
00644
if ( it == account->jobsEnd() )
return;
00645 (*it).done = processed;
00646
if ( (*it).progressItem ) {
00647 (*it).progressItem->setCompletedItems( processed );
00648 (*it).progressItem->updateProgress();
00649 }
00650 emit progress( (*it).done, (*it).total );
00651 }
00652
00653 }
00654
00655
#include "imapjob.moc"