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