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"
37 using KMail::ImapAccountBase;
38 #include "imapjob.h"
39 using KMail::ImapJob;
40 #include "attachmentstrategy.h"
41 using KMail::AttachmentStrategy;
42 #include "progressmanager.h"
43 using KPIM::ProgressItem;
44 using KPIM::ProgressManager;
45 #include "listjob.h"
46 using KMail::ListJob;
47 #include "kmsearchpattern.h"
48 #include "searchjob.h"
49 using KMail::SearchJob;
50 #include "renamejob.h"
51 using KMail::RenameJob;
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 
64 KMFolderImap::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 
89 KMFolderImap::~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 //-----------------------------------------------------------------------------
111 void 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 
127 KMFolder* KMFolderImap::trashFolder() const
128 {
129  TQString trashStr = account()->trash();
130  return kmkernel->imapFolderMgr()->findIdString( trashStr );
131 }
132 
133 //-----------------------------------------------------------------------------
134 KMMessage* 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 //-----------------------------------------------------------------------------
153 KMAcctImap* 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 
173 void 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 //-----------------------------------------------------------------------------
187 void 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 //-----------------------------------------------------------------------------
211 void 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 //-----------------------------------------------------------------------------
226 void 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 //-----------------------------------------------------------------------------
257 void 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 //-----------------------------------------------------------------------------
273 void 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 
288 void 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 //-----------------------------------------------------------------------------
313 int 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 //-----------------------------------------------------------------------------
322 void 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 //-----------------------------------------------------------------------------
347 void 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 //-----------------------------------------------------------------------------
382 int 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 
392 int 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 //-----------------------------------------------------------------------------
510 void 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 //-----------------------------------------------------------------------------
518 void 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 //-----------------------------------------------------------------------------
544 TQPtrList<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 //-----------------------------------------------------------------------------
582 KMMessage* 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 
595 void KMFolderImap::take(TQPtrList<KMMessage> msgList)
596 {
597  deleteMessage(msgList);
598 
599  mLastUid = 0;
600  KMFolderMbox::take(msgList);
601 }
602 
603 //-----------------------------------------------------------------------------
604 void 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 //-----------------------------------------------------------------------------
662 void 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 //-----------------------------------------------------------------------------
733 bool 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 //-----------------------------------------------------------------------------
768 void 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 //-----------------------------------------------------------------------------
885 void 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 //-----------------------------------------------------------------------------
915 KMFolderImap* 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 //-----------------------------------------------------------------------------
942 void 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 //-----------------------------------------------------------------------------
987 void 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 //-----------------------------------------------------------------------------
997 bool KMFolderImap::mailCheckInProgress() const
998 {
999  return getContentState() != imapNoInformation &&
1000  getContentState() != imapFinished;
1001 }
1002 
1003 //-----------------------------------------------------------------------------
1004 void 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 //-----------------------------------------------------------------------------
1025 void 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 //-----------------------------------------------------------------------------
1092 ulong 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 //-----------------------------------------------------------------------------
1108 void 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 //-----------------------------------------------------------------------------
1186 void 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 //-----------------------------------------------------------------------------
1200 void 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 //-----------------------------------------------------------------------------
1220 void 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 //-----------------------------------------------------------------------------
1266 void 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 //-----------------------------------------------------------------------------
1374 void 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 //-----------------------------------------------------------------------------
1424 void 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 
1457 void 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 //-----------------------------------------------------------------------------
1481 TQString 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 //-------------------------------------------------------------
1508 void
1509 KMFolderImap::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 //-----------------------------------------------------------------------------
1522 void 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 //-------------------------------------------------------------
1645 FolderJob*
1646 KMFolderImap::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 //-------------------------------------------------------------
1679 FolderJob*
1680 KMFolderImap::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 //-----------------------------------------------------------------------------
1690 void 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 //-----------------------------------------------------------------------------
1707 void KMFolderImap::slotGetLastMessagesResult(TDEIO::Job * job)
1708 {
1709  getMessagesResult(job, true);
1710 }
1711 
1712 
1713 //-----------------------------------------------------------------------------
1714 void KMFolderImap::slotGetMessagesResult(TDEIO::Job * job)
1715 {
1716  getMessagesResult(job, false);
1717 }
1718 
1719 
1720 //-----------------------------------------------------------------------------
1721 void 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 //-----------------------------------------------------------------------------
1749 void 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 //-----------------------------------------------------------------------------
1775 static TQTextCodec *sUtf7Codec = 0;
1776 
1777 TQTextCodec * KMFolderImap::utf7Codec()
1778 {
1779  if (!sUtf7Codec) sUtf7Codec = TQTextCodec::codecForName("utf-7");
1780  return sUtf7Codec;
1781 }
1782 
1783 
1784 //-----------------------------------------------------------------------------
1785 TQString KMFolderImap::encodeFileName(const TQString &name)
1786 {
1787  TQString result = utf7Codec()->fromUnicode(name);
1788  return KURL::encode_string_no_slash(result);
1789 }
1790 
1791 
1792 //-----------------------------------------------------------------------------
1793 TQString KMFolderImap::decodeFileName(const TQString &name)
1794 {
1795  TQString result = KURL::decode_string(name);
1796  return utf7Codec()->toUnicode(result.latin1());
1797 }
1798 
1799 //-----------------------------------------------------------------------------
1800 bool KMFolderImap::autoExpunge()
1801 {
1802  if (account())
1803  return account()->autoExpunge();
1804 
1805  return false;
1806 }
1807 
1808 
1809 //-----------------------------------------------------------------------------
1810 void 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 //-----------------------------------------------------------------------------
1822 void 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 
1848 void 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 //-----------------------------------------------------------------------------
1883 void KMFolderImap::setStatus(int idx, KMMsgStatus status, bool toggle)
1884 {
1885  TQValueList<int> ids; ids.append(idx);
1886  setStatus(ids, status, toggle);
1887 }
1888 
1889 void 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 //-----------------------------------------------------------------------------
1978 TQStringList 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 
1986 TQStringList 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 //-----------------------------------------------------------------------------
2040 void 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 
2052 void 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 //-----------------------------------------------------------------------------
2066 void 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 //-----------------------------------------------------------------------------
2083 void 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 //-----------------------------------------------------------------------------
2095 bool 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 //-----------------------------------------------------------------------------
2147 void 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 //-----------------------------------------------------------------------------
2176 int KMFolderImap::create()
2177 {
2178  readConfig();
2179  mUnreadMsgs = -1;
2180  return KMFolderMbox::create();
2181 }
2182 
2183 TQValueList<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 //-----------------------------------------------------------------------------
2235 int 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 //-----------------------------------------------------------------------------
2264 void
2265 KMFolderImap::setUserRights( unsigned int userRights, KMail::ACLJobs::ACLFetchState userRightsState )
2266 {
2267  mUserRights = userRights;
2268  mUserRightsState = userRightsState;
2269 }
2270 
2271 //-----------------------------------------------------------------------------
2272 void KMFolderImap::slotCompleteMailCheckProgress()
2273 {
2274  if ( mMailCheckProgressItem ) {
2275  mMailCheckProgressItem->setComplete();
2276  mMailCheckProgressItem = 0;
2277  emit numUnreadMsgsChanged( folder() );
2278  }
2279 }
2280 
2281 //-----------------------------------------------------------------------------
2282 void 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 //-----------------------------------------------------------------------------
2301 void KMFolderImap::setIncludeInMailCheck( bool check )
2302 {
2303  bool changed = ( mCheckMail != check );
2304  mCheckMail = check;
2305  if ( changed )
2306  account()->slotUpdateFolderList();
2307 }
2308 
2309 //-----------------------------------------------------------------------------
2310 void 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 
2328 void 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 //-----------------------------------------------------------------------------
2343 void 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 //-----------------------------------------------------------------------------
2359 void KMFolderImap::slotSearchDone( TQValueList<TQ_UINT32> serNums,
2360  const KMSearchPattern* pattern,
2361  bool complete )
2362 {
2363  emit searchResult( folder(), serNums, pattern, complete );
2364 }
2365 
2366 //-----------------------------------------------------------------------------
2367 void 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 //-----------------------------------------------------------------------------
2382 void KMFolderImap::slotSearchDone( TQ_UINT32 serNum, const KMSearchPattern* pattern,
2383  bool matches )
2384 {
2385  emit searchDone( folder(), serNum, pattern, matches );
2386 }
2387 
2388 //-----------------------------------------------------------------------------
2389 bool KMFolderImap::isMoveable() const
2390 {
2391  return ( hasChildren() == HasNoChildren &&
2392  !folder()->isSystemFolder() ) ? true : false;
2393 }
2394 
2395 //-----------------------------------------------------------------------------
2396 ulong 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 //-----------------------------------------------------------------------------
2408 void 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 //-----------------------------------------------------------------------------
2418 void 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 
2427 void 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 
2435 bool 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
KMFolderDir * child() const
Returns the folder directory associated with this node or 0 if no such directory exists.
Definition: kmfolder.h:157
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
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