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 kmkernel->folderMgr()->syncAllFolders();
00815 }
00816
00817
00818
00819 void PopAccount::saveUidList()
00820 {
00821 kdDebug(5006) << k_funcinfo << endl;
00822
00823
00824 if (!mUidlFinished) return;
00825
00826 QStringList uidsOfNextSeenMsgs;
00827 QValueList<int> seenUidTimeList;
00828 QDictIterator<int> it( mUidsOfNextSeenMsgsDict );
00829 for( ; it.current(); ++it ) {
00830 uidsOfNextSeenMsgs.append( it.currentKey() );
00831 seenUidTimeList.append( mTimeOfNextSeenMsgsMap[it.currentKey()] );
00832 }
00833 QString seenUidList = locateLocal( "data", "kmail/" + mLogin + ":" + "@" +
00834 mHost + ":" + QString("%1").arg(mPort) );
00835 KConfig config( seenUidList );
00836 config.writeEntry( "seenUidList", uidsOfNextSeenMsgs );
00837 config.writeEntry( "seenUidTimeList", seenUidTimeList );
00838 config.writeEntry( "downloadLater", QStringList( mHeaderLaterUids.keys() ) );
00839 config.sync();
00840 }
00841
00842
00843
00844 void PopAccount::slotGetNextMsg()
00845 {
00846 QMap<QString, int>::Iterator next = mMsgsPendingDownload.begin();
00847
00848 curMsgData.resize(0);
00849 numMsgBytesRead = 0;
00850 curMsgLen = 0;
00851 delete curMsgStrm;
00852 curMsgStrm = 0;
00853
00854 if ( next != mMsgsPendingDownload.end() ) {
00855
00856 int nextLen = next.data();
00857 curMsgStrm = new QDataStream( curMsgData, IO_WriteOnly );
00858 curMsgLen = nextLen;
00859 ++indexOfCurrentMsg;
00860 kdDebug(5006) << QString("Length of message about to get %1").arg( nextLen ) << endl;
00861 mMsgsPendingDownload.remove( next.key() );
00862 }
00863 }
00864
00865
00866
00867 void PopAccount::slotData( KIO::Job* job, const QByteArray &data)
00868 {
00869 if (data.size() == 0) {
00870 kdDebug(5006) << "Data: <End>" << endl;
00871 if ((stage == Retr) && (numMsgBytesRead < curMsgLen))
00872 numBytesRead += curMsgLen - numMsgBytesRead;
00873 else if (stage == Head){
00874 kdDebug(5006) << "Head: <End>" << endl;
00875 }
00876 return;
00877 }
00878
00879 int oldNumMsgBytesRead = numMsgBytesRead;
00880 if (stage == Retr) {
00881 headers = false;
00882 curMsgStrm->writeRawBytes( data.data(), data.size() );
00883 numMsgBytesRead += data.size();
00884 if (numMsgBytesRead > curMsgLen)
00885 numMsgBytesRead = curMsgLen;
00886 numBytesRead += numMsgBytesRead - oldNumMsgBytesRead;
00887 dataCounter++;
00888 if ( mMailCheckProgressItem &&
00889 ( dataCounter % 5 == 0 ||
00890 ( indexOfCurrentMsg + 1 == numMsgs && numMsgBytesRead == curMsgLen ) ) )
00891 {
00892 QString msg;
00893 if (numBytes != numBytesToRead && mLeaveOnServer)
00894 {
00895 msg = i18n("Fetching message %1 of %2 (%3 of %4 KB) for %5@%6 "
00896 "(%7 KB remain on the server).")
00897 .arg(indexOfCurrentMsg+1).arg(numMsgs).arg(numBytesRead/1024)
00898 .arg(numBytesToRead/1024).arg(mLogin).arg(mHost).arg(numBytes/1024);
00899 }
00900 else
00901 {
00902 msg = i18n("Fetching message %1 of %2 (%3 of %4 KB) for %5@%6.")
00903 .arg(indexOfCurrentMsg+1).arg(numMsgs).arg(numBytesRead/1024)
00904 .arg(numBytesToRead/1024).arg(mLogin).arg(mHost);
00905 }
00906 mMailCheckProgressItem->setStatus( msg );
00907 mMailCheckProgressItem->setProgress(
00908 (numBytesToRead <= 100) ? 50
00909
00910 : (numBytesRead / (numBytesToRead / 100)) );
00911 }
00912 return;
00913 }
00914
00915 if (stage == Head) {
00916 curMsgStrm->writeRawBytes( data.data(), data.size() );
00917 return;
00918 }
00919
00920
00921 QString qdata = data;
00922 qdata = qdata.simplifyWhiteSpace();
00923 int spc = qdata.find( ' ' );
00924 if (spc > 0) {
00925 if (stage == List) {
00926 QString length = qdata.mid(spc+1);
00927 if (length.find(' ') != -1) length.truncate(length.find(' '));
00928 int len = length.toInt();
00929 numBytes += len;
00930 QString id = qdata.left(spc);
00931 idsOfMsgs.append( id );
00932 mMsgsPendingDownload.insert( id, len );
00933 }
00934 else {
00935 const QString id = qdata.left(spc);
00936 const QString uid = qdata.mid(spc + 1);
00937 int *size = new int;
00938 *size = mMsgsPendingDownload[id];
00939 mSizeOfNextSeenMsgsDict.insert( uid, size );
00940 if ( mUidsOfSeenMsgsDict.find( uid ) != 0 ) {
00941
00942 if ( mMsgsPendingDownload.contains( id ) ) {
00943 mMsgsPendingDownload.remove( id );
00944 }
00945 else
00946 kdDebug(5006) << "PopAccount::slotData synchronization failure." << endl;
00947 idsOfMsgsToDelete.append( id );
00948 mUidsOfNextSeenMsgsDict.insert( uid, (const int *)1 );
00949 if ( mTimeOfSeenMsgsVector.empty() ) {
00950 mTimeOfNextSeenMsgsMap.insert( uid, time(0) );
00951 }
00952 else {
00953
00954
00955 mTimeOfNextSeenMsgsMap.insert( uid,
00956 mTimeOfSeenMsgsVector[(int)( long )mUidsOfSeenMsgsDict[uid] - 1] );
00957 }
00958 }
00959 mUidForIdMap.insert( id, uid );
00960 }
00961 }
00962 else {
00963 stage = Idle;
00964 if (job) job->kill();
00965 job = 0;
00966 mSlave = 0;
00967 KMessageBox::error(0, i18n( "Unable to complete LIST operation." ),
00968 i18n("Invalid Response From Server"));
00969 return;
00970 }
00971 }
00972
00973
00974
00975 void PopAccount::slotResult( KIO::Job* )
00976 {
00977 if (!job) return;
00978 if ( job->error() )
00979 {
00980 if (interactive) {
00981 if (headers) {
00982 idsOfMsgs.clear();
00983 }
00984 if (stage == Head && job->error() == KIO::ERR_COULD_NOT_READ)
00985 {
00986 KMessageBox::error(0, i18n("Your server does not support the "
00987 "TOP command. Therefore it is not possible to fetch the headers "
00988 "of large emails first, before downloading them."));
00989 slotCancel();
00990 return;
00991 }
00992
00993 if (!mStorePasswd) mPasswd = "";
00994 job->showErrorDialog();
00995 }
00996 slotCancel();
00997 }
00998 else
00999 slotJobFinished();
01000 }
01001
01002
01003
01004 void PopAccount::slotSlaveError(KIO::Slave *aSlave, int error,
01005 const QString &errorMsg)
01006 {
01007 if (aSlave != mSlave) return;
01008 if (error == KIO::ERR_SLAVE_DIED) mSlave = 0;
01009
01010
01011 if ( error == KIO::ERR_CONNECTION_BROKEN && mSlave ) {
01012 KIO::Scheduler::disconnectSlave( mSlave );
01013 mSlave = 0;
01014 }
01015
01016 if (interactive) {
01017 KMessageBox::error(kmkernel->mainWin(), KIO::buildErrorString(error, errorMsg));
01018 }
01019
01020
01021 stage = Quit;
01022 if (error == KIO::ERR_COULD_NOT_LOGIN && !mStorePasswd)
01023 mAskAgain = TRUE;
01024
01025
01026
01027 QTimer::singleShot(0, this, SLOT(slotCancel()));
01028 }
01029
01030
01031 void PopAccount::slotGetNextHdr(){
01032 kdDebug(5006) << "slotGetNextHeader" << endl;
01033
01034 curMsgData.resize(0);
01035 delete curMsgStrm;
01036 curMsgStrm = 0;
01037
01038 curMsgStrm = new QDataStream( curMsgData, IO_WriteOnly );
01039 }
01040
01041 void PopAccount::killAllJobs( bool ) {
01042
01043 }
01044
01045 }
01046 #include "popaccount.moc"