00001
00023
#ifdef HAVE_CONFIG_H
00024
#include <config.h>
00025
#endif
00026
00027
#include "kmfolderimap.h"
00028
#include "kmfoldermbox.h"
00029
#include "kmfoldertree.h"
00030
#include "undostack.h"
00031
#include "kmfoldermgr.h"
00032
#include "imapjob.h"
00033
using KMail::ImapJob;
00034
#include "attachmentstrategy.h"
00035
using KMail::AttachmentStrategy;
00036
#include "progressmanager.h"
00037
using KPIM::ProgressItem;
00038
using KPIM::ProgressManager;
00039
#include "listjob.h"
00040
using KMail::ListJob;
00041
00042
#include <kdebug.h>
00043
#include <kio/scheduler.h>
00044
#include <kconfig.h>
00045
00046
#include <qbuffer.h>
00047
#include <qtextcodec.h>
00048
00049
#include <assert.h>
00050
00051 KMFolderImap::KMFolderImap(
KMFolder* folder,
const char* aName)
00052 : KMFolderMbox(folder, aName)
00053 {
00054 mContentState = imapNoInformation;
00055 mSubfolderState = imapNoInformation;
00056 mAccount = 0;
00057 mIsSelected = FALSE;
00058 mLastUid = 0;
00059 mCheckFlags = TRUE;
00060 mCheckMail = TRUE;
00061 mCheckingValidity = FALSE;
00062 mUserRights = 0;
00063 mAlreadyRemoved =
false;
00064 mHasChildren = ChildrenUnknown;
00065 mMailCheckProgressItem = 0;
00066 mListDirProgressItem = 0;
00067
00068 connect (
this, SIGNAL( folderComplete( KMFolderImap*,
bool ) ),
00069
this, SLOT( slotCompleteMailCheckProgress()) );
00070 }
00071
00072 KMFolderImap::~KMFolderImap()
00073 {
00074
if (mAccount) {
00075 mAccount->removeSlaveJobsForFolder( folder() );
00076
00077
00078
00079
00080
if ( mAccount->checkingMail( folder() ) ) {
00081 mAccount->killAllJobs();
00082 }
00083 }
00084 writeConfig();
00085
if (kmkernel->undoStack()) kmkernel->undoStack()->folderDestroyed( folder() );
00086 mMetaDataMap.setAutoDelete(
true );
00087 mMetaDataMap.clear();
00088 }
00089
00090
00091
00092
void KMFolderImap::close(
bool aForced)
00093 {
00094
if (mOpenCount <= 0 )
return;
00095
if (mOpenCount > 0) mOpenCount--;
00096
if (mOpenCount > 0 && !aForced)
return;
00097
00098
if (mAccount)
00099 mAccount->ignoreJobsForFolder( folder() );
00100
int idx = count();
00101
while (--idx >= 0) {
00102
if ( mMsgList[idx]->isMessage() ) {
00103 KMMessage *msg = static_cast<KMMessage*>(mMsgList[idx]);
00104
if (msg->transferInProgress())
00105 msg->setTransferInProgress(
false );
00106 }
00107 }
00108
00109 mOpenCount++;
00110 KMFolderMbox::close(aForced);
00111 }
00112
00113
KMFolder* KMFolderImap::trashFolder()
const
00114
{
00115
QString trashStr = account()->trash();
00116
return kmkernel->imapFolderMgr()->findIdString( trashStr );
00117 }
00118
00119
00120 KMMessage* KMFolderImap::getMsg(
int idx)
00121 {
00122
if(!(idx >= 0 && idx <= count()))
00123
return 0;
00124
00125 KMMsgBase* mb = getMsgBase(idx);
00126
if (!mb)
return 0;
00127
if (mb->isMessage())
00128 {
00129
return ((KMMessage*)mb);
00130 }
else {
00131 KMMessage* msg =
FolderStorage::getMsg( idx );
00132
if ( msg )
00133 msg->setComplete(
false );
00134
return msg;
00135 }
00136 }
00137
00138
00139
void KMFolderImap::setAccount(KMAcctImap *aAccount)
00140 {
00141 mAccount = aAccount;
00142
if( !folder() || !folder()->
child() )
return;
00143 KMFolderNode* node;
00144
for (node = folder()->
child()->first(); node;
00145 node = folder()->
child()->next())
00146 {
00147
if (!node->isDir())
00148 static_cast<KMFolderImap*>(static_cast<KMFolder*>(node)->storage())->setAccount(aAccount);
00149 }
00150 }
00151
00152
00153
void KMFolderImap::readConfig()
00154 {
00155 KConfig* config = KMKernel::config();
00156 KConfigGroupSaver saver(config,
"Folder-" + folder()->idString());
00157 mCheckMail = config->readBoolEntry(
"checkmail",
true);
00158
00159 mUidValidity = config->readEntry(
"UidValidity");
00160
if (mImapPath.isEmpty()) mImapPath = config->readEntry(
"ImapPath");
00161
if (
QString(name()).upper() ==
"INBOX" && mImapPath ==
"/INBOX/")
00162 {
00163 folder()->
setSystemFolder(
true );
00164 folder()->
setLabel( i18n(
"inbox") );
00165 }
00166 mNoContent = config->readBoolEntry(
"NoContent", FALSE);
00167 mReadOnly = config->readBoolEntry(
"ReadOnly", FALSE);
00168
00169 KMFolderMbox::readConfig();
00170 }
00171
00172
00173
void KMFolderImap::writeConfig()
00174 {
00175 KConfig* config = KMKernel::config();
00176 KConfigGroupSaver saver(config,
"Folder-" + folder()->idString());
00177 config->writeEntry(
"checkmail", mCheckMail);
00178 config->writeEntry(
"UidValidity", mUidValidity);
00179 config->writeEntry(
"ImapPath", mImapPath);
00180 config->writeEntry(
"NoContent", mNoContent);
00181 config->writeEntry(
"ReadOnly", mReadOnly);
00182 KMFolderMbox::writeConfig();
00183 }
00184
00185
00186
void KMFolderImap::remove()
00187 {
00188
if ( mAlreadyRemoved || !mAccount )
00189 {
00190
00191
FolderStorage::remove();
00192
return;
00193 }
00194 KURL url = mAccount->getUrl();
00195 url.setPath(imapPath());
00196
if ( mAccount->makeConnection() == ImapAccountBase::Error )
00197 {
00198 emit removed(folder(),
false);
00199
return;
00200 }
00201 KIO::SimpleJob *job = KIO::file_delete(url, FALSE);
00202 KIO::Scheduler::assignJobToSlave(mAccount->slave(), job);
00203 ImapAccountBase::jobData jd(url.url());
00204 jd.progressItem = ProgressManager::createProgressItem(
00205
"ImapFolderRemove" + ProgressManager::getUniqueID(),
00206
"Removing folder",
00207
"URL: " + folder()->
prettyURL(),
00208
false,
00209 mAccount->useSSL() || mAccount->useTLS() );
00210 mAccount->insertJob(job, jd);
00211 connect(job, SIGNAL(result(KIO::Job *)),
00212
this, SLOT(slotRemoveFolderResult(KIO::Job *)));
00213 }
00214
00215
00216
void KMFolderImap::slotRemoveFolderResult(KIO::Job *job)
00217 {
00218 ImapAccountBase::JobIterator it = mAccount->findJob(job);
00219
if ( it == mAccount->jobsEnd() )
return;
00220
if (job->error())
00221 {
00222 mAccount->handleJobError( job, i18n(
"Error while removing a folder.") );
00223 emit removed(folder(),
false);
00224 }
else {
00225 mAccount->removeJob(it);
00226
FolderStorage::remove();
00227 }
00228
00229 }
00230
00231
00232
void KMFolderImap::removeMsg(
int idx,
bool quiet)
00233 {
00234
if (idx < 0)
00235
return;
00236
00237
if (!quiet)
00238 {
00239 KMMessage *msg = getMsg(idx);
00240 deleteMessage(msg);
00241 }
00242
00243 mLastUid = 0;
00244 KMFolderMbox::removeMsg(idx);
00245 }
00246
00247
void KMFolderImap::removeMsg(
const QPtrList<KMMessage>& msgList,
bool quiet )
00248 {
00249
if ( msgList.isEmpty() )
return;
00250
if (!quiet)
00251 deleteMessage(msgList);
00252
00253 mLastUid = 0;
00254
00255
00256
00257
00258
00259
00260
QPtrListIterator<KMMessage> it( msgList );
00261 KMMessage *msg;
00262
while ( (msg = it.current()) != 0 ) {
00263 ++it;
00264
int idx = find(msg);
00265 assert( idx != -1);
00266
00267 KMFolderMbox::removeMsg(idx, quiet);
00268 }
00269 }
00270
00271
00272
int KMFolderImap::rename(
const QString& newName,
KMFolderDir * )
00273 {
00274
if ( newName == name() )
00275
return 0;
00276
00277
QString path = imapPath();
00278 path.replace( name(), newName );
00279 KURL src( mAccount->getUrl() );
00280 src.setPath( imapPath() );
00281 KURL dst( mAccount->getUrl() );
00282 dst.setPath( path );
00283
00284 ImapAccountBase::jobData jd;
00285 jd.path = newName;
00286 KIO::SimpleJob *job = KIO::rename( src, dst,
true );
00287 kdDebug(5006)<<
"KMFolderImap::rename - " << src.prettyURL()
00288 <<
" |=> " << dst.prettyURL()
00289 << endl;
00290 mAccount->insertJob( job, jd );
00291 KIO::Scheduler::assignJobToSlave( mAccount->slave(), job );
00292 connect( job, SIGNAL(result(KIO::Job*)),
00293 SLOT(slotRenameResult(KIO::Job*)) );
00294 setImapPath( path );
00295
return 0;
00296 }
00297
00298
00299
void KMFolderImap::slotRenameResult( KIO::Job *job )
00300 {
00301 ImapAccountBase::JobIterator it = mAccount->findJob( job );
00302
if ( it == mAccount->jobsEnd() )
return;
00303 KIO::SimpleJob* sj = static_cast<KIO::SimpleJob*>(job);
00304
if ( job->error() ) {
00305
00306 setImapPath( sj->url().path() );
00307 mAccount->handleJobError( job, i18n(
"Error while renaming a folder.") );
00308
return;
00309 }
00310
00311 mAccount->changeSubscription(
false, sj->url().path() );
00312
00313 mAccount->changeSubscription(
true, imapPath() );
00314
00315 KMFolderMbox::rename( (*it).path );
00316 mAccount->removeJob(it);
00317 kmkernel->folderMgr()->contentsChanged();
00318 }
00319
00320
00321
void KMFolderImap::addMsgQuiet(KMMessage* aMsg)
00322 {
00323
KMFolder *aFolder = aMsg->parent();
00324 Q_UINT32 serNum = 0;
00325 aMsg->setTransferInProgress(
false );
00326
if (aFolder) {
00327 serNum = aMsg->getMsgSerNum();
00328 kmkernel->undoStack()->pushSingleAction( serNum, aFolder, folder() );
00329
int idx = aFolder->
find( aMsg );
00330 assert( idx != -1 );
00331 aFolder->
take( idx );
00332 }
00333
00334 mMetaDataMap.insert(aMsg->msgIdMD5(),
new KMMsgMetaData(aMsg->status(), serNum));
00335
00336
delete aMsg;
00337 aMsg = 0;
00338 getFolder();
00339 }
00340
00341
00342
void KMFolderImap::addMsgQuiet(
QPtrList<KMMessage> msgList)
00343 {
00344
KMFolder *aFolder = msgList.first()->parent();
00345 Q_UINT32 serNum = 0;
00346
if (aFolder) serNum = msgList.first()->getMsgSerNum();
00347
int undoId = -1;
00348
for ( KMMessage* msg = msgList.first(); msg; msg = msgList.next() )
00349 {
00350
if ( undoId == -1 )
00351 undoId = kmkernel->undoStack()->newUndoAction( aFolder, folder() );
00352 kmkernel->undoStack()->addMsgToAction( undoId, msg->getMsgSerNum() );
00353
00354 mMetaDataMap.insert(msg->msgIdMD5(),
new KMMsgMetaData(msg->status(), serNum));
00355 msg->setTransferInProgress(
false );
00356 }
00357
if (aFolder) aFolder->
take(msgList);
00358 msgList.setAutoDelete(
true);
00359 msgList.clear();
00360 getFolder();
00361 }
00362
00363
00364
int KMFolderImap::addMsg(KMMessage* aMsg,
int* aIndex_ret)
00365 {
00366
QPtrList<KMMessage> list; list.append(aMsg);
00367
return addMsg(list, aIndex_ret);
00368 }
00369
00370
int KMFolderImap::addMsg(
QPtrList<KMMessage>& msgList,
int* aIndex_ret)
00371 {
00372 KMMessage *aMsg = msgList.getFirst();
00373
KMFolder *msgParent = aMsg->parent();
00374
00375 ImapJob *imapJob = 0;
00376
if (msgParent)
00377 {
00378
if (msgParent->
folderType() == KMFolderTypeImap)
00379 {
00380
if (static_cast<KMFolderImap*>(msgParent->
storage())->account() == account())
00381 {
00382
00383
for ( KMMessage* msg = msgList.first(); msg; msg = msgList.next() )
00384 msg->setTransferInProgress(
true);
00385
00386
if (folder() == msgParent)
00387 {
00388
00389
for ( KMMessage* msg = msgList.first(); msg; msg = msgList.next() )
00390 {
00391
if (!msg->isComplete())
00392 {
00393
int idx = msgParent->
find(msg);
00394 assert(idx != -1);
00395 msg = msgParent->
getMsg(idx);
00396 }
00397 imapJob =
new ImapJob(msg, ImapJob::tPutMessage,
this);
00398 connect(imapJob, SIGNAL(messageStored(KMMessage*)),
00399 SLOT(addMsgQuiet(KMMessage*)));
00400 imapJob->start();
00401 }
00402
00403 }
else {
00404
00405
00406
QValueList<ulong> uids;
00407 getUids(msgList, uids);
00408
00409
00410
QStringList sets = makeSets(uids,
false);
00411
00412
for ( QStringList::Iterator it = sets.begin(); it != sets.end(); ++it )
00413 {
00414
00415
QPtrList<KMMessage> temp_msgs = splitMessageList(*it, msgList);
00416
if ( temp_msgs.isEmpty() ) kdDebug(5006) <<
"Wow! KMFolderImap::splitMessageList() returned an empty list!" << endl;
00417 imapJob =
new ImapJob(temp_msgs, *it, ImapJob::tMoveMessage,
this);
00418 connect(imapJob, SIGNAL(messageCopied(
QPtrList<KMMessage>)),
00419 SLOT(addMsgQuiet(
QPtrList<KMMessage>)));
00420 imapJob->start();
00421 }
00422 }
00423
if (aIndex_ret) *aIndex_ret = -1;
00424
return 0;
00425 }
00426
else
00427 {
00428
00429
QPtrListIterator<KMMessage> it( msgList );
00430 KMMessage *msg;
00431
while ( (msg = it.current()) != 0 )
00432 {
00433 ++it;
00434
if (!canAddMsgNow(msg, aIndex_ret))
00435 msgList.remove(msg);
00436
else {
00437
if (!msg->transferInProgress())
00438 msg->setTransferInProgress(
true);
00439 }
00440 }
00441 }
00442 }
00443 }
00444
00445
for ( KMMessage* msg = msgList.first(); msg; msg = msgList.next() )
00446 {
00447
00448
if (msgParent && !msg->
isMessage())
00449 {
00450
int idx = msgParent->
find(msg);
00451 assert(idx != -1);
00452 msg = msgParent->
getMsg(idx);
00453 }
00454
if (!msg->transferInProgress())
00455 msg->setTransferInProgress(
true);
00456 imapJob =
new ImapJob(msg, ImapJob::tPutMessage,
this);
00457 connect(imapJob, SIGNAL(messageStored(KMMessage*)),
00458 SLOT(addMsgQuiet(KMMessage*)));
00459 imapJob->start();
00460 }
00461
00462
if (aIndex_ret) *aIndex_ret = -1;
00463
return 0;
00464 }
00465
00466
00467
void KMFolderImap::copyMsg(
QPtrList<KMMessage>& msgList)
00468 {
00469
for (KMMessage *msg = msgList.first(); msg; msg = msgList.next()) {
00470
00471 mMetaDataMap.insert(msg->msgIdMD5(),
new KMMsgMetaData(msg->status()));
00472 }
00473
QValueList<ulong> uids;
00474 getUids(msgList, uids);
00475
QStringList sets = makeSets(uids,
false);
00476
for ( QStringList::Iterator it = sets.begin(); it != sets.end(); ++it )
00477 {
00478
00479
QPtrList<KMMessage> temp_msgs = splitMessageList(*it, msgList);
00480
00481 ImapJob *job =
new ImapJob(temp_msgs, *it, ImapJob::tCopyMessage,
this);
00482 job->start();
00483 }
00484 }
00485
00486
00487
QPtrList<KMMessage> KMFolderImap::splitMessageList(
const QString& set,
00488
QPtrList<KMMessage>& msgList)
00489 {
00490
int lastcomma = set.findRev(
",");
00491
int lastdub = set.findRev(
":");
00492
int last = 0;
00493
if (lastdub > lastcomma) last = lastdub;
00494
else last = lastcomma;
00495 last++;
00496
if (last < 0) last = set.length();
00497
00498
const QString last_uid = set.right(set.length() - last);
00499
QPtrList<KMMessage> temp_msgs;
00500
QString uid;
00501
if (!last_uid.isEmpty())
00502 {
00503
QPtrListIterator<KMMessage> it( msgList );
00504 KMMessage* msg = 0;
00505
while ( (msg = it.current()) != 0 )
00506 {
00507
00508 temp_msgs.append(msg);
00509 uid.setNum( msg->UID() );
00510
00511 msgList.remove(msg);
00512
if (uid == last_uid)
break;
00513 }
00514 }
00515
else
00516 {
00517
00518 temp_msgs = msgList;
00519 }
00520
00521
return temp_msgs;
00522 }
00523
00524
00525 KMMessage* KMFolderImap::take(
int idx)
00526 {
00527 KMMsgBase* mb(mMsgList[idx]);
00528
if (!mb)
return 0;
00529
if (!mb->isMessage()) readMsg(idx);
00530
00531 KMMessage *msg = static_cast<KMMessage*>(mb);
00532 deleteMessage(msg);
00533
00534 mLastUid = 0;
00535
return KMFolderMbox::take(idx);
00536 }
00537
00538
void KMFolderImap::take(
QPtrList<KMMessage> msgList)
00539 {
00540 deleteMessage(msgList);
00541
00542 mLastUid = 0;
00543 KMFolderMbox::take(msgList);
00544 }
00545
00546
00547
bool KMFolderImap::listDirectory(
bool secondStep)
00548 {
00549
if ( !mAccount ||
00550 ( mAccount && mAccount->makeConnection() == ImapAccountBase::Error ) )
00551 {
00552 kdDebug(5006) <<
"KMFolderImap::listDirectory - got no connection" << endl;
00553
return false;
00554 }
00555
00556
00557
if (
this == mAccount->rootFolder() )
00558 {
00559 mAccount->setHasInbox(
false );
00560
00561 setSubfolderState( imapNoInformation );
00562 }
00563 mSubfolderState = imapInProgress;
00564
00565
00566 ImapAccountBase::ListType type = ImapAccountBase::List;
00567
if ( mAccount->onlySubscribedFolders() )
00568 type = ImapAccountBase::ListSubscribed;
00569
ListJob* job =
new ListJob(
this, mAccount, type, secondStep,
00570
false, mAccount->hasInbox(), QString::null, account()->listDirProgressItem() );
00571 connect( job, SIGNAL(receivedFolders(
const QStringList&,
const QStringList&,
00572
const QStringList&,
const QStringList&,
const ImapAccountBase::jobData&)),
00573
this, SLOT(slotListResult(
const QStringList&,
const QStringList&,
00574
const QStringList&,
const QStringList&,
const ImapAccountBase::jobData&)));
00575 job->start();
00576
00577
return true;
00578 }
00579
00580
00581
00582
void KMFolderImap::slotListResult(
const QStringList& subfolderNames_,
00583
const QStringList& subfolderPaths,
00584
const QStringList& subfolderMimeTypes,
00585
const QStringList& subfolderAttributes,
00586
const ImapAccountBase::jobData& jobData )
00587 {
00588
QStringList subfolderNames( subfolderNames_ );
00589 mSubfolderState = imapFinished;
00590
bool it_inboxOnly = jobData.inboxOnly;
00591
bool createInbox = jobData.createInbox;
00592
00593
00594
00595
00596 kmkernel->imapFolderMgr()->quiet(
true);
00597
if (it_inboxOnly) {
00598
00599 listDirectory(
true);
00600 }
else {
00601
if ( folder()->
isSystemFolder() && mImapPath ==
"/INBOX/"
00602 && mAccount->prefix() ==
"/INBOX/" )
00603 {
00604
00605 createInbox =
false;
00606 subfolderNames.clear();
00607 }
00608 folder()->
createChildFolder();
00609 KMFolderImap *f;
00610 KMFolderNode *node = folder()->
child()->first();
00611
while (node)
00612 {
00613
00614
if (!node->isDir() && (node->name().upper() !=
"INBOX" || !createInbox)
00615 && subfolderNames.findIndex(node->name()) == -1)
00616 {
00617 kdDebug(5006) << node->name() <<
" disappeared" << endl;
00618
00619
KMFolder* fld = static_cast<KMFolder*>(node);
00620 static_cast<KMFolderImap*>(fld->
storage())->setAlreadyRemoved(
true);
00621 kmkernel->imapFolderMgr()->remove(fld);
00622 node = folder()->
child()->first();
00623 }
00624
else node = folder()->
child()->next();
00625 }
00626
if ( createInbox )
00627 {
00628
00629
for (node = folder()->
child()->first(); node;
00630 node = folder()->
child()->next())
00631
if (!node->isDir() && node->name() ==
"INBOX")
break;
00632
if (node) {
00633 f = static_cast<KMFolderImap*>(static_cast<KMFolder*>(node)->storage());
00634 }
else {
00635 f = static_cast<KMFolderImap*>
00636 (folder()->
child()->
createFolder(
"INBOX",
true)->
storage());
00637
if ( !mAccount->listOnlyOpenFolders() )
00638 f->setHasChildren( FolderStorage::HasNoChildren );
00639 }
00640 f->setAccount(mAccount);
00641 f->setImapPath(
"/INBOX/");
00642 f->folder()->setLabel(i18n(
"inbox"));
00643
for (uint i = 0; i < subfolderNames.count(); i++)
00644 {
00645
if ( subfolderNames[i] ==
"INBOX" &&
00646 subfolderPaths[i] ==
"/INBOX/" )
00647 f->setNoChildren( subfolderMimeTypes[i] ==
"message/digest" );
00648 }
00649
if (!node) f->close();
00650
00651 mAccount->setHasInbox(
true );
00652 kmkernel->imapFolderMgr()->contentsChanged();
00653
if ( !mAccount->listOnlyOpenFolders() ) {
00654 f->listDirectory();
00655 }
00656 }
00657
for (uint i = 0; i < subfolderNames.count(); i++)
00658 {
00659
00660
if (subfolderNames[i].upper() ==
"INBOX" &&
00661 subfolderPaths[i] ==
"/INBOX/" &&
00662 mAccount->hasInbox())
00663
continue;
00664
for (node = folder()->
child()->first(); node;
00665 node = folder()->
child()->next())
00666
if (!node->isDir() && node->name() == subfolderNames[i])
break;
00667
if (node)
00668 f = static_cast<KMFolderImap*>(static_cast<KMFolder*>(node)->storage());
00669
else {
00670 f = static_cast<KMFolderImap*>
00671 (folder()->
child()->
createFolder(subfolderNames[i])->
storage());
00672
if (f)
00673 {
00674 f->close();
00675 }
else {
00676 kdWarning(5006) <<
"can't create folder " << subfolderNames[i] << endl;
00677 }
00678 }
00679
if (f)
00680 {
00681
00682 account()->listDirProgressItem()->incCompletedItems();
00683 account()->listDirProgressItem()->updateProgress();
00684 account()->listDirProgressItem()->setStatus( folder()->
prettyURL() + i18n(
" completed") );
00685 f->setAccount(mAccount);
00686
if ( f->hasChildren() == FolderStorage::ChildrenUnknown )
00687 {
00688
00689 kmkernel->imapFolderMgr()->contentsChanged();
00690 }
00691
00692
00693
if ( subfolderAttributes[i].find(
"haschildren", 0,
false ) != -1 )
00694 {
00695 f->setHasChildren( FolderStorage::HasChildren );
00696 }
else if ( subfolderAttributes[i].find(
"hasnochildren", 0,
false ) != -1 )
00697 {
00698 f->setHasChildren( FolderStorage::HasNoChildren );
00699 }
else
00700 {
00701
if ( mAccount->listOnlyOpenFolders() )
00702 f->setHasChildren( FolderStorage::ChildrenUnknown );
00703
else
00704 f->setHasChildren( FolderStorage::HasNoChildren );
00705 }
00706 f->setImapPath(subfolderPaths[i]);
00707 f->setNoContent(subfolderMimeTypes[i] ==
"inode/directory");
00708 f->setNoChildren(subfolderMimeTypes[i] ==
"message/digest");
00709
if ( mAccount->listOnlyOpenFolders() &&
00710 f->hasChildren() != FolderStorage::ChildrenUnknown )
00711 {
00712
00713 kmkernel->imapFolderMgr()->contentsChanged();
00714 }
00715
if ( ( subfolderMimeTypes[i] ==
"message/directory" ||
00716 subfolderMimeTypes[i] ==
"inode/directory" ) &&
00717 !mAccount->listOnlyOpenFolders() )
00718 {
00719 f->listDirectory();
00720 }
00721 }
00722 }
00723 }
00724
00725 kmkernel->imapFolderMgr()->quiet(
false);
00726 emit directoryListingFinished(
this );
00727 account()->listDirProgressItem()->setComplete();
00728 }
00729
00730
00731
void KMFolderImap::checkValidity()
00732 {
00733
if (!mAccount) {
00734 emit folderComplete(
this,
false);
00735
return;
00736 }
00737 KURL url = mAccount->getUrl();
00738 url.setPath(imapPath() +
";UID=0:0");
00739 kdDebug(5006) <<
"KMFolderImap::checkValidity of: " << imapPath() << endl;
00740
00741
if ( mAccount->makeConnection() == ImapAccountBase::Error ) {
00742 kdDebug(5006) <<
"KMFolderImap::checkValidity - got no connection" << endl;
00743 emit folderComplete(
this, FALSE);
00744 mContentState = imapNoInformation;
00745
return;
00746 }
else if ( mAccount->makeConnection() == ImapAccountBase::Connecting ) {
00747
00748
00749 kdDebug(5006) <<
"CheckValidity - waiting for connection" << endl;
00750 connect( mAccount, SIGNAL( connectionResult(
int,
const QString&) ),
00751
this, SLOT( checkValidity() ) );
00752
return;
00753 }
00754
00755
if (mCheckingValidity) {
00756 kdDebug(5006) <<
"KMFolderImap::checkValidity - already checking" << endl;
00757
return;
00758 }
00759
00760
if ( !mMailCheckProgressItem ) {
00761 mMailCheckProgressItem = ProgressManager::createProgressItem(
00762 account()->mailCheckProgressItem(),
00763
"MailCheck" + folder()->
prettyURL(),
00764 folder()->
prettyURL(),
00765 i18n(
"checking"),
00766
false,
00767 account()->useSSL() || account()->useTLS() );
00768 }
else {
00769 mMailCheckProgressItem->setProgress(0);
00770 }
00771
if ( account()->mailCheckProgressItem() ) {
00772 account()->mailCheckProgressItem()->setStatus( folder()->
prettyURL() );
00773 }
00774 ImapAccountBase::jobData jd( url.url() );
00775 KIO::SimpleJob *job = KIO::get(url, FALSE, FALSE);
00776 KIO::Scheduler::assignJobToSlave(mAccount->slave(), job);
00777 mAccount->insertJob(job, jd);
00778 connect(job, SIGNAL(result(KIO::Job *)),
00779 SLOT(slotCheckValidityResult(KIO::Job *)));
00780 connect(job, SIGNAL(data(KIO::Job *,
const QByteArray &)),
00781 SLOT(slotSimpleData(KIO::Job *,
const QByteArray &)));
00782
00783 mCheckingValidity =
true;
00784 }
00785
00786
00787
00788 ulong KMFolderImap::lastUid()
00789 {
00790
if (mLastUid)
return mLastUid;
00791 open();
00792
if (count() > 0)
00793 {
00794 KMMsgBase * base = getMsgBase(count()-1);
00795 mLastUid = base->UID();
00796 }
00797 close();
00798
return mLastUid;
00799 }
00800
00801
00802
00803
void KMFolderImap::slotCheckValidityResult(KIO::Job * job)
00804 {
00805 kdDebug(5006) <<
"KMFolderImap::slotCheckValidityResult of: " << fileName() << endl;
00806 mCheckingValidity =
false;
00807 ImapAccountBase::JobIterator it = mAccount->findJob(job);
00808
if ( it == mAccount->jobsEnd() )
return;
00809
if (job->error()) {
00810 mAccount->handleJobError( job, i18n(
"Error while querying the server status.") );
00811 mContentState = imapNoInformation;
00812 emit folderComplete(
this, FALSE);
00813 }
else {
00814
QCString cstr((*it).data.data(), (*it).data.size() + 1);
00815
int a = cstr.find(
"X-uidValidity: ");
00816
int b = cstr.find(
"\r\n", a);
00817
QString uidv;
00818
if ( (b - a - 15) >= 0 ) uidv = cstr.mid(a + 15, b - a - 15);
00819 a = cstr.find(
"X-Access: ");
00820 b = cstr.find(
"\r\n", a);
00821
QString access;
00822
if ( (b - a - 10) >= 0 ) access = cstr.mid(a + 10, b - a - 10);
00823 mReadOnly = access ==
"Read only";
00824
int c = (*it).cdata.find(
"\r\nX-Count:");
00825
int exists = -1;
00826
if ( c != -1 )
00827 {
00828
bool ok;
00829 exists = (*it).cdata.mid( c+10,
00830 (*it).cdata.find(
"\r\n", c+1) - c-10 ).toInt(&ok);
00831
if ( !ok ) exists = -1;
00832 }
00833
QString startUid;
00834
if (uidValidity() != uidv)
00835 {
00836
00837 kdDebug(5006) <<
"KMFolderImap::slotCheckValidityResult uidValidty changed." << endl;
00838 mAccount->ignoreJobsForFolder( folder() );
00839 mLastUid = 0;
00840 uidmap.clear();
00841 setUidValidity(uidv);
00842 }
else {
00843
if (!mCheckFlags)
00844 startUid = QString::number(lastUid() + 1);
00845 }
00846 mAccount->removeJob(it);
00847
if ( mMailCheckProgressItem )
00848 {
00849
if ( startUid.isEmpty() ) {
00850
00851 mMailCheckProgressItem->setTotalItems( exists );
00852 }
else {
00853
00854
int remain = exists - count();
00855
if ( remain < 0 ) remain = 1;
00856 mMailCheckProgressItem->setTotalItems( remain );
00857 }
00858 mMailCheckProgressItem->setCompletedItems( 0 );
00859 }
00860 reallyGetFolder(startUid);
00861 }
00862 }
00863
00864
00865
void KMFolderImap::getAndCheckFolder(
bool force)
00866 {
00867
if (mNoContent)
00868
return getFolder(force);
00869
00870
if ( mAccount )
00871 mAccount->processNewMailSingleFolder( folder() );
00872
if (force) {
00873
00874 mCheckFlags = TRUE;
00875 }
00876 }
00877
00878
00879
void KMFolderImap::getFolder(
bool force)
00880 {
00881 mGuessedUnreadMsgs = -1;
00882
if (mNoContent)
00883 {
00884 mContentState = imapFinished;
00885 emit folderComplete(
this,
true);
00886
return;
00887 }
00888 mContentState = imapInProgress;
00889
if (force) {
00890
00891 mCheckFlags = TRUE;
00892 }
00893 checkValidity();
00894 }
00895
00896
00897
00898
void KMFolderImap::reallyGetFolder(
const QString &startUid)
00899 {
00900 KURL url = mAccount->getUrl();
00901
if ( mAccount->makeConnection() != ImapAccountBase::Connected )
00902 {
00903 mContentState = imapNoInformation;
00904 emit folderComplete(
this, FALSE);
00905
return;
00906 }
00907 quiet(
true);
00908
if (startUid.isEmpty())
00909 {
00910
if ( mMailCheckProgressItem )
00911 mMailCheckProgressItem->setStatus( i18n(
"Retrieving message status") );
00912 url.setPath(imapPath() +
";SECTION=UID FLAGS");
00913 KIO::SimpleJob *job = KIO::listDir(url, FALSE);
00914 KIO::Scheduler::assignJobToSlave(mAccount->slave(), job);
00915 ImapAccountBase::jobData jd( url.url(), folder() );
00916 jd.cancellable =
true;
00917 mAccount->insertJob(job, jd);
00918 connect(job, SIGNAL(result(KIO::Job *)),
00919
this, SLOT(slotListFolderResult(KIO::Job *)));
00920 connect(job, SIGNAL(entries(KIO::Job *,
const KIO::UDSEntryList &)),
00921
this, SLOT(slotListFolderEntries(KIO::Job *,
00922
const KIO::UDSEntryList &)));
00923 }
else {
00924
if ( mMailCheckProgressItem )
00925 mMailCheckProgressItem->setStatus( i18n(
"Retrieving messages") );
00926 url.setPath(imapPath() +
";UID=" + startUid
00927 +
":*;SECTION=ENVELOPE");
00928 KIO::SimpleJob *newJob = KIO::get(url, FALSE, FALSE);
00929 KIO::Scheduler::assignJobToSlave(mAccount->slave(), newJob);
00930 ImapAccountBase::jobData jd( url.url(), folder() );
00931 jd.cancellable =
true;
00932 mAccount->insertJob(newJob, jd);
00933 connect(newJob, SIGNAL(result(KIO::Job *)),
00934
this, SLOT(slotGetLastMessagesResult(KIO::Job *)));
00935 connect(newJob, SIGNAL(data(KIO::Job *,
const QByteArray &)),
00936
this, SLOT(slotGetMessagesData(KIO::Job *,
const QByteArray &)));
00937 }
00938 }
00939
00940
00941
00942
void KMFolderImap::slotListFolderResult(KIO::Job * job)
00943 {
00944 ImapAccountBase::JobIterator it = mAccount->findJob(job);
00945
if ( it == mAccount->jobsEnd() )
return;
00946
QString uids;
00947
if (job->error())
00948 {
00949 mAccount->handleJobError( job,
00950 i18n(
"Error while listing the contents of the folder %1.").arg(
label() ) );
00951 quiet(
false );
00952 mContentState = imapNoInformation;
00953 emit folderComplete(
this, FALSE);
00954 mAccount->removeJob(it);
00955
return;
00956 }
00957 mCheckFlags = FALSE;
00958 QStringList::Iterator uid;
00959
00960
00961
00962
00963
00964
00965
00966
00967
00968
if ( count() ) {
00969
int idx = 0, c, serverFlags;
00970 ulong mailUid, serverUid;
00971 uid = (*it).items.begin();
00972
while ( idx < count() && uid != (*it).items.end() ) {
00973 KMMsgBase *msgBase = getMsgBase( idx );
00974 mailUid = msgBase->UID();
00975
00976
00977 c = (*uid).find(
",");
00978 serverUid = (*uid).left( c ).toLong();
00979 serverFlags = (*uid).mid( c+1 ).toInt();
00980
if ( mailUid < serverUid ) {
00981 removeMsg( idx, TRUE );
00982 }
else if ( mailUid == serverUid ) {
00983
00984
00985
00986
if (!mReadOnly)
00987 flagsToStatus( msgBase, serverFlags,
false );
00988 idx++;
00989 uid = (*it).items.remove(uid);
00990 }
00991
else break;
00992 }
00993
00994
00995
while (idx < count()) removeMsg(idx, TRUE);
00996 }
00997
00998
for (uid = (*it).items.begin(); uid != (*it).items.end(); uid++)
00999 (*uid).truncate((*uid).find(
","));
01000 ImapAccountBase::jobData jd( QString::null, (*it).parent );
01001 jd.total = (*it).items.count();
01002
if (jd.total == 0)
01003 {
01004 quiet(
false);
01005 mContentState = imapFinished;
01006 emit folderComplete(
this, TRUE);
01007 mAccount->removeJob(it);
01008
return;
01009 }
01010
if ( mMailCheckProgressItem )
01011 {
01012
01013 mMailCheckProgressItem->setProgress( 0 );
01014 mMailCheckProgressItem->setTotalItems( jd.total );
01015 mMailCheckProgressItem->updateProgress();
01016 mMailCheckProgressItem->setStatus( i18n(
"Retrieving messages") );
01017 }
01018
01019
QStringList sets;
01020 uid = (*it).items.begin();
01021
if (jd.total == 1) sets.append(*uid +
":" + *uid);
01022
else sets = makeSets( (*it).items );
01023 mAccount->removeJob(it);
01024
01025
01026
for (QStringList::Iterator i = sets.begin(); i != sets.end(); ++i)
01027 {
01028 KURL url = mAccount->getUrl();
01029 url.setPath(imapPath() +
";UID=" + *i +
";SECTION=ENVELOPE");
01030
if ( mAccount->makeConnection() != ImapAccountBase::Connected )
01031 {
01032 quiet(
false);
01033 emit folderComplete(
this, FALSE);
01034
return;
01035 }
01036 KIO::SimpleJob *newJob = KIO::get(url, FALSE, FALSE);
01037 jd.url = url.url();
01038 KIO::Scheduler::assignJobToSlave(mAccount->slave(), newJob);
01039 mAccount->insertJob(newJob, jd);
01040 connect(newJob, SIGNAL(result(KIO::Job *)),
01041
this, (i == sets.at(sets.count() - 1))
01042 ? SLOT(slotGetLastMessagesResult(KIO::Job *))
01043 : SLOT(slotGetMessagesResult(KIO::Job *)));
01044 connect(newJob, SIGNAL(data(KIO::Job *,
const QByteArray &)),
01045
this, SLOT(slotGetMessagesData(KIO::Job *,
const QByteArray &)));
01046 }
01047 }
01048
01049
01050
01051
void KMFolderImap::slotListFolderEntries(KIO::Job * job,
01052
const KIO::UDSEntryList & uds)
01053 {
01054 ImapAccountBase::JobIterator it = mAccount->findJob(job);
01055
if ( it == mAccount->jobsEnd() )
return;
01056
QString mimeType, name;
01057
long int flags = 0;
01058
for (KIO::UDSEntryList::ConstIterator udsIt = uds.begin();
01059 udsIt != uds.end(); udsIt++)
01060 {
01061
for (KIO::UDSEntry::ConstIterator eIt = (*udsIt).begin();
01062 eIt != (*udsIt).end(); eIt++)
01063 {
01064
if ((*eIt).m_uds == KIO::UDS_NAME)
01065 name = (*eIt).m_str;
01066
else if ((*eIt).m_uds == KIO::UDS_MIME_TYPE)
01067 mimeType = (*eIt).m_str;
01068
else if ((*eIt).m_uds == KIO::UDS_ACCESS)
01069 flags = (*eIt).m_long;
01070 }
01071
if ((mimeType ==
"message/rfc822-imap" || mimeType ==
"message/rfc822") &&
01072 !(flags & 8)) {
01073 (*it).items.append(name +
"," + QString::number(flags));
01074
if ( mMailCheckProgressItem ) {
01075 mMailCheckProgressItem->incCompletedItems();
01076 mMailCheckProgressItem->updateProgress();
01077 }
01078 }
01079 }
01080 }
01081
01082
01083
01084
void KMFolderImap::flagsToStatus(KMMsgBase *msg,
int flags,
bool newMsg)
01085 {
01086
if (flags & 4)
01087 msg->setStatus( KMMsgStatusFlag );
01088
if (flags & 2)
01089 msg->setStatus( KMMsgStatusReplied );
01090
if (flags & 1)
01091 msg->setStatus( KMMsgStatusOld );
01092
01093
01094
01095
01096
if (msg->isOfUnknownStatus() || !(flags&1) ) {
01097
if (newMsg)
01098 msg->setStatus( KMMsgStatusNew );
01099
else
01100 msg->setStatus( KMMsgStatusUnread );
01101 }
01102 }
01103
01104
01105
01106
QString KMFolderImap::statusToFlags(KMMsgStatus status)
01107 {
01108
QString flags;
01109
if (status & KMMsgStatusDeleted)
01110 flags =
"\\DELETED";
01111
else {
01112
if (status & KMMsgStatusOld || status & KMMsgStatusRead)
01113 flags =
"\\SEEN ";
01114
if (status & KMMsgStatusReplied)
01115 flags +=
"\\ANSWERED ";
01116
if (status & KMMsgStatusFlag)
01117 flags +=
"\\FLAGGED";
01118 }
01119
01120
return flags.simplifyWhiteSpace();
01121 }
01122
01123
01124
void
01125 KMFolderImap::ignoreJobsForMessage( KMMessage* msg )
01126 {
01127
if ( !msg || msg->transferInProgress() ||
01128 !msg->parent() || msg->parent()->folderType() != KMFolderTypeImap )
01129
return;
01130 KMAcctImap *account;
01131
if ( !(account = static_cast<KMFolderImap*>(msg->storage())->account()) )
01132
return;
01133
01134 account->ignoreJobsForMessage( msg );
01135 }
01136
01137
01138
void KMFolderImap::slotGetMessagesData(KIO::Job * job,
const QByteArray & data)
01139 {
01140
if ( data.isEmpty() )
return;
01141 ImapAccountBase::JobIterator it = mAccount->findJob(job);
01142
if ( it == mAccount->jobsEnd() )
return;
01143 (*it).cdata +=
QCString(data, data.size() + 1);
01144
int pos = (*it).cdata.find(
"\r\n--IMAPDIGEST");
01145
if (pos > 0)
01146 {
01147
int p = (*it).cdata.find(
"\r\nX-uidValidity:");
01148
if (p != -1) setUidValidity((*it).cdata
01149 .mid(p + 17, (*it).cdata.find(
"\r\n", p+1) - p - 17));
01150
int c = (*it).cdata.find(
"\r\nX-Count:");
01151
if ( c != -1 )
01152 {
01153
bool ok;
01154
int exists = (*it).cdata.mid( c+10,
01155 (*it).cdata.find(
"\r\n", c+1) - c-10 ).toInt(&ok);
01156
if ( ok && exists < count() ) {
01157 kdDebug(5006) <<
"KMFolderImap::slotGetMessagesData - server has less messages (" <<
01158 exists <<
") then folder (" << count() <<
"), so reload" << endl;
01159 reallyGetFolder( QString::null );
01160 (*it).cdata.remove(0, pos);
01161
return;
01162 }
else if ( ok ) {
01163
int delta = exists - count();
01164
if ( mMailCheckProgressItem ) {
01165 mMailCheckProgressItem->setTotalItems( delta );
01166 mMailCheckProgressItem->setStatus( i18n(
"Retrieving message list") );
01167 }
01168 }
01169 }
01170 (*it).cdata.remove(0, pos);
01171 }
01172 pos = (*it).cdata.find(
"\r\n--IMAPDIGEST", 1);
01173
int flags;
01174 open();
01175
while (pos >= 0)
01176 {
01177 KMMessage *msg =
new KMMessage;
01178 msg->setComplete(
false);
01179 msg->setReadyToShow(
false);
01180 msg->fromString((*it).cdata.mid(16, pos - 16));
01181 flags = msg->headerField(
"X-Flags").toInt();
01182 ulong uid = msg->UID();
01183
bool ok =
true;
01184
if ( uid <= lastUid() )
01185 {
01186
01187
01188
int idx = 0;
01189 KMMsgBase *msg;
01190
while ( idx < count() )
01191 {
01192 msg = getMsgBase( idx );
01193
if ( msg && msg->UID() == uid )
01194 {
01195 ok =
false;
01196
break;
01197 }
01198 ++idx;
01199 }
01200 }
01201
01202
if ( flags & 8 )
01203 ok =
false;
01204
if ( !ok ) {
01205
delete msg;
01206 msg = 0;
01207 }
else {
01208
if (uidmap.find(uid)) {
01209
01210
const ulong sernum = (ulong) uidmap[uid];
01211 msg->setMsgSerNum(sernum);
01212
01213 uidmap.remove(uid);
01214 }
01215 KMFolderMbox::addMsg(msg, 0);
01216
01217
QString id = msg->msgIdMD5();
01218
if ( mMetaDataMap.find(
id ) ) {
01219 KMMsgMetaData *md = mMetaDataMap[
id];
01220 msg->setStatus( md->status() );
01221
if ( md->serNum() != 0 )
01222 msg->setMsgSerNum( md->serNum() );
01223 mMetaDataMap.remove(
id );
01224
delete md;
01225 }
01226
01227 flagsToStatus((KMMsgBase*)msg, flags);
01228
01229 msg->setMsgSizeServer( msg->headerField(
"X-Length").toUInt() );
01230 msg->setUID(uid);
01231
01232
if (count() > 1) unGetMsg(count() - 1);
01233 mLastUid = uid;
01234
if ( mMailCheckProgressItem ) {
01235 mMailCheckProgressItem->incCompletedItems();
01236 mMailCheckProgressItem->updateProgress();
01237 }
01238 }
01239 (*it).cdata.remove(0, pos);
01240 (*it).done++;
01241 pos = (*it).cdata.find(
"\r\n--IMAPDIGEST", 1);
01242 }
01243 close();
01244 }
01245
01246
01247 FolderJob*
01248 KMFolderImap::doCreateJob( KMMessage *msg, FolderJob::JobType jt,
01249
KMFolder *folder,
QString partSpecifier,
01250
const AttachmentStrategy *as )
const
01251
{
01252 KMFolderImap* kmfi = folder? dynamic_cast<KMFolderImap*>(folder->
storage()) : 0;
01253
if ( jt == FolderJob::tGetMessage && partSpecifier ==
"STRUCTURE" &&
01254 mAccount && mAccount->loadOnDemand() &&
01255 ( msg->msgSizeServer() > 5000 || msg->msgSizeServer() == 0 ) &&
01256 ( msg->signatureState() == KMMsgNotSigned ||
01257 msg->signatureState() == KMMsgSignatureStateUnknown ) &&
01258 ( msg->encryptionState() == KMMsgNotEncrypted ||
01259 msg->encryptionState() == KMMsgEncryptionStateUnknown ) )
01260 {
01261
01262
01263 ImapJob *job =
new ImapJob( msg, jt, kmfi,
"HEADER" );
01264 job->start();
01265 ImapJob *job2 =
new ImapJob( msg, jt, kmfi,
"STRUCTURE", as );
01266 job2->start();
01267 job->setParentFolder(
this );
01268
return job;
01269 }
else {
01270
01271
if ( partSpecifier ==
"STRUCTURE" )
01272 partSpecifier = QString::null;
01273
01274 ImapJob *job =
new ImapJob( msg, jt, kmfi, partSpecifier );
01275 job->setParentFolder(
this );
01276
return job;
01277 }
01278 }
01279
01280
01281 FolderJob*
01282 KMFolderImap::doCreateJob(
QPtrList<KMMessage>& msgList,
const QString& sets,
01283 FolderJob::JobType jt,
KMFolder *folder )
const
01284
{
01285 KMFolderImap* kmfi = dynamic_cast<KMFolderImap*>(folder->
storage());
01286 ImapJob *job =
new ImapJob( msgList, sets, jt, kmfi );
01287 job->setParentFolder(
this );
01288
return job;
01289 }
01290
01291
01292
void KMFolderImap::getMessagesResult(KIO::Job * job,
bool lastSet)
01293 {
01294 ImapAccountBase::JobIterator it = mAccount->findJob(job);
01295
if ( it == mAccount->jobsEnd() )
return;
01296
if (job->error())
01297 {
01298 mAccount->handleJobError( job, i18n(
"Error while retrieving messages.") );
01299 mContentState = imapNoInformation;
01300 quiet(
false );
01301 emit folderComplete(
this,
false);
01302 }
01303
else
01304 {
01305
if (lastSet)
01306 {
01307 mContentState = imapFinished;
01308 quiet(
false);
01309 emit folderComplete(
this,
true);
01310 }
01311 mAccount->removeJob(it);
01312 }
01313 }
01314
01315
01316
01317
void KMFolderImap::slotGetLastMessagesResult(KIO::Job * job)
01318 {
01319 getMessagesResult(job,
true);
01320 }
01321
01322
01323
01324
void KMFolderImap::slotGetMessagesResult(KIO::Job * job)
01325 {
01326 getMessagesResult(job,
false);
01327 }
01328
01329
01330
01331
void KMFolderImap::createFolder(
const QString &name)
01332 {
01333
if ( mAccount->makeConnection() == ImapAccountBase::Error ) {
01334 kdWarning(5006) <<
"KMFolderImap::createFolder - got no connection" << endl;
01335
return;
01336 }
else if ( mAccount->makeConnection() == ImapAccountBase::Connecting ) {
01337
01338 kdDebug(5006) <<
"KMFolderImap::createFolder - waiting for connection" << endl;
01339
01340
if ( mFoldersPendingCreation.isEmpty() ) {
01341
01342 connect( mAccount, SIGNAL( connectionResult(
int,
const QString&) ),
01343
this, SLOT( slotCreatePendingFolders() ) );
01344 }
01345 mFoldersPendingCreation << name;
01346
return;
01347 }
01348 KURL url = mAccount->getUrl();
01349 url.setPath(imapPath() + name);
01350
01351 KIO::SimpleJob *job = KIO::mkdir(url);
01352 KIO::Scheduler::assignJobToSlave(mAccount->slave(), job);
01353 ImapAccountBase::jobData jd( url.url(), folder() );
01354 jd.items = name;
01355 mAccount->insertJob(job, jd);
01356 connect(job, SIGNAL(result(KIO::Job *)),
01357
this, SLOT(slotCreateFolderResult(KIO::Job *)));
01358 }
01359
01360
01361
01362
void KMFolderImap::slotCreateFolderResult(KIO::Job * job)
01363 {
01364 ImapAccountBase::JobIterator it = mAccount->findJob(job);
01365
if ( it == mAccount->jobsEnd() )
return;
01366
if (job->error())
01367 {
01368
if ( job->error() == KIO::ERR_COULD_NOT_MKDIR ) {
01369
01370 mAccount->listDirectory( );
01371 }
01372 mAccount->handleJobError( job, i18n(
"Error while creating a folder.") );
01373 }
else {
01374 listDirectory();
01375 mAccount->removeJob(job);
01376 }
01377 }
01378
01379
01380
01381
static QTextCodec *sUtf7Codec = 0;
01382
01383
QTextCodec * KMFolderImap::utf7Codec()
01384 {
01385
if (!sUtf7Codec) sUtf7Codec = QTextCodec::codecForName(
"utf-7");
01386
return sUtf7Codec;
01387 }
01388
01389
01390
01391
QString KMFolderImap::encodeFileName(
const QString &name)
01392 {
01393
QString result = utf7Codec()->fromUnicode(name);
01394
return KURL::encode_string_no_slash(result);
01395 }
01396
01397
01398
01399
QString KMFolderImap::decodeFileName(
const QString &name)
01400 {
01401
QString result = KURL::decode_string(name);
01402
return utf7Codec()->toUnicode(result.latin1());
01403 }
01404
01405
01406
bool KMFolderImap::autoExpunge()
01407 {
01408
if (mAccount)
01409
return mAccount->autoExpunge();
01410
01411
return false;
01412 }
01413
01414
01415
01416
void KMFolderImap::slotSimpleData(KIO::Job * job,
const QByteArray & data)
01417 {
01418
if ( data.isEmpty() )
return;
01419 ImapAccountBase::JobIterator it = mAccount->findJob(job);
01420
if ( it == mAccount->jobsEnd() )
return;
01421
QBuffer buff((*it).data);
01422 buff.open(IO_WriteOnly | IO_Append);
01423 buff.writeBlock(data.data(), data.size());
01424 buff.close();
01425 }
01426
01427
01428
void KMFolderImap::deleteMessage(KMMessage * msg)
01429 {
01430 KURL url = mAccount->getUrl();
01431 KMFolderImap *msg_parent = static_cast<KMFolderImap*>(msg->storage());
01432 ulong uid = msg->UID();
01433
01434
01435
01436
if ( uid == 0 ) {
01437 kdDebug( 5006 ) <<
"KMFolderImap::deleteMessage: Attempt to delete "
01438
"an empty UID. Aborting." << endl;
01439
return;
01440 }
01441 url.setPath(msg_parent->imapPath() +
";UID=" + QString::number(uid) );
01442
if ( mAccount->makeConnection() != ImapAccountBase::Connected )
01443
return;
01444 KIO::SimpleJob *job = KIO::file_delete(url, FALSE);
01445 KIO::Scheduler::assignJobToSlave(mAccount->slave(), job);
01446 ImapAccountBase::jobData jd( url.url(), 0 );
01447 mAccount->insertJob(job, jd);
01448 connect(job, SIGNAL(result(KIO::Job *)),
01449 mAccount, SLOT(slotSimpleResult(KIO::Job *)));
01450 }
01451
01452
void KMFolderImap::deleteMessage(
const QPtrList<KMMessage>& msgList)
01453 {
01454
QValueList<ulong> uids;
01455 getUids(msgList, uids);
01456
QStringList sets = makeSets(uids);
01457
01458 KURL url = mAccount->getUrl();
01459 KMFolderImap *msg_parent = static_cast<KMFolderImap*>(msgList.getFirst()->storage());
01460
for ( QStringList::Iterator it = sets.begin(); it != sets.end(); ++it )
01461 {
01462
QString uid = *it;
01463
01464
01465
if ( uid.isEmpty() )
continue;
01466 url.setPath(msg_parent->imapPath() +
";UID=" + uid);
01467
if ( mAccount->makeConnection() != ImapAccountBase::Connected )
01468
return;
01469 KIO::SimpleJob *job = KIO::file_delete(url, FALSE);
01470 KIO::Scheduler::assignJobToSlave(mAccount->slave(), job);
01471 ImapAccountBase::jobData jd( url.url(), 0 );
01472 mAccount->insertJob(job, jd);
01473 connect(job, SIGNAL(result(KIO::Job *)),
01474 mAccount, SLOT(slotSimpleResult(KIO::Job *)));
01475 }
01476 }
01477
01478
01479
void KMFolderImap::setStatus(
int idx, KMMsgStatus status,
bool toggle)
01480 {
01481
QValueList<int> ids; ids.append(idx);
01482 setStatus(ids, status, toggle);
01483 }
01484
01485
void KMFolderImap::setStatus(
QValueList<int>& ids, KMMsgStatus status,
bool toggle)
01486 {
01487
FolderStorage::setStatus(ids, status, toggle);
01488
if (mReadOnly)
return;
01489
01490
01491
01492
01493
01494
01495
01496
01497
01498
01499
01500
QMap< QString, QStringList > groups;
01501
for (
QValueList<int>::Iterator it = ids.begin(); it != ids.end(); ++it ) {
01502 KMMessage *msg = 0;
01503
bool unget = !isMessage(*it);
01504 msg = getMsg(*it);
01505
if (!msg)
continue;
01506
QString flags = statusToFlags(msg->status());
01507
01508 groups[flags].append(QString::number(msg->UID()));
01509
if (unget) unGetMsg(*it);
01510 }
01511
QMapIterator< QString, QStringList > dit;
01512
for ( dit = groups.begin(); dit != groups.end(); ++dit ) {
01513
QCString flags = dit.key().latin1();
01514
QStringList sets = makeSets( (*dit),
true );
01515
01516
for ( QStringList::Iterator slit = sets.begin(); slit != sets.end(); ++slit ) {
01517
QString imappath = imapPath() +
";UID=" + ( *slit );
01518 mAccount->setImapStatus(folder(), imappath, flags);
01519 }
01520 }
01521
if ( mContentState == imapInProgress ) {
01522
01523
01524
01525 disconnect(
this, SLOT(slotListFolderResult(KIO::Job *)));
01526 reallyGetFolder( QString::null );
01527 }
01528 }
01529
01530
01531
QStringList KMFolderImap::makeSets(
const QStringList& uids,
bool sort)
01532 {
01533
QValueList<ulong> tmp;
01534
for ( QStringList::ConstIterator it = uids.begin(); it != uids.end(); ++it )
01535 tmp.append( (*it).toInt() );
01536
return makeSets(tmp, sort);
01537 }
01538
01539
QStringList KMFolderImap::makeSets(
QValueList<ulong>& uids,
bool sort )
01540 {
01541
QStringList sets;
01542
QString set;
01543
01544
if (uids.size() == 1)
01545 {
01546 sets.append(QString::number(uids.first()));
01547
return sets;
01548 }
01549
01550
if (sort) qHeapSort(uids);
01551
01552 ulong last = 0;
01553
01554
bool inserted =
false;
01555
01556
for (
QValueList<ulong>::Iterator it = uids.begin(); it != uids.end(); ++it )
01557 {
01558
if (it == uids.begin() || set.isEmpty()) {
01559 set = QString::number(*it);
01560 inserted =
true;
01561 }
else
01562 {
01563
if (last+1 != *it)
01564 {
01565
01566
if (inserted)
01567 set +=
',' + QString::number(*it);
01568
else
01569 set +=
':' + QString::number(last) +
',' + QString::number(*it);
01570 inserted =
true;
01571
if (set.length() > 100)
01572 {
01573
01574 sets.append(set);
01575 set =
"";
01576 }
01577 }
else {
01578 inserted =
false;
01579 }
01580 }
01581 last = *it;
01582 }
01583
01584
if (!inserted)
01585 set +=
':' + QString::number(uids.last());
01586
01587
if (!set.isEmpty()) sets.append(set);
01588
01589
return sets;
01590 }
01591
01592
01593
void KMFolderImap::getUids(
QValueList<int>& ids,
QValueList<ulong>& uids)
01594 {
01595 KMMsgBase *msg = 0;
01596
01597
for (
QValueList<int>::Iterator it = ids.begin(); it != ids.end(); ++it )
01598 {
01599 msg = getMsgBase(*it);
01600
if (!msg)
continue;
01601 uids.append(msg->UID());
01602 }
01603 }
01604
01605
void KMFolderImap::getUids(
const QPtrList<KMMessage>& msgList,
QValueList<ulong>& uids,
KMFolder* msgParent)
01606 {
01607 KMMessage *msg = 0;
01608
01609
if (!msgParent)
01610 msgParent = msgList.getFirst()->parent();
01611
if (!msgParent)
return;
01612
01613
QPtrListIterator<KMMessage> it( msgList );
01614
while ( (msg = it.current()) != 0 ) {
01615 ++it;
01616 uids.append(msg->UID());
01617 }
01618 }
01619
01620
01621
void KMFolderImap::expungeFolder(KMFolderImap * aFolder,
bool quiet)
01622 {
01623 aFolder->setNeedsCompacting(FALSE);
01624 KURL url = mAccount->getUrl();
01625 url.setPath(aFolder->imapPath() +
";UID=*");
01626
if ( mAccount->makeConnection() != ImapAccountBase::Connected )
01627
return;
01628 KIO::SimpleJob *job = KIO::file_delete(url, FALSE);
01629 KIO::Scheduler::assignJobToSlave(mAccount->slave(), job);
01630 ImapAccountBase::jobData jd( url.url(), 0 );
01631 jd.quiet = quiet;
01632 mAccount->insertJob(job, jd);
01633 connect(job, SIGNAL(result(KIO::Job *)),
01634 mAccount, SLOT(slotSimpleResult(KIO::Job *)));
01635 }
01636
01637
01638
void KMFolderImap::slotProcessNewMail(
int errorCode,
const QString &errorMsg )
01639 {
01640 Q_UNUSED( errorMsg );
01641 disconnect( mAccount, SIGNAL( connectionResult(
int,
const QString&) ),
01642
this, SLOT( slotProcessNewMail(
int,
const QString&) ) );
01643
if ( !errorCode )
01644 processNewMail(
false );
01645
else
01646 emit numUnreadMsgsChanged( folder() );
01647 }
01648
01649
01650
bool KMFolderImap::processNewMail(
bool)
01651 {
01652
01653
if ( !mAccount ) {
01654 kdDebug(5006) <<
"KMFolderImap::processNewMail - account is null!" << endl;
01655
return false;
01656 }
01657
if (imapPath().isEmpty()) {
01658 kdDebug(5006) <<
"KMFolderImap::processNewMail - imapPath of " << name() <<
" is empty!" << endl;
01659 kmkernel->imapFolderMgr()->remove( folder() );
01660
return false;
01661 }
01662
01663
if ( mAccount->makeConnection() == ImapAccountBase::Error ) {
01664 kdDebug(5006) <<
"KMFolderImap::processNewMail - got no connection!" << endl;
01665
return false;
01666 }
else if ( mAccount->makeConnection() == ImapAccountBase::Connecting )
01667 {
01668
01669 kdDebug(5006) <<
"KMFolderImap::processNewMail - waiting for connection" << endl;
01670 connect( mAccount, SIGNAL( connectionResult(
int,
const QString&) ),
01671
this, SLOT( slotProcessNewMail(
int,
const QString&) ) );
01672
return true;
01673 }
01674 KURL url = mAccount->getUrl();
01675
if (mReadOnly)
01676 url.setPath(imapPath() +
";SECTION=UIDNEXT");
01677
else
01678 url.setPath(imapPath() +
";SECTION=UNSEEN");
01679
01680 mMailCheckProgressItem = ProgressManager::createProgressItem(
01681
"MailCheckAccount" + account()->name(),
01682
"MailCheck" + folder()->
prettyURL(),
01683 folder()->
prettyURL(),
01684 i18n(
"updating message counts"),
01685
false,
01686 account()->useSSL() || account()->useTLS() );
01687
01688 KIO::SimpleJob *job = KIO::stat(url, FALSE);
01689 KIO::Scheduler::assignJobToSlave(mAccount->slave(), job);
01690 ImapAccountBase::jobData jd(url.url(), folder() );
01691 jd.cancellable =
true;
01692 mAccount->insertJob(job, jd);
01693 connect(job, SIGNAL(result(KIO::Job *)),
01694 SLOT(slotStatResult(KIO::Job *)));
01695
return true;
01696 }
01697
01698
01699
01700
void KMFolderImap::slotStatResult(KIO::Job * job)
01701 {
01702 ImapAccountBase::JobIterator it = mAccount->findJob(job);
01703
if ( it == mAccount->jobsEnd() )
return;
01704 mAccount->removeJob(it);
01705 slotCompleteMailCheckProgress();
01706
if (job->error())
01707 {
01708 mAccount->handleJobError( job, i18n(
"Error while getting folder information.") );
01709 }
else {
01710 KIO::UDSEntry uds = static_cast<KIO::StatJob*>(job)->statResult();
01711
for (KIO::UDSEntry::ConstIterator it = uds.begin(); it != uds.end(); it++)
01712 {
01713
if ((*it).m_uds == KIO::UDS_SIZE)
01714 {
01715
if (mReadOnly)
01716 {
01717 mGuessedUnreadMsgs = -1;
01718 mGuessedUnreadMsgs = countUnread() + (*it).m_long - lastUid() - 1;
01719
if (mGuessedUnreadMsgs < 0) mGuessedUnreadMsgs = 0;
01720 }
else {
01721 mGuessedUnreadMsgs = (*it).m_long;
01722 }
01723 }
01724 }
01725 emit numUnreadMsgsChanged( folder() );
01726 }
01727 }
01728
01729
01730
int KMFolderImap::create(
bool imap)
01731 {
01732 readConfig();
01733 mUnreadMsgs = -1;
01734
return KMFolderMbox::create(imap);
01735 }
01736
01737
QValueList<ulong> KMFolderImap::splitSets(
const QString uids)
01738 {
01739
QValueList<ulong> uidlist;
01740
01741
01742
QString buffer = QString::null;
01743
int setstart = -1;
01744
01745
for (uint i = 0; i < uids.length(); i++)
01746 {
01747
QChar chr = uids[i];
01748
if (chr ==
',')
01749 {
01750
if (setstart > -1)
01751 {
01752
01753
for (
int j = setstart; j <= buffer.toInt(); j++)
01754 {
01755 uidlist.append(j);
01756 }
01757 setstart = -1;
01758 }
else {
01759
01760 uidlist.append(buffer.toInt());
01761 }
01762 buffer =
"";
01763 }
else if (chr ==
':') {
01764
01765 setstart = buffer.toInt();
01766 buffer =
"";
01767 }
else if (chr.category() == QChar::Number_DecimalDigit) {
01768
01769 buffer += chr;
01770 }
else {
01771
01772 }
01773 }
01774
01775
if (setstart > -1)
01776 {
01777
for (
int j = setstart; j <= buffer.toInt(); j++)
01778 {
01779 uidlist.append(j);
01780 }
01781 }
else {
01782 uidlist.append(buffer.toInt());
01783 }
01784
01785
return uidlist;
01786 }
01787
01788
01789
int KMFolderImap::expungeContents()
01790 {
01791
int rc = KMFolderMbox::expungeContents();
01792
if (autoExpunge())
01793 expungeFolder(
this,
true);
01794 getFolder();
01795
01796
return rc;
01797 }
01798
01799
01800
void
01801 KMFolderImap::setUserRights(
unsigned int userRights )
01802 {
01803 mUserRights = userRights;
01804 kdDebug(5006) << imapPath() <<
" setUserRights: " << userRights << endl;
01805 }
01806
01807
01808
void KMFolderImap::slotCompleteMailCheckProgress()
01809 {
01810
if ( mMailCheckProgressItem ) {
01811 mMailCheckProgressItem->setComplete();
01812 }
01813 }
01814
01815
01816
void KMFolderImap::setSubfolderState( imapState state )
01817 {
01818 mSubfolderState = state;
01819
if ( state == imapNoInformation && folder()->
child() )
01820 {
01821
01822 KMFolderNode* node;
01823
QPtrListIterator<KMFolderNode> it( *folder()->child() );
01824
for ( ; (node = it.current()); )
01825 {
01826 ++it;
01827
if (node->isDir())
continue;
01828
KMFolder *folder = static_cast<KMFolder*>(node);
01829 static_cast<KMFolderImap*>(folder->
storage())->setSubfolderState( state );
01830 }
01831 }
01832 }
01833
01834
01835
void KMFolderImap::setIncludeInMailCheck(
bool check )
01836 {
01837
bool changed = ( mCheckMail != check );
01838 mCheckMail = check;
01839
if ( changed )
01840 account()->slotUpdateFolderList();
01841 }
01842
01843
01844
void KMFolderImap::setAlreadyRemoved(
bool removed )
01845 {
01846 mAlreadyRemoved = removed;
01847
if ( folder()->
child() )
01848 {
01849
01850 KMFolderNode* node;
01851
QPtrListIterator<KMFolderNode> it( *folder()->child() );
01852
for ( ; (node = it.current()); )
01853 {
01854 ++it;
01855
if (node->isDir())
continue;
01856
KMFolder *folder = static_cast<KMFolder*>(node);
01857 static_cast<KMFolderImap*>(folder->
storage())->setAlreadyRemoved( removed );
01858 }
01859 }
01860 }
01861
01862
void KMFolderImap::slotCreatePendingFolders()
01863 {
01864 QStringList::Iterator it = mFoldersPendingCreation.begin();
01865
for ( ; it != mFoldersPendingCreation.end(); ++it ) {
01866
createFolder( *it );
01867 }
01868 mFoldersPendingCreation.clear();
01869 }
01870
01871
#include "kmfolderimap.moc"