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 "kmmsgpart.h"
00039
00040 #include <kio/scheduler.h>
00041 #include <kdebug.h>
00042 #include <mimelib/body.h>
00043 #include <mimelib/bodypart.h>
00044 #include <mimelib/string.h>
00045
00046
00047 namespace KMail {
00048
00049
00050 ImapJob::ImapJob( KMMessage *msg, JobType jt, KMFolderImap* folder,
00051 QString partSpecifier, const AttachmentStrategy *as )
00052 : FolderJob( msg, jt, folder, partSpecifier ),
00053 mAttachmentStrategy( as )
00054 {
00055 }
00056
00057
00058 ImapJob::ImapJob( QPtrList<KMMessage>& msgList, QString sets, JobType jt,
00059 KMFolderImap* folder )
00060 : FolderJob( msgList, sets, jt, folder ),
00061 mAttachmentStrategy ( 0 )
00062 {
00063 }
00064
00065 void ImapJob::init( JobType jt, QString sets, KMFolderImap* folder,
00066 QPtrList<KMMessage>& msgList )
00067 {
00068 mJob = 0;
00069 assert(jt == tGetMessage || folder);
00070 KMMessage* msg = msgList.first();
00071 mType = jt;
00072 mDestFolder = folder;
00073
00074 if (folder) {
00075 folder->open();
00076 }
00077 KMFolder *msg_parent = msg->parent();
00078 if (msg_parent) {
00079 if (!folder || folder!= msg_parent) {
00080 msg_parent->open();
00081 }
00082 }
00083 mSrcFolder = msg_parent;
00084
00085
00086
00087
00088 KMAcctImap *account;
00089 if (folder) {
00090 account = folder->account();
00091 } else {
00092 account = static_cast<KMFolderImap*>(msg_parent)->account();
00093 }
00094 if ( !account ||
00095 account->makeConnection() == ImapAccountBase::Error ) {
00096 deleteLater();
00097 return;
00098 }
00099 account->mJobList.append( this );
00100 if ( jt == tPutMessage )
00101 {
00102
00103 KURL url = account->getUrl();
00104 QString flags = KMFolderImap::statusToFlags( msg->status() );
00105 url.setPath( folder->imapPath() + ";SECTION=" + flags );
00106 ImapAccountBase::jobData jd;
00107 jd.parent = 0; jd.offset = 0;
00108 jd.total = 1; jd.done = 0;
00109 jd.msgList.append(msg);
00110 QCString cstr( msg->asString() );
00111 int a = cstr.find( "\nX-UID: " );
00112 int b = cstr.find( "\n", a );
00113 if ( a != -1 && b != -1 && cstr.find( "\n\n" ) > a ) cstr.remove( a, b-a );
00114 mData.resize( cstr.length() + cstr.contains( "\n" ) - cstr.contains( "\r\n" ) );
00115 unsigned int i = 0;
00116 char prevChar = '\0';
00117
00118 for ( char *ch = cstr.data(); *ch; ch++ )
00119 {
00120 if ( *ch == '\n' && (prevChar != '\r') ) {
00121 mData.at( i ) = '\r';
00122 i++;
00123 }
00124 mData.at( i ) = *ch;
00125 prevChar = *ch;
00126 i++;
00127 }
00128 jd.data = mData;
00129 KIO::SimpleJob *simpleJob = KIO::put( url, 0, FALSE, FALSE, FALSE );
00130 KIO::Scheduler::assignJobToSlave( account->slave(), simpleJob );
00131 mJob = simpleJob;
00132 account->insertJob( mJob, jd );
00133 connect( mJob, SIGNAL(result(KIO::Job *)),
00134 SLOT(slotPutMessageResult(KIO::Job *)) );
00135 connect( mJob, SIGNAL(dataReq(KIO::Job *, QByteArray &)),
00136 SLOT(slotPutMessageDataReq(KIO::Job *, QByteArray &)) );
00137 connect( mJob, SIGNAL(infoMessage(KIO::Job *, const QString &)),
00138 SLOT(slotPutMessageInfoData(KIO::Job *, const QString &)) );
00139 }
00140 else if ( jt == tCopyMessage || jt == tMoveMessage )
00141 {
00142 KURL url = account->getUrl();
00143 KURL destUrl = account->getUrl();
00144 destUrl.setPath(folder->imapPath());
00145 KMFolderImap *imapDestFolder = static_cast<KMFolderImap*>(msg_parent);
00146 url.setPath( imapDestFolder->imapPath() + ";UID=" + sets );
00147 ImapAccountBase::jobData jd;
00148 jd.parent = 0; mOffset = 0;
00149 jd.total = 1; jd.done = 0;
00150 jd.msgList = msgList;
00151
00152 QByteArray packedArgs;
00153 QDataStream stream( packedArgs, IO_WriteOnly );
00154
00155 stream << (int) 'C' << url << destUrl;
00156
00157 KIO::SimpleJob *simpleJob = KIO::special( url, packedArgs, FALSE );
00158 KIO::Scheduler::assignJobToSlave( account->slave(), simpleJob );
00159 mJob = simpleJob;
00160 account->insertJob( mJob, jd );
00161 connect( mJob, SIGNAL(result(KIO::Job *)),
00162 SLOT(slotCopyMessageResult(KIO::Job *)) );
00163 if ( jt == tMoveMessage )
00164 {
00165 connect( mJob, SIGNAL(infoMessage(KIO::Job *, const QString &)),
00166 SLOT(slotCopyMessageInfoData(KIO::Job *, const QString &)) );
00167 }
00168 } else {
00169 slotGetNextMessage();
00170 }
00171 }
00172
00173
00174
00175 ImapJob::~ImapJob()
00176 {
00177
00178 if ( mDestFolder )
00179 {
00180 KMAcctImap *account = static_cast<KMFolderImap*>(mDestFolder)->account();
00181 if ( account )
00182 account->mJobList.remove(this);
00183 if ( account && mJob )
00184 {
00185 ImapAccountBase::JobIterator it = account->findJob( mJob );
00186 if ( it != account->jobsEnd() && !(*it).msgList.isEmpty() )
00187 {
00188 for ( QPtrListIterator<KMMessage> mit( (*it).msgList ); mit.current(); ++mit )
00189 mit.current()->setTransferInProgress(false);
00190 }
00191 }
00192
00193 mDestFolder->close();
00194 }
00195
00196 if (mSrcFolder) {
00197 if (!mDestFolder || mDestFolder != mSrcFolder) {
00198 if (! (mSrcFolder->folderType() == KMFolderTypeImap) ) return;
00199 KMAcctImap *account = static_cast<KMFolderImap*>(mSrcFolder)->account();
00200 if ( account )
00201 account->mJobList.remove(this);
00202 if ( account && mJob )
00203 {
00204 ImapAccountBase::JobIterator it = account->findJob( mJob );
00205 if ( it != account->jobsEnd() && !(*it).msgList.isEmpty() )
00206 {
00207 for ( QPtrListIterator<KMMessage> mit( (*it).msgList ); mit.current(); ++mit )
00208 mit.current()->setTransferInProgress(false);
00209 }
00210 }
00211 }
00212
00213 mSrcFolder->close();
00214 }
00215 }
00216
00217
00218
00219 void ImapJob::slotGetNextMessage()
00220 {
00221 KMMessage *msg = mMsgList.first();
00222 KMFolderImap *msgParent = static_cast<KMFolderImap*>(msg->parent());
00223 KMAcctImap *account = msgParent->account();
00224 if ( msg->headerField("X-UID").isEmpty() )
00225 {
00226 emit messageRetrieved( msg );
00227 account->mJobList.remove( this );
00228 deleteLater();
00229 return;
00230 }
00231 KURL url = account->getUrl();
00232 QString path = msgParent->imapPath() + ";UID=" + msg->headerField("X-UID");
00233 if ( !mPartSpecifier.isEmpty() )
00234 {
00235 if ( mPartSpecifier.find ("STRUCTURE", 0, false) != -1 ) {
00236 path += ";SECTION=STRUCTURE";
00237 } else if ( mPartSpecifier == "HEADER" ) {
00238 path += ";SECTION=HEADER";
00239 } else {
00240 path += ";SECTION=BODY.PEEK[" + mPartSpecifier +"]";
00241 }
00242 } else {
00243 path += ";SECTION=BODY.PEEK[]";
00244 }
00245 url.setPath( path );
00246
00247 ImapAccountBase::jobData jd;
00248 jd.parent = 0;
00249 jd.total = 1; jd.done = 0;
00250
00251 msg->setTransferInProgress( true );
00252 KIO::SimpleJob *simpleJob = KIO::get( url, FALSE, FALSE );
00253 KIO::Scheduler::assignJobToSlave( account->slave(), simpleJob );
00254 mJob = simpleJob;
00255 account->insertJob( mJob, jd );
00256 if ( mPartSpecifier.find( "STRUCTURE", 0, false ) != -1 )
00257 {
00258 connect( mJob, SIGNAL(result(KIO::Job *)),
00259 this, SLOT(slotGetBodyStructureResult(KIO::Job *)) );
00260 } else {
00261 connect( mJob, SIGNAL(result(KIO::Job *)),
00262 this, SLOT(slotGetMessageResult(KIO::Job *)) );
00263 }
00264 connect( mJob, SIGNAL(data(KIO::Job *, const QByteArray &)),
00265 msgParent, SLOT(slotSimpleData(KIO::Job *, const QByteArray &)) );
00266 }
00267
00268
00269
00270 void ImapJob::slotGetMessageResult( KIO::Job * job )
00271 {
00272 KMMessage *msg = mMsgList.first();
00273 if (!msg || !msg->parent() || !job) {
00274 deleteLater();
00275 return;
00276 }
00277 KMFolderImap* parent = static_cast<KMFolderImap*>(msg->parent());
00278 if (msg->transferInProgress())
00279 msg->setTransferInProgress( false );
00280 KMAcctImap *account = parent->account();
00281 if ( !account ) {
00282 deleteLater();
00283 return;
00284 }
00285 ImapAccountBase::JobIterator it = account->findJob( job );
00286 if ( it == account->jobsEnd() ) return;
00287
00288 bool gotData = true;
00289 if (job->error())
00290 {
00291 account->slotSlaveError( account->slave(), job->error(), job->errorText() );
00292 return;
00293 } else {
00294 if ((*it).data.size() > 0)
00295 {
00296 kdDebug(5006) << "ImapJob::slotGetMessageResult - retrieved part " << mPartSpecifier << endl;
00297 if ( mPartSpecifier.isEmpty() ||
00298 mPartSpecifier == "HEADER" )
00299 {
00300 uint size = msg->headerField("X-Length").toUInt();
00301 QString uid = msg->headerField("X-UID");
00302 msg->fromByteArray( (*it).data );
00303 msg->setHeaderField("X-UID",uid);
00304
00305 if ( size > 0 ) msg->setMsgLength(size);
00306 if ( mPartSpecifier.isEmpty() )
00307 msg->setComplete( true );
00308 else
00309 msg->setReadyToShow( false );
00310 } else {
00311
00312 msg->updateBodyPart( mPartSpecifier, (*it).data );
00313 msg->setReadyToShow( true );
00314 }
00315 } else {
00316 kdDebug(5006) << "ImapJob::slotGetMessageResult - got no data for " << mPartSpecifier << endl;
00317 gotData = false;
00318 msg->setReadyToShow( true );
00319
00320 msg->notify();
00321 }
00322 }
00323 if (account->slave()) {
00324 account->removeJob(it);
00325 account->mJobList.remove(this);
00326 }
00327
00328
00329 if ( mPartSpecifier.isEmpty() ||
00330 mPartSpecifier == "HEADER" )
00331 {
00332 if ( gotData )
00333 emit messageRetrieved(msg);
00334 else
00335 {
00336
00337
00338 parent->ignoreJobsForMessage( msg );
00339 int idx = parent->find( msg );
00340 if (idx != -1) parent->removeMsg( idx, true );
00341 emit messageRetrieved( 0 );
00342 }
00343 } else {
00344 emit messageUpdated(msg, mPartSpecifier);
00345 }
00346 deleteLater();
00347 }
00348
00349
00350 void ImapJob::slotGetBodyStructureResult( KIO::Job * job )
00351 {
00352 KMMessage *msg = mMsgList.first();
00353 if (!msg || !msg->parent() || !job) {
00354 deleteLater();
00355 return;
00356 }
00357 KMFolderImap* parent = static_cast<KMFolderImap*>(msg->parent());
00358 if (msg->transferInProgress())
00359 msg->setTransferInProgress( false );
00360 KMAcctImap *account = parent->account();
00361 if ( !account ) {
00362 deleteLater();
00363 return;
00364 }
00365 ImapAccountBase::JobIterator it = account->findJob( job );
00366 if ( it == account->jobsEnd() ) return;
00367
00368
00369 if (job->error())
00370 {
00371 account->slotSlaveError( account->slave(), job->error(),
00372 job->errorText() );
00373 return;
00374 } else {
00375 if ((*it).data.size() > 0)
00376 {
00377 QDataStream stream( (*it).data, IO_ReadOnly );
00378 account->handleBodyStructure(stream, msg, mAttachmentStrategy);
00379 }
00380 }
00381 if (account->slave()) {
00382 account->removeJob(it);
00383 account->mJobList.remove(this);
00384 }
00385 deleteLater();
00386 }
00387
00388
00389 void ImapJob::slotPutMessageDataReq( KIO::Job *job, QByteArray &data )
00390 {
00391 KMAcctImap *account = static_cast<KMFolderImap*>(mDestFolder)->account();
00392 ImapAccountBase::JobIterator it = account->findJob( job );
00393 if ( it == account->jobsEnd() ) return;
00394
00395 if ((*it).data.size() - (*it).offset > 0x8000)
00396 {
00397 data.duplicate((*it).data.data() + (*it).offset, 0x8000);
00398 (*it).offset += 0x8000;
00399 }
00400 else if ((*it).data.size() - (*it).offset > 0)
00401 {
00402 data.duplicate((*it).data.data() + (*it).offset, (*it).data.size() - (*it).offset);
00403 (*it).offset = (*it).data.size();
00404 } else data.resize(0);
00405 }
00406
00407
00408
00409 void ImapJob::slotPutMessageResult( KIO::Job *job )
00410 {
00411 KMMessage *msg = mMsgList.first();
00412 KMAcctImap *account = static_cast<KMFolderImap*>(mDestFolder)->account();
00413 ImapAccountBase::JobIterator it = account->findJob( job );
00414 if ( it == account->jobsEnd() ) return;
00415
00416 if (job->error())
00417 {
00418 account->slotSlaveError( account->slave(), job->error(),
00419 job->errorText() );
00420 return;
00421 } else {
00422 if ( !(*it).msgList.isEmpty() )
00423 {
00424 emit messageStored((*it).msgList.last());
00425 (*it).msgList.removeLast();
00426 } else if (msg)
00427 {
00428 emit messageStored(msg);
00429 }
00430 msg = 0;
00431 }
00432 if (account->slave()) {
00433 account->removeJob(it);
00434 account->mJobList.remove(this);
00435 }
00436 deleteLater();
00437 }
00438
00439
00440 void ImapJob::slotCopyMessageInfoData(KIO::Job * job, const QString & data)
00441 {
00442 KMFolderImap * imapFolder = static_cast<KMFolderImap*>(mDestFolder);
00443 KMAcctImap *account = imapFolder->account();
00444 ImapAccountBase::JobIterator it = account->findJob( job );
00445 if ( it == account->jobsEnd() ) return;
00446
00447 if (data.find("UID") != -1)
00448 {
00449
00450 QString oldUid = data.section(' ', 1, 1);
00451 QString newUid = data.section(' ', 2, 2);
00452
00453
00454 QValueList<int> olduids = KMFolderImap::splitSets(oldUid);
00455 QValueList<int> newuids = KMFolderImap::splitSets(newUid);
00456
00457 int index = -1;
00458 if ( !(*it).msgList.isEmpty() )
00459 {
00460 KMMessage * msg;
00461 for ( msg = (*it).msgList.first(); msg; msg = (*it).msgList.next() )
00462 {
00463 uint uid = msg->headerField("X-UID").toInt();
00464 index = olduids.findIndex(uid);
00465 if (index > -1)
00466 {
00467
00468 const ulong * sernum = (ulong *)msg->getMsgSerNum();
00469 imapFolder->insertUidSerNumEntry(newuids[index], sernum);
00470 }
00471 }
00472 } else if (mMsgList.first()) {
00473 uint uid = mMsgList.first()->headerField("X-UID").toInt();
00474 index = olduids.findIndex(uid);
00475 if (index > -1)
00476 {
00477
00478 const ulong * sernum = (ulong *)mMsgList.first()->getMsgSerNum();
00479 imapFolder->insertUidSerNumEntry(newuids[index], sernum);
00480 }
00481 }
00482 }
00483 }
00484
00485
00486 void ImapJob::slotPutMessageInfoData(KIO::Job *job, const QString &data)
00487 {
00488 KMFolderImap * imapFolder = static_cast<KMFolderImap*>(mDestFolder);
00489 KMAcctImap *account = imapFolder->account();
00490 ImapAccountBase::JobIterator it = account->findJob( job );
00491 if ( it == account->jobsEnd() ) return;
00492
00493 if (data.find("UID") != -1)
00494 {
00495 int uid = (data.right(data.length()-4)).toInt();
00496
00497 if ( !(*it).msgList.isEmpty() )
00498 {
00499 const ulong * sernum = (ulong *)(*it).msgList.last()->getMsgSerNum();
00500
00501 imapFolder->insertUidSerNumEntry(uid, sernum);
00502 } else if (mMsgList.first())
00503 {
00504 const ulong * sernum = (ulong *)mMsgList.first()->getMsgSerNum();
00505
00506 imapFolder->insertUidSerNumEntry(uid, sernum);
00507 }
00508 }
00509 }
00510
00511
00512
00513 void ImapJob::slotCopyMessageResult( KIO::Job *job )
00514 {
00515 KMAcctImap *account = static_cast<KMFolderImap*>(mDestFolder)->account();
00516 ImapAccountBase::JobIterator it = account->findJob( job );
00517 if ( it == account->jobsEnd() ) return;
00518
00519 if (job->error())
00520 {
00521 account->slotSlaveError( account->slave(), job->error(),
00522 job->errorText() );
00523 return;
00524 } else {
00525 if ( !(*it).msgList.isEmpty() )
00526 {
00527 emit messageCopied((*it).msgList);
00528 } else if (mMsgList.first()) {
00529 emit messageCopied(mMsgList.first());
00530 }
00531 }
00532 if (account->slave()) {
00533 account->removeJob(it);
00534 account->mJobList.remove(this);
00535 }
00536 deleteLater();
00537 }
00538
00539
00540 void ImapJob::execute()
00541 {
00542 init( mType, mSets, static_cast<KMFolderImap*>( mDestFolder ), mMsgList );
00543 }
00544
00545
00546 void ImapJob::expireMessages()
00547 {
00548 return;
00549 }
00550
00551 }
00552
00553 #include "imapjob.moc"