kmail

kmfolderimap.cpp
1
23#ifdef HAVE_CONFIG_H
24#include <config.h>
25#endif
26
27#include "kmfolder.h"
28#include "kmfolderimap.h"
29#include "kmfoldermbox.h"
30#include "kmfoldertree.h"
31#include "kmmsgdict.h"
32#include "undostack.h"
33#include "kmfoldermgr.h"
34#include "kmfiltermgr.h"
35#include "kmmsgdict.h"
36#include "imapaccountbase.h"
37using KMail::ImapAccountBase;
38#include "imapjob.h"
39using KMail::ImapJob;
40#include "attachmentstrategy.h"
41using KMail::AttachmentStrategy;
42#include "progressmanager.h"
43using KPIM::ProgressItem;
44using KPIM::ProgressManager;
45#include "listjob.h"
46using KMail::ListJob;
47#include "kmsearchpattern.h"
48#include "searchjob.h"
50#include "renamejob.h"
52#include "acljobs.h"
53
54#include <kdebug.h>
55#include <tdeio/scheduler.h>
56#include <tdeconfig.h>
57
58#include <tqbuffer.h>
59#include <tqtextcodec.h>
60#include <tqstylesheet.h>
61
62#include <assert.h>
63
64KMFolderImap::KMFolderImap(KMFolder* folder, const char* aName)
65 : KMFolderMbox(folder, aName),
66 mUploadAllFlags( false )
67{
68 mContentState = imapNoInformation;
69 mSubfolderState = imapNoInformation;
70 mAccount = 0;
71 mIsSelected = false;
72 mLastUid = 0;
73 mCheckFlags = true;
74 mCheckMail = true;
75 mCheckingValidity = false;
76 mUserRights = 0;
77 mUserRightsState = KMail::ACLJobs::NotFetchedYet;
78 mAlreadyRemoved = false;
79 mHasChildren = ChildrenUnknown;
80 mMailCheckProgressItem = 0;
81 mListDirProgressItem = 0;
82 mAddMessageProgressItem = 0;
83 mReadOnly = false;
84
85 connect (this, TQ_SIGNAL( folderComplete( KMFolderImap*, bool ) ),
86 this, TQ_SLOT( slotCompleteMailCheckProgress()) );
87}
88
89KMFolderImap::~KMFolderImap()
90{
91 if (mAccount) {
92 mAccount->removeSlaveJobsForFolder( folder() );
93 /* Now that we've removed ourselves from the accounts jobs map, kill all
94 ongoing operations and reset mailcheck if we were deleted during an
95 ongoing mailcheck of our account. Not very gracefull, but safe, and the
96 only way I can see to reset the account state cleanly. */
97 if ( mAccount->checkingMail( folder() ) ) {
98 mAccount->killAllJobs();
99 }
100 }
101 writeConfig();
102 if (kmkernel->undoStack()) kmkernel->undoStack()->folderDestroyed( folder() );
103 mMetaDataMap.setAutoDelete( true );
104 mMetaDataMap.clear();
105 mUidMetaDataMap.setAutoDelete( true );
106 mUidMetaDataMap.clear();
107}
108
109
110//-----------------------------------------------------------------------------
111void KMFolderImap::reallyDoClose(const char* owner)
112{
113 // FIXME is this still needed?
114 if (account())
115 account()->ignoreJobsForFolder( folder() );
116 int idx = count();
117 while (--idx >= 0) {
118 if ( mMsgList[idx]->isMessage() ) {
119 KMMessage *msg = static_cast<KMMessage*>(mMsgList[idx]);
120 if (msg->transferInProgress())
121 msg->setTransferInProgress( false );
122 }
123 }
124 KMFolderMbox::reallyDoClose( owner );
125}
126
127KMFolder* KMFolderImap::trashFolder() const
128{
129 TQString trashStr = account()->trash();
130 return kmkernel->imapFolderMgr()->findIdString( trashStr );
131}
132
133//-----------------------------------------------------------------------------
134KMMessage* KMFolderImap::getMsg(int idx)
135{
136 if(!(idx >= 0 && idx <= count()))
137 return 0;
138
139 KMMsgBase* mb = getMsgBase(idx);
140 if (!mb) return 0;
141 if (mb->isMessage())
142 {
143 return ((KMMessage*)mb);
144 } else {
145 KMMessage* msg = FolderStorage::getMsg( idx );
146 if ( msg ) // set it incomplete as the msg was not transferred from the server
147 msg->setComplete( false );
148 return msg;
149 }
150}
151
152//-----------------------------------------------------------------------------
153KMAcctImap* KMFolderImap::account() const
154{
155 if ( !mAccount ) {
156 KMFolderDir *parentFolderDir = dynamic_cast<KMFolderDir*>( folder()->parent() );
157 if ( !parentFolderDir ) {
158 kdWarning() << k_funcinfo << "No parent folder dir found for " << name() << endl;
159 return 0;
160 }
161 KMFolder *parentFolder = parentFolderDir->owner();
162 if ( !parentFolder ) {
163 kdWarning() << k_funcinfo << "No parent folder found for " << name() << endl;
164 return 0;
165 }
166 KMFolderImap *parentStorage = dynamic_cast<KMFolderImap*>( parentFolder->storage() );
167 if ( parentStorage )
168 mAccount = parentStorage->account();
169 }
170 return mAccount;
171}
172
173void KMFolderImap::setAccount(KMAcctImap *aAccount)
174{
175 mAccount = aAccount;
176 if( !folder() || !folder()->child() ) return;
177 KMFolderNode* node;
178 for (node = folder()->child()->first(); node;
179 node = folder()->child()->next())
180 {
181 if (!node->isDir())
182 static_cast<KMFolderImap*>(static_cast<KMFolder*>(node)->storage())->setAccount(aAccount);
183 }
184}
185
186//-----------------------------------------------------------------------------
187void KMFolderImap::readConfig()
188{
189 TDEConfig* config = KMKernel::config();
190 TDEConfigGroupSaver saver(config, "Folder-" + folder()->idString());
191 mCheckMail = config->readBoolEntry("checkmail", true);
192
193 mUidValidity = config->readEntry("UidValidity");
194 if ( mImapPath.isEmpty() ) {
195 setImapPath( config->readEntry("ImapPath") );
196 }
197 if (TQString(name()).upper() == "INBOX" && mImapPath == "/INBOX/")
198 {
199 folder()->setSystemFolder( true );
200 folder()->setLabel( i18n("inbox") );
201 }
202 mNoContent = config->readBoolEntry("NoContent", false);
203 mReadOnly = config->readBoolEntry("ReadOnly", false);
204 mUploadAllFlags = config->readBoolEntry( "UploadAllFlags", true );
205 mPermanentFlags = config->readNumEntry( "PermanentFlags", 31 /* default flags */ );
206
208}
209
210//-----------------------------------------------------------------------------
211void KMFolderImap::writeConfig()
212{
213 TDEConfig* config = KMKernel::config();
214 TDEConfigGroupSaver saver(config, "Folder-" + folder()->idString());
215 config->writeEntry("checkmail", mCheckMail);
216 config->writeEntry("UidValidity", mUidValidity);
217 config->writeEntry("ImapPath", mImapPath);
218 config->writeEntry("NoContent", mNoContent);
219 config->writeEntry("ReadOnly", mReadOnly);
220 config->writeEntry( "UploadAllFlags", mUploadAllFlags );
221 config->writeEntry( "PermanentFlags", mPermanentFlags );
223}
224
225//-----------------------------------------------------------------------------
226void KMFolderImap::remove()
227{
228 if ( mAlreadyRemoved || !account() )
229 {
230 // override
232 return;
233 }
234 KURL url = account()->getUrl();
235 url.setPath(imapPath());
236 if ( account()->makeConnection() == ImapAccountBase::Error ||
237 imapPath().isEmpty() )
238 {
239 emit removed(folder(), false);
240 return;
241 }
242 TDEIO::SimpleJob *job = TDEIO::file_delete(url, false);
243 TDEIO::Scheduler::assignJobToSlave(account()->slave(), job);
244 ImapAccountBase::jobData jd(url.url());
245 jd.progressItem = ProgressManager::createProgressItem(
246 "ImapFolderRemove" + ProgressManager::getUniqueID(),
247 i18n("Removing folder"),
248 i18n( "URL: %1" ).arg( TQStyleSheet::escape( folder()->prettyURL() ) ),
249 false,
250 account()->useSSL() || account()->useTLS() );
251 account()->insertJob(job, jd);
252 connect(job, TQ_SIGNAL(result(TDEIO::Job *)),
253 this, TQ_SLOT(slotRemoveFolderResult(TDEIO::Job *)));
254}
255
256//-----------------------------------------------------------------------------
257void KMFolderImap::slotRemoveFolderResult(TDEIO::Job *job)
258{
259 ImapAccountBase::JobIterator it = account()->findJob(job);
260 if ( it == account()->jobsEnd() ) return;
261 if (job->error())
262 {
263 account()->handleJobError( job, i18n("Error while removing a folder.") );
264 emit removed(folder(), false);
265 } else {
266 account()->removeJob(it);
268 }
269
270}
271
272//-----------------------------------------------------------------------------
273void KMFolderImap::removeMsg(int idx, bool quiet)
274{
275 if (idx < 0)
276 return;
277
278 if (!quiet)
279 {
280 KMMessage *msg = getMsg(idx);
281 deleteMessage(msg);
282 }
283
284 mLastUid = 0;
286}
287
288void KMFolderImap::removeMsg( const TQPtrList<KMMessage>& msgList, bool quiet )
289{
290 if ( msgList.isEmpty() ) return;
291 if (!quiet)
292 deleteMessage(msgList);
293
294 mLastUid = 0;
295
296 /* Remove the messages from the local store as well.
297 We don't call KMFolderInherited::removeMsg(TQPtrList<KMMessage>) but
298 iterate ourselves, as that would call KMFolderImap::removeMsg(int)
299 and not the one from the store we want to be used. */
300
301 TQPtrListIterator<KMMessage> it( msgList );
302 KMMessage *msg;
303 while ( (msg = it.current()) != 0 ) {
304 ++it;
305 int idx = find(msg);
306 assert( idx != -1);
307 // ATTENTION port me to maildir
308 KMFolderMbox::removeMsg(idx, quiet);
309 }
310}
311
312//-----------------------------------------------------------------------------
313int KMFolderImap::rename( const TQString& newName, KMFolderDir *aParent )
314{
315 if ( !aParent )
316 KMFolderMbox::rename( newName );
317 kmkernel->folderMgr()->contentsChanged();
318 return 0;
319}
320
321//-----------------------------------------------------------------------------
322void KMFolderImap::addMsgQuiet(KMMessage* aMsg)
323{
324 KMFolder *aFolder = aMsg->parent();
325 TQ_UINT32 serNum = 0;
326 aMsg->setTransferInProgress( false );
327 if (aFolder) {
328 serNum = aMsg->getMsgSerNum();
329 kmkernel->undoStack()->pushSingleAction( serNum, aFolder, folder() );
330 int idx = aFolder->find( aMsg );
331 assert( idx != -1 );
332 aFolder->take( idx );
333 }
334 if ( !account()->hasCapability("uidplus") ) {
335 // Remember the status with the MD5 as key
336 // so it can be transfered to the new message
337 mMetaDataMap.insert( aMsg->msgIdMD5(),
338 new KMMsgMetaData(aMsg->status(), serNum) );
339 }
340
341 delete aMsg;
342 aMsg = 0;
343 getFolder();
344}
345
346//-----------------------------------------------------------------------------
347void KMFolderImap::addMsgQuiet(TQPtrList<KMMessage> msgList)
348{
349 if ( mAddMessageProgressItem )
350 {
351 mAddMessageProgressItem->setComplete();
352 mAddMessageProgressItem = 0;
353 }
354 KMFolder *aFolder = msgList.first()->parent();
355 int undoId = -1;
356 bool uidplus = account()->hasCapability("uidplus");
357 for ( KMMessage* msg = msgList.first(); msg; msg = msgList.next() )
358 {
359 if ( undoId == -1 )
360 undoId = kmkernel->undoStack()->newUndoAction( aFolder, folder() );
361 if ( msg->getMsgSerNum() > 0 )
362 kmkernel->undoStack()->addMsgToAction( undoId, msg->getMsgSerNum() );
363 if ( !uidplus ) {
364 // Remember the status with the MD5 as key
365 // so it can be transfered to the new message
366 mMetaDataMap.insert( msg->msgIdMD5(),
367 new KMMsgMetaData(msg->status(), msg->getMsgSerNum()) );
368 }
369 msg->setTransferInProgress( false );
370 }
371 if ( aFolder ) {
372 aFolder->take( msgList );
373 } else {
374 kdDebug(5006) << k_funcinfo << "no parent" << endl;
375 }
376 msgList.setAutoDelete(true);
377 msgList.clear();
378 getFolder();
379}
380
381//-----------------------------------------------------------------------------
382int KMFolderImap::addMsg(KMMessage* aMsg, int* aIndex_ret)
383{
384 TQPtrList<KMMessage> list;
385 list.append(aMsg);
386 TQValueList<int> index;
387 int ret = addMsg(list, index);
388 aIndex_ret = &index.first();
389 return ret;
390}
391
392int KMFolderImap::addMsg(TQPtrList<KMMessage>& msgList, TQValueList<int>& aIndex_ret)
393{
394 KMMessage *aMsg = msgList.getFirst();
395 KMFolder *msgParent = aMsg->parent();
396
397 ImapJob *imapJob = 0;
398 if (msgParent)
399 {
400 if (msgParent->folderType() == KMFolderTypeImap)
401 {
402 if (static_cast<KMFolderImap*>(msgParent->storage())->account() == account())
403 {
404 // make sure the messages won't be deleted while we work with them
405 for ( KMMessage* msg = msgList.first(); msg; msg = msgList.next() )
406 msg->setTransferInProgress(true);
407
408 if (folder() == msgParent)
409 {
410 // transfer the whole message, e.g. a draft-message is canceled and re-added to the drafts-folder
411 for ( KMMessage* msg = msgList.first(); msg; msg = msgList.next() )
412 {
413 if (!msg->isComplete())
414 {
415 int idx = msgParent->find(msg);
416 assert(idx != -1);
417 msg = msgParent->getMsg(idx);
418 }
419 imapJob = new ImapJob(msg, ImapJob::tPutMessage, this);
420 connect(imapJob, TQ_SIGNAL(messageStored(KMMessage*)),
421 TQ_SLOT(addMsgQuiet(KMMessage*)));
422 connect(imapJob, TQ_SIGNAL(result(KMail::FolderJob*)),
423 TQ_SLOT(slotCopyMsgResult(KMail::FolderJob*)));
424 imapJob->start();
425 }
426
427 } else {
428
429 // get the messages and the uids
430 TQValueList<ulong> uids;
431 getUids(msgList, uids);
432
433 // get the sets (do not sort the uids)
434 TQStringList sets = makeSets(uids, false);
435
436 for ( TQStringList::Iterator it = sets.begin(); it != sets.end(); ++it )
437 {
438 // we need the messages that belong to the current set to pass them to the ImapJob
439 TQPtrList<KMMessage> temp_msgs = splitMessageList(*it, msgList);
440 if ( temp_msgs.isEmpty() ) kdDebug(5006) << "Wow! KMFolderImap::splitMessageList() returned an empty list!" << endl;
441 imapJob = new ImapJob(temp_msgs, *it, ImapJob::tMoveMessage, this);
442 connect(imapJob, TQ_SIGNAL(messageCopied(TQPtrList<KMMessage>)),
443 TQ_SLOT(addMsgQuiet(TQPtrList<KMMessage>)));
444 connect(imapJob, TQ_SIGNAL(result(KMail::FolderJob*)),
445 TQ_SLOT(slotCopyMsgResult(KMail::FolderJob*)));
446 imapJob->start();
447 }
448 }
449 return 0;
450 }
451 else
452 {
453 // different account, check if messages can be added
454 TQPtrListIterator<KMMessage> it( msgList );
455 KMMessage *msg;
456 while ( (msg = it.current()) != 0 )
457 {
458 ++it;
459 int index;
460 if (!canAddMsgNow(msg, &index)) {
461 aIndex_ret << index;
462 msgList.remove(msg);
463 } else {
464 if (!msg->transferInProgress())
465 msg->setTransferInProgress(true);
466 }
467 }
468 }
469 } // if imap
470 }
471
472 if ( !msgList.isEmpty() )
473 {
474 // transfer from local folders or other accounts
475 TQPtrListIterator<KMMessage> it( msgList );
476 KMMessage* msg;
477 while ( ( msg = it.current() ) != 0 )
478 {
479 ++it;
480 if ( !msg->transferInProgress() )
481 msg->setTransferInProgress( true );
482 }
483 imapJob = new ImapJob( msgList, TQString(), ImapJob::tPutMessage, this );
484 if ( !mAddMessageProgressItem && msgList.count() > 1 )
485 {
486 // use a parent progress if we have more than 1 message
487 // otherwise the normal progress is more accurate
488 mAddMessageProgressItem = ProgressManager::createProgressItem(
489 "Uploading"+ProgressManager::getUniqueID(),
490 i18n("Uploading message data"),
491 i18n("Destination folder: %1").arg( TQStyleSheet::escape( folder()->prettyURL() ) ),
492 true,
493 account()->useSSL() || account()->useTLS() );
494 mAddMessageProgressItem->setTotalItems( msgList.count() );
495 connect ( mAddMessageProgressItem, TQ_SIGNAL( progressItemCanceled( KPIM::ProgressItem*)),
496 account(), TQ_SLOT( slotAbortRequested( KPIM::ProgressItem* ) ) );
497 imapJob->setParentProgressItem( mAddMessageProgressItem );
498 }
499 connect( imapJob, TQ_SIGNAL( messageCopied(TQPtrList<KMMessage>) ),
500 TQ_SLOT( addMsgQuiet(TQPtrList<KMMessage>) ) );
501 connect( imapJob, TQ_SIGNAL(result(KMail::FolderJob*)),
502 TQ_SLOT(slotCopyMsgResult(KMail::FolderJob*)) );
503 imapJob->start();
504 }
505
506 return 0;
507}
508
509//-----------------------------------------------------------------------------
510void KMFolderImap::slotCopyMsgResult( KMail::FolderJob* job )
511{
512 kdDebug(5006) << k_funcinfo << job->error() << endl;
513 if ( job->error() ) // getFolder() will not be called in this case
514 emit folderComplete( this, false );
515}
516
517//-----------------------------------------------------------------------------
518void KMFolderImap::copyMsg(TQPtrList<KMMessage>& msgList)
519{
520 if ( !account()->hasCapability("uidplus") ) {
521 for ( KMMessage *msg = msgList.first(); msg; msg = msgList.next() ) {
522 // Remember the status with the MD5 as key
523 // so it can be transfered to the new message
524 mMetaDataMap.insert( msg->msgIdMD5(), new KMMsgMetaData(msg->status()) );
525 }
526 }
527
528 TQValueList<ulong> uids;
529 getUids(msgList, uids);
530 TQStringList sets = makeSets(uids, false);
531 for ( TQStringList::Iterator it = sets.begin(); it != sets.end(); ++it )
532 {
533 // we need the messages that belong to the current set to pass them to the ImapJob
534 TQPtrList<KMMessage> temp_msgs = splitMessageList(*it, msgList);
535
536 ImapJob *job = new ImapJob(temp_msgs, *it, ImapJob::tCopyMessage, this);
537 connect(job, TQ_SIGNAL(result(KMail::FolderJob*)),
538 TQ_SLOT(slotCopyMsgResult(KMail::FolderJob*)));
539 job->start();
540 }
541}
542
543//-----------------------------------------------------------------------------
544TQPtrList<KMMessage> KMFolderImap::splitMessageList(const TQString& set,
545 TQPtrList<KMMessage>& msgList)
546{
547 int lastcomma = set.findRev(",");
548 int lastdub = set.findRev(":");
549 int last = 0;
550 if (lastdub > lastcomma) last = lastdub;
551 else last = lastcomma;
552 last++;
553 if (last < 0) last = set.length();
554 // the last uid of the current set
555 const TQString last_uid = set.right(set.length() - last);
556 TQPtrList<KMMessage> temp_msgs;
557 TQString uid;
558 if (!last_uid.isEmpty())
559 {
560 TQPtrListIterator<KMMessage> it( msgList );
561 KMMessage* msg = 0;
562 while ( (msg = it.current()) != 0 )
563 {
564 // append the msg to the new list and delete it from the old
565 temp_msgs.append(msg);
566 uid.setNum( msg->UID() );
567 // remove modifies the current
568 msgList.remove(msg);
569 if (uid == last_uid) break;
570 }
571 }
572 else
573 {
574 // probably only one element
575 temp_msgs = msgList;
576 }
577
578 return temp_msgs;
579}
580
581//-----------------------------------------------------------------------------
582KMMessage* KMFolderImap::take(int idx)
583{
584 KMMsgBase* mb(mMsgList[idx]);
585 if (!mb) return 0;
586 if (!mb->isMessage()) readMsg(idx);
587
588 KMMessage *msg = static_cast<KMMessage*>(mb);
589 deleteMessage(msg);
590
591 mLastUid = 0;
592 return KMFolderMbox::take(idx);
593}
594
595void KMFolderImap::take(TQPtrList<KMMessage> msgList)
596{
597 deleteMessage(msgList);
598
599 mLastUid = 0;
600 KMFolderMbox::take(msgList);
601}
602
603//-----------------------------------------------------------------------------
604void KMFolderImap::slotListNamespaces()
605{
606 disconnect( account(), TQ_SIGNAL( connectionResult(int, const TQString&) ),
607 this, TQ_SLOT( slotListNamespaces() ) );
608 if ( account()->makeConnection() == ImapAccountBase::Error )
609 {
610 kdWarning(5006) << "slotListNamespaces - got no connection" << endl;
611 return;
612 } else if ( account()->makeConnection() == ImapAccountBase::Connecting )
613 {
614 // wait for the connectionResult
615 kdDebug(5006) << "slotListNamespaces - waiting for connection" << endl;
616 connect( account(), TQ_SIGNAL( connectionResult(int, const TQString&) ),
617 this, TQ_SLOT( slotListNamespaces() ) );
618 return;
619 }
620 kdDebug(5006) << "slotListNamespaces" << endl;
621 // reset subfolder states recursively
622 setSubfolderState( imapNoInformation );
623 mSubfolderState = imapListingInProgress;
624 account()->setHasInbox( false );
625
626 ImapAccountBase::ListType type = ImapAccountBase::List;
627 if ( account()->onlySubscribedFolders() )
628 type = ImapAccountBase::ListSubscribed;
629
630 ImapAccountBase::nsMap map = account()->namespaces();
631 TQStringList personal = map[ImapAccountBase::PersonalNS];
632 // start personal namespace listing and send it directly to slotListResult
633 for ( TQStringList::Iterator it = personal.begin(); it != personal.end(); ++it )
634 {
635 KMail::ListJob* job = new KMail::ListJob( account(), type, this,
636 account()->addPathToNamespace( *it ) );
637 job->setNamespace( *it );
638 job->setHonorLocalSubscription( true );
639 connect( job, TQ_SIGNAL(receivedFolders(const TQStringList&, const TQStringList&,
640 const TQStringList&, const TQStringList&, const ImapAccountBase::jobData&)),
641 this, TQ_SLOT(slotListResult(const TQStringList&, const TQStringList&,
642 const TQStringList&, const TQStringList&, const ImapAccountBase::jobData&)));
643 job->start();
644 }
645
646 // and now we list all other namespaces and check them ourself
647 TQStringList ns = map[ImapAccountBase::OtherUsersNS];
648 ns += map[ImapAccountBase::SharedNS];
649 for ( TQStringList::Iterator it = ns.begin(); it != ns.end(); ++it )
650 {
651 KMail::ListJob* job = new KMail::ListJob( account(), type, this, account()->addPathToNamespace( *it ) );
652 job->setHonorLocalSubscription( true );
653 connect( job, TQ_SIGNAL(receivedFolders(const TQStringList&, const TQStringList&,
654 const TQStringList&, const TQStringList&, const ImapAccountBase::jobData&)),
655 this, TQ_SLOT(slotCheckNamespace(const TQStringList&, const TQStringList&,
656 const TQStringList&, const TQStringList&, const ImapAccountBase::jobData&)));
657 job->start();
658 }
659}
660
661//-----------------------------------------------------------------------------
662void KMFolderImap::slotCheckNamespace( const TQStringList& subfolderNames,
663 const TQStringList& subfolderPaths,
664 const TQStringList& subfolderMimeTypes,
665 const TQStringList& subfolderAttributes,
666 const ImapAccountBase::jobData& jobData )
667{
668 kdDebug(5006) << "slotCheckNamespace - " << subfolderNames.join(",") << endl;
669
670 // get a correct foldername:
671 // strip / and make sure it does not contain the delimiter
672 TQString name = jobData.path.mid( 1, jobData.path.length()-2 );
673 name.remove( account()->delimiterForNamespace( name ) );
674 if ( name.isEmpty() ) {
675 // happens when an empty namespace is defined
676 slotListResult( subfolderNames, subfolderPaths,
677 subfolderMimeTypes, subfolderAttributes, jobData );
678 return;
679 }
680
681 folder()->createChildFolder();
682 KMFolderNode *node = 0;
683 for ( node = folder()->child()->first(); node;
684 node = folder()->child()->next())
685 {
686 if ( !node->isDir() && node->name() == name )
687 break;
688 }
689 if ( subfolderNames.isEmpty() )
690 {
691 if ( node )
692 {
693 kdDebug(5006) << "delete namespace folder " << name << endl;
694 KMFolder *fld = static_cast<KMFolder*>(node);
695 KMFolderImap* nsFolder = static_cast<KMFolderImap*>(fld->storage());
696 nsFolder->setAlreadyRemoved( true );
697 kmkernel->imapFolderMgr()->remove( fld );
698 }
699 } else {
700 if ( node )
701 {
702 // folder exists so pass on the attributes
703 kdDebug(5006) << "found namespace folder " << name << endl;
704 if ( !account()->listOnlyOpenFolders() )
705 {
706 KMFolderImap* nsFolder =
707 static_cast<KMFolderImap*>(static_cast<KMFolder*>(node)->storage());
708 nsFolder->slotListResult( subfolderNames, subfolderPaths,
709 subfolderMimeTypes, subfolderAttributes, jobData );
710 }
711 } else
712 {
713 // create folder
714 kdDebug(5006) << "create namespace folder " << name << endl;
715 KMFolder *fld = folder()->child()->createFolder( name );
716 if ( fld ) {
717 KMFolderImap* f = static_cast<KMFolderImap*> ( fld->storage() );
718 f->initializeFrom( this, account()->addPathToNamespace( name ),
719 "inode/directory" );
720 f->close( "kmfolderimap_create" );
721 if ( !account()->listOnlyOpenFolders() )
722 {
723 f->slotListResult( subfolderNames, subfolderPaths,
724 subfolderMimeTypes, subfolderAttributes, jobData );
725 }
726 }
727 kmkernel->imapFolderMgr()->contentsChanged();
728 }
729 }
730}
731
732//-----------------------------------------------------------------------------
733bool KMFolderImap::listDirectory()
734{
735 if ( !account() ||
736 ( account() && account()->makeConnection() == ImapAccountBase::Error ) )
737 {
738 kdDebug(5006) << "KMFolderImap::listDirectory - got no connection" << endl;
739 return false;
740 }
741
742 if ( this == account()->rootFolder() )
743 {
744 // a new listing started
745 slotListNamespaces();
746 return true;
747 }
748 mSubfolderState = imapListingInProgress;
749
750 // get the folders
751 ImapAccountBase::ListType type = ImapAccountBase::List;
752 if ( account()->onlySubscribedFolders() )
753 type = ImapAccountBase::ListSubscribed;
754 KMail::ListJob* job = new KMail::ListJob( account(), type, this );
755 job->setParentProgressItem( account()->listDirProgressItem() );
756 job->setHonorLocalSubscription( true );
757 connect( job, TQ_SIGNAL(receivedFolders(const TQStringList&, const TQStringList&,
758 const TQStringList&, const TQStringList&, const ImapAccountBase::jobData&)),
759 this, TQ_SLOT(slotListResult(const TQStringList&, const TQStringList&,
760 const TQStringList&, const TQStringList&, const ImapAccountBase::jobData&)));
761 job->start();
762
763 return true;
764}
765
766
767//-----------------------------------------------------------------------------
768void KMFolderImap::slotListResult( const TQStringList& subfolderNames,
769 const TQStringList& subfolderPaths,
770 const TQStringList& subfolderMimeTypes,
771 const TQStringList& subfolderAttributes,
772 const ImapAccountBase::jobData& jobData )
773{
774 mSubfolderState = imapFinished;
775 //kdDebug(5006) << label() << ": folderNames=" << subfolderNames << " folderPaths="
776 //<< subfolderPaths << " mimeTypes=" << subfolderMimeTypes << endl;
777
778 // don't react on changes
779 kmkernel->imapFolderMgr()->quiet(true);
780
781 bool root = ( this == account()->rootFolder() );
782 folder()->createChildFolder();
783 if ( root && !account()->hasInbox() )
784 {
785 // create the INBOX
786 initInbox();
787 }
788
789 // see if we have a better parent
790 // if you have a prefix that contains a folder (e.g "INBOX.") the folders
791 // need to be created underneath it
792 if ( root && !subfolderNames.empty() )
793 {
794 KMFolderImap* parent = findParent( subfolderPaths.first(), subfolderNames.first() );
795 if ( parent )
796 {
797 kdDebug(5006) << "KMFolderImap::slotListResult - pass listing to "
798 << parent->label() << endl;
799 parent->slotListResult( subfolderNames, subfolderPaths,
800 subfolderMimeTypes, subfolderAttributes, jobData );
801 // cleanup
802 TQStringList list;
803 checkFolders( list, jobData.curNamespace );
804 // finish
805 emit directoryListingFinished( this );
806 kmkernel->imapFolderMgr()->quiet( false );
807 return;
808 }
809 }
810
811 bool emptyList = ( root && subfolderNames.empty() );
812 if ( !emptyList )
813 {
814 checkFolders( subfolderNames, jobData.curNamespace );
815 }
816
817 KMFolderImap *f = 0;
818 KMFolderNode *node = 0;
819 for ( uint i = 0; i < subfolderNames.count(); i++ )
820 {
821 bool settingsChanged = false;
822 // create folders if necessary
823 for ( node = folder()->child()->first(); node;
824 node = folder()->child()->next() ) {
825 if ( !node->isDir() && node->name() == subfolderNames[i] )
826 break;
827 }
828 if ( node ) {
829 f = static_cast<KMFolderImap*>(static_cast<KMFolder*>(node)->storage());
830 }
831 else if ( subfolderPaths[i].upper() != "/INBOX/" )
832 {
833 kdDebug(5006) << "create folder " << subfolderNames[i] << endl;
834 KMFolder *fld = folder()->child()->createFolder(subfolderNames[i]);
835 if ( fld ) {
836 f = static_cast<KMFolderImap*> ( fld->storage() );
837 f->close( "kmfolderimap_create" );
838 settingsChanged = true;
839 } else {
840 kdWarning(5006) << "can't create folder " << subfolderNames[i] << endl;
841 }
842 }
843 if ( f )
844 {
845 // sanity check
846 if ( f->imapPath().isEmpty() ) {
847 settingsChanged = true;
848 }
849 // update progress
850 account()->listDirProgressItem()->incCompletedItems();
851 account()->listDirProgressItem()->updateProgress();
852 account()->listDirProgressItem()->setStatus( folder()->prettyURL() + i18n(" completed") );
853
854 f->initializeFrom( this, subfolderPaths[i], subfolderMimeTypes[i] );
855 f->setChildrenState( subfolderAttributes[i] );
856 if ( account()->listOnlyOpenFolders() &&
857 f->hasChildren() != FolderStorage::ChildrenUnknown )
858 {
859 settingsChanged = true;
860 }
861
862 if ( settingsChanged )
863 {
864 // tell the tree our information changed
865 kmkernel->imapFolderMgr()->contentsChanged();
866 }
867 if ( ( subfolderMimeTypes[i] == "message/directory" ||
868 subfolderMimeTypes[i] == "inode/directory" ) &&
869 !account()->listOnlyOpenFolders() )
870 {
871 f->listDirectory();
872 }
873 } else {
874 kdWarning(5006) << "can't find folder " << subfolderNames[i] << endl;
875 }
876 } // for subfolders
877
878 // now others should react on the changes
879 kmkernel->imapFolderMgr()->quiet( false );
880 emit directoryListingFinished( this );
881 account()->listDirProgressItem()->setComplete();
882}
883
884//-----------------------------------------------------------------------------
885void KMFolderImap::initInbox()
886{
887 KMFolderImap *f = 0;
888 KMFolderNode *node = 0;
889
890 for (node = folder()->child()->first(); node;
891 node = folder()->child()->next()) {
892 if (!node->isDir() && node->name() == "INBOX") break;
893 }
894 if (node) {
895 f = static_cast<KMFolderImap*>(static_cast<KMFolder*>(node)->storage());
896 } else {
897 f = static_cast<KMFolderImap*>
898 (folder()->child()->createFolder("INBOX", true)->storage());
899 if ( f )
900 {
901 f->folder()->setLabel( i18n("inbox") );
902 f->close( "kmfolderimap" );
903 }
904 kmkernel->imapFolderMgr()->contentsChanged();
905 }
906 if ( f ) {
907 f->initializeFrom( this, "/INBOX/", "message/directory" );
908 f->setChildrenState( TQString() );
909 }
910 // so we have an INBOX
911 account()->setHasInbox( true );
912}
913
914//-----------------------------------------------------------------------------
915KMFolderImap* KMFolderImap::findParent( const TQString& path, const TQString& name )
916{
917 TQString parent = path.left( path.length() - name.length() - 2 );
918 if ( parent.length() > 1 )
919 {
920 // extract name of the parent
921 parent = parent.right( parent.length() - 1 );
922 if ( parent != label() )
923 {
924 KMFolderNode *node = folder()->child()->first();
925 // look for a better parent
926 while ( node )
927 {
928 if ( node->name() == parent )
929 {
930 KMFolder* fld = static_cast<KMFolder*>(node);
931 KMFolderImap* imapFld = static_cast<KMFolderImap*>( fld->storage() );
932 return imapFld;
933 }
934 node = folder()->child()->next();
935 }
936 }
937 }
938 return 0;
939}
940
941//-----------------------------------------------------------------------------
942void KMFolderImap::checkFolders( const TQStringList& subfolderNames,
943 const TQString& myNamespace )
944{
945 TQPtrList<KMFolder> toRemove;
946 KMFolderNode *node = folder()->child()->first();
947 while ( node )
948 {
949 if ( !node->isDir() && subfolderNames.findIndex(node->name()) == -1 )
950 {
951 KMFolder* fld = static_cast<KMFolder*>(node);
952 KMFolderImap* imapFld = static_cast<KMFolderImap*>( fld->storage() );
953 // as more than one namespace can be listed in the root folder we need to make sure
954 // that the folder is within the current namespace
955 bool isInNamespace = ( myNamespace.isEmpty() ||
956 myNamespace == account()->namespaceForFolder( imapFld ) );
957 kdDebug(5006) << node->name() << " in namespace " << myNamespace << ":" <<
958 isInNamespace << endl;
959 // ignore some cases
960 TQString name = node->name();
961 bool ignore = ( ( this == account()->rootFolder() ) &&
962 ( imapFld->imapPath() == "/INBOX/" ||
963 account()->isNamespaceFolder( name ) ||
964 !isInNamespace ) );
965 // additional sanity check for broken folders
966 if ( imapFld->imapPath().isEmpty() ) {
967 ignore = false;
968 }
969 if ( !ignore )
970 {
971 // remove the folder without server round trip
972 kdDebug(5006) << "checkFolders - " << node->name() << " disappeared" << endl;
973 imapFld->setAlreadyRemoved( true );
974 toRemove.append( fld );
975 } else {
976 kdDebug(5006) << "checkFolders - " << node->name() << " ignored" << endl;
977 }
978 }
979 node = folder()->child()->next();
980 }
981 // remove folders
982 for ( KMFolder* doomed=toRemove.first(); doomed; doomed = toRemove.next() )
983 kmkernel->imapFolderMgr()->remove( doomed );
984}
985
986//-----------------------------------------------------------------------------
987void KMFolderImap::initializeFrom( KMFolderImap* parent, TQString folderPath,
988 TQString mimeType )
989{
990 setAccount( parent->account() );
991 setImapPath( folderPath );
992 setNoContent( mimeType == "inode/directory" );
993 setNoChildren( mimeType == "message/digest" );
994}
995
996//-----------------------------------------------------------------------------
997bool KMFolderImap::mailCheckInProgress() const
998{
999 return getContentState() != imapNoInformation &&
1000 getContentState() != imapFinished;
1001}
1002
1003//-----------------------------------------------------------------------------
1004void KMFolderImap::setChildrenState( TQString attributes )
1005{
1006 // update children state
1007 if ( attributes.find( "haschildren", 0, false ) != -1 )
1008 {
1009 setHasChildren( FolderStorage::HasChildren );
1010 } else if ( attributes.find( "hasnochildren", 0, false ) != -1 ||
1011 attributes.find( "noinferiors", 0, false ) != -1 )
1012 {
1013 setHasChildren( FolderStorage::HasNoChildren );
1014 } else
1015 {
1016 if ( account()->listOnlyOpenFolders() ) {
1017 setHasChildren( FolderStorage::HasChildren );
1018 } else {
1019 setHasChildren( FolderStorage::ChildrenUnknown );
1020 }
1021 }
1022}
1023
1024//-----------------------------------------------------------------------------
1025void KMFolderImap::checkValidity()
1026{
1027 if (!account()) {
1028 emit folderComplete(this, false);
1029 close("checkvalidity");
1030 return;
1031 }
1032 KURL url = account()->getUrl();
1033 url.setPath(imapPath() + ";UID=0:0");
1034 kdDebug(5006) << "KMFolderImap::checkValidity of: " << imapPath() << endl;
1035
1036 // Start with a clean slate
1037 disconnect( account(), TQ_SIGNAL( connectionResult(int, const TQString&) ),
1038 this, TQ_SLOT( checkValidity() ) );
1039
1040 KMAcctImap::ConnectionState connectionState = account()->makeConnection();
1041 if ( connectionState == ImapAccountBase::Error ) {
1042 kdDebug(5006) << "KMFolderImap::checkValidity - got no connection" << endl;
1043 emit folderComplete(this, false);
1044 mContentState = imapNoInformation;
1045 close("checkvalidity");
1046 return;
1047 } else if ( connectionState == ImapAccountBase::Connecting ) {
1048 // We'll wait for the connectionResult signal from the account. If it
1049 // errors, the above will catch it.
1050 kdDebug(5006) << "CheckValidity - waiting for connection" << endl;
1051 connect( account(), TQ_SIGNAL( connectionResult(int, const TQString&) ),
1052 this, TQ_SLOT( checkValidity() ) );
1053 return;
1054 }
1055 // Only check once at a time.
1056 if (mCheckingValidity) {
1057 kdDebug(5006) << "KMFolderImap::checkValidity - already checking" << endl;
1058 close("checkvalidity");
1059 return;
1060 }
1061 // otherwise we already are inside a mailcheck
1062 if ( !mMailCheckProgressItem ) {
1063 ProgressItem* parent = ( account()->checkingSingleFolder() ? 0 :
1064 account()->mailCheckProgressItem() );
1065 mMailCheckProgressItem = ProgressManager::createProgressItem(
1066 parent,
1067 "MailCheck" + folder()->prettyURL(),
1068 TQStyleSheet::escape( folder()->prettyURL() ),
1069 i18n("checking"),
1070 false,
1071 account()->useSSL() || account()->useTLS() );
1072 } else {
1073 mMailCheckProgressItem->setProgress(0);
1074 }
1075 if ( account()->mailCheckProgressItem() ) {
1076 account()->mailCheckProgressItem()->setStatus( folder()->prettyURL() );
1077 }
1078 ImapAccountBase::jobData jd( url.url() );
1079 TDEIO::SimpleJob *job = TDEIO::get(url, false, false);
1080 TDEIO::Scheduler::assignJobToSlave(account()->slave(), job);
1081 account()->insertJob(job, jd);
1082 connect(job, TQ_SIGNAL(result(TDEIO::Job *)),
1083 TQ_SLOT(slotCheckValidityResult(TDEIO::Job *)));
1084 connect(job, TQ_SIGNAL(data(TDEIO::Job *, const TQByteArray &)),
1085 TQ_SLOT(slotSimpleData(TDEIO::Job *, const TQByteArray &)));
1086 // Only check once at a time.
1087 mCheckingValidity = true;
1088}
1089
1090
1091//-----------------------------------------------------------------------------
1092ulong KMFolderImap::lastUid()
1093{
1094 if ( mLastUid > 0 )
1095 return mLastUid;
1096 open("lastuid");
1097 if (count() > 0)
1098 {
1099 KMMsgBase * base = getMsgBase(count()-1);
1100 mLastUid = base->UID();
1101 }
1102 close("lastuid");
1103 return mLastUid;
1104}
1105
1106
1107//-----------------------------------------------------------------------------
1108void KMFolderImap::slotCheckValidityResult(TDEIO::Job * job)
1109{
1110 kdDebug(5006) << "KMFolderImap::slotCheckValidityResult of: " << fileName() << endl;
1111 mCheckingValidity = false;
1112 ImapAccountBase::JobIterator it = account()->findJob(job);
1113 if ( it == account()->jobsEnd() ) return;
1114 if (job->error()) {
1115 if ( job->error() != TDEIO::ERR_ACCESS_DENIED ) {
1116 // we suppress access denied messages because they are normally a result of
1117 // explicitely set ACLs. Do not save this information (e.g. setNoContent) so that
1118 // we notice when this changes
1119 account()->handleJobError( job, i18n("Error while querying the server status.") );
1120 }
1121 mContentState = imapNoInformation;
1122 emit folderComplete(this, false);
1123 close("checkvalidity");
1124 } else {
1125 TQCString cstr((*it).data.data(), (*it).data.size() + 1);
1126 int a = cstr.find("X-uidValidity: ");
1127 int b = cstr.find("\r\n", a);
1128 TQString uidv;
1129 if ( (b - a - 15) >= 0 )
1130 uidv = cstr.mid(a + 15, b - a - 15);
1131 a = cstr.find("X-Access: ");
1132 b = cstr.find("\r\n", a);
1133 TQString access;
1134 if ( (b - a - 10) >= 0 )
1135 access = cstr.mid(a + 10, b - a - 10);
1136 mReadOnly = access == "Read only";
1137 a = cstr.find("X-Count: ");
1138 b = cstr.find("\r\n", a);
1139 int exists = -1;
1140 bool ok = false;
1141 if ( (b - a - 9) >= 0 )
1142 exists = cstr.mid(a + 9, b - a - 9).toInt(&ok);
1143 if ( !ok ) exists = -1;
1144 a = cstr.find( "X-PermanentFlags: " );
1145 b = cstr.find( "\r\n", a );
1146 if ( a >= 0 && (b - a - 18) >= 0 )
1147 mPermanentFlags = cstr.mid( a + 18, b - a - 18 ).toInt(&ok);
1148 if ( !ok ) mPermanentFlags = 0;
1149 TQString startUid;
1150 if (uidValidity() != uidv)
1151 {
1152 // uidValidity changed
1153 kdDebug(5006) << k_funcinfo << "uidValidty changed from "
1154 << uidValidity() << " to " << uidv << endl;
1155 if ( !uidValidity().isEmpty() )
1156 {
1157 account()->ignoreJobsForFolder( folder() );
1158 mUidMetaDataMap.clear();
1159 }
1160 mLastUid = 0;
1161 setUidValidity(uidv);
1162 writeConfig();
1163 } else {
1164 if (!mCheckFlags)
1165 startUid = TQString::number(lastUid() + 1);
1166 }
1167 account()->removeJob(it);
1168 if ( mMailCheckProgressItem )
1169 {
1170 if ( startUid.isEmpty() ) {
1171 // flags for all messages are loaded
1172 mMailCheckProgressItem->setTotalItems( exists );
1173 } else {
1174 // only an approximation but doesn't hurt
1175 int remain = exists - count();
1176 if ( remain < 0 ) remain = 1;
1177 mMailCheckProgressItem->setTotalItems( remain );
1178 }
1179 mMailCheckProgressItem->setCompletedItems( 0 );
1180 }
1181 reallyGetFolder(startUid);
1182 }
1183}
1184
1185//-----------------------------------------------------------------------------
1186void KMFolderImap::getAndCheckFolder(bool force)
1187{
1188 if (mNoContent)
1189 return getFolder(force);
1190
1191 if ( account() )
1192 account()->processNewMailInFolder( folder() );
1193 if (force) {
1194 // force an update
1195 mCheckFlags = true;
1196 }
1197}
1198
1199//-----------------------------------------------------------------------------
1200void KMFolderImap::getFolder(bool force)
1201{
1202 mGuessedUnreadMsgs = -1;
1203 if (mNoContent)
1204 {
1205 mContentState = imapFinished;
1206 emit folderComplete(this, true);
1207 return;
1208 }
1209 open("getfolder");
1210 mContentState = imapListingInProgress;
1211 if (force) {
1212 // force an update
1213 mCheckFlags = true;
1214 }
1215 checkValidity();
1216}
1217
1218
1219//-----------------------------------------------------------------------------
1220void KMFolderImap::reallyGetFolder(const TQString &startUid)
1221{
1222 KURL url = account()->getUrl();
1223 if ( account()->makeConnection() != ImapAccountBase::Connected )
1224 {
1225 mContentState = imapNoInformation;
1226 emit folderComplete(this, false);
1227 close("listfolder");
1228 return;
1229 }
1230 quiet(true);
1231 if (startUid.isEmpty())
1232 {
1233 if ( mMailCheckProgressItem )
1234 mMailCheckProgressItem->setStatus( i18n("Retrieving message status") );
1235 url.setPath(imapPath() + ";SECTION=UID FLAGS");
1236 TDEIO::SimpleJob *job = TDEIO::listDir(url, false);
1237 TDEIO::Scheduler::assignJobToSlave(account()->slave(), job);
1238 ImapAccountBase::jobData jd( url.url(), folder() );
1239 jd.cancellable = true;
1240 account()->insertJob(job, jd);
1241 connect(job, TQ_SIGNAL(result(TDEIO::Job *)),
1242 this, TQ_SLOT(slotListFolderResult(TDEIO::Job *)));
1243 connect(job, TQ_SIGNAL(entries(TDEIO::Job *, const TDEIO::UDSEntryList &)),
1244 this, TQ_SLOT(slotListFolderEntries(TDEIO::Job *,
1245 const TDEIO::UDSEntryList &)));
1246 } else {
1247 mContentState = imapDownloadInProgress;
1248 if ( mMailCheckProgressItem )
1249 mMailCheckProgressItem->setStatus( i18n("Retrieving messages") );
1250 url.setPath(imapPath() + ";UID=" + startUid
1251 + ":*;SECTION=ENVELOPE");
1252 TDEIO::SimpleJob *newJob = TDEIO::get(url, false, false);
1253 TDEIO::Scheduler::assignJobToSlave(account()->slave(), newJob);
1254 ImapAccountBase::jobData jd( url.url(), folder() );
1255 jd.cancellable = true;
1256 account()->insertJob(newJob, jd);
1257 connect(newJob, TQ_SIGNAL(result(TDEIO::Job *)),
1258 this, TQ_SLOT(slotGetLastMessagesResult(TDEIO::Job *)));
1259 connect(newJob, TQ_SIGNAL(data(TDEIO::Job *, const TQByteArray &)),
1260 this, TQ_SLOT(slotGetMessagesData(TDEIO::Job *, const TQByteArray &)));
1261 }
1262}
1263
1264
1265//-----------------------------------------------------------------------------
1266void KMFolderImap::slotListFolderResult(TDEIO::Job * job)
1267{
1268 ImapAccountBase::JobIterator it = account()->findJob(job);
1269 if ( it == account()->jobsEnd() ) return;
1270 TQString uids;
1271 if (job->error())
1272 {
1273 account()->handleJobError( job,
1274 i18n("Error while listing the contents of the folder %1.").arg( label() ) );
1275 account()->removeJob(it);
1276 finishMailCheck( "listfolder", imapNoInformation );
1277 return;
1278 }
1279 mCheckFlags = false;
1280 TQStringList::Iterator uid;
1281 /*
1282 The code below does the following:
1283 - for each mail in the local store and each entry we got from the server,
1284 compare the local uid with the one from the server and update the status
1285 flags of the mails
1286 - for all mails that are not already locally present, start a job which
1287 gets the envelope of each
1288 - remove all locally present mails if the server does not list them anymore
1289 */
1290 if ( count() ) {
1291 int idx = 0, c, serverFlags;
1292 ulong mailUid, serverUid;
1293 uid = (*it).items.begin();
1294 while ( idx < count() && uid != (*it).items.end() ) {
1295 KMMsgBase *msgBase = getMsgBase( idx );
1296 mailUid = msgBase->UID();
1297 // parse the uid from the server and the flags out of the list from
1298 // the server. Format: 1234, 1
1299 c = (*uid).find(",");
1300 serverUid = (*uid).left( c ).toLong();
1301 serverFlags = (*uid).mid( c+1 ).toInt();
1302 if ( mailUid < serverUid ) {
1303 removeMsg( idx, true );
1304 } else if ( mailUid == serverUid ) {
1305 // if this is a read only folder, ignore status updates from the server
1306 // since we can't write our status back our local version is what has to
1307 // be considered correct.
1308 if ( !mReadOnly || !GlobalSettings::allowLocalFlags() ) {
1309 int supportedFlags = mUploadAllFlags ? 31 : mPermanentFlags;
1310 if ( mReadOnly )
1311 supportedFlags = INT_MAX;
1312 flagsToStatus( msgBase, serverFlags, false, supportedFlags );
1313 } else
1314 seenFlagToStatus( msgBase, serverFlags, false );
1315 idx++;
1316 uid = (*it).items.remove(uid);
1317 if ( msgBase->getMsgSerNum() > 0 ) {
1318 saveMsgMetaData( static_cast<KMMessage*>(msgBase) );
1319 }
1320 }
1321 else break; // happens only, if deleted mails reappear on the server
1322 }
1323 // remove all remaining entries in the local cache, they are no longer
1324 // present on the server
1325 while (idx < count()) removeMsg(idx, true);
1326 }
1327 // strip the flags from the list of uids, so it can be reused
1328 for (uid = (*it).items.begin(); uid != (*it).items.end(); ++uid)
1329 (*uid).truncate((*uid).find(","));
1330 ImapAccountBase::jobData jd( TQString(), (*it).parent );
1331 jd.total = (*it).items.count();
1332 if (jd.total == 0)
1333 {
1334 finishMailCheck( "listfolder", imapFinished );
1335 account()->removeJob(it);
1336 return;
1337 }
1338 if ( mMailCheckProgressItem )
1339 {
1340 // next step for the progressitem
1341 mMailCheckProgressItem->setCompletedItems( 0 );
1342 mMailCheckProgressItem->setTotalItems( jd.total );
1343 mMailCheckProgressItem->setProgress( 0 );
1344 mMailCheckProgressItem->setStatus( i18n("Retrieving messages") );
1345 }
1346
1347 TQStringList sets;
1348 uid = (*it).items.begin();
1349 if (jd.total == 1) sets.append(*uid + ":" + *uid);
1350 else sets = makeSets( (*it).items );
1351 account()->removeJob(it); // don't use *it below
1352
1353 // Now kick off the getting of envelopes for the new mails in the folder
1354 for (TQStringList::Iterator i = sets.begin(); i != sets.end(); ++i)
1355 {
1356 mContentState = imapDownloadInProgress;
1357 KURL url = account()->getUrl();
1358 url.setPath(imapPath() + ";UID=" + *i + ";SECTION=ENVELOPE");
1359 TDEIO::SimpleJob *newJob = TDEIO::get(url, false, false);
1360 jd.url = url.url();
1361 TDEIO::Scheduler::assignJobToSlave(account()->slave(), newJob);
1362 account()->insertJob(newJob, jd);
1363 connect(newJob, TQ_SIGNAL(result(TDEIO::Job *)),
1364 this, (i == sets.at(sets.count() - 1))
1365 ? TQ_SLOT(slotGetLastMessagesResult(TDEIO::Job *))
1366 : TQ_SLOT(slotGetMessagesResult(TDEIO::Job *)));
1367 connect(newJob, TQ_SIGNAL(data(TDEIO::Job *, const TQByteArray &)),
1368 this, TQ_SLOT(slotGetMessagesData(TDEIO::Job *, const TQByteArray &)));
1369 }
1370}
1371
1372
1373//-----------------------------------------------------------------------------
1374void KMFolderImap::slotListFolderEntries(TDEIO::Job * job,
1375 const TDEIO::UDSEntryList & uds)
1376{
1377 ImapAccountBase::JobIterator it = account()->findJob(job);
1378 if ( it == account()->jobsEnd() ) return;
1379 TQString mimeType, name;
1380 long int flags = 0;
1381 for (TDEIO::UDSEntryList::ConstIterator udsIt = uds.begin();
1382 udsIt != uds.end(); udsIt++)
1383 {
1384 for (TDEIO::UDSEntry::ConstIterator eIt = (*udsIt).begin();
1385 eIt != (*udsIt).end(); eIt++)
1386 {
1387 if ((*eIt).m_uds == TDEIO::UDS_NAME)
1388 name = (*eIt).m_str;
1389 else if ((*eIt).m_uds == TDEIO::UDS_MIME_TYPE)
1390 mimeType = (*eIt).m_str;
1391 else if ((*eIt).m_uds == TDEIO::UDS_ACCESS)
1392 flags = (*eIt).m_long;
1393 }
1394 if ((mimeType == "message/rfc822-imap" || mimeType == "message/rfc822") &&
1395 !(flags & 8)) {
1396 (*it).items.append(name + "," + TQString::number(flags));
1397 if ( mMailCheckProgressItem ) {
1398 mMailCheckProgressItem->incCompletedItems();
1399 mMailCheckProgressItem->updateProgress();
1400 }
1401 }
1402 }
1403}
1404
1405
1406// debugging helper
1407//X static TQString flagsToString( int flags )
1408//X {
1409//X TQString str("(");
1410//X if ( flags & 4 ) {
1411//X str += "\\Flagged ";
1412//X }
1413//X if ( flags & 2 ) {
1414//X str += "\\Answered ";
1415//X }
1416//X if ( flags & 1 ) {
1417//X str += "\\Seen";
1418//X }
1419//X str += ")";
1420//X return str;
1421//X }
1422
1423//-----------------------------------------------------------------------------
1424void KMFolderImap::flagsToStatus(KMMsgBase *msg, int flags, bool newMsg, int supportedFlags )
1425{
1426 if ( !msg ) return;
1427
1428 // see imap4/imapinfo.h for the magic numbers
1429 static const struct {
1430 const int imapFlag;
1431 const int kmFlag;
1432 const bool standardFlag;
1433 } imapFlagMap[] = {
1434 { 2, KMMsgStatusReplied, true },
1435 { 4, KMMsgStatusFlag, true },
1436 { 128, KMMsgStatusForwarded, false },
1437 { 256, KMMsgStatusTodo, false },
1438 { 512, KMMsgStatusWatched, false },
1439 { 1024, KMMsgStatusIgnored, false }
1440 };
1441 static const int numFlags = sizeof imapFlagMap / sizeof *imapFlagMap;
1442
1443 const KMMsgStatus oldStatus = msg->status();
1444 for ( int i = 0; i < numFlags; ++i ) {
1445 if ( ( (supportedFlags & imapFlagMap[i].imapFlag) == 0 && (supportedFlags & 64) == 0 )
1446 && !imapFlagMap[i].standardFlag ) {
1447 continue;
1448 }
1449 if ( ((flags & imapFlagMap[i].imapFlag) > 0) != ((oldStatus & imapFlagMap[i].kmFlag) > 0) ) {
1450 msg->toggleStatus( imapFlagMap[i].kmFlag );
1451 }
1452 }
1453
1454 seenFlagToStatus( msg, flags, newMsg );
1455}
1456
1457void KMFolderImap::seenFlagToStatus(KMMsgBase * msg, int flags, bool newMsg)
1458{
1459 if ( !msg ) return;
1460
1461 const KMMsgStatus oldStatus = msg->status();
1462 if ( (flags & 1) && (oldStatus & KMMsgStatusOld) == 0 )
1463 msg->setStatus( KMMsgStatusOld );
1464
1465 // In case the message does not have the seen flag set, override our local
1466 // notion that it is read. Otherwise the count of unread messages and the
1467 // number of messages which actually show up as read can go out of sync.
1468 if ( msg->isOfUnknownStatus() || (!(flags&1) && !(oldStatus&(KMMsgStatusNew|KMMsgStatusUnread)) ) ) {
1469 if (newMsg) {
1470 if ( (oldStatus & KMMsgStatusNew) == 0 )
1471 msg->setStatus( KMMsgStatusNew );
1472 } else {
1473 if ( (oldStatus & KMMsgStatusUnread) == 0 )
1474 msg->setStatus( KMMsgStatusUnread );
1475 }
1476 }
1477}
1478
1479
1480//-----------------------------------------------------------------------------
1481TQString KMFolderImap::statusToFlags(KMMsgStatus status, int supportedFlags)
1482{
1483 TQString flags;
1484 if (status & KMMsgStatusDeleted)
1485 flags = "\\DELETED";
1486 else {
1487 if (status & KMMsgStatusOld || status & KMMsgStatusRead)
1488 flags = "\\SEEN ";
1489 if (status & KMMsgStatusReplied)
1490 flags += "\\ANSWERED ";
1491 if (status & KMMsgStatusFlag)
1492 flags += "\\FLAGGED ";
1493 // non standard flags
1494 if ( (status & KMMsgStatusForwarded) && ((supportedFlags & 64) || (supportedFlags & 128)) )
1495 flags += "$FORWARDED ";
1496 if ( (status & KMMsgStatusTodo) && ((supportedFlags & 64) || (supportedFlags & 256)) )
1497 flags += "$TODO ";
1498 if ( (status & KMMsgStatusWatched) && ((supportedFlags & 64) || (supportedFlags & 512)) )
1499 flags += "$WATCHED ";
1500 if ( (status & KMMsgStatusIgnored) && ((supportedFlags & 64) || (supportedFlags & 1024)) )
1501 flags += "$IGNORED ";
1502 }
1503
1504 return flags.simplifyWhiteSpace();
1505}
1506
1507//-------------------------------------------------------------
1508void
1509KMFolderImap::ignoreJobsForMessage( KMMessage* msg )
1510{
1511 if ( !msg || msg->transferInProgress() ||
1512 !msg->parent() || msg->parent()->folderType() != KMFolderTypeImap )
1513 return;
1514 KMAcctImap *account;
1515 if ( !(account = static_cast<KMFolderImap*>(msg->storage())->account()) )
1516 return;
1517
1518 account->ignoreJobsForMessage( msg );
1519}
1520
1521//-----------------------------------------------------------------------------
1522void KMFolderImap::slotGetMessagesData(TDEIO::Job * job, const TQByteArray & data)
1523{
1524 if ( data.isEmpty() ) return; // optimization
1525 ImapAccountBase::JobIterator it = account()->findJob(job);
1526 if ( it == account()->jobsEnd() ) return;
1527 (*it).cdata += TQCString(data, data.size() + 1);
1528 int pos = (*it).cdata.find("\r\n--IMAPDIGEST");
1529 if ( pos == -1 ) {
1530 // if we do not find the pattern in the complete string we will not find
1531 // it in a substring.
1532 return;
1533 }
1534 if (pos > 0)
1535 {
1536 int p = (*it).cdata.find("\r\nX-uidValidity:");
1537 if (p != -1) setUidValidity((*it).cdata
1538 .mid(p + 17, (*it).cdata.find("\r\n", p+1) - p - 17));
1539 int c = (*it).cdata.find("\r\nX-Count:");
1540 if ( c != -1 )
1541 {
1542 bool ok;
1543 int exists = (*it).cdata.mid( c+10,
1544 (*it).cdata.find("\r\n", c+1) - c-10 ).toInt(&ok);
1545 if ( ok && exists < count() ) {
1546 kdDebug(5006) << "KMFolderImap::slotGetMessagesData - server has less messages (" <<
1547 exists << ") then folder (" << count() << "), so reload" << endl;
1548 open("getMessage");
1549 reallyGetFolder( TQString() );
1550 (*it).cdata.remove(0, pos);
1551 return;
1552 } else if ( ok ) {
1553 int delta = exists - count();
1554 if ( mMailCheckProgressItem ) {
1555 mMailCheckProgressItem->setTotalItems( delta );
1556 }
1557 }
1558 }
1559 (*it).cdata.remove(0, pos);
1560 }
1561 pos = (*it).cdata.find("\r\n--IMAPDIGEST", 1);
1562 int flags;
1563 while (pos >= 0)
1564 {
1565 KMMessage *msg = new KMMessage;
1566 msg->setComplete( false );
1567 msg->setReadyToShow( false );
1568 // nothing between the boundaries, older UWs do that
1569 if ( pos != 14 ) {
1570 msg->fromString( (*it).cdata.mid(16, pos - 16) );
1571 flags = msg->headerField("X-Flags").toInt();
1572 ulong uid = msg->UID();
1573 KMMsgMetaData *md = 0;
1574 if ( mUidMetaDataMap.find( uid ) ) {
1575 md = mUidMetaDataMap[uid];
1576 }
1577 ulong serNum = 0;
1578 if ( md ) {
1579 serNum = md->serNum();
1580 }
1581 bool ok = true;
1582 if ( uid <= lastUid() && serNum > 0 ) {
1583 // the UID is already known so no need to create it
1584 ok = false;
1585 }
1586 // deleted flag
1587 if ( flags & 8 )
1588 ok = false;
1589 if ( !ok ) {
1590 delete msg;
1591 msg = 0;
1592 } else {
1593 if ( serNum > 0 ) {
1594 // assign the sernum from the cache
1595 msg->setMsgSerNum( serNum );
1596 }
1597 // Transfer the status, if it is cached.
1598 if ( md ) {
1599 msg->setStatus( md->status() );
1600 } else if ( !account()->hasCapability("uidplus") ) {
1601 // see if we have cached the msgIdMD5 and get the status +
1602 // serial number from there
1603 TQString id = msg->msgIdMD5();
1604 if ( mMetaDataMap.find( id ) ) {
1605 md = mMetaDataMap[id];
1606 msg->setStatus( md->status() );
1607 if ( md->serNum() != 0 && serNum == 0 ) {
1608 msg->setMsgSerNum( md->serNum() );
1609 }
1610 mMetaDataMap.remove( id );
1611 delete md;
1612 }
1613 }
1614 KMFolderMbox::addMsg(msg, 0);
1615 // Merge with the flags from the server.
1616 flagsToStatus((KMMsgBase*)msg, flags, true, mUploadAllFlags ? 31 : mPermanentFlags);
1617 // set the correct size
1618 msg->setMsgSizeServer( msg->headerField("X-Length").toUInt() );
1619 msg->setUID(uid);
1620 if ( msg->getMsgSerNum() > 0 ) {
1621 saveMsgMetaData( msg );
1622 }
1623 // Filter messages that have arrived in the inbox folder
1624 if ( folder()->isSystemFolder() && imapPath() == "/INBOX/"
1625 && kmkernel->filterMgr()->atLeastOneIncomingFilterAppliesTo( account()->id() ) )
1626 account()->execFilters( msg->getMsgSerNum() );
1627
1628 if ( count() > 1 ) {
1629 unGetMsg(count() - 1);
1630 }
1631 mLastUid = uid;
1632 if ( mMailCheckProgressItem ) {
1633 mMailCheckProgressItem->incCompletedItems();
1634 mMailCheckProgressItem->updateProgress();
1635 }
1636 }
1637 }
1638 (*it).cdata.remove(0, pos);
1639 (*it).done++;
1640 pos = (*it).cdata.find("\r\n--IMAPDIGEST", 1);
1641 } // while
1642}
1643
1644//-------------------------------------------------------------
1645FolderJob*
1646KMFolderImap::doCreateJob( KMMessage *msg, FolderJob::JobType jt,
1647 KMFolder *folder, TQString partSpecifier,
1648 const AttachmentStrategy *as ) const
1649{
1650 KMFolderImap* kmfi = folder? dynamic_cast<KMFolderImap*>(folder->storage()) : 0;
1651 if ( jt == FolderJob::tGetMessage && partSpecifier == "STRUCTURE" &&
1652 account() && account()->loadOnDemand() &&
1653 ( msg->msgSizeServer() > 5000 || msg->msgSizeServer() == 0 ) &&
1654 ( msg->signatureState() == KMMsgNotSigned ||
1655 msg->signatureState() == KMMsgSignatureStateUnknown ) &&
1656 ( msg->encryptionState() == KMMsgNotEncrypted ||
1657 msg->encryptionState() == KMMsgEncryptionStateUnknown ) )
1658 {
1659 // load-on-demand: retrieve the BODYSTRUCTURE and to speed things up also the headers
1660 // this is not activated for small or signed messages
1661 ImapJob *job = new ImapJob( msg, jt, kmfi, "HEADER" );
1662 job->start();
1663 ImapJob *job2 = new ImapJob( msg, jt, kmfi, "STRUCTURE", as );
1664 job2->start();
1665 job->setParentFolder( this );
1666 return job;
1667 } else {
1668 // download complete message or part (attachment)
1669 if ( partSpecifier == "STRUCTURE" ) // hide from outside
1670 partSpecifier = TQString();
1671
1672 ImapJob *job = new ImapJob( msg, jt, kmfi, partSpecifier );
1673 job->setParentFolder( this );
1674 return job;
1675 }
1676}
1677
1678//-------------------------------------------------------------
1679FolderJob*
1680KMFolderImap::doCreateJob( TQPtrList<KMMessage>& msgList, const TQString& sets,
1681 FolderJob::JobType jt, KMFolder *folder ) const
1682{
1683 KMFolderImap* kmfi = dynamic_cast<KMFolderImap*>(folder->storage());
1684 ImapJob *job = new ImapJob( msgList, sets, jt, kmfi );
1685 job->setParentFolder( this );
1686 return job;
1687}
1688
1689//-----------------------------------------------------------------------------
1690void KMFolderImap::getMessagesResult(TDEIO::Job * job, bool lastSet)
1691{
1692 ImapAccountBase::JobIterator it = account()->findJob(job);
1693 if ( it == account()->jobsEnd() ) return;
1694 if (job->error()) {
1695 account()->handleJobError( job, i18n("Error while retrieving messages.") );
1696 finishMailCheck( "getMessage", imapNoInformation );
1697 return;
1698 }
1699 if (lastSet) {
1700 finishMailCheck( "getMessage", imapFinished );
1701 account()->removeJob(it);
1702 }
1703}
1704
1705
1706//-----------------------------------------------------------------------------
1707void KMFolderImap::slotGetLastMessagesResult(TDEIO::Job * job)
1708{
1709 getMessagesResult(job, true);
1710}
1711
1712
1713//-----------------------------------------------------------------------------
1714void KMFolderImap::slotGetMessagesResult(TDEIO::Job * job)
1715{
1716 getMessagesResult(job, false);
1717}
1718
1719
1720//-----------------------------------------------------------------------------
1721void KMFolderImap::createFolder(const TQString &name, const TQString& parentPath,
1722 bool askUser)
1723{
1724 kdDebug(5006) << "KMFolderImap::createFolder - name=" << name << ",parent=" <<
1725 parentPath << ",askUser=" << askUser << endl;
1726 if ( account()->makeConnection() != ImapAccountBase::Connected ) {
1727 kdWarning(5006) << "KMFolderImap::createFolder - got no connection" << endl;
1728 return;
1729 }
1730 KURL url = account()->getUrl();
1731 TQString parent = ( parentPath.isEmpty() ? imapPath() : parentPath );
1732 TQString path = account()->createImapPath( parent, name );
1733 if ( askUser ) {
1734 path += "/;INFO=ASKUSER";
1735 }
1736 url.setPath( path );
1737
1738 TDEIO::SimpleJob *job = TDEIO::mkdir(url);
1739 TDEIO::Scheduler::assignJobToSlave(account()->slave(), job);
1740 ImapAccountBase::jobData jd( url.url(), folder() );
1741 jd.items = name;
1742 account()->insertJob(job, jd);
1743 connect(job, TQ_SIGNAL(result(TDEIO::Job *)),
1744 this, TQ_SLOT(slotCreateFolderResult(TDEIO::Job *)));
1745}
1746
1747
1748//-----------------------------------------------------------------------------
1749void KMFolderImap::slotCreateFolderResult(TDEIO::Job * job)
1750{
1751 ImapAccountBase::JobIterator it = account()->findJob(job);
1752 if ( it == account()->jobsEnd() ) return;
1753
1754 TQString name;
1755 if ( it.data().items.count() > 0 )
1756 name = it.data().items.first();
1757
1758 if (job->error())
1759 {
1760 if ( job->error() == TDEIO::ERR_COULD_NOT_MKDIR ) {
1761 // Creating a folder failed, remove it from the tree.
1762 account()->listDirectory( );
1763 }
1764 account()->handleJobError( job, i18n("Error while creating a folder.") );
1765 emit folderCreationResult( name, false );
1766 } else {
1767 listDirectory();
1768 account()->removeJob(job);
1769 emit folderCreationResult( name, true );
1770 }
1771}
1772
1773
1774//-----------------------------------------------------------------------------
1775static TQTextCodec *sUtf7Codec = 0;
1776
1777TQTextCodec * KMFolderImap::utf7Codec()
1778{
1779 if (!sUtf7Codec) sUtf7Codec = TQTextCodec::codecForName("utf-7");
1780 return sUtf7Codec;
1781}
1782
1783
1784//-----------------------------------------------------------------------------
1785TQString KMFolderImap::encodeFileName(const TQString &name)
1786{
1787 TQString result = utf7Codec()->fromUnicode(name);
1788 return KURL::encode_string_no_slash(result);
1789}
1790
1791
1792//-----------------------------------------------------------------------------
1793TQString KMFolderImap::decodeFileName(const TQString &name)
1794{
1795 TQString result = KURL::decode_string(name);
1796 return utf7Codec()->toUnicode(result.latin1());
1797}
1798
1799//-----------------------------------------------------------------------------
1800bool KMFolderImap::autoExpunge()
1801{
1802 if (account())
1803 return account()->autoExpunge();
1804
1805 return false;
1806}
1807
1808
1809//-----------------------------------------------------------------------------
1810void KMFolderImap::slotSimpleData(TDEIO::Job * job, const TQByteArray & data)
1811{
1812 if ( data.isEmpty() ) return; // optimization
1813 ImapAccountBase::JobIterator it = account()->findJob(job);
1814 if ( it == account()->jobsEnd() ) return;
1815 TQBuffer buff((*it).data);
1816 buff.open(IO_WriteOnly | IO_Append);
1817 buff.writeBlock(data.data(), data.size());
1818 buff.close();
1819}
1820
1821//-----------------------------------------------------------------------------
1822void KMFolderImap::deleteMessage(KMMessage * msg)
1823{
1824 mUidMetaDataMap.remove( msg->UID() );
1825 mMetaDataMap.remove( msg->msgIdMD5() );
1826 KURL url = account()->getUrl();
1827 KMFolderImap *msg_parent = static_cast<KMFolderImap*>(msg->storage());
1828 ulong uid = msg->UID();
1829 /* If the uid is empty the delete job below will nuke all mail in the
1830 folder, so we better safeguard against that. See ::expungeFolder, as
1831 to why. :( */
1832 if ( uid == 0 ) {
1833 kdDebug( 5006 ) << "KMFolderImap::deleteMessage: Attempt to delete "
1834 "an empty UID. Aborting." << endl;
1835 return;
1836 }
1837 url.setPath(msg_parent->imapPath() + ";UID=" + TQString::number(uid) );
1838 if ( account()->makeConnection() != ImapAccountBase::Connected )
1839 return;
1840 TDEIO::SimpleJob *job = TDEIO::file_delete(url, false);
1841 TDEIO::Scheduler::assignJobToSlave(account()->slave(), job);
1842 ImapAccountBase::jobData jd( url.url(), 0 );
1843 account()->insertJob(job, jd);
1844 connect(job, TQ_SIGNAL(result(TDEIO::Job *)),
1845 account(), TQ_SLOT(slotSimpleResult(TDEIO::Job *)));
1846}
1847
1848void KMFolderImap::deleteMessage(const TQPtrList<KMMessage>& msgList)
1849{
1850 TQPtrListIterator<KMMessage> it( msgList );
1851 KMMessage *msg;
1852 while ( (msg = it.current()) != 0 ) {
1853 ++it;
1854 mUidMetaDataMap.remove( msg->UID() );
1855 mMetaDataMap.remove( msg->msgIdMD5() );
1856 }
1857
1858 TQValueList<ulong> uids;
1859 getUids(msgList, uids);
1860 TQStringList sets = makeSets(uids);
1861
1862 KURL url = account()->getUrl();
1863 KMFolderImap *msg_parent = static_cast<KMFolderImap*>(msgList.getFirst()->storage());
1864 for ( TQStringList::Iterator it = sets.begin(); it != sets.end(); ++it )
1865 {
1866 TQString uid = *it;
1867 // Don't delete with no uid, that nukes the folder. Should not happen, but
1868 // better safe than sorry.
1869 if ( uid.isEmpty() ) continue;
1870 url.setPath(msg_parent->imapPath() + ";UID=" + uid);
1871 if ( account()->makeConnection() != ImapAccountBase::Connected )
1872 return;
1873 TDEIO::SimpleJob *job = TDEIO::file_delete(url, false);
1874 TDEIO::Scheduler::assignJobToSlave(account()->slave(), job);
1875 ImapAccountBase::jobData jd( url.url(), 0 );
1876 account()->insertJob(job, jd);
1877 connect(job, TQ_SIGNAL(result(TDEIO::Job *)),
1878 account(), TQ_SLOT(slotSimpleResult(TDEIO::Job *)));
1879 }
1880}
1881
1882//-----------------------------------------------------------------------------
1883void KMFolderImap::setStatus(int idx, KMMsgStatus status, bool toggle)
1884{
1885 TQValueList<int> ids; ids.append(idx);
1886 setStatus(ids, status, toggle);
1887}
1888
1889void KMFolderImap::setStatus(TQValueList<int>& _ids, KMMsgStatus status, bool toggle)
1890{
1891 FolderStorage::setStatus(_ids, status, toggle);
1892 TQValueList<int> ids;
1893 if ( mUploadAllFlags ) {
1894 kdDebug(5006) << k_funcinfo << "Migrating all flags to the server" << endl;
1895 ids.clear();
1896 for ( int i = 0; i < count(); ++i )
1897 ids << i;
1898 mUploadAllFlags = false;
1899 } else {
1900 ids = _ids;
1901 }
1902
1903 /* The status has been already set in the local index. Update the flags on
1904 * the server. To avoid doing that for each message individually, group them
1905 * by the status string they will be assigned and make sets for each of those
1906 * groups of mails. This is necessary because the imap tdeio_slave status job
1907 * does not append flags but overwrites them. Example:
1908 *
1909 * 2 important mails and 3 unimportant mail, all unread. Mark all as read calls
1910 * this method with a list of uids. The 2 important mails need to get the string
1911 * \SEEN \FLAGGED while the others need to get just \SEEN. Build sets for each
1912 * of those and sort them, so the server can handle them efficiently. */
1913
1914 if ( mReadOnly ) { // mUserRights is not available here
1915 // FIXME duplicated code in KMFolderCachedImap
1916 TQValueList<ulong> seenUids, unseenUids;
1917 for ( TQValueList<int>::ConstIterator it = ids.constBegin(); it != ids.constEnd(); ++it ) {
1918 KMMessage *msg = 0;
1919 bool unget = !isMessage(*it);
1920 msg = getMsg(*it);
1921 if (!msg) continue;
1922 if ( msg->status() & KMMsgStatusOld || msg->status() & KMMsgStatusRead )
1923 seenUids.append( msg->UID() );
1924 else
1925 unseenUids.append( msg->UID() );
1926 if (unget) unGetMsg(*it);
1927 }
1928 if ( !seenUids.isEmpty() ) {
1929 TQStringList sets = KMFolderImap::makeSets( seenUids, true );
1930 for( TQStringList::Iterator it = sets.begin(); it != sets.end(); ++it ) {
1931 TQString imappath = imapPath() + ";UID=" + ( *it );
1932 account()->setImapSeenStatus( folder(), imappath, true );
1933 }
1934 }
1935 if ( !unseenUids.isEmpty() ) {
1936 TQStringList sets = KMFolderImap::makeSets( unseenUids, true );
1937 for( TQStringList::Iterator it = sets.begin(); it != sets.end(); ++it ) {
1938 TQString imappath = imapPath() + ";UID=" + ( *it );
1939 account()->setImapSeenStatus( folder(), imappath, false );
1940 }
1941 }
1942 return;
1943 }
1944
1945 TQMap< TQString, TQStringList > groups;
1946 for ( TQValueList<int>::Iterator it = ids.begin(); it != ids.end(); ++it ) {
1947 KMMessage *msg = 0;
1948 bool unget = !isMessage(*it);
1949 msg = getMsg(*it);
1950 if (!msg) continue;
1951 TQString flags = statusToFlags(msg->status(), mPermanentFlags);
1952 // Collect uids for each type of flags.
1953 groups[flags].append(TQString::number(msg->UID()));
1954 if (unget) unGetMsg(*it);
1955 }
1956 TQMapIterator< TQString, TQStringList > dit;
1957 for ( dit = groups.begin(); dit != groups.end(); ++dit ) {
1958 TQCString flags = dit.key().latin1();
1959 TQStringList sets = makeSets( (*dit), true );
1960 // Send off a status setting job for each set.
1961 for ( TQStringList::Iterator slit = sets.begin(); slit != sets.end(); ++slit ) {
1962 TQString imappath = imapPath() + ";UID=" + ( *slit );
1963 account()->setImapStatus(folder(), imappath, flags);
1964 }
1965 }
1966 if ( mContentState == imapListingInProgress ) {
1967 // we're currently get'ing this folder
1968 // to make sure that we get the latest flags abort the current listing and
1969 // create a new one
1970 kdDebug(5006) << "Set status during folder listing, restarting listing." << endl;
1971 disconnect(this, TQ_SLOT(slotListFolderResult(TDEIO::Job *)));
1972 quiet( false );
1973 reallyGetFolder( TQString() );
1974 }
1975}
1976
1977//-----------------------------------------------------------------------------
1978TQStringList KMFolderImap::makeSets(const TQStringList& uids, bool sort)
1979{
1980 TQValueList<ulong> tmp;
1981 for ( TQStringList::ConstIterator it = uids.begin(); it != uids.end(); ++it )
1982 tmp.append( (*it).toInt() );
1983 return makeSets(tmp, sort);
1984}
1985
1986TQStringList KMFolderImap::makeSets( TQValueList<ulong>& uids, bool sort )
1987{
1988 TQStringList sets;
1989 TQString set;
1990
1991 if (uids.size() == 1)
1992 {
1993 sets.append(TQString::number(uids.first()));
1994 return sets;
1995 }
1996
1997 if (sort) qHeapSort(uids);
1998
1999 ulong last = 0;
2000 // needed to make a uid like 124 instead of 124:124
2001 bool inserted = false;
2002 /* iterate over uids and build sets like 120:122,124,126:150 */
2003 for ( TQValueList<ulong>::Iterator it = uids.begin(); it != uids.end(); ++it )
2004 {
2005 if (it == uids.begin() || set.isEmpty()) {
2006 set = TQString::number(*it);
2007 inserted = true;
2008 } else
2009 {
2010 if (last+1 != *it)
2011 {
2012 // end this range
2013 if (inserted)
2014 set += ',' + TQString::number(*it);
2015 else
2016 set += ':' + TQString::number(last) + ',' + TQString::number(*it);
2017 inserted = true;
2018 if (set.length() > 100)
2019 {
2020 // just in case the server has a problem with longer lines..
2021 sets.append(set);
2022 set = "";
2023 }
2024 } else {
2025 inserted = false;
2026 }
2027 }
2028 last = *it;
2029 }
2030 // last element
2031 if (!inserted)
2032 set += ':' + TQString::number(uids.last());
2033
2034 if (!set.isEmpty()) sets.append(set);
2035
2036 return sets;
2037}
2038
2039//-----------------------------------------------------------------------------
2040void KMFolderImap::getUids(TQValueList<int>& ids, TQValueList<ulong>& uids)
2041{
2042 KMMsgBase *msg = 0;
2043 // get the uids
2044 for ( TQValueList<int>::Iterator it = ids.begin(); it != ids.end(); ++it )
2045 {
2046 msg = getMsgBase(*it);
2047 if (!msg) continue;
2048 uids.append(msg->UID());
2049 }
2050}
2051
2052void KMFolderImap::getUids(const TQPtrList<KMMessage>& msgList, TQValueList<ulong>& uids)
2053{
2054 KMMessage *msg = 0;
2055
2056 TQPtrListIterator<KMMessage> it( msgList );
2057 while ( (msg = it.current()) != 0 ) {
2058 ++it;
2059 if ( msg->UID() > 0 ) {
2060 uids.append( msg->UID() );
2061 }
2062 }
2063}
2064
2065//-----------------------------------------------------------------------------
2066void KMFolderImap::expungeFolder(KMFolderImap * aFolder, bool quiet)
2067{
2068 aFolder->setNeedsCompacting(false);
2069 KURL url = account()->getUrl();
2070 url.setPath(aFolder->imapPath() + ";UID=*");
2071 if ( account()->makeConnection() != ImapAccountBase::Connected )
2072 return;
2073 TDEIO::SimpleJob *job = TDEIO::file_delete(url, false);
2074 TDEIO::Scheduler::assignJobToSlave(account()->slave(), job);
2075 ImapAccountBase::jobData jd( url.url(), 0 );
2076 jd.quiet = quiet;
2077 account()->insertJob(job, jd);
2078 connect(job, TQ_SIGNAL(result(TDEIO::Job *)),
2079 account(), TQ_SLOT(slotSimpleResult(TDEIO::Job *)));
2080}
2081
2082//-----------------------------------------------------------------------------
2083void KMFolderImap::slotProcessNewMail( int errorCode, const TQString &errorMsg )
2084{
2085 Q_UNUSED( errorMsg );
2086 disconnect( account(), TQ_SIGNAL( connectionResult(int, const TQString&) ),
2087 this, TQ_SLOT( slotProcessNewMail(int, const TQString&) ) );
2088 if ( !errorCode )
2089 processNewMail( false );
2090 else
2091 emit numUnreadMsgsChanged( folder() );
2092}
2093
2094//-----------------------------------------------------------------------------
2095bool KMFolderImap::processNewMail(bool)
2096{
2097 // a little safety
2098 if ( !account() ) {
2099 kdDebug(5006) << "KMFolderImap::processNewMail - account is null!" << endl;
2100 return false;
2101 }
2102 if ( imapPath().isEmpty() ) {
2103 kdDebug(5006) << "KMFolderImap::processNewMail - imapPath of " << name() << " is empty!" << endl;
2104 // remove it locally
2105 setAlreadyRemoved( true );
2106 kmkernel->imapFolderMgr()->remove( folder() );
2107 return false;
2108 }
2109 // check the connection
2110 if ( account()->makeConnection() == ImapAccountBase::Error ) {
2111 kdDebug(5006) << "KMFolderImap::processNewMail - got no connection!" << endl;
2112 return false;
2113 } else if ( account()->makeConnection() == ImapAccountBase::Connecting )
2114 {
2115 // wait
2116 kdDebug(5006) << "KMFolderImap::processNewMail - waiting for connection: " << label() << endl;
2117 connect( account(), TQ_SIGNAL( connectionResult(int, const TQString&) ),
2118 this, TQ_SLOT( slotProcessNewMail(int, const TQString&) ) );
2119 return true;
2120 }
2121 KURL url = account()->getUrl();
2122 if (mReadOnly)
2123 url.setPath(imapPath() + ";SECTION=UIDNEXT");
2124 else
2125 url.setPath(imapPath() + ";SECTION=UNSEEN");
2126
2127 mMailCheckProgressItem = ProgressManager::createProgressItem(
2128 "MailCheckAccount" + account()->name(),
2129 "MailCheck" + folder()->prettyURL(),
2130 TQStyleSheet::escape( folder()->prettyURL() ),
2131 i18n("updating message counts"),
2132 false,
2133 account()->useSSL() || account()->useTLS() );
2134
2135 TDEIO::SimpleJob *job = TDEIO::stat(url, false);
2136 TDEIO::Scheduler::assignJobToSlave(account()->slave(), job);
2137 ImapAccountBase::jobData jd(url.url(), folder() );
2138 jd.cancellable = true;
2139 account()->insertJob(job, jd);
2140 connect(job, TQ_SIGNAL(result(TDEIO::Job *)),
2141 TQ_SLOT(slotStatResult(TDEIO::Job *)));
2142 return true;
2143}
2144
2145
2146//-----------------------------------------------------------------------------
2147void KMFolderImap::slotStatResult(TDEIO::Job * job)
2148{
2149 slotCompleteMailCheckProgress();
2150 ImapAccountBase::JobIterator it = account()->findJob(job);
2151 if ( it == account()->jobsEnd() ) return;
2152 account()->removeJob(it);
2153 if (job->error())
2154 {
2155 account()->handleJobError( job, i18n("Error while getting folder information.") );
2156 } else {
2157 TDEIO::UDSEntry uds = static_cast<TDEIO::StatJob*>(job)->statResult();
2158 for (TDEIO::UDSEntry::ConstIterator it = uds.begin(); it != uds.end(); it++)
2159 {
2160 if ((*it).m_uds == TDEIO::UDS_SIZE)
2161 {
2162 if (mReadOnly)
2163 {
2164 mGuessedUnreadMsgs = -1;
2165 mGuessedUnreadMsgs = countUnread() + (*it).m_long - lastUid() - 1;
2166 if (mGuessedUnreadMsgs < 0) mGuessedUnreadMsgs = 0;
2167 } else {
2168 mGuessedUnreadMsgs = (*it).m_long;
2169 }
2170 }
2171 }
2172 }
2173}
2174
2175//-----------------------------------------------------------------------------
2176int KMFolderImap::create()
2177{
2178 readConfig();
2179 mUnreadMsgs = -1;
2180 return KMFolderMbox::create();
2181}
2182
2183TQValueList<ulong> KMFolderImap::splitSets(const TQString uids)
2184{
2185 TQValueList<ulong> uidlist;
2186
2187 // ex: 1205,1204,1203,1202,1236:1238
2188 TQString buffer = TQString();
2189 int setstart = -1;
2190 // iterate over the uids
2191 for (uint i = 0; i < uids.length(); i++)
2192 {
2193 TQChar chr = uids[i];
2194 if (chr == ',')
2195 {
2196 if (setstart > -1)
2197 {
2198 // a range (uid:uid) was before
2199 for (int j = setstart; j <= buffer.toInt(); j++)
2200 {
2201 uidlist.append(j);
2202 }
2203 setstart = -1;
2204 } else {
2205 // single uid
2206 uidlist.append(buffer.toInt());
2207 }
2208 buffer = "";
2209 } else if (chr == ':') {
2210 // remember the start of the range
2211 setstart = buffer.toInt();
2212 buffer = "";
2213 } else if (chr.category() == TQChar::Number_DecimalDigit) {
2214 // digit
2215 buffer += chr;
2216 } else {
2217 // ignore
2218 }
2219 }
2220 // process the last data
2221 if (setstart > -1)
2222 {
2223 for (int j = setstart; j <= buffer.toInt(); j++)
2224 {
2225 uidlist.append(j);
2226 }
2227 } else {
2228 uidlist.append(buffer.toInt());
2229 }
2230
2231 return uidlist;
2232}
2233
2234//-----------------------------------------------------------------------------
2235int KMFolderImap::expungeContents()
2236{
2237 // nuke the local cache
2238 int rc = KMFolderMbox::expungeContents();
2239
2240 // set the deleted flag for all messages in the folder
2241 KURL url = account()->getUrl();
2242 url.setPath( imapPath() + ";UID=1:*");
2243 if ( account()->makeConnection() == ImapAccountBase::Connected )
2244 {
2245 TDEIO::SimpleJob *job = TDEIO::file_delete(url, false);
2246 TDEIO::Scheduler::assignJobToSlave(account()->slave(), job);
2247 ImapAccountBase::jobData jd( url.url(), 0 );
2248 jd.quiet = true;
2249 account()->insertJob(job, jd);
2250 connect(job, TQ_SIGNAL(result(TDEIO::Job *)),
2251 account(), TQ_SLOT(slotSimpleResult(TDEIO::Job *)));
2252 }
2253 /* Is the below correct? If we are expunging (in the folder sense, not the imap sense),
2254 why delete but not (imap-)expunge? Since the folder is not active there is no concept
2255 of "leaving the folder", so the setting really has little to do with it. */
2256 // if ( autoExpunge() )
2257 expungeFolder(this, true);
2258 getFolder();
2259
2260 return rc;
2261}
2262
2263//-----------------------------------------------------------------------------
2264void
2265KMFolderImap::setUserRights( unsigned int userRights, KMail::ACLJobs::ACLFetchState userRightsState )
2266{
2267 mUserRights = userRights;
2268 mUserRightsState = userRightsState;
2269}
2270
2271//-----------------------------------------------------------------------------
2272void KMFolderImap::slotCompleteMailCheckProgress()
2273{
2274 if ( mMailCheckProgressItem ) {
2275 mMailCheckProgressItem->setComplete();
2276 mMailCheckProgressItem = 0;
2277 emit numUnreadMsgsChanged( folder() );
2278 }
2279}
2280
2281//-----------------------------------------------------------------------------
2282void KMFolderImap::setSubfolderState( imapState state )
2283{
2284 mSubfolderState = state;
2285 if ( state == imapNoInformation && folder()->child() )
2286 {
2287 // pass through to children
2288 KMFolderNode* node;
2289 TQPtrListIterator<KMFolderNode> it( *folder()->child() );
2290 for ( ; (node = it.current()); )
2291 {
2292 ++it;
2293 if (node->isDir()) continue;
2294 KMFolder *folder = static_cast<KMFolder*>(node);
2295 static_cast<KMFolderImap*>(folder->storage())->setSubfolderState( state );
2296 }
2297 }
2298}
2299
2300//-----------------------------------------------------------------------------
2301void KMFolderImap::setIncludeInMailCheck( bool check )
2302{
2303 bool changed = ( mCheckMail != check );
2304 mCheckMail = check;
2305 if ( changed )
2306 account()->slotUpdateFolderList();
2307}
2308
2309//-----------------------------------------------------------------------------
2310void KMFolderImap::setAlreadyRemoved( bool removed )
2311{
2312 mAlreadyRemoved = removed;
2313 if ( folder()->child() )
2314 {
2315 // pass through to childs
2316 KMFolderNode* node;
2317 TQPtrListIterator<KMFolderNode> it( *folder()->child() );
2318 for ( ; (node = it.current()); )
2319 {
2320 ++it;
2321 if (node->isDir()) continue;
2322 KMFolder *folder = static_cast<KMFolder*>(node);
2323 static_cast<KMFolderImap*>(folder->storage())->setAlreadyRemoved( removed );
2324 }
2325 }
2326}
2327
2328void KMFolderImap::slotCreatePendingFolders( int errorCode, const TQString& errorMsg )
2329{
2330 Q_UNUSED( errorMsg );
2331 disconnect( account(), TQ_SIGNAL( connectionResult( int, const TQString& ) ),
2332 this, TQ_SLOT( slotCreatePendingFolders( int, const TQString& ) ) );
2333 if ( !errorCode ) {
2334 TQStringList::Iterator it = mFoldersPendingCreation.begin();
2335 for ( ; it != mFoldersPendingCreation.end(); ++it ) {
2336 createFolder( *it );
2337 }
2338 }
2339 mFoldersPendingCreation.clear();
2340}
2341
2342//-----------------------------------------------------------------------------
2343void KMFolderImap::search( const KMSearchPattern* pattern )
2344{
2345 if ( !pattern || pattern->isEmpty() )
2346 {
2347 // not much to do here
2348 TQValueList<TQ_UINT32> serNums;
2349 emit searchResult( folder(), serNums, pattern, true );
2350 return;
2351 }
2352 SearchJob* job = new SearchJob( this, account(), pattern );
2353 connect( job, TQ_SIGNAL( searchDone( TQValueList<TQ_UINT32>, const KMSearchPattern*, bool ) ),
2354 this, TQ_SLOT( slotSearchDone( TQValueList<TQ_UINT32>, const KMSearchPattern*, bool ) ) );
2355 job->start();
2356}
2357
2358//-----------------------------------------------------------------------------
2359void KMFolderImap::slotSearchDone( TQValueList<TQ_UINT32> serNums,
2360 const KMSearchPattern* pattern,
2361 bool complete )
2362{
2363 emit searchResult( folder(), serNums, pattern, complete );
2364}
2365
2366//-----------------------------------------------------------------------------
2367void KMFolderImap::search( const KMSearchPattern* pattern, TQ_UINT32 serNum )
2368{
2369 if ( !pattern || pattern->isEmpty() )
2370 {
2371 // not much to do here
2372 emit searchDone( folder(), serNum, pattern, false );
2373 return;
2374 }
2375 SearchJob* job = new SearchJob( this, account(), pattern, serNum );
2376 connect( job, TQ_SIGNAL( searchDone( TQ_UINT32, const KMSearchPattern*, bool ) ),
2377 this, TQ_SLOT( slotSearchDone( TQ_UINT32, const KMSearchPattern*, bool ) ) );
2378 job->start();
2379}
2380
2381//-----------------------------------------------------------------------------
2382void KMFolderImap::slotSearchDone( TQ_UINT32 serNum, const KMSearchPattern* pattern,
2383 bool matches )
2384{
2385 emit searchDone( folder(), serNum, pattern, matches );
2386}
2387
2388//-----------------------------------------------------------------------------
2389bool KMFolderImap::isMoveable() const
2390{
2391 return ( hasChildren() == HasNoChildren &&
2392 !folder()->isSystemFolder() ) ? true : false;
2393}
2394
2395//-----------------------------------------------------------------------------
2396ulong KMFolderImap::serNumForUID( ulong uid )
2397{
2398 if ( mUidMetaDataMap.find( uid ) ) {
2399 KMMsgMetaData *md = mUidMetaDataMap[uid];
2400 return md->serNum();
2401 } else {
2402 kdDebug(5006) << "serNumForUID: unknown uid " << uid << endl;
2403 return 0;
2404 }
2405}
2406
2407//-----------------------------------------------------------------------------
2408void KMFolderImap::saveMsgMetaData( KMMessage* msg, ulong uid )
2409{
2410 if ( uid == 0 ) {
2411 uid = msg->UID();
2412 }
2413 ulong serNum = msg->getMsgSerNum();
2414 mUidMetaDataMap.replace( uid, new KMMsgMetaData(msg->status(), serNum) );
2415}
2416
2417//-----------------------------------------------------------------------------
2418void KMFolderImap::setImapPath( const TQString& path )
2419{
2420 if ( path.isEmpty() ) {
2421 kdWarning(5006) << k_funcinfo << "ignoring empty path" << endl;
2422 } else {
2423 mImapPath = path;
2424 }
2425}
2426
2427void KMFolderImap::finishMailCheck( const char *dbg, imapState state )
2428{
2429 quiet( false );
2430 mContentState = state;
2431 emit folderComplete( this, mContentState == imapFinished );
2432 close(dbg);
2433}
2434
2435bool KMFolderImap::canDeleteMessages() const
2436{
2437 if ( isReadOnly() )
2438 return false;
2439 if ( mUserRightsState == KMail::ACLJobs::Ok && !(mUserRights & KMail::ACLJobs::Delete) )
2440 return false;
2441 return true;
2442}
2443
2444#include "kmfolderimap.moc"
virtual KMMessage * take(int idx)
Detach message from this folder.
virtual int rename(const TQString &newName, KMFolderDir *aParent=0)
Physically rename the folder.
virtual void readConfig()
Read the config file.
virtual void setStatus(int idx, KMMsgStatus status, bool toggle=false)
Set the status of the message at index idx to status.
virtual void removeMsg(int i, bool imapQuiet=false)
Remove (first occurrence of) given message from the folder.
virtual void remove()
Removes the folder physically from disk and empties the contents of the folder in memory.
virtual void writeConfig()
Write the config file.
virtual KMMessage * getMsg(int idx)
Read message at given index.
virtual int addMsg(TQPtrList< KMMessage > &, TQValueList< int > &index_return)
Adds the given messages to the folder.
KMail list that manages the contents of one directory that may contain folders and/or other directori...
Definition: kmfolderdir.h:16
virtual KMFolder * createFolder(const TQString &folderName, bool sysFldr=false, KMFolderType folderType=KMFolderTypeMbox)
Create a mail folder in this directory with given name.
Definition: kmfolderdir.cpp:95
KMFolder * owner() const
Returns the folder whose children we are holding.
Definition: kmfolderdir.h:59
Mail folder.
Definition: kmfolder.h:69
KMMessage * take(int idx)
Detach message from this folder.
Definition: kmfolder.cpp:380
void close(const char *owner, bool force=false)
Close folder.
Definition: kmfolder.cpp:489
KMFolderDir * createChildFolder()
Create a child folder directory and associates it with this folder.
Definition: kmfolder.cpp:264
KMMessage * getMsg(int idx)
Read message at given index.
Definition: kmfolder.cpp:321
KMFolderType folderType() const
Returns the type of this folder.
Definition: kmfolder.cpp:233
KMFolderDir * child() const
Returns the folder directory associated with this node or 0 if no such directory exists.
Definition: kmfolder.h:157
int find(const KMMsgBase *msg) const
Returns the index of the given message or -1 if not found.
Definition: kmfolder.cpp:435
This is a Mime Message.
Definition: kmmessage.h:68
void setReadyToShow(bool v)
Set if the message is ready to be shown.
Definition: kmmessage.h:874
size_t msgSizeServer() const
Get/set size on server.
Definition: kmmessage.cpp:2212
void setTransferInProgress(bool value, bool force=false)
Set that the message shall not be deleted because it is still required.
Definition: kmmessage.cpp:243
void setStatus(const KMMsgStatus status, int idx=-1)
Set status and mark dirty.
Definition: kmmessage.cpp:4153
KMMsgEncryptionState encryptionState() const
Encryption status of the message.
Definition: kmmessage.h:844
bool transferInProgress() const
Return, if the message should not be deleted.
Definition: kmmessage.cpp:236
void setMsgSerNum(unsigned long newMsgSerNum=0)
Sets the message serial number.
Definition: kmmessage.cpp:223
void setComplete(bool v)
Set if the message is a complete message.
Definition: kmmessage.h:869
KMMsgStatus status() const
Status of the message.
Definition: kmmessage.h:830
TQString headerField(const TQCString &name) const
Returns the value of a header field with the given name.
Definition: kmmessage.cpp:2289
bool isComplete() const
Return true if the complete message is available without referring to the backing store.
Definition: kmmessage.h:867
ulong UID() const
Get/set UID.
Definition: kmmessage.cpp:2225
KMMsgSignatureState signatureState() const
Signature status of the message.
Definition: kmmessage.h:847
This class is an abstraction of a search over messages.
Generic folder list job for (d)imap accounts.
Definition: listjob.h:55
void setHonorLocalSubscription(bool value)
Set whether the listing should include only folders that the account is subscribed to locally.
Definition: listjob.cpp:245
void setNamespace(const TQString &ns)
Set the namespace for this listing.
Definition: listjob.h:105
void setParentProgressItem(KPIM::ProgressItem *it)
Set parent progress item.
Definition: listjob.h:101
Rename and move (d)imap folders They can be moved everywhere (except search folders) as a new folder ...
Definition: renamejob.h:52
Search job.
Definition: searchjob.h:54
@ NotFetchedYet
The user rights/ACL have not been fetched from the server yet, we don't know them.
Definition: acljobs.h:65
@ Ok
The user rights/ACL have been fetched from the server sucessfully.
Definition: acljobs.h:66