kmail Library API Documentation

kmacctexppop.cpp

00001 // KMAcctExpPop.cpp 00002 // Authors: Don Sanders, (based on kmacctpop by) 00003 // Stefan Taferner and Markus Wuebben 00004 00005 #ifdef HAVE_CONFIG_H 00006 #include <config.h> 00007 #endif 00008 00009 #include "kmacctexppop.h" 00010 00011 #include "broadcaststatus.h" 00012 using KPIM::BroadcastStatus; 00013 #include "progressmanager.h" 00014 #include "kmfoldermgr.h" 00015 #include "kmfiltermgr.h" 00016 #include "kmpopfiltercnfrmdlg.h" 00017 #include "kmkernel.h" 00018 #include "protocols.h" 00019 #include "kmdict.h" 00020 00021 #include <kdebug.h> 00022 #include <kstandarddirs.h> 00023 #include <klocale.h> 00024 #include <kmessagebox.h> 00025 #include <kmainwindow.h> 00026 #include <kio/scheduler.h> 00027 #include <kio/passdlg.h> 00028 #include <kconfig.h> 00029 using KIO::MetaData; 00030 00031 static const unsigned short int pop3DefaultPort = 110; 00032 00033 //----------------------------------------------------------------------------- 00034 KMAcctExpPop::KMAcctExpPop(KMAcctMgr* aOwner, const QString& aAccountName, uint id) 00035 : NetworkAccount(aOwner, aAccountName, id), 00036 headerIt(headersOnServer) 00037 { 00038 init(); 00039 job = 0; 00040 mSlave = 0; 00041 mPort = defaultPort(); 00042 stage = Idle; 00043 indexOfCurrentMsg = -1; 00044 curMsgStrm = 0; 00045 processingDelay = 2*100; 00046 mProcessing = false; 00047 dataCounter = 0; 00048 mUidsOfSeenMsgsDict.setAutoDelete( false ); 00049 mUidsOfNextSeenMsgsDict.setAutoDelete( false ); 00050 00051 headersOnServer.setAutoDelete(true); 00052 connect(&processMsgsTimer,SIGNAL(timeout()),SLOT(slotProcessPendingMsgs())); 00053 KIO::Scheduler::connect( 00054 SIGNAL(slaveError(KIO::Slave *, int, const QString &)), 00055 this, SLOT(slotSlaveError(KIO::Slave *, int, const QString &))); 00056 00057 mHeaderDeleteUids.clear(); 00058 mHeaderDownUids.clear(); 00059 mHeaderLaterUids.clear(); 00060 } 00061 00062 00063 //----------------------------------------------------------------------------- 00064 KMAcctExpPop::~KMAcctExpPop() 00065 { 00066 if (job) { 00067 job->kill(); 00068 mMsgsPendingDownload.clear(); 00069 processRemainingQueuedMessages(); 00070 saveUidList(); 00071 } 00072 } 00073 00074 00075 //----------------------------------------------------------------------------- 00076 QString KMAcctExpPop::type(void) const 00077 { 00078 return "pop"; 00079 } 00080 00081 QString KMAcctExpPop::protocol() const { 00082 return useSSL() ? POP_SSL_PROTOCOL : POP_PROTOCOL; 00083 } 00084 00085 unsigned short int KMAcctExpPop::defaultPort() const { 00086 return pop3DefaultPort; 00087 } 00088 00089 //----------------------------------------------------------------------------- 00090 void KMAcctExpPop::init(void) 00091 { 00092 NetworkAccount::init(); 00093 00094 mUsePipelining = FALSE; 00095 mLeaveOnServer = FALSE; 00096 mFilterOnServer = FALSE; 00097 //tz todo 00098 mFilterOnServerCheckSize = 50000; 00099 } 00100 00101 //----------------------------------------------------------------------------- 00102 void KMAcctExpPop::pseudoAssign( const KMAccount * a ) { 00103 slotAbortRequested(); 00104 NetworkAccount::pseudoAssign( a ); 00105 00106 const KMAcctExpPop * p = dynamic_cast<const KMAcctExpPop*>( a ); 00107 if ( !p ) return; 00108 00109 setUsePipelining( p->usePipelining() ); 00110 setLeaveOnServer( p->leaveOnServer() ); 00111 setFilterOnServer( p->filterOnServer() ); 00112 setFilterOnServerCheckSize( p->filterOnServerCheckSize() ); 00113 } 00114 00115 //----------------------------------------------------------------------------- 00116 void KMAcctExpPop::processNewMail(bool _interactive) 00117 { 00118 if (stage == Idle) { 00119 00120 if(mAskAgain || mPasswd.isEmpty() || mLogin.isEmpty()) { 00121 QString passwd = decryptStr(mPasswd); 00122 bool b = FALSE; 00123 if (KIO::PasswordDialog::getNameAndPassword(mLogin, passwd, &b, 00124 i18n("You need to supply a username and a password to access this " 00125 "mailbox."), FALSE, QString::null, mName, i18n("Account:")) 00126 != QDialog::Accepted) 00127 { 00128 checkDone( false, CheckAborted ); 00129 return; 00130 } else { 00131 mPasswd = encryptStr(passwd); 00132 mAskAgain = FALSE; 00133 } 00134 } 00135 00136 QString seenUidList = locateLocal( "data", "kmail/" + mLogin + ":" + "@" + 00137 mHost + ":" + QString("%1").arg(mPort) ); 00138 KConfig config( seenUidList ); 00139 QStringList uidsOfSeenMsgs = config.readListEntry( "seenUidList" ); 00140 mUidsOfSeenMsgsDict.clear(); 00141 mUidsOfSeenMsgsDict.resize( KMail::nextPrime( ( uidsOfSeenMsgs.count() * 11 ) / 10 ) ); 00142 for ( QStringList::ConstIterator it = uidsOfSeenMsgs.begin(); 00143 it != uidsOfSeenMsgs.end(); ++it ) { 00144 // we use mUidsOfSeenMsgsDict to provide fast random access to the keys, 00145 // so we simply set the values to (const int *)1 00146 mUidsOfSeenMsgsDict.insert( *it, (const int *)1 ); 00147 } 00148 QStringList downloadLater = config.readListEntry( "downloadLater" ); 00149 for ( QStringList::Iterator it = downloadLater.begin(); it != downloadLater.end(); ++it ) { 00150 mHeaderLaterUids.insert( *it, true ); 00151 } 00152 mUidsOfNextSeenMsgsDict.clear(); 00153 00154 interactive = _interactive; 00155 mUidlFinished = FALSE; 00156 startJob(); 00157 } 00158 else { 00159 checkDone( false, CheckIgnored ); 00160 return; 00161 } 00162 } 00163 00164 00165 //----------------------------------------------------------------------------- 00166 void KMAcctExpPop::readConfig(KConfig& config) 00167 { 00168 NetworkAccount::readConfig(config); 00169 00170 mUsePipelining = config.readNumEntry("pipelining", FALSE); 00171 mLeaveOnServer = config.readNumEntry("leave-on-server", FALSE); 00172 mFilterOnServer = config.readNumEntry("filter-on-server", FALSE); 00173 mFilterOnServerCheckSize = config.readUnsignedNumEntry("filter-os-check-size", 50000); 00174 } 00175 00176 00177 //----------------------------------------------------------------------------- 00178 void KMAcctExpPop::writeConfig(KConfig& config) 00179 { 00180 NetworkAccount::writeConfig(config); 00181 00182 config.writeEntry("pipelining", mUsePipelining); 00183 config.writeEntry("leave-on-server", mLeaveOnServer); 00184 config.writeEntry("filter-on-server", mFilterOnServer); 00185 config.writeEntry("filter-os-check-size", mFilterOnServerCheckSize); 00186 } 00187 00188 00189 //----------------------------------------------------------------------------- 00190 void KMAcctExpPop::setUsePipelining(bool b) 00191 { 00192 mUsePipelining = b; 00193 } 00194 00195 //----------------------------------------------------------------------------- 00196 void KMAcctExpPop::setLeaveOnServer(bool b) 00197 { 00198 mLeaveOnServer = b; 00199 } 00200 00201 00202 //--------------------------------------------------------------------------- 00203 void KMAcctExpPop::setFilterOnServer(bool b) 00204 { 00205 mFilterOnServer = b; 00206 } 00207 00208 //--------------------------------------------------------------------------- 00209 void KMAcctExpPop::setFilterOnServerCheckSize(unsigned int aSize) 00210 { 00211 mFilterOnServerCheckSize = aSize; 00212 } 00213 00214 //----------------------------------------------------------------------------- 00215 void KMAcctExpPop::connectJob() { 00216 KIO::Scheduler::assignJobToSlave(mSlave, job); 00217 if (stage != Dele) 00218 connect(job, SIGNAL( data( KIO::Job*, const QByteArray &)), 00219 SLOT( slotData( KIO::Job*, const QByteArray &))); 00220 connect(job, SIGNAL( result( KIO::Job * ) ), 00221 SLOT( slotResult( KIO::Job * ) ) ); 00222 connect(job, SIGNAL(infoMessage( KIO::Job*, const QString & )), 00223 SLOT( slotMsgRetrieved(KIO::Job*, const QString &))); 00224 } 00225 00226 00227 //----------------------------------------------------------------------------- 00228 void KMAcctExpPop::slotCancel() 00229 { 00230 mMsgsPendingDownload.clear(); 00231 processRemainingQueuedMessages(); 00232 saveUidList(); 00233 slotJobFinished(); 00234 } 00235 00236 00237 //----------------------------------------------------------------------------- 00238 void KMAcctExpPop::slotProcessPendingMsgs() 00239 { 00240 if (mProcessing) // not reentrant 00241 return; 00242 mProcessing = true; 00243 00244 bool addedOk; 00245 QValueList<KMMessage*>::Iterator cur = msgsAwaitingProcessing.begin(); 00246 QStringList::Iterator curId = msgIdsAwaitingProcessing.begin(); 00247 QStringList::Iterator curUid = msgUidsAwaitingProcessing.begin(); 00248 00249 while (cur != msgsAwaitingProcessing.end()) { 00250 // note we can actually end up processing events in processNewMsg 00251 // this happens when send receipts is turned on 00252 // hence the check for re-entry at the start of this method. 00253 // -sanders Update processNewMsg should no longer process events 00254 00255 addedOk = processNewMsg(*cur); //added ok? Error displayed if not. 00256 00257 if (!addedOk) { 00258 mMsgsPendingDownload.clear(); 00259 msgIdsAwaitingProcessing.clear(); 00260 msgUidsAwaitingProcessing.clear(); 00261 break; 00262 } 00263 else { 00264 idsOfMsgsToDelete.append( *curId ); 00265 mUidsOfNextSeenMsgsDict.insert( *curUid, (const int *)1 ); 00266 } 00267 ++cur; 00268 ++curId; 00269 ++curUid; 00270 } 00271 00272 msgsAwaitingProcessing.clear(); 00273 msgIdsAwaitingProcessing.clear(); 00274 msgUidsAwaitingProcessing.clear(); 00275 mProcessing = false; 00276 } 00277 00278 00279 //----------------------------------------------------------------------------- 00280 void KMAcctExpPop::slotAbortRequested() 00281 { 00282 if (stage == Idle) return; 00283 disconnect( mMailCheckProgressItem, SIGNAL( progressItemCanceled( ProgressItem* ) ), 00284 this, SLOT( slotAbortRequested() ) ); 00285 stage = Quit; 00286 if (job) job->kill(); 00287 job = 0; 00288 mSlave = 0; 00289 slotCancel(); 00290 } 00291 00292 00293 //----------------------------------------------------------------------------- 00294 void KMAcctExpPop::startJob() 00295 { 00296 // Run the precommand 00297 if (!runPrecommand(precommand())) 00298 { 00299 KMessageBox::sorry(0, 00300 i18n("Could not execute precommand: %1").arg(precommand()), 00301 i18n("KMail Error Message")); 00302 checkDone( false, CheckError ); 00303 return; 00304 } 00305 // end precommand code 00306 00307 KURL url = getUrl(); 00308 00309 if ( !url.isValid() ) { 00310 KMessageBox::error(0, i18n("Source URL is malformed"), 00311 i18n("Kioslave Error Message") ); 00312 return; 00313 } 00314 00315 mMsgsPendingDownload.clear(); 00316 idsOfMsgs.clear(); 00317 mUidForIdMap.clear(); 00318 idsOfMsgsToDelete.clear(); 00319 //delete any headers if there are some this have to be done because of check again 00320 headersOnServer.clear(); 00321 headers = false; 00322 indexOfCurrentMsg = -1; 00323 00324 Q_ASSERT( !mMailCheckProgressItem ); 00325 mMailCheckProgressItem = KPIM::ProgressManager::createProgressItem( 00326 "MailCheck" + mName, 00327 mName, 00328 i18n("Preparing transmission from \"%1\"...").arg(mName), 00329 true, // can be canceled 00330 useSSL() || useTLS() ); 00331 connect( mMailCheckProgressItem, SIGNAL( progressItemCanceled( ProgressItem* ) ), 00332 this, SLOT( slotAbortRequested() ) ); 00333 00334 numBytes = 0; 00335 numBytesRead = 0; 00336 stage = List; 00337 mSlave = KIO::Scheduler::getConnectedSlave( url, slaveConfig() ); 00338 if (!mSlave) 00339 { 00340 slotSlaveError(0, KIO::ERR_CANNOT_LAUNCH_PROCESS, url.protocol()); 00341 return; 00342 } 00343 url.setPath(QString("/index")); 00344 job = KIO::get( url, false, false ); 00345 connectJob(); 00346 } 00347 00348 MetaData KMAcctExpPop::slaveConfig() const { 00349 MetaData m = NetworkAccount::slaveConfig(); 00350 00351 m.insert("progress", "off"); 00352 m.insert("pipelining", (mUsePipelining) ? "on" : "off"); 00353 if (mAuth == "PLAIN" || mAuth == "LOGIN" || mAuth == "CRAM-MD5" || 00354 mAuth == "DIGEST-MD5") { 00355 m.insert("auth", "SASL"); 00356 m.insert("sasl", mAuth); 00357 } else if ( mAuth == "*" ) 00358 m.insert("auth", "USER"); 00359 else 00360 m.insert("auth", mAuth); 00361 00362 return m; 00363 } 00364 00365 //----------------------------------------------------------------------------- 00366 // one message is finished 00367 // add data to a KMMessage 00368 void KMAcctExpPop::slotMsgRetrieved(KIO::Job*, const QString & infoMsg) 00369 { 00370 if (infoMsg != "message complete") return; 00371 KMMessage *msg = new KMMessage; 00372 msg->setComplete(true); 00373 // Make sure to use LF as line ending to make the processing easier 00374 // when piping through external programs 00375 uint newSize = KMFolder::crlf2lf( curMsgData.data(), curMsgData.size() ); 00376 curMsgData.resize( newSize ); 00377 msg->fromByteArray( curMsgData , true ); 00378 if (stage == Head) 00379 { 00380 int size = mMsgsPendingDownload[ headerIt.current()->id() ]; 00381 kdDebug(5006) << "Size of Message: " << size << endl; 00382 msg->setMsgLength( size ); 00383 headerIt.current()->setHeader(msg); 00384 ++headerIt; 00385 slotGetNextHdr(); 00386 } else { 00387 //kdDebug(5006) << kfuncinfo << "stage == Retr" << endl; 00388 //kdDebug(5006) << "curMsgData.size() = " << curMsgData.size() << endl; 00389 msg->setMsgLength( curMsgData.size() ); 00390 msgsAwaitingProcessing.append(msg); 00391 msgIdsAwaitingProcessing.append(idsOfMsgs[indexOfCurrentMsg]); 00392 msgUidsAwaitingProcessing.append( mUidForIdMap[idsOfMsgs[indexOfCurrentMsg]] ); 00393 slotGetNextMsg(); 00394 } 00395 } 00396 00397 00398 //----------------------------------------------------------------------------- 00399 // finit state machine to cycle trow the stages 00400 void KMAcctExpPop::slotJobFinished() { 00401 QStringList emptyList; 00402 if (stage == List) { 00403 kdDebug(5006) << k_funcinfo << "stage == List" << endl; 00404 // set the initial size of mUidsOfNextSeenMsgsDict to the number of 00405 // messages on the server + 10% 00406 mUidsOfNextSeenMsgsDict.resize( KMail::nextPrime( ( idsOfMsgs.count() * 11 ) / 10 ) ); 00407 KURL url = getUrl(); 00408 url.setPath(QString("/uidl")); 00409 job = KIO::get( url, false, false ); 00410 connectJob(); 00411 stage = Uidl; 00412 } 00413 else if (stage == Uidl) { 00414 kdDebug(5006) << k_funcinfo << "stage == Uidl" << endl; 00415 mUidlFinished = TRUE; 00416 00417 if ( mLeaveOnServer && mUidForIdMap.isEmpty() && 00418 mUidsOfNextSeenMsgsDict.isEmpty() && !idsOfMsgs.isEmpty() ) { 00419 KMessageBox::sorry(0, i18n("Your POP3 server does not support the UIDL " 00420 "command: this command is required to determine, in a reliable way, " 00421 "which of the mails on the server KMail has already seen before;\n" 00422 "the feature to leave the mails on the server will therefore not " 00423 "work properly.")); 00424 // An attempt to work around buggy pop servers, these seem to be popular. 00425 mUidsOfNextSeenMsgsDict = mUidsOfSeenMsgsDict; 00426 } 00427 00428 //check if filter on server 00429 if (mFilterOnServer == true) { 00430 QMap<QString, int>::Iterator hids; 00431 for ( hids = mMsgsPendingDownload.begin(); 00432 hids != mMsgsPendingDownload.end(); hids++ ) { 00433 kdDebug(5006) << "Length: " << hids.data() << endl; 00434 //check for mails bigger mFilterOnServerCheckSize 00435 if ( (unsigned int)hids.data() >= mFilterOnServerCheckSize ) { 00436 kdDebug(5006) << "bigger than " << mFilterOnServerCheckSize << endl; 00437 headersOnServer.append(new KMPopHeaders( hids.key(), 00438 mUidForIdMap[hids.key()], 00439 Later));//TODO 00440 //set Action if already known 00441 if( mHeaderDeleteUids.contains( headersOnServer.current()->uid() ) ) { 00442 headersOnServer.current()->setAction(Delete); 00443 } 00444 else if( mHeaderDownUids.contains( headersOnServer.current()->uid() ) ) { 00445 headersOnServer.current()->setAction(Down); 00446 } 00447 else if( mHeaderLaterUids.contains( headersOnServer.current()->uid() ) ) { 00448 headersOnServer.current()->setAction(Later); 00449 } 00450 } 00451 } 00452 // delete the uids so that you don't get them twice in the list 00453 mHeaderDeleteUids.clear(); 00454 mHeaderDownUids.clear(); 00455 mHeaderLaterUids.clear(); 00456 } 00457 // kdDebug(5006) << "Num of Msgs to Filter: " << headersOnServer.count() << endl; 00458 // if there are mails which should be checkedc download the headers 00459 if ((headersOnServer.count() > 0) && (mFilterOnServer == true)) { 00460 headerIt.toFirst(); 00461 KURL url = getUrl(); 00462 QString headerIds; 00463 while (headerIt.current()) 00464 { 00465 headerIds += headerIt.current()->id(); 00466 if (!headerIt.atLast()) headerIds += ","; 00467 ++headerIt; 00468 } 00469 headerIt.toFirst(); 00470 url.setPath(QString("/headers/") + headerIds); 00471 job = KIO::get( url, false, false ); 00472 connectJob(); 00473 slotGetNextHdr(); 00474 stage = Head; 00475 } 00476 else { 00477 stage = Retr; 00478 numMsgs = mMsgsPendingDownload.count(); 00479 numBytesToRead = 0; 00480 QMap<QString, int>::Iterator len; 00481 for ( len = mMsgsPendingDownload.begin(); 00482 len != mMsgsPendingDownload.end(); len++ ) 00483 numBytesToRead += len.data(); 00484 idsOfMsgs = QStringList( mMsgsPendingDownload.keys() ); 00485 KURL url = getUrl(); 00486 url.setPath( "/download/" + idsOfMsgs.join(",") ); 00487 job = KIO::get( url, false, false ); 00488 connectJob(); 00489 slotGetNextMsg(); 00490 processMsgsTimer.start(processingDelay); 00491 } 00492 } 00493 else if (stage == Head) { 00494 kdDebug(5006) << k_funcinfo << "stage == Head" << endl; 00495 00496 // All headers have been downloaded, check which mail you want to get 00497 // data is in list headersOnServer 00498 00499 // check if headers apply to a filter 00500 // if set the action of the filter 00501 KMPopFilterAction action; 00502 bool dlgPopup = false; 00503 for (headersOnServer.first(); headersOnServer.current(); headersOnServer.next()) { 00504 action = (KMPopFilterAction)kmkernel->popFilterMgr()->process(headersOnServer.current()->header()); 00505 //debug todo 00506 switch ( action ) { 00507 case NoAction: 00508 kdDebug(5006) << "PopFilterAction = NoAction" << endl; 00509 break; 00510 case Later: 00511 kdDebug(5006) << "PopFilterAction = Later" << endl; 00512 break; 00513 case Delete: 00514 kdDebug(5006) << "PopFilterAction = Delete" << endl; 00515 break; 00516 case Down: 00517 kdDebug(5006) << "PopFilterAction = Down" << endl; 00518 break; 00519 default: 00520 kdDebug(5006) << "PopFilterAction = default oops!" << endl; 00521 break; 00522 } 00523 switch ( action ) { 00524 case NoAction: 00525 //kdDebug(5006) << "PopFilterAction = NoAction" << endl; 00526 dlgPopup = true; 00527 break; 00528 case Later: 00529 if (kmkernel->popFilterMgr()->showLaterMsgs()) 00530 dlgPopup = true; 00531 default: 00532 headersOnServer.current()->setAction(action); 00533 headersOnServer.current()->setRuleMatched(true); 00534 break; 00535 } 00536 } 00537 00538 // if there are some messages which are not coverd by a filter 00539 // show the dialog 00540 headers = true; 00541 if (dlgPopup) { 00542 KMPopFilterCnfrmDlg dlg(&headersOnServer, this->name(), kmkernel->popFilterMgr()->showLaterMsgs()); 00543 dlg.exec(); 00544 } 00545 00546 for (headersOnServer.first(); headersOnServer.current(); headersOnServer.next()) { 00547 if (headersOnServer.current()->action() == Delete || 00548 headersOnServer.current()->action() == Later) { 00549 //remove entries from the lists when the mails should not be downloaded 00550 //(deleted or downloaded later) 00551 if ( mMsgsPendingDownload.contains( headersOnServer.current()->id() ) ) { 00552 mMsgsPendingDownload.remove( headersOnServer.current()->id() ); 00553 } 00554 if (headersOnServer.current()->action() == Delete) { 00555 mHeaderDeleteUids.insert(headersOnServer.current()->uid(), true); 00556 mUidsOfNextSeenMsgsDict.insert( headersOnServer.current()->uid(), 00557 (const int *)1 ); 00558 idsOfMsgsToDelete.append(headersOnServer.current()->id()); 00559 } 00560 else { 00561 mHeaderLaterUids.insert(headersOnServer.current()->uid(), true); 00562 } 00563 } 00564 else if (headersOnServer.current()->action() == Down) { 00565 mHeaderDownUids.insert(headersOnServer.current()->uid(), true); 00566 } 00567 } 00568 00569 headersOnServer.clear(); 00570 stage = Retr; 00571 numMsgs = mMsgsPendingDownload.count(); 00572 numBytesToRead = 0; 00573 QMap<QString, int>::Iterator len; 00574 for (len = mMsgsPendingDownload.begin(); 00575 len != mMsgsPendingDownload.end(); len++) 00576 numBytesToRead += len.data(); 00577 idsOfMsgs = QStringList( mMsgsPendingDownload.keys() ); 00578 KURL url = getUrl(); 00579 url.setPath( "/download/" + idsOfMsgs.join(",") ); 00580 job = KIO::get( url, false, false ); 00581 connectJob(); 00582 slotGetNextMsg(); 00583 processMsgsTimer.start(processingDelay); 00584 } 00585 else if (stage == Retr) { 00586 mMailCheckProgressItem->setProgress( 100 ); 00587 processRemainingQueuedMessages(); 00588 00589 mHeaderDeleteUids.clear(); 00590 mHeaderDownUids.clear(); 00591 mHeaderLaterUids.clear(); 00592 00593 kmkernel->folderMgr()->syncAllFolders(); 00594 00595 KURL url = getUrl(); 00596 if (mLeaveOnServer || idsOfMsgsToDelete.isEmpty()) { 00597 stage = Quit; 00598 mMailCheckProgressItem->setStatus( 00599 i18n( "Fetched 1 message from %1. Terminating transmission...", 00600 "Fetched %n messages from %1. Terminating transmission...", 00601 numMsgs ) 00602 .arg( mHost ) ); 00603 url.setPath(QString("/commit")); 00604 job = KIO::get(url, false, false ); 00605 } 00606 else { 00607 stage = Dele; 00608 mMailCheckProgressItem->setStatus( 00609 i18n( "Fetched 1 message from %1. Deleting messages from server...", 00610 "Fetched %n messages from %1. Deleting messages from server...", 00611 numMsgs ) 00612 .arg( mHost ) ); 00613 url.setPath("/remove/" + idsOfMsgsToDelete.join(",")); 00614 kdDebug(5006) << "url: " << url.prettyURL() << endl; 00615 job = KIO::get( url, false, false ); 00616 } 00617 connectJob(); 00618 } 00619 else if (stage == Dele) { 00620 kdDebug(5006) << k_funcinfo << "stage == Dele" << endl; 00621 // remove the uids of all messages which have been deleted 00622 for ( QStringList::ConstIterator it = idsOfMsgsToDelete.begin(); 00623 it != idsOfMsgsToDelete.end(); ++it ) { 00624 mUidsOfNextSeenMsgsDict.remove( mUidForIdMap[*it] ); 00625 } 00626 idsOfMsgsToDelete.clear(); 00627 mMailCheckProgressItem->setStatus( 00628 i18n( "Fetched 1 message from %1. Terminating transmission...", 00629 "Fetched %n messages from %1. Terminating transmission...", 00630 numMsgs ) 00631 .arg( mHost ) ); 00632 KURL url = getUrl(); 00633 url.setPath(QString("/commit")); 00634 job = KIO::get( url, false, false ); 00635 stage = Quit; 00636 connectJob(); 00637 } 00638 else if (stage == Quit) { 00639 kdDebug(5006) << k_funcinfo << "stage == Quit" << endl; 00640 saveUidList(); 00641 job = 0; 00642 if (mSlave) KIO::Scheduler::disconnectSlave(mSlave); 00643 mSlave = 0; 00644 stage = Idle; 00645 if( mMailCheckProgressItem ) { // do this only once... 00646 bool canceled = kmkernel->mailCheckAborted() || mMailCheckProgressItem->canceled(); 00647 int numMessages = canceled ? indexOfCurrentMsg : idsOfMsgs.count(); 00648 BroadcastStatus::instance()->setStatusMsgTransmissionCompleted( 00649 numMessages, numBytes, numBytesRead, numBytesToRead, mLeaveOnServer, mMailCheckProgressItem ); 00650 mMailCheckProgressItem->setComplete(); 00651 mMailCheckProgressItem = 0; 00652 checkDone( ( numMessages > 0 ), canceled ? CheckAborted : CheckOK ); 00653 } 00654 } 00655 } 00656 00657 00658 //----------------------------------------------------------------------------- 00659 void KMAcctExpPop::processRemainingQueuedMessages() 00660 { 00661 kdDebug(5006) << k_funcinfo << endl; 00662 slotProcessPendingMsgs(); // Force processing of any messages still in the queue 00663 processMsgsTimer.stop(); 00664 00665 stage = Quit; 00666 kmkernel->folderMgr()->syncAllFolders(); 00667 } 00668 00669 00670 //----------------------------------------------------------------------------- 00671 void KMAcctExpPop::saveUidList() 00672 { 00673 kdDebug(5006) << k_funcinfo << endl; 00674 // Don't update the seen uid list unless we successfully got 00675 // a new list from the server 00676 if (!mUidlFinished) return; 00677 00678 QStringList uidsOfNextSeenMsgs; 00679 QDictIterator<int> it( mUidsOfNextSeenMsgsDict ); 00680 for( ; it.current(); ++it ) 00681 uidsOfNextSeenMsgs.append( it.currentKey() ); 00682 QString seenUidList = locateLocal( "data", "kmail/" + mLogin + ":" + "@" + 00683 mHost + ":" + QString("%1").arg(mPort) ); 00684 KConfig config( seenUidList ); 00685 config.writeEntry( "seenUidList", uidsOfNextSeenMsgs ); 00686 config.writeEntry( "downloadLater", QStringList( mHeaderLaterUids.keys() ) ); 00687 config.sync(); 00688 } 00689 00690 00691 //----------------------------------------------------------------------------- 00692 void KMAcctExpPop::slotGetNextMsg() 00693 { 00694 QMap<QString, int>::Iterator next = mMsgsPendingDownload.begin(); 00695 00696 curMsgData.resize(0); 00697 numMsgBytesRead = 0; 00698 curMsgLen = 0; 00699 delete curMsgStrm; 00700 curMsgStrm = 0; 00701 00702 if ( next != mMsgsPendingDownload.end() ) { 00703 // get the next message 00704 int nextLen = next.data(); 00705 curMsgStrm = new QDataStream( curMsgData, IO_WriteOnly ); 00706 curMsgLen = nextLen; 00707 ++indexOfCurrentMsg; 00708 kdDebug(5006) << QString("Length of message about to get %1").arg( nextLen ) << endl; 00709 mMsgsPendingDownload.remove( next.key() ); 00710 } 00711 } 00712 00713 00714 //----------------------------------------------------------------------------- 00715 void KMAcctExpPop::slotData( KIO::Job* job, const QByteArray &data) 00716 { 00717 if (data.size() == 0) { 00718 kdDebug(5006) << "Data: <End>" << endl; 00719 if ((stage == Retr) && (numMsgBytesRead < curMsgLen)) 00720 numBytesRead += curMsgLen - numMsgBytesRead; 00721 else if (stage == Head){ 00722 kdDebug(5006) << "Head: <End>" << endl; 00723 } 00724 return; 00725 } 00726 00727 int oldNumMsgBytesRead = numMsgBytesRead; 00728 if (stage == Retr) { 00729 headers = false; 00730 curMsgStrm->writeRawBytes( data.data(), data.size() ); 00731 numMsgBytesRead += data.size(); 00732 if (numMsgBytesRead > curMsgLen) 00733 numMsgBytesRead = curMsgLen; 00734 numBytesRead += numMsgBytesRead - oldNumMsgBytesRead; 00735 dataCounter++; 00736 if (dataCounter % 5 == 0) 00737 { 00738 QString msg; 00739 if (numBytes != numBytesToRead && mLeaveOnServer) 00740 { 00741 msg = i18n("Fetching message %1 of %2 (%3 of %4 KB) from %5 " 00742 "(%6 KB remain on the server).") 00743 .arg(indexOfCurrentMsg+1).arg(numMsgs).arg(numBytesRead/1024) 00744 .arg(numBytesToRead/1024).arg(mHost).arg(numBytes/1024); 00745 } 00746 else 00747 { 00748 msg = i18n("Fetching message %1 of %2 (%3 of %4 KB) from %5.") 00749 .arg(indexOfCurrentMsg+1).arg(numMsgs).arg(numBytesRead/1024) 00750 .arg(numBytesToRead/1024).arg(mHost); 00751 } 00752 mMailCheckProgressItem->setStatus( msg ); 00753 mMailCheckProgressItem->setProgress( 00754 (numBytesToRead <= 100) ? 50 // We never know what the server tells us 00755 // This way of dividing is required for > 21MB of mail 00756 : (numBytesRead / (numBytesToRead / 100)) ); 00757 } 00758 return; 00759 } 00760 00761 if (stage == Head) { 00762 curMsgStrm->writeRawBytes( data.data(), data.size() ); 00763 return; 00764 } 00765 00766 // otherwise stage is List Or Uidl 00767 QString qdata = data; 00768 qdata = qdata.simplifyWhiteSpace(); // Workaround for Maillennium POP3/UNIBOX 00769 int spc = qdata.find( ' ' ); 00770 if (spc > 0) { 00771 if (stage == List) { 00772 QString length = qdata.mid(spc+1); 00773 if (length.find(' ') != -1) length.truncate(length.find(' ')); 00774 int len = length.toInt(); 00775 numBytes += len; 00776 QString id = qdata.left(spc); 00777 idsOfMsgs.append( id ); 00778 mMsgsPendingDownload.insert( id, len ); 00779 } 00780 else { // stage == Uidl 00781 const QString id = qdata.left(spc); 00782 const QString uid = qdata.mid(spc + 1); 00783 if ( mUidsOfSeenMsgsDict.find( uid ) != 0 ) { 00784 if ( mMsgsPendingDownload.contains( id ) ) { 00785 mMsgsPendingDownload.remove( id ); 00786 } 00787 else 00788 kdDebug(5006) << "KMAcctExpPop::slotData synchronization failure." << endl; 00789 idsOfMsgsToDelete.append( id ); 00790 mUidsOfNextSeenMsgsDict.insert( uid, (const int *)1 ); 00791 } 00792 mUidForIdMap.insert( id, uid ); 00793 } 00794 } 00795 else { 00796 stage = Idle; 00797 if (job) job->kill(); 00798 job = 0; 00799 mSlave = 0; 00800 KMessageBox::error(0, i18n( "Unable to complete LIST operation." ), 00801 i18n("Invalid Response From Server")); 00802 return; 00803 } 00804 } 00805 00806 00807 //----------------------------------------------------------------------------- 00808 void KMAcctExpPop::slotResult( KIO::Job* ) 00809 { 00810 if (!job) return; 00811 if ( job->error() ) 00812 { 00813 if (interactive) { 00814 if (headers) { // nothing to be done for headers 00815 idsOfMsgs.clear(); 00816 } 00817 if (stage == Head && job->error() == KIO::ERR_COULD_NOT_READ) 00818 { 00819 KMessageBox::error(0, i18n("Your server does not support the " 00820 "TOP command. Therefore it is not possible to fetch the headers " 00821 "of large emails first, before downloading them.")); 00822 slotCancel(); 00823 return; 00824 } 00825 // force the dialog to be shown next time the account is checked 00826 if (!mStorePasswd) mPasswd = ""; 00827 job->showErrorDialog(); 00828 } 00829 slotCancel(); 00830 } 00831 else 00832 slotJobFinished(); 00833 } 00834 00835 00836 //----------------------------------------------------------------------------- 00837 void KMAcctExpPop::slotSlaveError(KIO::Slave *aSlave, int error, 00838 const QString &errorMsg) 00839 { 00840 if (aSlave != mSlave) return; 00841 if (error == KIO::ERR_SLAVE_DIED) mSlave = 0; 00842 00843 // explicitely disconnect the slave if the connection went down 00844 if ( error == KIO::ERR_CONNECTION_BROKEN && mSlave ) { 00845 KIO::Scheduler::disconnectSlave( mSlave ); 00846 mSlave = 0; 00847 } 00848 00849 if (interactive) { 00850 KMessageBox::error(kmkernel->mainWin(), KIO::buildErrorString(error, errorMsg)); 00851 } 00852 00853 00854 stage = Quit; 00855 if (error == KIO::ERR_COULD_NOT_LOGIN && !mStorePasswd) 00856 mAskAgain = TRUE; 00857 /* We need a timer, otherwise slotSlaveError of the next account is also 00858 executed, if it reuses the slave, because the slave member variable 00859 is changed too early */ 00860 QTimer::singleShot(0, this, SLOT(slotCancel())); 00861 } 00862 00863 //----------------------------------------------------------------------------- 00864 void KMAcctExpPop::slotGetNextHdr(){ 00865 kdDebug(5006) << "slotGetNextHeader" << endl; 00866 00867 curMsgData.resize(0); 00868 delete curMsgStrm; 00869 curMsgStrm = 0; 00870 00871 curMsgStrm = new QDataStream( curMsgData, IO_WriteOnly ); 00872 } 00873 00874 void KMAcctExpPop::killAllJobs( bool ) { 00875 // must reimpl., but we don't use it yet 00876 } 00877 00878 #include "kmacctexppop.moc"
KDE Logo
This file is part of the documentation for kmail Library Version 3.3.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Fri Aug 27 12:52:19 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003