/* -*- mode: C++; c-file-style: "gnu" -*-
 * kmail: KDE mail client
 * Copyright (c) 1996-1998 Stefan Taferner <taferner@kde.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 */
#include <config.h>

#include "kmfolder.h"
#include "kmfolderdir.h"
#include "kmfoldermbox.h"
#include "folderstorage.h"
#include "kmfoldercachedimap.h"
#include "kmfoldersearch.h"
#include "kmfolderimap.h"
#include "kmfoldermgr.h"
#include <libkpimidentities/identitymanager.h>
#include <libkpimidentities/identity.h>
#include "expirejob.h"
#include "compactionjob.h"
#include "kmfoldertree.h"
#include "kmailicalifaceimpl.h"
#include "kmaccount.h"

#include <errno.h>

#include <kdebug.h>
#include <tdelocale.h>
#include <tdeshortcut.h>
#include <tdemessagebox.h>
#include <tqfile.h>
#include <tqfileinfo.h>


KMFolder::KMFolder( KMFolderDir* aParent, const TQString& aFolderName,
                             KMFolderType aFolderType, bool withIndex, bool exportedSernums )
  : KMFolderNode( aParent, aFolderName ), mStorage(0),
    mChild( 0 ),
    mIsSystemFolder( false ),
    mHasIndex( withIndex ),
    mExportsSernums( exportedSernums ),
    mMoveInProgress( false ),
    mExpireMessages( false ), mUnreadExpireAge( 28 ),
    mReadExpireAge( 14 ), mUnreadExpireUnits( expireNever ),
    mReadExpireUnits( expireNever ),
    mExpireAction( ExpireDelete ),
    mUseCustomIcons( false ), mMailingListEnabled( false ),
    mAcctList( 0 ),
    mIdentity( 0 ), // default identity
    mPutRepliesInSameFolder( false ),
    mIgnoreNewMail( false )
{
  if( aFolderType == KMFolderTypeCachedImap )
    mStorage = new KMFolderCachedImap( this, aFolderName.latin1() );
  else if( aFolderType == KMFolderTypeImap )
    mStorage = new KMFolderImap( this, aFolderName.latin1() );
  else if( aFolderType == KMFolderTypeMaildir )
    mStorage = new KMFolderMaildir( this, aFolderName.latin1() );
  else if( aFolderType == KMFolderTypeSearch )
    mStorage = new KMFolderSearch( this, aFolderName.latin1() );
  else
    mStorage = new KMFolderMbox( this, aFolderName.latin1() );

  assert( mStorage );

  TQFileInfo dirinfo;
  dirinfo.setFile( mStorage->location() );
  if ( !dirinfo.exists() ) {
    int rc = mStorage->create();
    TQString msg = i18n("<qt>Error while creating file <b>%1</b>:<br>%2</qt>").arg(aFolderName).arg(strerror(rc));
    if ( rc ) {
      KMessageBox::information(0, msg);
    }
  }

  if ( aParent ) {
    connect( mStorage, TQT_SIGNAL( msgAdded( KMFolder*, TQ_UINT32 ) ),
             aParent->manager(), TQT_SIGNAL( msgAdded( KMFolder*, TQ_UINT32 ) ) );
    connect( mStorage, TQT_SIGNAL( msgRemoved( KMFolder*, TQ_UINT32 ) ),
             parent()->manager(), TQT_SIGNAL( msgRemoved( KMFolder*, TQ_UINT32 ) ) );
    connect( this, TQT_SIGNAL( msgChanged( KMFolder*, TQ_UINT32, int ) ),
             parent()->manager(), TQT_SIGNAL( msgChanged( KMFolder*, TQ_UINT32, int ) ) );
    connect( this, TQT_SIGNAL( msgHeaderChanged( KMFolder*,  int ) ),
             parent()->manager(), TQT_SIGNAL( msgHeaderChanged( KMFolder*, int ) ) );
    connect( mStorage, TQT_SIGNAL( invalidated( KMFolder* ) ),
             parent()->manager(), TQT_SIGNAL( folderInvalidated( KMFolder* ) ) );
  }

  // Resend all mStorage signals
  connect( mStorage, TQT_SIGNAL( changed() ), TQT_SIGNAL( changed() ) );
  connect( mStorage, TQT_SIGNAL( cleared() ), TQT_SIGNAL( cleared() ) );
  connect( mStorage, TQT_SIGNAL( expunged( KMFolder* ) ),
           TQT_SIGNAL( expunged( KMFolder* ) ) );
  connect( mStorage, TQT_SIGNAL( nameChanged() ), TQT_SIGNAL( nameChanged() ) );
  connect( mStorage, TQT_SIGNAL( msgRemoved( KMFolder*, TQ_UINT32 ) ),
           TQT_SIGNAL( msgRemoved( KMFolder*, TQ_UINT32 ) ) );
  connect( mStorage, TQT_SIGNAL( msgRemoved( int, TQString ) ),
           TQT_SIGNAL( msgRemoved( int, TQString ) ) );
  connect( mStorage, TQT_SIGNAL( msgRemoved( KMFolder* ) ),
           TQT_SIGNAL( msgRemoved( KMFolder* ) ) );
  connect( mStorage, TQT_SIGNAL( msgAdded( int ) ), TQT_SIGNAL( msgAdded( int ) ) );
  connect( mStorage, TQT_SIGNAL( msgAdded( KMFolder*, TQ_UINT32 ) ),
           TQT_SIGNAL( msgAdded( KMFolder*, TQ_UINT32 ) ) );
  connect( mStorage, TQT_SIGNAL( msgChanged( KMFolder*, TQ_UINT32 , int ) ),
           TQT_SIGNAL( msgChanged( KMFolder*, TQ_UINT32 , int ) ) );
  connect( mStorage, TQT_SIGNAL( msgHeaderChanged( KMFolder*, int ) ),
           TQT_SIGNAL( msgHeaderChanged( KMFolder*, int ) ) );
  connect( mStorage, TQT_SIGNAL( statusMsg( const TQString& ) ),
           TQT_SIGNAL( statusMsg( const TQString& ) ) );
  connect( mStorage, TQT_SIGNAL( numUnreadMsgsChanged( KMFolder* ) ),
           TQT_SIGNAL( numUnreadMsgsChanged( KMFolder* ) ) );
  connect( mStorage, TQT_SIGNAL( removed( KMFolder*, bool ) ),
           TQT_SIGNAL( removed( KMFolder*, bool ) ) );
  connect( mStorage, TQT_SIGNAL(noContentChanged()),
           TQT_SIGNAL(noContentChanged()) );
  connect( mStorage, TQT_SIGNAL(syncStateChanged()),
           TQT_SIGNAL(syncStateChanged()) );

  connect( mStorage, TQT_SIGNAL( contentsTypeChanged( KMail::FolderContentsType ) ),
                this, TQT_SLOT( slotContentsTypeChanged( KMail::FolderContentsType ) ) );

  connect( mStorage, TQT_SIGNAL( folderSizeChanged() ),
           this, TQT_SLOT( slotFolderSizeChanged() ) );

  //FIXME: Centralize all the readConfig calls somehow - Zack
  // Meanwhile, readConfig must be done before registerWithMessageDict, since
  // that one can call writeConfig in some circumstances - David
  mStorage->readConfig();

   // trigger from here, since it needs a fully constructed FolderStorage
  if ( mExportsSernums )
    mStorage->registerWithMessageDict();
  if ( !mHasIndex )
    mStorage->setAutoCreateIndex( false );

  if ( mId == 0 && aParent )
    mId = aParent->manager()->createId();
}

KMFolder::~KMFolder()
{
  mStorage->close( "~KMFolder", true );
  delete mAcctList;
  if ( mHasIndex ) mStorage->deregisterFromMessageDict();
  delete mStorage;
}

void KMFolder::readConfig( TDEConfig* config )
{
  if ( !config->readEntry("SystemLabel").isEmpty() )
    mSystemLabel = config->readEntry("SystemLabel");
  mExpireMessages = config->readBoolEntry("ExpireMessages", false);
  mReadExpireAge = config->readNumEntry("ReadExpireAge", 3);
  mReadExpireUnits = (ExpireUnits)config->readNumEntry("ReadExpireUnits", expireMonths);
  mUnreadExpireAge = config->readNumEntry("UnreadExpireAge", 12);
  mUnreadExpireUnits = (ExpireUnits)config->readNumEntry("UnreadExpireUnits", expireNever);
  mExpireAction = config->readEntry("ExpireAction", "Delete") == "Move" ? ExpireMove : ExpireDelete;
  mExpireToFolderId = config->readEntry("ExpireToFolder");

  mUseCustomIcons = config->readBoolEntry("UseCustomIcons", false );
  mNormalIconPath = config->readEntry("NormalIconPath" );
  mUnreadIconPath = config->readEntry("UnreadIconPath" );

  mMailingListEnabled = config->readBoolEntry("MailingListEnabled");
  mMailingList.readConfig( config );

  mIdentity = config->readUnsignedNumEntry("Identity",0);

  setUserWhoField( config->readEntry("WhoField"), false );
  uint savedId = config->readUnsignedNumEntry("Id", 0);
  // make sure that we don't overwrite a valid id
  if ( savedId != 0 && mId == 0 )
    mId = savedId;
  mPutRepliesInSameFolder = config->readBoolEntry( "PutRepliesInSameFolder", false );
  mIgnoreNewMail = config->readBoolEntry( "IgnoreNewMail", false );

  if ( mUseCustomIcons )
    emit iconsChanged();

  TQString shortcut( config->readEntry( "Shortcut" ) );
  if ( !shortcut.isEmpty() ) {
    TDEShortcut sc( shortcut );
    setShortcut( sc );
  }
}

void KMFolder::writeConfig( TDEConfig* config ) const
{
  config->writeEntry("SystemLabel", mSystemLabel);
  config->writeEntry("ExpireMessages", mExpireMessages);
  config->writeEntry("ReadExpireAge", mReadExpireAge);
  config->writeEntry("ReadExpireUnits", mReadExpireUnits);
  config->writeEntry("UnreadExpireAge", mUnreadExpireAge);
  config->writeEntry("UnreadExpireUnits", mUnreadExpireUnits);
  config->writeEntry("ExpireAction", mExpireAction == ExpireDelete ? "Delete" : "Move");
  config->writeEntry("ExpireToFolder", mExpireToFolderId);

  config->writeEntry("UseCustomIcons", mUseCustomIcons);
  config->writeEntry("NormalIconPath", mNormalIconPath);
  config->writeEntry("UnreadIconPath", mUnreadIconPath);

  config->writeEntry("MailingListEnabled", mMailingListEnabled);
  mMailingList.writeConfig( config );

  if ( mIdentity != 0 && ( !mStorage || !mStorage->account() || mIdentity != mStorage->account()->identityId() ) )
      config->writeEntry("Identity", mIdentity);
  else
      config->deleteEntry("Identity");

  config->writeEntry("WhoField", mUserWhoField);
  config->writeEntry("Id", mId);
  config->writeEntry( "PutRepliesInSameFolder", mPutRepliesInSameFolder );
  config->writeEntry( "IgnoreNewMail", mIgnoreNewMail );
  if ( !mShortcut.isNull() )
    config->writeEntry( "Shortcut", mShortcut.toString() );
  else
    config->deleteEntry( "Shortcut" );
}

KMFolderType KMFolder::folderType() const
{
  return mStorage ? mStorage->folderType() : KMFolderTypeUnknown;
}

TQString KMFolder::fileName() const
{
  return mStorage ? mStorage->fileName() : TQString();
}

TQString KMFolder::location() const
{
  return mStorage ? mStorage->location() : TQString();
}

TQString KMFolder::indexLocation() const
{
  return mStorage ? mStorage->indexLocation() : TQString();
}

TQString KMFolder::subdirLocation() const
{
  TQString sLocation( path() );

  if( !sLocation.isEmpty() )
    sLocation += '/';
  sLocation += '.' + FolderStorage::dotEscape( fileName() ) + ".directory";

  return sLocation;
}

KMFolderDir* KMFolder::createChildFolder()
{
  if( mChild )
    return mChild;

  TQString childName = "." + fileName() + ".directory";
  TQString childDir = path() + "/" + childName;
  if (access(TQFile::encodeName(childDir), W_OK) != 0) // Not there or not writable
  {
    if (mkdir(TQFile::encodeName(childDir), S_IRWXU) != 0
      && chmod(TQFile::encodeName(childDir), S_IRWXU) != 0) {
      TQString wmsg = TQString(" '%1': %2").arg(childDir).arg(strerror(errno));
      KMessageBox::information(0,i18n("Failed to create folder") + wmsg);
      return 0;
    }
  }

  KMFolderDirType newType = KMStandardDir;
  if( folderType() == KMFolderTypeCachedImap )
    newType = KMDImapDir;
  else if( folderType() == KMFolderTypeImap )
    newType = KMImapDir;

  mChild = new KMFolderDir( this, parent(), childName, newType );
  if( !mChild )
    return 0;
  mChild->reload();
  parent()->append( mChild );
  return mChild;
}

void KMFolder::setChild( KMFolderDir* aChild )
{
  mChild = aChild;
  mStorage->updateChildrenState();
}

bool KMFolder::noContent() const
{
  return mStorage ? mStorage->noContent() : true;
}

void KMFolder::setNoContent( bool aNoContent )
{
  mStorage->setNoContent( aNoContent );
}

bool KMFolder::noChildren() const
{
  return mStorage->noChildren();
}

void KMFolder::setNoChildren( bool aNoChildren )
{
  mStorage->setNoChildren( aNoChildren );
}

KMMessage* KMFolder::getMsg( int idx )
{
  return mStorage->getMsg( idx );
}

KMMsgInfo* KMFolder::unGetMsg( int idx )
{
  return mStorage->unGetMsg( idx );
}

bool KMFolder::isMessage( int idx )
{
  return mStorage->isMessage( idx );
}

DwString KMFolder::getDwString( int idx )
{
  return mStorage->getDwString( idx );
}

void KMFolder::ignoreJobsForMessage( KMMessage* m )
{
  mStorage->ignoreJobsForMessage( m );
}

FolderJob* KMFolder::createJob( KMMessage *msg, FolderJob::JobType jt,
                                KMFolder *folder, TQString partSpecifier,
                                const AttachmentStrategy *as ) const
{
  return mStorage->createJob( msg, jt, folder, partSpecifier, as );
}

FolderJob* KMFolder::createJob( TQPtrList<KMMessage>& msgList,
                                const TQString& sets,
                                FolderJob::JobType jt, KMFolder *folder ) const
{
  return mStorage->createJob( msgList, sets, jt, folder );
}

const KMMsgBase* KMFolder::getMsgBase( int idx ) const
{
  return mStorage->getMsgBase( idx );
}

KMMsgBase* KMFolder::getMsgBase( int idx )
{
  return mStorage->getMsgBase( idx );
}

const KMMsgBase* KMFolder::operator[]( int idx ) const
{
  return mStorage->operator[]( idx );
}

KMMsgBase* KMFolder::operator[]( int idx )
{
  return mStorage->operator[]( idx );
}

KMMessage* KMFolder::take( int idx )
{
  return mStorage->take( idx );
}

void KMFolder::take( TQPtrList<KMMessage> msgList ) // TODO const ref
{
  mStorage->take( msgList );
}

int KMFolder::addMsg( KMMessage* msg, int* index_return )
{
  return mStorage->addMsg( msg, index_return );
}

int KMFolder::addMsgKeepUID( KMMessage* msg, int* index_return )
{
  return mStorage->addMsgKeepUID( msg, index_return );
}

int KMFolder::addMsg( TQPtrList<KMMessage>& list, TQValueList<int>& index_return )
{
  return mStorage->addMsg( list, index_return );
}

void KMFolder::emitMsgAddedSignals( int idx )
{
  mStorage->emitMsgAddedSignals( idx );
}

void KMFolder::removeMsg( int i, bool imapQuiet )
{
  mStorage->removeMsg( i, imapQuiet );
}

void KMFolder::removeMsg( TQPtrList<KMMessage> msgList, bool imapQuiet ) // TODO const ref
{
  mStorage->removeMsg( msgList, imapQuiet );
}

int KMFolder::expungeOldMsg( int days )
{
  return mStorage->expungeOldMsg( days );
}

int KMFolder::moveMsg( KMMessage* msg, int* index_return )
{
  return mStorage->moveMsg( msg, index_return );
}

int KMFolder::moveMsg(TQPtrList<KMMessage> q, int* index_return )
{
  return mStorage->moveMsg( q, index_return );
}

int KMFolder::find( const KMMsgBase* msg ) const
{
  return mStorage ? mStorage->find( msg ) : -1;
}

int KMFolder::find( const KMMessage* msg ) const
{
  return mStorage ? mStorage->find( msg ) : -1;
}

int KMFolder::count( bool cache ) const
{
  return mStorage->count( cache );
}

int KMFolder::countUnread()
{
  return mStorage->countUnread();
}

int KMFolder::countUnreadRecursive()
{
  KMFolder *folder;
  int count = countUnread();
  KMFolderDir *dir = child();
  if (!dir)
    return count;

  TQPtrListIterator<KMFolderNode> it(*dir);
  for ( ; it.current(); ++it )
    if (!it.current()->isDir()) {
      folder = static_cast<KMFolder*>(it.current());
      count += folder->countUnreadRecursive();
    }

  return count;
}

void KMFolder::msgStatusChanged( const KMMsgStatus oldStatus,
                                 const KMMsgStatus newStatus, int idx )
{
  mStorage->msgStatusChanged( oldStatus, newStatus, idx );
}

int KMFolder::open(const char *owner)
{
  return mStorage->open(owner);
}

int KMFolder::canAccess()
{
  return mStorage->canAccess();
}

void KMFolder::close( const char *owner, bool force )
{
  // do not emit closed() in here - as this would regain too early
  mStorage->close( owner, force );
}

void KMFolder::sync()
{
  mStorage->sync();
}

bool KMFolder::isOpened() const
{
  return mStorage->isOpened();
}

void KMFolder::markNewAsUnread()
{
  mStorage->markNewAsUnread();
}

void KMFolder::markUnreadAsRead()
{
  mStorage->markUnreadAsRead();
}

void KMFolder::remove()
{
  /* The storage needs to be open before remove is called, otherwise
     it will not unregister the corresponding serial numbers from
     the message dict, since its message list is empty, and the .ids
     file contents are not loaded. That can lead to lookups in the
     dict returning stale pointers to the folder later. */
  mStorage->open("kmfolder_remove");
  mStorage->remove();
}

int KMFolder::expunge()
{
  return mStorage->expunge();
}

int KMFolder::rename( const TQString& newName, KMFolderDir *aParent )
{
  return mStorage->rename( newName, aParent );
}

bool KMFolder::dirty() const
{
  return mStorage->dirty();
}

void KMFolder::setDirty( bool f )
{
  mStorage->setDirty( f );
}

bool KMFolder::needsCompacting() const
{
  return mStorage->needsCompacting();
}

void KMFolder::setNeedsCompacting( bool f )
{
  mStorage->setNeedsCompacting( f );
}

void KMFolder::quiet( bool beQuiet )
{
  mStorage->quiet( beQuiet );
}

bool KMFolder::isReadOnly() const
{
  return mStorage->isReadOnly();
}

bool KMFolder::mailCheckInProgress() const
{
  return mStorage->mailCheckInProgress();
}

bool KMFolder::isWritable() const
{
  return !mStorage->isReadOnly() && mStorage->canDeleteMessages();
}

bool KMFolder::canDeleteMessages() const
{
  return mStorage->canDeleteMessages();
}

TQString KMFolder::label() const
{
  if ( !mSystemLabel.isEmpty() )
     return mSystemLabel;
  if ( !mLabel.isEmpty() )
     return mLabel;
  if ( isSystemFolder() )
     return i18n( name().utf8() );
  return name();
}

//-----------------------------------------------------------------------------
TQString KMFolder::prettyURL() const
{
  TQString parentUrl;
  if ( parent() )
    parentUrl = parent()->prettyURL();
  if ( !parentUrl.isEmpty() )
    return parentUrl + '/' + label();
  else
    return label();
}

//--------------------------------------------------------------------------
TQString KMFolder::mailingListPostAddress() const
{
  if ( mMailingList.features() & MailingList::Post ) {
    KURL::List::const_iterator it;
    KURL::List post = mMailingList.postURLS();
    for( it = post.begin(); it != post.end(); ++it ) {
      // We check for isEmpty because before 3.3 postAddress was just an
      // email@kde.org and that leaves protocol() field in the kurl class
      if ( (*it).protocol() == "mailto" || (*it).protocol().isEmpty() )
        return (*it).path();
    }
  }
  return TQString();
}

void KMFolder::setMailingListEnabled( bool enabled )
{
  mMailingListEnabled = enabled;
  mStorage->writeConfig();
}

void KMFolder::setMailingList( const MailingList& mlist )
{
  mMailingList = mlist;
  mStorage->writeConfig();
}

void KMFolder::setIdentity( uint identity )
{
  mIdentity = identity;
  kmkernel->slotRequestConfigSync();
}

uint KMFolder::identity() const
{
  // if we don't have one set ourselves, check our account
  kdDebug() << "FOO: " << mIdentity << " :: " << mStorage << endl;
  if ( !mIdentity && mStorage )
    if ( KMAccount *act = mStorage->account() )
      return act->identityId();
  return mIdentity;
}

void KMFolder::setWhoField(const TQString& aWhoField )
{
  mWhoField = aWhoField;
#if 0
  // This isn't saved in the config anyway
  mStorage->writeConfig();
#endif
}

void KMFolder::setUserWhoField( const TQString& whoField, bool writeConfig )
{
  if ( mUserWhoField == whoField )
    return;
  if ( whoField.isEmpty() )
  {
    // default setting
    const KPIM::Identity & identity =
      kmkernel->identityManager()->identityForUoidOrDefault( mIdentity );

    if ( isSystemFolder() && folderType() != KMFolderTypeImap ) {
      // local system folders
      if ( this == kmkernel->inboxFolder() ||
           this == kmkernel->trashFolder() )
        mWhoField = "From";
      if ( this == kmkernel->outboxFolder() ||
           this == kmkernel->sentFolder() ||
           this == kmkernel->draftsFolder() ||
           this == kmkernel->templatesFolder() )
        mWhoField = "To";
    } else if ( identity.drafts() == idString() ||
                identity.templates() == idString() ||
                identity.fcc() == idString() )
      // drafts, templates or sent of the identity
      mWhoField = "To";
    else
      mWhoField = "From";
  } else if ( whoField == "From" || whoField == "To" )
    // set the whoField according to the user-setting
    mWhoField = whoField;
  else {
    // this should not happen...
    kdDebug(5006) << "Illegal setting " << whoField << " for userWhoField!"
                  << endl;
    return; // don't use the value
  }
  mUserWhoField = whoField;

  if (writeConfig)
    mStorage->writeConfig();
  emit viewConfigChanged();
}

void KMFolder::correctUnreadMsgsCount()
{
  mStorage->correctUnreadMsgsCount();
}

TQString KMFolder::idString() const
{
  KMFolderNode* folderNode = parent();
  if (!folderNode)
    return "";
  while ( folderNode->parent() )
    folderNode = folderNode->parent();
  TQString myPath = path();
  int pathLen = myPath.length() - folderNode->path().length();
  TQString relativePath = myPath.right( pathLen );
  if (!relativePath.isEmpty())
    relativePath = relativePath.right( relativePath.length() - 1 ) + "/";
  TQString escapedName = name();
  /* Escape [ and ] as they are disallowed for tdeconfig sections and that is
     what the idString is primarily used for. */
  escapedName.replace( "[", "%(" );
  escapedName.replace( "]", "%)" );
  return relativePath + escapedName;
}

void KMFolder::setAutoExpire( bool enabled )
{
  if( enabled != mExpireMessages ) {
    mExpireMessages = enabled;
    mStorage->writeConfig();
  }
}

void KMFolder::setUnreadExpireAge( int age )
{
  if( age >= 0 && age != mUnreadExpireAge ) {
    mUnreadExpireAge = age;
    mStorage->writeConfig();
  }
}

void KMFolder::setUnreadExpireUnits( ExpireUnits units )
{
  if (units >= expireNever && units < expireMaxUnits)
    mUnreadExpireUnits = units;
    mStorage->writeConfig();
}

void KMFolder::setReadExpireAge( int age )
{
  if( age >= 0 && age != mReadExpireAge ) {
    mReadExpireAge = age;
    mStorage->writeConfig();
  }
}

void KMFolder::setReadExpireUnits( ExpireUnits units )
{
  if (units >= expireNever && units <= expireMaxUnits)
    mReadExpireUnits = units;
    mStorage->writeConfig();
}


void KMFolder::setExpireAction( ExpireAction a )
{
  if ( a != mExpireAction ) {
    mExpireAction = a;
    mStorage->writeConfig();
  }
}

void KMFolder::setExpireToFolderId( const TQString& id )
{
  if ( id != mExpireToFolderId ) {
    mExpireToFolderId = id;
    mStorage->writeConfig();
  }
}


static int daysToExpire( int number, ExpireUnits units )
{
  switch (units) {
  case expireDays: // Days
    return number;
  case expireWeeks: // Weeks
    return number * 7;
  case expireMonths: // Months - this could be better rather than assuming 31day months.
    return number * 31;
  default: // this avoids a compiler warning (not handled enumeration values)
    ;
  }
  return -1;
}

void KMFolder::daysToExpire(int& unreadDays, int& readDays) {
  unreadDays = ::daysToExpire( getUnreadExpireAge(), getUnreadExpireUnits() );
  readDays = ::daysToExpire( getReadExpireAge(), getReadExpireUnits() );
}

void KMFolder::expireOldMessages( bool immediate )
{
  KMail::ScheduledExpireTask* task = new KMail::ScheduledExpireTask(this, immediate);
  kmkernel->jobScheduler()->registerTask( task );
  if ( immediate ) {
    // #82259: compact after expiring.
    compact( CompactLater );
  }
}

void KMFolder::compact( CompactOptions options )
{
  if ( options == CompactLater ) {
    KMail::ScheduledCompactionTask* task = new KMail::ScheduledCompactionTask(this, false);
    kmkernel->jobScheduler()->registerTask( task );
  } else {
    mStorage->compact( options == CompactSilentlyNow );
  }
}

KMFolder* KMFolder::trashFolder() const
{
  return mStorage ? mStorage->trashFolder() : 0;
}

int KMFolder::writeIndex( bool createEmptyIndex )
{
  return mStorage->writeIndex( createEmptyIndex );
}

void KMFolder::setStatus( int idx, KMMsgStatus status, bool toggle )
{
  mStorage->setStatus( idx, status, toggle );
}

void KMFolder::setStatus( TQValueList<int>& ids, KMMsgStatus status,
                          bool toggle )
{
  mStorage->setStatus( ids, status, toggle);
}

void KMFolder::setIconPaths( const TQString &normalPath,
                             const TQString &unreadPath )
{
  mNormalIconPath = normalPath;
  mUnreadIconPath = unreadPath;
  mStorage->writeConfig();
  emit iconsChanged();
}

void KMFolder::removeJobs()
{
  mStorage->removeJobs();
}

int KMFolder::updateIndex()
{
  return mStorage->updateIndex();
}

void KMFolder::reallyAddMsg( KMMessage* aMsg )
{
  mStorage->reallyAddMsg( aMsg );
}

void KMFolder::reallyAddCopyOfMsg( KMMessage* aMsg )
{
  mStorage->reallyAddCopyOfMsg( aMsg );
}

void KMFolder::setShortcut( const TDEShortcut &sc )
{
  if ( mShortcut != sc ) {
    mShortcut = sc;
    emit shortcutChanged( this );
  }
}

bool KMFolder::isMoveable() const
{
  return !isSystemFolder();
}

void KMFolder::slotContentsTypeChanged( KMail::FolderContentsType type )
{
  kmkernel->iCalIface().folderContentsTypeChanged( this, type );
  emit iconsChanged();
}

void KMFolder::slotFolderSizeChanged()
{
  emit folderSizeChanged( this );
  KMFolder* papa = parent()->manager()->parentFolder( this );
  if ( papa && papa != this ) {
    papa->slotFolderSizeChanged();
  }
}

bool KMFolder::isValidName( const TQString &folderName, TQString &message )
{
  KMFolderType fldType = folderType();

  // names of local folders must not contain a '/'
  if ( folderName.find( '/' ) != -1 &&
       fldType != KMFolderTypeImap &&
       fldType != KMFolderTypeCachedImap ) {
    message = i18n( "Folder names cannot contain the / (slash) character; please choose another folder name." );
    return false;
  }

  // folder names must not start with a '.'
  if ( folderName.startsWith( "." ) ) {
    message = i18n( "Folder names cannot start with a . (dot) character; please choose another folder name." );
    return false;
  }

  // names of IMAP folders must not contain the folder delimiter
  if ( fldType == KMFolderTypeImap || fldType == KMFolderTypeCachedImap ) {
    TQString delimiter;
    if ( fldType == KMFolderTypeImap ) {
      KMAcctImap *ai = static_cast<KMFolderImap*>( mStorage )->account();
      if ( ai ) {
        delimiter = ai->delimiterForFolder( mStorage );
      }
    } else {
      KMAcctCachedImap *ai = static_cast<KMFolderCachedImap*>( mStorage )->account();
      if ( ai ) {
        delimiter = ai->delimiterForFolder( mStorage );
      }
    }
    if ( !delimiter.isEmpty() && folderName.find( delimiter ) != -1 ) {
      message = i18n( "Your IMAP server does not allow the character '%1'; please choose another folder name." ).arg( delimiter );
      return false;
    }
  }
  return true;
}

#include "kmfolder.moc"
