Index: configuredialog.cpp =================================================================== RCS file: /cvs/kdenetwork/kmail/configuredialog.cpp,v retrieving revision 1.74 diff -u -3 -p -r1.74 configuredialog.cpp --- configuredialog.cpp 2001/01/25 21:46:28 1.74 +++ configuredialog.cpp 2001/01/30 16:11:56 @@ -1259,14 +1259,52 @@ void ConfigureDialog::makeMiscPage( void QVBoxLayout *topLevel = new QVBoxLayout( page, 0, spacingHint() ); mMisc.pageIndex = pageIndex(page); - //---------- group: folders - QGroupBox *group = new QGroupBox( i18n("&Folders"), page ); + //---------- group: trash folder + QGroupBox *group = new QGroupBox( i18n("&Trash folder"), page ); topLevel->addWidget( group ); QVBoxLayout *vlay = new QVBoxLayout( group, spacingHint() ); + vlay->addSpacing( fontMetrics().lineSpacing() ); mMisc.emptyTrashCheck = new QCheckBox(i18n("Empty trash on exit"), group ); + connect( mMisc.emptyTrashCheck, SIGNAL(stateChanged(int)), + this, SLOT(slotEmptyTrashState(int)) ); vlay->addWidget( mMisc.emptyTrashCheck ); + QHBoxLayout *stlay = new QHBoxLayout( spacingHint() ,"hly1"); + stlay->setMargin(0); + vlay->addLayout( stlay ); + mMisc.keepSmallTrashCheck = + new QCheckBox(i18n("Keep trash size below "), group ); + stlay->addWidget( mMisc.keepSmallTrashCheck ); + mMisc.smallTrashSizeSpin = new KIntNumInput( group ); + mMisc.smallTrashSizeSpin->setValue(1); +// mMisc.smallTrashSizeSpin->setMinValue(1); + stlay->addWidget( mMisc.smallTrashSizeSpin ); + stlay->addWidget( new QLabel( "Mo", group ) ); + stlay->addStretch( 100 ); + + QHBoxLayout *rmvlay = new QHBoxLayout( spacingHint(),"hly2" ); + rmvlay->setMargin(0); + vlay->addLayout( rmvlay ); + mMisc.removeOldMailCheck = + new QCheckBox(i18n("In trash, on exit, remove messages older than"), group ); + rmvlay->addWidget( mMisc.removeOldMailCheck ); + mMisc.oldMailAgeSpin = new KIntNumInput( group ); + mMisc.oldMailAgeSpin->setValue(1); +// mMisc.oldMailAgeSpin->setMinValue(1); + rmvlay->addWidget( mMisc.oldMailAgeSpin ); + mMisc.timeUnitCombo = new QComboBox( group ); + mMisc.timeUnitCombo->insertItem(i18n("month(s)")); + mMisc.timeUnitCombo->insertItem(i18n("week(s)")); + mMisc.timeUnitCombo->insertItem(i18n("day(s)")); + rmvlay->addWidget( mMisc.timeUnitCombo ); + rmvlay->addStretch( 100 ); + + + + //---------- group: folders + group = new QGroupBox( i18n("&Folders"), page ); + topLevel->addWidget( group ); mMisc.sendOutboxCheck = new QCheckBox(i18n("Send Mail in outbox Folder on Check"), group ); vlay->addWidget( mMisc.sendOutboxCheck ); @@ -1661,8 +1699,20 @@ void ConfigureDialog::setupMiscPage( voi KConfig &config = *kapp->config(); config.setGroup("General"); - bool state = config.readBoolEntry("empty-trash-on-exit",true); + bool state = config.readBoolEntry("empty-trash-on-exit",false); mMisc.emptyTrashCheck->setChecked( state ); + + state = config.readBoolEntry("keep-small-trash", true); + mMisc.keepSmallTrashCheck->setChecked( state ); + int num = config.readNumEntry("small-trash-size", 1); + mMisc.smallTrashSizeSpin->setValue( num ); + + state = config.readBoolEntry("remove-old-mail-from-trash", true); + mMisc.removeOldMailCheck->setChecked( state ); + num = config.readNumEntry("old-mail-age", 1); + mMisc.oldMailAgeSpin->setValue( num ); + num = config.readNumEntry("old-mail-age-unit", 1); + mMisc.timeUnitCombo->setCurrentItem( num ); state = config.readBoolEntry("sendOnCheck", false); mMisc.sendOutboxCheck->setChecked( state ); state = config.readBoolEntry("send-receipts", false ); @@ -2055,6 +2105,18 @@ void ConfigureDialog::slotDoApply( bool config.setGroup("General"); config.writeEntry( "empty-trash-on-exit", mMisc.emptyTrashCheck->isChecked() ); + + config.writeEntry( "keep-small-trash", + mMisc.keepSmallTrashCheck->isChecked() ); + config.writeEntry( "small-trash-size", + mMisc.smallTrashSizeSpin->value() ); + + config.writeEntry( "remove-old-mail-from-trash", + mMisc.removeOldMailCheck->isChecked() ); + config.writeEntry( "old-mail-age", + mMisc.oldMailAgeSpin->value() ); + config.writeEntry( "old-mail-age-unit", + mMisc.timeUnitCombo->currentItem() ); config.writeEntry( "sendOnCheck", mMisc.sendOutboxCheck->isChecked() ); config.writeEntry( "send-receipts", @@ -3092,6 +3154,15 @@ void ConfigureDialog::slotMailCommandCho } } +void ConfigureDialog::slotEmptyTrashState( int state) +{ + bool on = ( state == 0 ); // button not checked + mMisc.removeOldMailCheck->setEnabled( on ); + mMisc.oldMailAgeSpin->setEnabled( on ); + mMisc.timeUnitCombo->setEnabled( on ); + mMisc.keepSmallTrashCheck->setEnabled( on ); + mMisc.smallTrashSizeSpin->setEnabled( on ); +} IdentityEntry::IdentityEntry( void ) { Index: configuredialog.h =================================================================== RCS file: /cvs/kdenetwork/kmail/configuredialog.h,v retrieving revision 1.30 diff -u -3 -p -r1.30 configuredialog.h --- configuredialog.h 2001/01/25 21:46:28 1.30 +++ configuredialog.h 2001/01/30 16:11:56 @@ -24,6 +24,7 @@ class QButtonGroup; class QCheckBox; class QComboBox; +class KIntNumInput; class QLabel; class QLineEdit; class QListViewItem; @@ -361,6 +362,11 @@ class ConfigureDialog : public KDialogBa { int pageIndex; QCheckBox *emptyTrashCheck; + QCheckBox *keepSmallTrashCheck; + KIntNumInput *smallTrashSizeSpin; + QCheckBox *removeOldMailCheck; + KIntNumInput *oldMailAgeSpin; + QComboBox *timeUnitCombo; QCheckBox *sendOutboxCheck; QCheckBox *sendReceiptCheck; QCheckBox *compactOnExitCheck; @@ -473,6 +479,7 @@ class ConfigureDialog : public KDialogBa void slotMailCommandSelectionChanged( void ); void slotExternalEditorChooser( void ); void slotMailCommandChooser( void ); + void slotEmptyTrashState( int ); private: IdentityWidget mIdentity; Index: kmfolder.cpp =================================================================== RCS file: /cvs/kdenetwork/kmail/kmfolder.cpp,v retrieving revision 1.127 diff -u -3 -p -r1.127 kmfolder.cpp --- kmfolder.cpp 2001/01/17 19:20:53 1.127 +++ kmfolder.cpp 2001/01/30 16:11:57 @@ -2,6 +2,7 @@ // Author: Stefan Taferner #include +#include #include "kmglobal.h" #include "kmfolder.h" @@ -834,9 +835,127 @@ void KMFolder::quiet(bool beQuiet) //----------------------------------------------------------------------------- + +// Needed to use QSortedList to sort the messages by date +/** Compare message's date. This is useful for message sorting */ +inline int operator<( KMMsgBase & m1, KMMsgBase & m2 ) +{ + return (m1.date() < m2.date()); +} + +/** Compare message's date. This is useful for message sorting */ +inline int operator==( KMMsgBase & m1, KMMsgBase & m2 ) +{ + return (m1.date() == m2.date()); +} + +//----------------------------------------------------------------------------- +int KMFolder::reduceSize( int aSize ) +{ + //kdDebug() << "Reducing folder to size of " << aSize << " Mo" << endl; + QSortedList * slice=0L; + QList< QSortedList > sliceArr; + KMMsgBase* mb; + ulong folderSize, msgSize, sliceSize, firstSliceSize, lastSliceSize, size; + int sliceIndex; + int delMsg = 0; + int i; + + sliceArr.setAutoDelete( true ); + +// Is it 1000 or 1024 ? +#define KILO (1000) + + size = KILO * KILO * aSize; // to have size in Ko; + sliceSize = KILO * KILO ; // slice of 1 Mo + lastSliceSize = 10 * sliceSize; // last slice is for item > 10 Mo + firstSliceSize = sliceSize / 2; // first slice is for < 500 Ko + folderSize = 0; + + for(i=0; i<12; i++) { + sliceArr.append( new QSortedList ); + sliceArr.at(i)->setAutoDelete(false); + } + + for (i=count()-1; i>=0; i--) { + mb = getMsgBase(i); + assert(mb); + msgSize = mb->msgSize(); + folderSize += msgSize; + + if (msgSize < firstSliceSize) { + sliceIndex = 0; + } else if (msgSize >= lastSliceSize) { + sliceIndex = 11; + } else { + sliceIndex = 1 + (int) (msgSize / sliceSize); // 1 <= n < 10 + } + + sliceArr.at(sliceIndex)->append( mb ); + } + + //kdDebug() << "Folder size : " << (folderSize/KILO) << " ko" << endl; + + // Ok, now we have our slices + + slice = sliceArr.last(); + while (folderSize > size) { + //kdDebug() << "Treating slice " << sliceArr.at()-1 << " Mo : " << slice->count() << endl; + assert( slice ); + + slice->sort(); + + // Empty this slice taking the oldest mails first: + while( slice->count() > 0 && folderSize > size ) { + mb = slice->take(0); + msgSize = mb->msgSize(); + //kdDebug() << "deleting msg : " << (msgSize / KILO) << " ko - " << mb->subject() << " - " << mb->dateStr(); + assert( folderSize >= msgSize ); + folderSize -= msgSize; + delMsg++; + removeMsg(mb); + } + + slice = sliceArr.prev(); + + } + + return delMsg; +} + + + +//----------------------------------------------------------------------------- +int KMFolder::expungeOldMsg(int days) +{ + int i, msgnb=0; + time_t msgTime, maxTime; + KMMsgBase* mb; + QValueList rmvMsgList; + + maxTime = time(0L) - days * 3600 * 24; + + for (i=count()-1; i>=0; i--) { + mb = getMsgBase(i); + assert(mb); + msgTime = mb->date(); + + if (msgTime < maxTime) { + //kdDebug() << "deleting msg " << i << " : " << mb->subject() << " - " << mb->dateStr(); + removeMsg( i ); + msgnb++; + } + } + return msgnb; +} + + +//----------------------------------------------------------------------------- void KMFolder::removeMsg(KMMsgBasePtr aMsg) { - removeMsg(find(aMsg)); + int idx = find(aMsg); + assert( idx != -1); + removeMsg(idx); } Index: kmfolder.h =================================================================== RCS file: /cvs/kdenetwork/kmail/kmfolder.h,v retrieving revision 1.36 diff -u -3 -p -r1.36 kmfolder.h --- kmfolder.h 2001/01/13 13:13:02 1.36 +++ kmfolder.h 2001/01/30 16:11:57 @@ -115,6 +115,14 @@ public: virtual void removeMsg(int i); virtual void removeMsg(KMMsgBasePtr msg); + /** Delete messages in the folder that are older than days. Return the + * number of deleted messages. */ + virtual int expungeOldMsg(int days); + + /** Delete messages until the size of the folder goes below size Mo. + * Returns the number of deleted messages. */ + virtual int reduceSize( int size ); + /** Detaches the given message from it's current folder and adds it to this folder. Returns zero on success and an errno error code on failure. The index of the new message is stored in index_return Index: kmfoldertree.cpp =================================================================== RCS file: /cvs/kdenetwork/kmail/kmfoldertree.cpp,v retrieving revision 1.87 diff -u -3 -p -r1.87 kmfoldertree.cpp --- kmfoldertree.cpp 2001/01/25 21:46:28 1.87 +++ kmfoldertree.cpp 2001/01/30 16:11:58 @@ -647,6 +647,9 @@ void KMFolderTree::rightButtonPressed(QL SLOT(slotModifyFolder())); folderMenu->insertItem(i18n("C&ompact"), topLevelWidget(), SLOT(slotCompactFolder())); + int m5 = folderMenu->insertItem(i18n("&Clean up"), topLevelWidget(), + SLOT(slotCleanupTrash())); + folderMenu->setItemEnabled(m5, false); folderMenu->insertSeparator(); folderMenu->insertItem(i18n("&Empty"), topLevelWidget(), SLOT(slotEmptyFolder())); @@ -662,6 +665,10 @@ void KMFolderTree::rightButtonPressed(QL folderMenu->setItemEnabled(m1,false); folderMenu->setItemEnabled(m2,false); folderMenu->setItemEnabled(m3,false); + + if (fti->folder->idString() == kernel->trashFolder()->idString() ) { + folderMenu->setItemEnabled(m5, true); + } } if (!fti->folder->isMailingList()) { Index: kmheaders.cpp =================================================================== RCS file: /cvs/kdenetwork/kmail/kmheaders.cpp,v retrieving revision 1.226 diff -u -3 -p -r1.226 kmheaders.cpp --- kmheaders.cpp 2001/01/25 21:46:28 1.226 +++ kmheaders.cpp 2001/01/30 16:11:59 @@ -1338,7 +1338,7 @@ void KMHeaders::copyMsgToFolder (KMFolde KMMessageList* msgList; KMMsgBase *msgBase; KMMessage *msg, *newMsg; - int top, rc, idx; + int top, rc, idx=-1; bool isMessage; if (!destFolder) return; Index: kmkernel.cpp =================================================================== RCS file: /cvs/kdenetwork/kmail/kmkernel.cpp,v retrieving revision 1.36 diff -u -3 -p -r1.36 kmkernel.cpp --- kmkernel.cpp 2001/01/19 14:41:43 1.36 +++ kmkernel.cpp 2001/01/30 16:12:00 @@ -498,17 +498,57 @@ bool KMKernel::doSessionManagement() return false; // no, we were not restored } -void KMKernel::cleanup(void) +void KMKernel::cleanup_trash(void) { - the_shuttingDown = TRUE; KConfig* config = kapp->config(); - if (the_trashFolder) { + the_trashFolder->close(TRUE); config->setGroup("General"); if (config->readBoolEntry("empty-trash-on-exit", true)) the_trashFolder->expunge(); + + if (config->readBoolEntry("remove-old-mail-from-trash", true) + || (config->readBoolEntry("keep-small-trash", true)) ) { + the_trashFolder->open(); + the_trashFolder->quiet(true); + } + + if (config->readBoolEntry("remove-old-mail-from-trash", true)) { + int age; + int old_age = config->readNumEntry("old-mail-age", 1); + int age_unit = config->readNumEntry("old-mail-age-unit", 1); + if (age_unit == 0) { // month + age = 31 * old_age; + } else if (age_unit == 1) { // week + age = 7 * old_age; + } else if (age_unit == 2) { // day + age = old_age; + } else { + kdDebug() << "Unknown unit for mail age : " << old_age << endl; + age = old_age; + } + kdDebug() << "Removing mail older than " << age << " days" << endl; + the_trashFolder->expungeOldMsg( age ); + } + + if (config->readBoolEntry("keep-small-trash", true)) { + int size = config->readNumEntry("small-trash-size", 10); + the_trashFolder->reduceSize( size ); + } + + the_trashFolder->close(); + the_trashFolder->compact(); + kdDebug() << "trash clean-up done."; } +} + +void KMKernel::cleanup(void) +{ + the_shuttingDown = TRUE; + KConfig* config = kapp->config(); + + cleanup_trash(); if (the_folderMgr) { if (config->readBoolEntry("compact-all-on-exit", true)) Index: kmkernel.h =================================================================== RCS file: /cvs/kdenetwork/kmail/kmkernel.h,v retrieving revision 1.14 diff -u -3 -p -r1.14 kmkernel.h --- kmkernel.h 2001/01/04 01:25:50 1.14 +++ kmkernel.h 2001/01/30 16:12:01 @@ -55,6 +55,7 @@ public: void testDir(const char *_name); void recoverDeadLetters(void); void initFolders(KConfig* cfg); + void cleanup_trash(void); void cleanup(void); void quit(); void transferMail(void); Index: kmmainwin.cpp =================================================================== RCS file: /cvs/kdenetwork/kmail/kmmainwin.cpp,v retrieving revision 1.257 diff -u -3 -p -r1.257 kmmainwin.cpp --- kmmainwin.cpp 2001/01/17 19:46:39 1.257 +++ kmmainwin.cpp 2001/01/30 16:12:01 @@ -629,7 +629,7 @@ void KMMainWin::slotMailChecked(bool new return; if (mBeepOnNew) { - KNotifyClient::beep(); + //KNotifyClient::beep(); } // FIXME: change system() to a KProcess @@ -1370,7 +1370,15 @@ void KMMainWin::slotMsgPopup(const KURL } } +//----------------------------------------------------------------------------- +void KMMainWin::slotCleanupTrash() +{ + statusMsg("Cleaning up trash folder"); + kernel->cleanup_trash(); + statusMsg("Trash folder cleaned up!"); +} + //----------------------------------------------------------------------------- void KMMainWin::getAccountMenu() { @@ -1398,6 +1406,10 @@ void KMMainWin::setupMenuBar() KStdAction::print (this, SLOT(slotPrintMsg()), actionCollection()); + (void) new KAction( i18n("Clean up trash folder"), 0, + this , SLOT(slotCleanupTrash()), + actionCollection(), "clean_up_trash_folder" ); + (void) new KAction( i18n("Compact all &folders"), 0, kernel->folderMgr(), SLOT(compactAll()), actionCollection(), "compact_all_folders" ); @@ -1588,7 +1600,7 @@ void KMMainWin::setupMenuBar() (void) new KAction( i18n("F&ilter Rules..."), 0, this, SLOT(slotFilter()), actionCollection(), "filter" ); - createGUI( "kmmainwin.rc", false ); + createGUI( "phil-kmmainwin.rc", false ); QObject::connect( guiFactory()->container("folder", this), SIGNAL( aboutToShow() ), this, SLOT( updateFolderMenu() )); Index: kmmainwin.h =================================================================== RCS file: /cvs/kdenetwork/kmail/kmmainwin.h,v retrieving revision 1.76 diff -u -3 -p -r1.76 kmmainwin.h --- kmmainwin.h 2000/12/14 14:19:13 1.76 +++ kmmainwin.h 2001/01/30 16:12:01 @@ -159,6 +159,7 @@ protected slots: void slotSearch(); void slotSearchClosed(); void slotFind(); + void slotCleanupTrash(); /** etc. */ void slotMsgActivated(KMMessage*); Index: kmmainwin.rc =================================================================== RCS file: /cvs/kdenetwork/kmail/kmmainwin.rc,v retrieving revision 1.14 diff -u -3 -p -r1.14 kmmainwin.rc --- kmmainwin.rc 2000/12/11 09:08:02 1.14 +++ kmmainwin.rc 2001/01/30 16:12:02 @@ -7,6 +7,7 @@ + Index: kmmsgbase.h =================================================================== RCS file: /cvs/kdenetwork/kmail/kmmsgbase.h,v retrieving revision 1.23 diff -u -3 -p -r1.23 kmmsgbase.h --- kmmsgbase.h 2000/12/08 09:49:25 1.23 +++ kmmsgbase.h 2001/01/30 16:12:02 @@ -148,6 +148,7 @@ public: /** Decode given string as described in RFC2231 */ static const QString decodeRFC2231String(const QString& aStr); + protected: KMFolder* mParent; unsigned long mFolderOffset, mMsgSize; Index: kmreaderwin.cpp =================================================================== RCS file: /cvs/kdenetwork/kmail/kmreaderwin.cpp,v retrieving revision 1.236 diff -u -3 -p -r1.236 kmreaderwin.cpp --- kmreaderwin.cpp 2001/01/25 21:46:28 1.236 +++ kmreaderwin.cpp 2001/01/30 16:12:03 @@ -339,10 +339,10 @@ void KMReaderWin::initHtmlWidget(void) { mViewer = new KHTMLPart(this, "khtml"); // Let's better be paranoid and disable plugins (it defaults to enabled): - mViewer->enablePlugins(false); + //mViewer->enablePlugins(false); mViewer->enableJScript(false); // just make this explicit mViewer->enableJava(false); // just make this explicit - mViewer->enableMetaRefresh(false); + //mViewer->enableMetaRefresh(false); mViewer->widget()->resize(width()-16, height()-110); mViewer->setURLCursor(KCursor::handCursor());