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