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