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 Sat May 1 11:37:19 2004 by doxygen 1.2.15 written by Dimitri van Heesch, © 1997-2003