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 if (stage != Dele)
00289 connect(job, SIGNAL( data( KIO::Job*, const QByteArray &)),
00290 SLOT( slotData( KIO::Job*, const QByteArray &)));
00291 connect(job, SIGNAL( result( KIO::Job * ) ),
00292 SLOT( slotResult( KIO::Job * ) ) );
00293 connect(job, SIGNAL(infoMessage( KIO::Job*, const QString & )),
00294 SLOT( slotMsgRetrieved(KIO::Job*, const QString &)));
00295 }
00296
00297
00298
00299 void PopAccount::slotCancel()
00300 {
00301 mMsgsPendingDownload.clear();
00302 processRemainingQueuedMessages();
00303 saveUidList();
00304 slotJobFinished();
00305 }
00306
00307
00308
00309 void PopAccount::slotProcessPendingMsgs()
00310 {
00311 if (mProcessing)
00312 return;
00313 mProcessing = true;
00314
00315 bool addedOk;
00316 QValueList<KMMessage*>::Iterator cur = msgsAwaitingProcessing.begin();
00317 QStringList::Iterator curId = msgIdsAwaitingProcessing.begin();
00318 QStringList::Iterator curUid = msgUidsAwaitingProcessing.begin();
00319
00320 while (cur != msgsAwaitingProcessing.end()) {
00321
00322
00323
00324
00325
00326 addedOk = processNewMsg(*cur);
00327
00328 if (!addedOk) {
00329 mMsgsPendingDownload.clear();
00330 msgIdsAwaitingProcessing.clear();
00331 msgUidsAwaitingProcessing.clear();
00332 break;
00333 }
00334 else {
00335 idsOfMsgsToDelete.append( *curId );
00336 mUidsOfNextSeenMsgsDict.insert( *curUid, (const int *)1 );
00337 mTimeOfNextSeenMsgsMap.insert( *curUid, time(0) );
00338 }
00339 ++cur;
00340 ++curId;
00341 ++curUid;
00342 }
00343
00344 msgsAwaitingProcessing.clear();
00345 msgIdsAwaitingProcessing.clear();
00346 msgUidsAwaitingProcessing.clear();
00347 mProcessing = false;
00348 }
00349
00350
00351
00352 void PopAccount::slotAbortRequested()
00353 {
00354 if (stage == Idle) return;
00355 if ( mMailCheckProgressItem )
00356 disconnect( mMailCheckProgressItem, SIGNAL( progressItemCanceled( KPIM::ProgressItem* ) ),
00357 this, SLOT( slotAbortRequested() ) );
00358 stage = Quit;
00359 if (job) job->kill();
00360 job = 0;
00361 mSlave = 0;
00362 slotCancel();
00363 }
00364
00365
00366
00367 void PopAccount::startJob()
00368 {
00369
00370 if (!runPrecommand(precommand()))
00371 {
00372 KMessageBox::sorry(0,
00373 i18n("Could not execute precommand: %1").arg(precommand()),
00374 i18n("KMail Error Message"));
00375 checkDone( false, CheckError );
00376 return;
00377 }
00378
00379
00380 KURL url = getUrl();
00381
00382 if ( !url.isValid() ) {
00383 KMessageBox::error(0, i18n("Source URL is malformed"),
00384 i18n("Kioslave Error Message") );
00385 return;
00386 }
00387
00388 mMsgsPendingDownload.clear();
00389 idsOfMsgs.clear();
00390 mUidForIdMap.clear();
00391 idsOfMsgsToDelete.clear();
00392
00393 headersOnServer.clear();
00394 headers = false;
00395 indexOfCurrentMsg = -1;
00396
00397 Q_ASSERT( !mMailCheckProgressItem );
00398 QString escapedName = QStyleSheet::escape( mName );
00399 mMailCheckProgressItem = KPIM::ProgressManager::createProgressItem(
00400 "MailCheck" + mName,
00401 escapedName,
00402 i18n("Preparing transmission from \"%1\"...").arg( escapedName ),
00403 true,
00404 useSSL() || useTLS() );
00405 connect( mMailCheckProgressItem, SIGNAL( progressItemCanceled( KPIM::ProgressItem* ) ),
00406 this, SLOT( slotAbortRequested() ) );
00407
00408 numBytes = 0;
00409 numBytesRead = 0;
00410 stage = List;
00411 mSlave = KIO::Scheduler::getConnectedSlave( url, slaveConfig() );
00412 if (!mSlave)
00413 {
00414 slotSlaveError(0, KIO::ERR_CANNOT_LAUNCH_PROCESS, url.protocol());
00415 return;
00416 }
00417 url.setPath(QString("/index"));
00418 job = KIO::get( url, false, false );
00419 connectJob();
00420 }
00421
00422 MetaData PopAccount::slaveConfig() const {
00423 MetaData m = NetworkAccount::slaveConfig();
00424
00425 m.insert("progress", "off");
00426 m.insert("pipelining", (mUsePipelining) ? "on" : "off");
00427 if (mAuth == "PLAIN" || mAuth == "LOGIN" || mAuth == "CRAM-MD5" ||
00428 mAuth == "DIGEST-MD5" || mAuth == "NTLM" || mAuth == "GSSAPI") {
00429 m.insert("auth", "SASL");
00430 m.insert("sasl", mAuth);
00431 } else if ( mAuth == "*" )
00432 m.insert("auth", "USER");
00433 else
00434 m.insert("auth", mAuth);
00435
00436 return m;
00437 }
00438
00439
00440
00441
00442 void PopAccount::slotMsgRetrieved(KIO::Job*, const QString & infoMsg)
00443 {
00444 if (infoMsg != "message complete") return;
00445 KMMessage *msg = new KMMessage;
00446 msg->setComplete(true);
00447
00448
00449 uint newSize = Util::crlf2lf( curMsgData.data(), curMsgData.size() );
00450 curMsgData.resize( newSize );
00451 msg->fromByteArray( curMsgData , true );
00452 if (stage == Head)
00453 {
00454 int size = mMsgsPendingDownload[ headerIt.current()->id() ];
00455 kdDebug(5006) << "Size of Message: " << size << endl;
00456 msg->setMsgLength( size );
00457 headerIt.current()->setHeader(msg);
00458 ++headerIt;
00459 slotGetNextHdr();
00460 } else {
00461
00462
00463 msg->setMsgLength( curMsgData.size() );
00464 msgsAwaitingProcessing.append(msg);
00465 msgIdsAwaitingProcessing.append(idsOfMsgs[indexOfCurrentMsg]);
00466 msgUidsAwaitingProcessing.append( mUidForIdMap[idsOfMsgs[indexOfCurrentMsg]] );
00467 slotGetNextMsg();
00468 }
00469 }
00470
00471
00472
00473
00474 void PopAccount::slotJobFinished() {
00475 QStringList emptyList;
00476 if (stage == List) {
00477 kdDebug(5006) << k_funcinfo << "stage == List" << endl;
00478
00479
00480 mUidsOfNextSeenMsgsDict.resize( KMail::nextPrime( ( idsOfMsgs.count() * 11 ) / 10 ) );
00481 KURL url = getUrl();
00482 url.setPath(QString("/uidl"));
00483 job = KIO::get( url, false, false );
00484 connectJob();
00485 stage = Uidl;
00486 }
00487 else if (stage == Uidl) {
00488 kdDebug(5006) << k_funcinfo << "stage == Uidl" << endl;
00489 mUidlFinished = TRUE;
00490
00491 if ( mLeaveOnServer && mUidForIdMap.isEmpty() &&
00492 mUidsOfNextSeenMsgsDict.isEmpty() && !idsOfMsgs.isEmpty() ) {
00493 KMessageBox::sorry(0, i18n("Your POP3 server (Account: %1) does not support "
00494 "the UIDL command: this command is required to determine, in a reliable way, "
00495 "which of the mails on the server KMail has already seen before;\n"
00496 "the feature to leave the mails on the server will therefore not "
00497 "work properly.").arg(NetworkAccount::name()) );
00498
00499 mUidsOfNextSeenMsgsDict = mUidsOfSeenMsgsDict;
00500 }
00501
00502
00503 if (mFilterOnServer == true) {
00504 QMap<QString, int>::Iterator hids;
00505 for ( hids = mMsgsPendingDownload.begin();
00506 hids != mMsgsPendingDownload.end(); hids++ ) {
00507 kdDebug(5006) << "Length: " << hids.data() << endl;
00508
00509 if ( (unsigned int)hids.data() >= mFilterOnServerCheckSize ) {
00510 kdDebug(5006) << "bigger than " << mFilterOnServerCheckSize << endl;
00511 headersOnServer.append(new KMPopHeaders( hids.key(),
00512 mUidForIdMap[hids.key()],
00513 Later));
00514
00515 if( mHeaderDeleteUids.contains( headersOnServer.current()->uid() ) ) {
00516 headersOnServer.current()->setAction(Delete);
00517 }
00518 else if( mHeaderDownUids.contains( headersOnServer.current()->uid() ) ) {
00519 headersOnServer.current()->setAction(Down);
00520 }
00521 else if( mHeaderLaterUids.contains( headersOnServer.current()->uid() ) ) {
00522 headersOnServer.current()->setAction(Later);
00523 }
00524 }
00525 }
00526
00527 mHeaderDeleteUids.clear();
00528 mHeaderDownUids.clear();
00529 mHeaderLaterUids.clear();
00530 }
00531
00532
00533 if ((headersOnServer.count() > 0) && (mFilterOnServer == true)) {
00534 headerIt.toFirst();
00535 KURL url = getUrl();
00536 QString headerIds;
00537 while (headerIt.current())
00538 {
00539 headerIds += headerIt.current()->id();
00540 if (!headerIt.atLast()) headerIds += ",";
00541 ++headerIt;
00542 }
00543 headerIt.toFirst();
00544 url.setPath(QString("/headers/") + headerIds);
00545 job = KIO::get( url, false, false );
00546 connectJob();
00547 slotGetNextHdr();
00548 stage = Head;
00549 }
00550 else {
00551 stage = Retr;
00552 numMsgs = mMsgsPendingDownload.count();
00553 numBytesToRead = 0;
00554 QMap<QString, int>::Iterator len;
00555 for ( len = mMsgsPendingDownload.begin();
00556 len != mMsgsPendingDownload.end(); len++ )
00557 numBytesToRead += len.data();
00558 idsOfMsgs = QStringList( mMsgsPendingDownload.keys() );
00559 KURL url = getUrl();
00560 url.setPath( "/download/" + idsOfMsgs.join(",") );
00561 job = KIO::get( url, false, false );
00562 connectJob();
00563 slotGetNextMsg();
00564 processMsgsTimer.start(processingDelay);
00565 }
00566 }
00567 else if (stage == Head) {
00568 kdDebug(5006) << k_funcinfo << "stage == Head" << endl;
00569
00570
00571
00572
00573
00574
00575 KMPopFilterAction action;
00576 bool dlgPopup = false;
00577 for (headersOnServer.first(); headersOnServer.current(); headersOnServer.next()) {
00578 action = (KMPopFilterAction)kmkernel->popFilterMgr()->process(headersOnServer.current()->header());
00579
00580 switch ( action ) {
00581 case NoAction:
00582 kdDebug(5006) << "PopFilterAction = NoAction" << endl;
00583 break;
00584 case Later:
00585 kdDebug(5006) << "PopFilterAction = Later" << endl;
00586 break;
00587 case Delete:
00588 kdDebug(5006) << "PopFilterAction = Delete" << endl;
00589 break;
00590 case Down:
00591 kdDebug(5006) << "PopFilterAction = Down" << endl;
00592 break;
00593 default:
00594 kdDebug(5006) << "PopFilterAction = default oops!" << endl;
00595 break;
00596 }
00597 switch ( action ) {
00598 case NoAction:
00599
00600 dlgPopup = true;
00601 break;
00602 case Later:
00603 if (kmkernel->popFilterMgr()->showLaterMsgs())
00604 dlgPopup = true;
00605
00606 default:
00607 headersOnServer.current()->setAction(action);
00608 headersOnServer.current()->setRuleMatched(true);
00609 break;
00610 }
00611 }
00612
00613
00614
00615 headers = true;
00616 if (dlgPopup) {
00617 KMPopFilterCnfrmDlg dlg(&headersOnServer, this->name(), kmkernel->popFilterMgr()->showLaterMsgs());
00618 dlg.exec();
00619 }
00620
00621 for (headersOnServer.first(); headersOnServer.current(); headersOnServer.next()) {
00622 if (headersOnServer.current()->action() == Delete ||
00623 headersOnServer.current()->action() == Later) {
00624
00625
00626 if ( mMsgsPendingDownload.contains( headersOnServer.current()->id() ) ) {
00627 mMsgsPendingDownload.remove( headersOnServer.current()->id() );
00628 }
00629 if (headersOnServer.current()->action() == Delete) {
00630 mHeaderDeleteUids.insert(headersOnServer.current()->uid(), true);
00631 mUidsOfNextSeenMsgsDict.insert( headersOnServer.current()->uid(),
00632 (const int *)1 );
00633 idsOfMsgsToDelete.append(headersOnServer.current()->id());
00634 mTimeOfNextSeenMsgsMap.insert( headersOnServer.current()->uid(),
00635 time(0) );
00636 }
00637 else {
00638 mHeaderLaterUids.insert(headersOnServer.current()->uid(), true);
00639 }
00640 }
00641 else if (headersOnServer.current()->action() == Down) {
00642 mHeaderDownUids.insert(headersOnServer.current()->uid(), true);
00643 }
00644 }
00645
00646 headersOnServer.clear();
00647 stage = Retr;
00648 numMsgs = mMsgsPendingDownload.count();
00649 numBytesToRead = 0;
00650 QMap<QString, int>::Iterator len;
00651 for (len = mMsgsPendingDownload.begin();
00652 len != mMsgsPendingDownload.end(); len++)
00653 numBytesToRead += len.data();
00654 idsOfMsgs = QStringList( mMsgsPendingDownload.keys() );
00655 KURL url = getUrl();
00656 url.setPath( "/download/" + idsOfMsgs.join(",") );
00657 job = KIO::get( url, false, false );
00658 connectJob();
00659 slotGetNextMsg();
00660 processMsgsTimer.start(processingDelay);
00661 }
00662 else if (stage == Retr) {
00663 if ( mMailCheckProgressItem )
00664 mMailCheckProgressItem->setProgress( 100 );
00665 processRemainingQueuedMessages();
00666
00667 mHeaderDeleteUids.clear();
00668 mHeaderDownUids.clear();
00669 mHeaderLaterUids.clear();
00670
00671 kmkernel->folderMgr()->syncAllFolders();
00672
00673 KURL url = getUrl();
00674 QMap< QPair<time_t, QString>, int > idsToSave;
00675 idsToSave.clear();
00676
00677 if ( mLeaveOnServer && !idsOfMsgsToDelete.isEmpty() ) {
00678
00679 if ( mLeaveOnServerDays == -1 && mLeaveOnServerCount <= 0 &&
00680 mLeaveOnServerSize <= 0)
00681 idsOfMsgsToDelete.clear();
00682
00683 else if ( mLeaveOnServerDays > 0 && !mTimeOfNextSeenMsgsMap.isEmpty() ) {
00684 time_t timeLimit = time(0) - (86400 * mLeaveOnServerDays);
00685 kdDebug() << "timeLimit is " << timeLimit << endl;
00686 QStringList::Iterator cur = idsOfMsgsToDelete.begin();
00687 for ( ; cur != idsOfMsgsToDelete.end(); ++cur) {
00688 time_t msgTime = mTimeOfNextSeenMsgsMap[mUidForIdMap[*cur]];
00689 kdDebug() << "id: " << *cur << " msgTime: " << msgTime << endl;
00690 if (msgTime >= timeLimit ||
00691 !mTimeOfNextSeenMsgsMap[mUidForIdMap[*cur]]) {
00692 kdDebug() << "Saving msg id " << *cur << endl;
00693 QPair<time_t, QString> msg(msgTime, *cur);
00694 idsToSave.insert( msg, 1 );
00695 }
00696 }
00697 }
00698
00699 if ( mLeaveOnServerCount > 0 ) {
00700 int numToDelete = idsToSave.count() - mLeaveOnServerCount;
00701 kdDebug() << "numToDelete is " << numToDelete << endl;
00702 if ( numToDelete > 0 && (unsigned)numToDelete < idsToSave.count() ) {
00703 QMap< QPair<time_t, QString>, int >::Iterator cur = idsToSave.begin();
00704 for ( int deleted = 0; deleted < numToDelete && cur != idsToSave.end()
00705 ; deleted++, cur++ ) {
00706 kdDebug() << "deleting msg id " << cur.key().second << endl;
00707 idsToSave.remove( cur );
00708 }
00709 }
00710 else if ( numToDelete > 0 && (unsigned)numToDelete >= idsToSave.count() )
00711 idsToSave.clear();
00712 }
00713
00714 if ( mLeaveOnServerSize > 0 ) {
00715 double sizeOnServer = 0;
00716 QMap< QPair<time_t, QString>, int >::Iterator cur = idsToSave.begin();
00717 for ( ; cur != idsToSave.end(); cur++ ) {
00718 sizeOnServer +=
00719 *mSizeOfNextSeenMsgsDict[ mUidForIdMap[ cur.key().second ] ];
00720 }
00721 kdDebug() << "sizeOnServer is " << sizeOnServer/(1024*1024) << "MB" << endl;
00722 long limitInBytes = mLeaveOnServerSize * ( 1024 * 1024 );
00723 for ( cur = idsToSave.begin(); cur != idsToSave.end()
00724 && sizeOnServer > limitInBytes; cur++ ) {
00725 sizeOnServer -=
00726 *mSizeOfNextSeenMsgsDict[ mUidForIdMap[ cur.key().second ] ];
00727 idsToSave.remove( cur );
00728 }
00729 }
00730
00731 QMap< QPair<time_t, QString>, int >::Iterator it = idsToSave.begin();
00732 kdDebug() << "Going to save " << idsToSave.count() << endl;
00733 for ( ; it != idsToSave.end(); ++it ) {
00734 kdDebug() << "saving msg id " << it.key().second << endl;
00735 idsOfMsgsToDelete.remove( it.key().second );
00736 }
00737 }
00738
00739 if ( !idsOfMsgsToDelete.isEmpty() ) {
00740 stage = Dele;
00741 if ( mMailCheckProgressItem )
00742 mMailCheckProgressItem->setStatus(
00743 i18n( "Fetched 1 message from %1. Deleting messages from server...",
00744 "Fetched %n messages from %1. Deleting messages from server...",
00745 numMsgs )
00746 .arg( mHost ) );
00747 url.setPath("/remove/" + idsOfMsgsToDelete.join(","));
00748 kdDebug(5006) << "url: " << url.prettyURL() << endl;
00749 } else {
00750 stage = Quit;
00751 if ( mMailCheckProgressItem )
00752 mMailCheckProgressItem->setStatus(
00753 i18n( "Fetched 1 message from %1. Terminating transmission...",
00754 "Fetched %n messages from %1. Terminating transmission...",
00755 numMsgs )
00756 .arg( mHost ) );
00757 url.setPath(QString("/commit"));
00758 kdDebug(5006) << "url: " << url.prettyURL() << endl;
00759 }
00760 job = KIO::get( url, false, false );
00761 connectJob();
00762 }
00763 else if (stage == Dele) {
00764 kdDebug(5006) << k_funcinfo << "stage == Dele" << endl;
00765
00766 for ( QStringList::ConstIterator it = idsOfMsgsToDelete.begin();
00767 it != idsOfMsgsToDelete.end(); ++it ) {
00768 mUidsOfNextSeenMsgsDict.remove( mUidForIdMap[*it] );
00769 }
00770 idsOfMsgsToDelete.clear();
00771 if ( mMailCheckProgressItem )
00772 mMailCheckProgressItem->setStatus(
00773 i18n( "Fetched 1 message from %1. Terminating transmission...",
00774 "Fetched %n messages from %1. Terminating transmission...",
00775 numMsgs )
00776 .arg( mHost ) );
00777 KURL url = getUrl();
00778 url.setPath(QString("/commit"));
00779 job = KIO::get( url, false, false );
00780 stage = Quit;
00781 connectJob();
00782 }
00783 else if (stage == Quit) {
00784 kdDebug(5006) << k_funcinfo << "stage == Quit" << endl;
00785 saveUidList();
00786 job = 0;
00787 if (mSlave) KIO::Scheduler::disconnectSlave(mSlave);
00788 mSlave = 0;
00789 stage = Idle;
00790 if( mMailCheckProgressItem ) {
00791 bool canceled = kmkernel->mailCheckAborted() || mMailCheckProgressItem->canceled();
00792 int numMessages = canceled ? indexOfCurrentMsg : idsOfMsgs.count();
00793 BroadcastStatus::instance()->setStatusMsgTransmissionCompleted(
00794 this->name(), numMessages, numBytes, numBytesRead, numBytesToRead, mLeaveOnServer, mMailCheckProgressItem );
00795
00796
00797 ProgressItem *savedMailCheckProgressItem = mMailCheckProgressItem;
00798 mMailCheckProgressItem = 0;
00799 savedMailCheckProgressItem->setComplete();
00800 checkDone( ( numMessages > 0 ), canceled ? CheckAborted : CheckOK );
00801 }
00802 }
00803 }
00804
00805
00806
00807 void PopAccount::processRemainingQueuedMessages()
00808 {
00809 kdDebug(5006) << k_funcinfo << endl;
00810 slotProcessPendingMsgs();
00811 processMsgsTimer.stop();
00812
00813 stage = Quit;
00814 if ( kmkernel && kmkernel->folderMgr() ) {
00815 kmkernel->folderMgr()->syncAllFolders();
00816 }
00817 }
00818
00819
00820
00821 void PopAccount::saveUidList()
00822 {
00823 kdDebug(5006) << k_funcinfo << endl;
00824
00825
00826 if (!mUidlFinished) return;
00827
00828 QStringList uidsOfNextSeenMsgs;
00829 QValueList<int> seenUidTimeList;
00830 QDictIterator<int> it( mUidsOfNextSeenMsgsDict );
00831 for( ; it.current(); ++it ) {
00832 uidsOfNextSeenMsgs.append( it.currentKey() );
00833 seenUidTimeList.append( mTimeOfNextSeenMsgsMap[it.currentKey()] );
00834 }
00835 QString seenUidList = locateLocal( "data", "kmail/" + mLogin + ":" + "@" +
00836 mHost + ":" + QString("%1").arg(mPort) );
00837 KConfig config( seenUidList );
00838 config.writeEntry( "seenUidList", uidsOfNextSeenMsgs );
00839 config.writeEntry( "seenUidTimeList", seenUidTimeList );
00840 config.writeEntry( "downloadLater", QStringList( mHeaderLaterUids.keys() ) );
00841 config.sync();
00842 }
00843
00844
00845
00846 void PopAccount::slotGetNextMsg()
00847 {
00848 QMap<QString, int>::Iterator next = mMsgsPendingDownload.begin();
00849
00850 curMsgData.resize(0);
00851 numMsgBytesRead = 0;
00852 curMsgLen = 0;
00853 delete curMsgStrm;
00854 curMsgStrm = 0;
00855
00856 if ( next != mMsgsPendingDownload.end() ) {
00857
00858 int nextLen = next.data();
00859 curMsgStrm = new QDataStream( curMsgData, IO_WriteOnly );
00860 curMsgLen = nextLen;
00861 ++indexOfCurrentMsg;
00862 kdDebug(5006) << QString("Length of message about to get %1").arg( nextLen ) << endl;
00863 mMsgsPendingDownload.remove( next.key() );
00864 }
00865 }
00866
00867
00868
00869 void PopAccount::slotData( KIO::Job* job, const QByteArray &data)
00870 {
00871 if (data.size() == 0) {
00872 kdDebug(5006) << "Data: <End>" << endl;
00873 if ((stage == Retr) && (numMsgBytesRead < curMsgLen))
00874 numBytesRead += curMsgLen - numMsgBytesRead;
00875 else if (stage == Head){
00876 kdDebug(5006) << "Head: <End>" << endl;
00877 }
00878 return;
00879 }
00880
00881 int oldNumMsgBytesRead = numMsgBytesRead;
00882 if (stage == Retr) {
00883 headers = false;
00884 curMsgStrm->writeRawBytes( data.data(), data.size() );
00885 numMsgBytesRead += data.size();
00886 if (numMsgBytesRead > curMsgLen)
00887 numMsgBytesRead = curMsgLen;
00888 numBytesRead += numMsgBytesRead - oldNumMsgBytesRead;
00889 dataCounter++;
00890 if ( mMailCheckProgressItem &&
00891 ( dataCounter % 5 == 0 ||
00892 ( indexOfCurrentMsg + 1 == numMsgs && numMsgBytesRead == curMsgLen ) ) )
00893 {
00894 QString msg;
00895 if (numBytes != numBytesToRead && mLeaveOnServer)
00896 {
00897 msg = i18n("Fetching message %1 of %2 (%3 of %4 KB) for %5@%6 "
00898 "(%7 KB remain on the server).")
00899 .arg(indexOfCurrentMsg+1).arg(numMsgs).arg(numBytesRead/1024)
00900 .arg(numBytesToRead/1024).arg(mLogin).arg(mHost).arg(numBytes/1024);
00901 }
00902 else
00903 {
00904 msg = i18n("Fetching message %1 of %2 (%3 of %4 KB) for %5@%6.")
00905 .arg(indexOfCurrentMsg+1).arg(numMsgs).arg(numBytesRead/1024)
00906 .arg(numBytesToRead/1024).arg(mLogin).arg(mHost);
00907 }
00908 mMailCheckProgressItem->setStatus( msg );
00909 mMailCheckProgressItem->setProgress(
00910 (numBytesToRead <= 100) ? 50
00911
00912 : (numBytesRead / (numBytesToRead / 100)) );
00913 }
00914 return;
00915 }
00916
00917 if (stage == Head) {
00918 curMsgStrm->writeRawBytes( data.data(), data.size() );
00919 return;
00920 }
00921
00922
00923 QString qdata = data;
00924 qdata = qdata.simplifyWhiteSpace();
00925 int spc = qdata.find( ' ' );
00926 if (spc > 0) {
00927 if (stage == List) {
00928 QString length = qdata.mid(spc+1);
00929 if (length.find(' ') != -1) length.truncate(length.find(' '));
00930 int len = length.toInt();
00931 numBytes += len;
00932 QString id = qdata.left(spc);
00933 idsOfMsgs.append( id );
00934 mMsgsPendingDownload.insert( id, len );
00935 }
00936 else {
00937 const QString id = qdata.left(spc);
00938 const QString uid = qdata.mid(spc + 1);
00939 int *size = new int;
00940 *size = mMsgsPendingDownload[id];
00941 mSizeOfNextSeenMsgsDict.insert( uid, size );
00942 if ( mUidsOfSeenMsgsDict.find( uid ) != 0 ) {
00943
00944 if ( mMsgsPendingDownload.contains( id ) ) {
00945 mMsgsPendingDownload.remove( id );
00946 }
00947 else
00948 kdDebug(5006) << "PopAccount::slotData synchronization failure." << endl;
00949 idsOfMsgsToDelete.append( id );
00950 mUidsOfNextSeenMsgsDict.insert( uid, (const int *)1 );
00951 if ( mTimeOfSeenMsgsVector.empty() ) {
00952 mTimeOfNextSeenMsgsMap.insert( uid, time(0) );
00953 }
00954 else {
00955
00956
00957 mTimeOfNextSeenMsgsMap.insert( uid,
00958 mTimeOfSeenMsgsVector[(int)( long )mUidsOfSeenMsgsDict[uid] - 1] );
00959 }
00960 }
00961 mUidForIdMap.insert( id, uid );
00962 }
00963 }
00964 else {
00965 stage = Idle;
00966 if (job) job->kill();
00967 job = 0;
00968 mSlave = 0;
00969 KMessageBox::error(0, i18n( "Unable to complete LIST operation." ),
00970 i18n("Invalid Response From Server"));
00971 return;
00972 }
00973 }
00974
00975
00976
00977 void PopAccount::slotResult( KIO::Job* )
00978 {
00979 if (!job) return;
00980 if ( job->error() )
00981 {
00982 if (interactive) {
00983 if (headers) {
00984 idsOfMsgs.clear();
00985 }
00986 if (stage == Head && job->error() == KIO::ERR_COULD_NOT_READ)
00987 {
00988 KMessageBox::error(0, i18n("Your server does not support the "
00989 "TOP command. Therefore it is not possible to fetch the headers "
00990 "of large emails first, before downloading them."));
00991 slotCancel();
00992 return;
00993 }
00994
00995 if (!mStorePasswd) mPasswd = "";
00996 job->showErrorDialog();
00997 }
00998 slotCancel();
00999 }
01000 else
01001 slotJobFinished();
01002 }
01003
01004
01005
01006 void PopAccount::slotSlaveError(KIO::Slave *aSlave, int error,
01007 const QString &errorMsg)
01008 {
01009 if (aSlave != mSlave) return;
01010 if (error == KIO::ERR_SLAVE_DIED) mSlave = 0;
01011
01012
01013 if ( error == KIO::ERR_CONNECTION_BROKEN && mSlave ) {
01014 KIO::Scheduler::disconnectSlave( mSlave );
01015 mSlave = 0;
01016 }
01017
01018 if (interactive) {
01019 KMessageBox::error(kmkernel->mainWin(), KIO::buildErrorString(error, errorMsg));
01020 }
01021
01022
01023 stage = Quit;
01024 if (error == KIO::ERR_COULD_NOT_LOGIN && !mStorePasswd)
01025 mAskAgain = TRUE;
01026
01027
01028
01029 QTimer::singleShot(0, this, SLOT(slotCancel()));
01030 }
01031
01032
01033 void PopAccount::slotGetNextHdr(){
01034 kdDebug(5006) << "slotGetNextHeader" << endl;
01035
01036 curMsgData.resize(0);
01037 delete curMsgStrm;
01038 curMsgStrm = 0;
01039
01040 curMsgStrm = new QDataStream( curMsgData, IO_WriteOnly );
01041 }
01042
01043 void PopAccount::killAllJobs( bool ) {
01044
01045 }
01046
01047 }
01048 #include "popaccount.moc"