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