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