kmail

kmfolder.cpp
1 /*
2  * kmail: KDE mail client
3  * Copyright (c) 1996-1998 Stefan Taferner <taferner@kde.org>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  *
19  */
20 #include <config.h>
21 
22 #include "kmfolder.h"
23 #include "kmfolderdir.h"
24 #include "kmfoldermbox.h"
25 #include "folderstorage.h"
26 #include "kmfoldercachedimap.h"
27 #include "kmfoldersearch.h"
28 #include "kmfolderimap.h"
29 #include "kmfoldermgr.h"
30 #include <libkpimidentities/identitymanager.h>
31 #include <libkpimidentities/identity.h>
32 #include "expirejob.h"
33 #include "compactionjob.h"
34 #include "kmfoldertree.h"
35 #include "kmailicalifaceimpl.h"
36 #include "kmaccount.h"
37 
38 #include <errno.h>
39 
40 #include <kdebug.h>
41 #include <tdelocale.h>
42 #include <tdeshortcut.h>
43 #include <tdemessagebox.h>
44 #include <tqfile.h>
45 #include <tqfileinfo.h>
46 
47 
48 KMFolder::KMFolder( KMFolderDir* aParent, const TQString& aFolderName,
49  KMFolderType aFolderType, bool withIndex, bool exportedSernums )
50  : KMFolderNode( aParent, aFolderName ), mStorage(0),
51  mChild( 0 ),
52  mIsSystemFolder( false ),
53  mHasIndex( withIndex ),
54  mExportsSernums( exportedSernums ),
55  mMoveInProgress( false ),
56  mExpireMessages( false ), mUnreadExpireAge( 28 ),
57  mReadExpireAge( 14 ), mUnreadExpireUnits( expireNever ),
58  mReadExpireUnits( expireNever ),
59  mExpireAction( ExpireDelete ),
60  mUseCustomIcons( false ), mMailingListEnabled( false ),
61  mAcctList( 0 ),
62  mIdentity( 0 ), // default identity
63  mPutRepliesInSameFolder( false ),
64  mIgnoreNewMail( false )
65 {
66  if( aFolderType == KMFolderTypeCachedImap )
67  mStorage = new KMFolderCachedImap( this, aFolderName.latin1() );
68  else if( aFolderType == KMFolderTypeImap )
69  mStorage = new KMFolderImap( this, aFolderName.latin1() );
70  else if( aFolderType == KMFolderTypeMaildir )
71  mStorage = new KMFolderMaildir( this, aFolderName.latin1() );
72  else if( aFolderType == KMFolderTypeSearch )
73  mStorage = new KMFolderSearch( this, aFolderName.latin1() );
74  else
75  mStorage = new KMFolderMbox( this, aFolderName.latin1() );
76 
77  assert( mStorage );
78 
79  TQFileInfo dirinfo;
80  dirinfo.setFile( mStorage->location() );
81  if ( !dirinfo.exists() ) {
82  int rc = mStorage->create();
83  TQString msg = i18n("<qt>Error while creating file <b>%1</b>:<br>%2</qt>").arg(aFolderName).arg(strerror(rc));
84  if ( rc ) {
85  KMessageBox::information(0, msg);
86  }
87  }
88 
89  if ( aParent ) {
90  connect( mStorage, TQT_SIGNAL( msgAdded( KMFolder*, TQ_UINT32 ) ),
91  aParent->manager(), TQT_SIGNAL( msgAdded( KMFolder*, TQ_UINT32 ) ) );
92  connect( mStorage, TQT_SIGNAL( msgRemoved( KMFolder*, TQ_UINT32 ) ),
93  parent()->manager(), TQT_SIGNAL( msgRemoved( KMFolder*, TQ_UINT32 ) ) );
94  connect( this, TQT_SIGNAL( msgChanged( KMFolder*, TQ_UINT32, int ) ),
95  parent()->manager(), TQT_SIGNAL( msgChanged( KMFolder*, TQ_UINT32, int ) ) );
96  connect( this, TQT_SIGNAL( msgHeaderChanged( KMFolder*, int ) ),
97  parent()->manager(), TQT_SIGNAL( msgHeaderChanged( KMFolder*, int ) ) );
98  connect( mStorage, TQT_SIGNAL( invalidated( KMFolder* ) ),
99  parent()->manager(), TQT_SIGNAL( folderInvalidated( KMFolder* ) ) );
100  }
101 
102  // Resend all mStorage signals
103  connect( mStorage, TQT_SIGNAL( changed() ), TQT_SIGNAL( changed() ) );
104  connect( mStorage, TQT_SIGNAL( cleared() ), TQT_SIGNAL( cleared() ) );
105  connect( mStorage, TQT_SIGNAL( expunged( KMFolder* ) ),
106  TQT_SIGNAL( expunged( KMFolder* ) ) );
107  connect( mStorage, TQT_SIGNAL( nameChanged() ), TQT_SIGNAL( nameChanged() ) );
108  connect( mStorage, TQT_SIGNAL( msgRemoved( KMFolder*, TQ_UINT32 ) ),
109  TQT_SIGNAL( msgRemoved( KMFolder*, TQ_UINT32 ) ) );
110  connect( mStorage, TQT_SIGNAL( msgRemoved( int, TQString ) ),
111  TQT_SIGNAL( msgRemoved( int, TQString ) ) );
112  connect( mStorage, TQT_SIGNAL( msgRemoved( KMFolder* ) ),
113  TQT_SIGNAL( msgRemoved( KMFolder* ) ) );
114  connect( mStorage, TQT_SIGNAL( msgAdded( int ) ), TQT_SIGNAL( msgAdded( int ) ) );
115  connect( mStorage, TQT_SIGNAL( msgAdded( KMFolder*, TQ_UINT32 ) ),
116  TQT_SIGNAL( msgAdded( KMFolder*, TQ_UINT32 ) ) );
117  connect( mStorage, TQT_SIGNAL( msgChanged( KMFolder*, TQ_UINT32 , int ) ),
118  TQT_SIGNAL( msgChanged( KMFolder*, TQ_UINT32 , int ) ) );
119  connect( mStorage, TQT_SIGNAL( msgHeaderChanged( KMFolder*, int ) ),
120  TQT_SIGNAL( msgHeaderChanged( KMFolder*, int ) ) );
121  connect( mStorage, TQT_SIGNAL( statusMsg( const TQString& ) ),
122  TQT_SIGNAL( statusMsg( const TQString& ) ) );
123  connect( mStorage, TQT_SIGNAL( numUnreadMsgsChanged( KMFolder* ) ),
124  TQT_SIGNAL( numUnreadMsgsChanged( KMFolder* ) ) );
125  connect( mStorage, TQT_SIGNAL( removed( KMFolder*, bool ) ),
126  TQT_SIGNAL( removed( KMFolder*, bool ) ) );
127  connect( mStorage, TQT_SIGNAL(noContentChanged()),
128  TQT_SIGNAL(noContentChanged()) );
129  connect( mStorage, TQT_SIGNAL(syncStateChanged()),
130  TQT_SIGNAL(syncStateChanged()) );
131 
132  connect( mStorage, TQT_SIGNAL( contentsTypeChanged( KMail::FolderContentsType ) ),
133  this, TQT_SLOT( slotContentsTypeChanged( KMail::FolderContentsType ) ) );
134 
135  connect( mStorage, TQT_SIGNAL( folderSizeChanged() ),
136  this, TQT_SLOT( slotFolderSizeChanged() ) );
137 
138  //FIXME: Centralize all the readConfig calls somehow - Zack
139  // Meanwhile, readConfig must be done before registerWithMessageDict, since
140  // that one can call writeConfig in some circumstances - David
141  mStorage->readConfig();
142 
143  // trigger from here, since it needs a fully constructed FolderStorage
144  if ( mExportsSernums )
145  mStorage->registerWithMessageDict();
146  if ( !mHasIndex )
147  mStorage->setAutoCreateIndex( false );
148 
149  if ( mId == 0 && aParent )
150  mId = aParent->manager()->createId();
151 }
152 
153 KMFolder::~KMFolder()
154 {
155  mStorage->close( "~KMFolder", true );
156  delete mAcctList;
157  if ( mHasIndex ) mStorage->deregisterFromMessageDict();
158  delete mStorage;
159 }
160 
161 void KMFolder::readConfig( TDEConfig* config )
162 {
163  if ( !config->readEntry("SystemLabel").isEmpty() )
164  mSystemLabel = config->readEntry("SystemLabel");
165  mExpireMessages = config->readBoolEntry("ExpireMessages", false);
166  mReadExpireAge = config->readNumEntry("ReadExpireAge", 3);
167  mReadExpireUnits = (ExpireUnits)config->readNumEntry("ReadExpireUnits", expireMonths);
168  mUnreadExpireAge = config->readNumEntry("UnreadExpireAge", 12);
169  mUnreadExpireUnits = (ExpireUnits)config->readNumEntry("UnreadExpireUnits", expireNever);
170  mExpireAction = config->readEntry("ExpireAction", "Delete") == "Move" ? ExpireMove : ExpireDelete;
171  mExpireToFolderId = config->readEntry("ExpireToFolder");
172 
173  mUseCustomIcons = config->readBoolEntry("UseCustomIcons", false );
174  mNormalIconPath = config->readEntry("NormalIconPath" );
175  mUnreadIconPath = config->readEntry("UnreadIconPath" );
176 
177  mMailingListEnabled = config->readBoolEntry("MailingListEnabled");
178  mMailingList.readConfig( config );
179 
180  mIdentity = config->readUnsignedNumEntry("Identity",0);
181 
182  setUserWhoField( config->readEntry("WhoField"), false );
183  uint savedId = config->readUnsignedNumEntry("Id", 0);
184  // make sure that we don't overwrite a valid id
185  if ( savedId != 0 && mId == 0 )
186  mId = savedId;
187  mPutRepliesInSameFolder = config->readBoolEntry( "PutRepliesInSameFolder", false );
188  mIgnoreNewMail = config->readBoolEntry( "IgnoreNewMail", false );
189 
190  if ( mUseCustomIcons )
191  emit iconsChanged();
192 
193  TQString shortcut( config->readEntry( "Shortcut" ) );
194  if ( !shortcut.isEmpty() ) {
195  TDEShortcut sc( shortcut );
196  setShortcut( sc );
197  }
198 }
199 
200 void KMFolder::writeConfig( TDEConfig* config ) const
201 {
202  config->writeEntry("SystemLabel", mSystemLabel);
203  config->writeEntry("ExpireMessages", mExpireMessages);
204  config->writeEntry("ReadExpireAge", mReadExpireAge);
205  config->writeEntry("ReadExpireUnits", mReadExpireUnits);
206  config->writeEntry("UnreadExpireAge", mUnreadExpireAge);
207  config->writeEntry("UnreadExpireUnits", mUnreadExpireUnits);
208  config->writeEntry("ExpireAction", mExpireAction == ExpireDelete ? "Delete" : "Move");
209  config->writeEntry("ExpireToFolder", mExpireToFolderId);
210 
211  config->writeEntry("UseCustomIcons", mUseCustomIcons);
212  config->writeEntry("NormalIconPath", mNormalIconPath);
213  config->writeEntry("UnreadIconPath", mUnreadIconPath);
214 
215  config->writeEntry("MailingListEnabled", mMailingListEnabled);
216  mMailingList.writeConfig( config );
217 
218  if ( mIdentity != 0 && ( !mStorage || !mStorage->account() || mIdentity != mStorage->account()->identityId() ) )
219  config->writeEntry("Identity", mIdentity);
220  else
221  config->deleteEntry("Identity");
222 
223  config->writeEntry("WhoField", mUserWhoField);
224  config->writeEntry("Id", mId);
225  config->writeEntry( "PutRepliesInSameFolder", mPutRepliesInSameFolder );
226  config->writeEntry( "IgnoreNewMail", mIgnoreNewMail );
227  if ( !mShortcut.isNull() )
228  config->writeEntry( "Shortcut", mShortcut.toString() );
229  else
230  config->deleteEntry( "Shortcut" );
231 }
232 
233 KMFolderType KMFolder::folderType() const
234 {
235  return mStorage ? mStorage->folderType() : KMFolderTypeUnknown;
236 }
237 
238 TQString KMFolder::fileName() const
239 {
240  return mStorage ? mStorage->fileName() : TQString();
241 }
242 
243 TQString KMFolder::location() const
244 {
245  return mStorage ? mStorage->location() : TQString();
246 }
247 
248 TQString KMFolder::indexLocation() const
249 {
250  return mStorage ? mStorage->indexLocation() : TQString();
251 }
252 
253 TQString KMFolder::subdirLocation() const
254 {
255  TQString sLocation( path() );
256 
257  if( !sLocation.isEmpty() )
258  sLocation += '/';
259  sLocation += '.' + FolderStorage::dotEscape( fileName() ) + ".directory";
260 
261  return sLocation;
262 }
263 
265 {
266  if( mChild )
267  return mChild;
268 
269  TQString childName = "." + fileName() + ".directory";
270  TQString childDir = path() + "/" + childName;
271  if (access(TQFile::encodeName(childDir), W_OK) != 0) // Not there or not writable
272  {
273  if (mkdir(TQFile::encodeName(childDir), S_IRWXU) != 0
274  && chmod(TQFile::encodeName(childDir), S_IRWXU) != 0) {
275  TQString wmsg = TQString(" '%1': %2").arg(childDir).arg(strerror(errno));
276  KMessageBox::information(0,i18n("Failed to create folder") + wmsg);
277  return 0;
278  }
279  }
280 
281  KMFolderDirType newType = KMStandardDir;
282  if( folderType() == KMFolderTypeCachedImap )
283  newType = KMDImapDir;
284  else if( folderType() == KMFolderTypeImap )
285  newType = KMImapDir;
286 
287  mChild = new KMFolderDir( this, parent(), childName, newType );
288  if( !mChild )
289  return 0;
290  mChild->reload();
291  parent()->append( mChild );
292  return mChild;
293 }
294 
296 {
297  mChild = aChild;
298  mStorage->updateChildrenState();
299 }
300 
302 {
303  return mStorage ? mStorage->noContent() : true;
304 }
305 
306 void KMFolder::setNoContent( bool aNoContent )
307 {
308  mStorage->setNoContent( aNoContent );
309 }
310 
312 {
313  return mStorage->noChildren();
314 }
315 
316 void KMFolder::setNoChildren( bool aNoChildren )
317 {
318  mStorage->setNoChildren( aNoChildren );
319 }
320 
322 {
323  return mStorage->getMsg( idx );
324 }
325 
326 KMMsgInfo* KMFolder::unGetMsg( int idx )
327 {
328  return mStorage->unGetMsg( idx );
329 }
330 
331 bool KMFolder::isMessage( int idx )
332 {
333  return mStorage->isMessage( idx );
334 }
335 
336 DwString KMFolder::getDwString( int idx )
337 {
338  return mStorage->getDwString( idx );
339 }
340 
342 {
343  mStorage->ignoreJobsForMessage( m );
344 }
345 
346 FolderJob* KMFolder::createJob( KMMessage *msg, FolderJob::JobType jt,
347  KMFolder *folder, TQString partSpecifier,
348  const AttachmentStrategy *as ) const
349 {
350  return mStorage->createJob( msg, jt, folder, partSpecifier, as );
351 }
352 
353 FolderJob* KMFolder::createJob( TQPtrList<KMMessage>& msgList,
354  const TQString& sets,
355  FolderJob::JobType jt, KMFolder *folder ) const
356 {
357  return mStorage->createJob( msgList, sets, jt, folder );
358 }
359 
360 const KMMsgBase* KMFolder::getMsgBase( int idx ) const
361 {
362  return mStorage->getMsgBase( idx );
363 }
364 
365 KMMsgBase* KMFolder::getMsgBase( int idx )
366 {
367  return mStorage->getMsgBase( idx );
368 }
369 
370 const KMMsgBase* KMFolder::operator[]( int idx ) const
371 {
372  return mStorage->operator[]( idx );
373 }
374 
375 KMMsgBase* KMFolder::operator[]( int idx )
376 {
377  return mStorage->operator[]( idx );
378 }
379 
381 {
382  return mStorage->take( idx );
383 }
384 
385 void KMFolder::take( TQPtrList<KMMessage> msgList ) // TODO const ref
386 {
387  mStorage->take( msgList );
388 }
389 
390 int KMFolder::addMsg( KMMessage* msg, int* index_return )
391 {
392  return mStorage->addMsg( msg, index_return );
393 }
394 
395 int KMFolder::addMsgKeepUID( KMMessage* msg, int* index_return )
396 {
397  return mStorage->addMsgKeepUID( msg, index_return );
398 }
399 
400 int KMFolder::addMsg( TQPtrList<KMMessage>& list, TQValueList<int>& index_return )
401 {
402  return mStorage->addMsg( list, index_return );
403 }
404 
406 {
407  mStorage->emitMsgAddedSignals( idx );
408 }
409 
410 void KMFolder::removeMsg( int i, bool imapQuiet )
411 {
412  mStorage->removeMsg( i, imapQuiet );
413 }
414 
415 void KMFolder::removeMsg( TQPtrList<KMMessage> msgList, bool imapQuiet ) // TODO const ref
416 {
417  mStorage->removeMsg( msgList, imapQuiet );
418 }
419 
420 int KMFolder::expungeOldMsg( int days )
421 {
422  return mStorage->expungeOldMsg( days );
423 }
424 
425 int KMFolder::moveMsg( KMMessage* msg, int* index_return )
426 {
427  return mStorage->moveMsg( msg, index_return );
428 }
429 
430 int KMFolder::moveMsg(TQPtrList<KMMessage> q, int* index_return )
431 {
432  return mStorage->moveMsg( q, index_return );
433 }
434 
435 int KMFolder::find( const KMMsgBase* msg ) const
436 {
437  return mStorage ? mStorage->find( msg ) : -1;
438 }
439 
440 int KMFolder::find( const KMMessage* msg ) const
441 {
442  return mStorage ? mStorage->find( msg ) : -1;
443 }
444 
445 int KMFolder::count( bool cache ) const
446 {
447  return mStorage->count( cache );
448 }
449 
451 {
452  return mStorage->countUnread();
453 }
454 
456 {
457  KMFolder *folder;
458  int count = countUnread();
459  KMFolderDir *dir = child();
460  if (!dir)
461  return count;
462 
463  TQPtrListIterator<KMFolderNode> it(*dir);
464  for ( ; it.current(); ++it )
465  if (!it.current()->isDir()) {
466  folder = static_cast<KMFolder*>(it.current());
467  count += folder->countUnreadRecursive();
468  }
469 
470  return count;
471 }
472 
473 void KMFolder::msgStatusChanged( const KMMsgStatus oldStatus,
474  const KMMsgStatus newStatus, int idx )
475 {
476  mStorage->msgStatusChanged( oldStatus, newStatus, idx );
477 }
478 
479 int KMFolder::open(const char *owner)
480 {
481  return mStorage->open(owner);
482 }
483 
485 {
486  return mStorage->canAccess();
487 }
488 
489 void KMFolder::close( const char *owner, bool force )
490 {
491  // do not emit closed() in here - as this would regain too early
492  mStorage->close( owner, force );
493 }
494 
496 {
497  mStorage->sync();
498 }
499 
500 bool KMFolder::isOpened() const
501 {
502  return mStorage->isOpened();
503 }
504 
506 {
507  mStorage->markNewAsUnread();
508 }
509 
511 {
512  mStorage->markUnreadAsRead();
513 }
514 
516 {
517  /* The storage needs to be open before remove is called, otherwise
518  it will not unregister the corresponding serial numbers from
519  the message dict, since its message list is empty, and the .ids
520  file contents are not loaded. That can lead to lookups in the
521  dict returning stale pointers to the folder later. */
522  mStorage->open("kmfolder_remove");
523  mStorage->remove();
524 }
525 
527 {
528  return mStorage->expunge();
529 }
530 
531 int KMFolder::rename( const TQString& newName, KMFolderDir *aParent )
532 {
533  return mStorage->rename( newName, aParent );
534 }
535 
536 bool KMFolder::dirty() const
537 {
538  return mStorage->dirty();
539 }
540 
541 void KMFolder::setDirty( bool f )
542 {
543  mStorage->setDirty( f );
544 }
545 
547 {
548  return mStorage->needsCompacting();
549 }
550 
551 void KMFolder::setNeedsCompacting( bool f )
552 {
553  mStorage->setNeedsCompacting( f );
554 }
555 
556 void KMFolder::quiet( bool beQuiet )
557 {
558  mStorage->quiet( beQuiet );
559 }
560 
562 {
563  return mStorage->isReadOnly();
564 }
565 
566 bool KMFolder::mailCheckInProgress() const
567 {
568  return mStorage->mailCheckInProgress();
569 }
570 
572 {
573  return !mStorage->isReadOnly() && mStorage->canDeleteMessages();
574 }
575 
577 {
578  return mStorage->canDeleteMessages();
579 }
580 
581 TQString KMFolder::label() const
582 {
583  if ( !mSystemLabel.isEmpty() )
584  return mSystemLabel;
585  if ( !mLabel.isEmpty() )
586  return mLabel;
587  if ( isSystemFolder() )
588  return i18n( name().utf8() );
589  return name();
590 }
591 
592 //-----------------------------------------------------------------------------
593 TQString KMFolder::prettyURL() const
594 {
595  TQString parentUrl;
596  if ( parent() )
597  parentUrl = parent()->prettyURL();
598  if ( !parentUrl.isEmpty() )
599  return parentUrl + '/' + label();
600  else
601  return label();
602 }
603 
604 //--------------------------------------------------------------------------
605 TQString KMFolder::mailingListPostAddress() const
606 {
607  if ( mMailingList.features() & MailingList::Post ) {
608  KURL::List::const_iterator it;
609  KURL::List post = mMailingList.postURLS();
610  for( it = post.begin(); it != post.end(); ++it ) {
611  // We check for isEmpty because before 3.3 postAddress was just an
612  // email@kde.org and that leaves protocol() field in the kurl class
613  if ( (*it).protocol() == "mailto" || (*it).protocol().isEmpty() )
614  return (*it).path();
615  }
616  }
617  return TQString();
618 }
619 
621 {
622  mMailingListEnabled = enabled;
623  mStorage->writeConfig();
624 }
625 
626 void KMFolder::setMailingList( const MailingList& mlist )
627 {
628  mMailingList = mlist;
629  mStorage->writeConfig();
630 }
631 
632 void KMFolder::setIdentity( uint identity )
633 {
634  mIdentity = identity;
635  kmkernel->slotRequestConfigSync();
636 }
637 
638 uint KMFolder::identity() const
639 {
640  // if we don't have one set ourselves, check our account
641  kdDebug() << "FOO: " << mIdentity << " :: " << mStorage << endl;
642  if ( !mIdentity && mStorage )
643  if ( KMAccount *act = mStorage->account() )
644  return act->identityId();
645  return mIdentity;
646 }
647 
648 void KMFolder::setWhoField(const TQString& aWhoField )
649 {
650  mWhoField = aWhoField;
651 #if 0
652  // This isn't saved in the config anyway
653  mStorage->writeConfig();
654 #endif
655 }
656 
657 void KMFolder::setUserWhoField( const TQString& whoField, bool writeConfig )
658 {
659  if ( mUserWhoField == whoField )
660  return;
661  if ( whoField.isEmpty() )
662  {
663  // default setting
664  const KPIM::Identity & identity =
665  kmkernel->identityManager()->identityForUoidOrDefault( mIdentity );
666 
667  if ( isSystemFolder() && folderType() != KMFolderTypeImap ) {
668  // local system folders
669  if ( this == kmkernel->inboxFolder() ||
670  this == kmkernel->trashFolder() )
671  mWhoField = "From";
672  if ( this == kmkernel->outboxFolder() ||
673  this == kmkernel->sentFolder() ||
674  this == kmkernel->draftsFolder() ||
675  this == kmkernel->templatesFolder() )
676  mWhoField = "To";
677  } else if ( identity.drafts() == idString() ||
678  identity.templates() == idString() ||
679  identity.fcc() == idString() )
680  // drafts, templates or sent of the identity
681  mWhoField = "To";
682  else
683  mWhoField = "From";
684  } else if ( whoField == "From" || whoField == "To" )
685  // set the whoField according to the user-setting
686  mWhoField = whoField;
687  else {
688  // this should not happen...
689  kdDebug(5006) << "Illegal setting " << whoField << " for userWhoField!"
690  << endl;
691  return; // don't use the value
692  }
693  mUserWhoField = whoField;
694 
695  if (writeConfig)
696  mStorage->writeConfig();
697  emit viewConfigChanged();
698 }
699 
701 {
702  mStorage->correctUnreadMsgsCount();
703 }
704 
705 TQString KMFolder::idString() const
706 {
707  KMFolderNode* folderNode = parent();
708  if (!folderNode)
709  return "";
710  while ( folderNode->parent() )
711  folderNode = folderNode->parent();
712  TQString myPath = path();
713  int pathLen = myPath.length() - folderNode->path().length();
714  TQString relativePath = myPath.right( pathLen );
715  if (!relativePath.isEmpty())
716  relativePath = relativePath.right( relativePath.length() - 1 ) + "/";
717  TQString escapedName = name();
718  /* Escape [ and ] as they are disallowed for tdeconfig sections and that is
719  what the idString is primarily used for. */
720  escapedName.replace( "[", "%(" );
721  escapedName.replace( "]", "%)" );
722  return relativePath + escapedName;
723 }
724 
725 void KMFolder::setAutoExpire( bool enabled )
726 {
727  if( enabled != mExpireMessages ) {
728  mExpireMessages = enabled;
729  mStorage->writeConfig();
730  }
731 }
732 
734 {
735  if( age >= 0 && age != mUnreadExpireAge ) {
736  mUnreadExpireAge = age;
737  mStorage->writeConfig();
738  }
739 }
740 
741 void KMFolder::setUnreadExpireUnits( ExpireUnits units )
742 {
743  if (units >= expireNever && units < expireMaxUnits)
744  mUnreadExpireUnits = units;
745  mStorage->writeConfig();
746 }
747 
749 {
750  if( age >= 0 && age != mReadExpireAge ) {
751  mReadExpireAge = age;
752  mStorage->writeConfig();
753  }
754 }
755 
756 void KMFolder::setReadExpireUnits( ExpireUnits units )
757 {
758  if (units >= expireNever && units <= expireMaxUnits)
759  mReadExpireUnits = units;
760  mStorage->writeConfig();
761 }
762 
763 
764 void KMFolder::setExpireAction( ExpireAction a )
765 {
766  if ( a != mExpireAction ) {
767  mExpireAction = a;
768  mStorage->writeConfig();
769  }
770 }
771 
772 void KMFolder::setExpireToFolderId( const TQString& id )
773 {
774  if ( id != mExpireToFolderId ) {
775  mExpireToFolderId = id;
776  mStorage->writeConfig();
777  }
778 }
779 
780 
781 static int daysToExpire( int number, ExpireUnits units )
782 {
783  switch (units) {
784  case expireDays: // Days
785  return number;
786  case expireWeeks: // Weeks
787  return number * 7;
788  case expireMonths: // Months - this could be better rather than assuming 31day months.
789  return number * 31;
790  default: // this avoids a compiler warning (not handled enumeration values)
791  ;
792  }
793  return -1;
794 }
795 
796 void KMFolder::daysToExpire(int& unreadDays, int& readDays) {
797  unreadDays = ::daysToExpire( getUnreadExpireAge(), getUnreadExpireUnits() );
798  readDays = ::daysToExpire( getReadExpireAge(), getReadExpireUnits() );
799 }
800 
801 void KMFolder::expireOldMessages( bool immediate )
802 {
803  KMail::ScheduledExpireTask* task = new KMail::ScheduledExpireTask(this, immediate);
804  kmkernel->jobScheduler()->registerTask( task );
805  if ( immediate ) {
806  // #82259: compact after expiring.
807  compact( CompactLater );
808  }
809 }
810 
811 void KMFolder::compact( CompactOptions options )
812 {
813  if ( options == CompactLater ) {
815  kmkernel->jobScheduler()->registerTask( task );
816  } else {
817  mStorage->compact( options == CompactSilentlyNow );
818  }
819 }
820 
822 {
823  return mStorage ? mStorage->trashFolder() : 0;
824 }
825 
826 int KMFolder::writeIndex( bool createEmptyIndex )
827 {
828  return mStorage->writeIndex( createEmptyIndex );
829 }
830 
831 void KMFolder::setStatus( int idx, KMMsgStatus status, bool toggle )
832 {
833  mStorage->setStatus( idx, status, toggle );
834 }
835 
836 void KMFolder::setStatus( TQValueList<int>& ids, KMMsgStatus status,
837  bool toggle )
838 {
839  mStorage->setStatus( ids, status, toggle);
840 }
841 
842 void KMFolder::setIconPaths( const TQString &normalPath,
843  const TQString &unreadPath )
844 {
845  mNormalIconPath = normalPath;
846  mUnreadIconPath = unreadPath;
847  mStorage->writeConfig();
848  emit iconsChanged();
849 }
850 
851 void KMFolder::removeJobs()
852 {
853  mStorage->removeJobs();
854 }
855 
857 {
858  return mStorage->updateIndex();
859 }
860 
862 {
863  mStorage->reallyAddMsg( aMsg );
864 }
865 
867 {
868  mStorage->reallyAddCopyOfMsg( aMsg );
869 }
870 
871 void KMFolder::setShortcut( const TDEShortcut &sc )
872 {
873  if ( mShortcut != sc ) {
874  mShortcut = sc;
875  emit shortcutChanged( this );
876  }
877 }
878 
880 {
881  return !isSystemFolder();
882 }
883 
884 void KMFolder::slotContentsTypeChanged( KMail::FolderContentsType type )
885 {
886  kmkernel->iCalIface().folderContentsTypeChanged( this, type );
887  emit iconsChanged();
888 }
889 
890 void KMFolder::slotFolderSizeChanged()
891 {
892  emit folderSizeChanged( this );
893  KMFolder* papa = parent()->manager()->parentFolder( this );
894  if ( papa && papa != this ) {
895  papa->slotFolderSizeChanged();
896  }
897 }
898 
899 bool KMFolder::isValidName( const TQString &folderName, TQString &message )
900 {
901  KMFolderType fldType = folderType();
902 
903  // names of local folders must not contain a '/'
904  if ( folderName.find( '/' ) != -1 &&
905  fldType != KMFolderTypeImap &&
906  fldType != KMFolderTypeCachedImap ) {
907  message = i18n( "Folder names cannot contain the / (slash) character; please choose another folder name." );
908  return false;
909  }
910 
911  // folder names must not start with a '.'
912  if ( folderName.startsWith( "." ) ) {
913  message = i18n( "Folder names cannot start with a . (dot) character; please choose another folder name." );
914  return false;
915  }
916 
917  // names of IMAP folders must not contain the folder delimiter
918  if ( fldType == KMFolderTypeImap || fldType == KMFolderTypeCachedImap ) {
919  TQString delimiter;
920  if ( fldType == KMFolderTypeImap ) {
921  KMAcctImap *ai = static_cast<KMFolderImap*>( mStorage )->account();
922  if ( ai ) {
923  delimiter = ai->delimiterForFolder( mStorage );
924  }
925  } else {
926  KMAcctCachedImap *ai = static_cast<KMFolderCachedImap*>( mStorage )->account();
927  if ( ai ) {
928  delimiter = ai->delimiterForFolder( mStorage );
929  }
930  }
931  if ( !delimiter.isEmpty() && folderName.find( delimiter ) != -1 ) {
932  message = i18n( "Your IMAP server does not allow the character '%1'; please choose another folder name." ).arg( delimiter );
933  return false;
934  }
935  }
936  return true;
937 }
938 
939 #include "kmfolder.moc"