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