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