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 if ( (*it).progressItem )
00353 (*it).progressItem->setStatus( errorStr );
00354 account->handleJobError( job, 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 if ( (*it).progressItem )
00495 (*it).progressItem->setStatus( i18n("Uploading message data failed.") );
00496 account->handlePutError( job, *it, mDestFolder );
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( i18n("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"