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