kmail Library API Documentation

imapjob.cpp

00001 /* -*- mode: C++; c-file-style: "gnu" -*- 00002 * 00003 * This file is part of KMail, the KDE mail client. 00004 * Copyright (c) 2002-2003 Zack Rusin <zack@kde.org> 00005 * 2000-2002 Michael Haeckel <haeckel@kde.org> 00006 * 00007 * KMail is free software; you can redistribute it and/or modify it 00008 * under the terms of the GNU General Public License, version 2, as 00009 * published by the Free Software Foundation. 00010 * 00011 * KMail is distributed in the hope that it will be useful, but 00012 * WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 * General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software 00018 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00019 * 00020 * In addition, as a special exception, the copyright holders give 00021 * permission to link the code of this program with any edition of 00022 * the Qt library by Trolltech AS, Norway (or with modified versions 00023 * of Qt that use the same license as Qt), and distribute linked 00024 * combinations including the two. You must obey the GNU General 00025 * Public License in all respects for all of the code used other than 00026 * Qt. If you modify this file, you may extend this exception to 00027 * your version of the file, but you are not obligated to do so. If 00028 * you do not wish to do so, delete this exception statement from 00029 * your version. 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 // refcount++ 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 // If there is a destination folder, this is a copy, move or put to an 00085 // imap folder, use its account for keeping track of the job. Otherwise, 00086 // this is a get job and the src folder is an imap one. Use its account 00087 // then. 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 // transfers the complete message to the server 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 // according to RFC 2060 we need CRLF 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 ) // just to be sure this job is removed from the list 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 ) // just to be sure this job is removed from the list 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 // kdDebug(5006) << "ImapJob::slotGetNextMessage - retrieve " << url.path() << endl; 00247 ImapAccountBase::jobData jd; 00248 jd.parent = 0; 00249 jd.total = 1; jd.done = 0; 00250 // protect the message, otherwise we'll get crashes afterwards 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 // set correct size 00305 if ( size > 0 ) msg->setMsgLength(size); 00306 if ( mPartSpecifier.isEmpty() ) 00307 msg->setComplete( true ); 00308 else 00309 msg->setReadyToShow( false ); 00310 } else { 00311 // Update the body of the retrieved part (the message notifies all observers) 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 // nevertheless give visual feedback 00320 msg->notify(); 00321 } 00322 } 00323 if (account->slave()) { 00324 account->removeJob(it); 00325 account->mJobList.remove(this); 00326 } 00327 /* This needs to be emitted last, so the slots that are hooked to it 00328 * don't unGetMsg the msg before we have finished. */ 00329 if ( mPartSpecifier.isEmpty() || 00330 mPartSpecifier == "HEADER" ) 00331 { 00332 if ( gotData ) 00333 emit messageRetrieved(msg); 00334 else 00335 { 00336 /* we got an answer but not data 00337 * this means that the msg is not on the server anymore so delete it */ 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 // split 00450 QString oldUid = data.section(' ', 1, 1); 00451 QString newUid = data.section(' ', 2, 2); 00452 00453 // get lists of uids 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 // found, get the new uid 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 // found, get the new uid 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 // kdDebug(5006) << "insert sernum " << (*it).msgList.last()->getMsgSerNum() << " for " << uid << endl; 00501 imapFolder->insertUidSerNumEntry(uid, sernum); 00502 } else if (mMsgList.first()) 00503 { 00504 const ulong * sernum = (ulong *)mMsgList.first()->getMsgSerNum(); 00505 // kdDebug(5006) << "insert sernum " << mMsgList.first()->getMsgSerNum() << " for " << uid << endl; 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 }//namespace KMail 00552 00553 #include "imapjob.moc"
KDE Logo
This file is part of the documentation for kmail Library Version 3.2.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Jul 28 23:57:58 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003