mutt: 1.6.0 -> 1.6.2

This commit is contained in:
rnhmjoj 2016-07-09 05:13:52 +02:00
parent 599cf0fe50
commit 8745e47909
No known key found for this signature in database
GPG key ID: 362BB82B7E496B7C
10 changed files with 4652 additions and 1807 deletions

View file

@ -1,43 +1,51 @@
{ stdenv, fetchurl, ncurses, which, perl, autoreconfHook
, sslSupport ? true
, imapSupport ? true
, headerCache ? true
, saslSupport ? true
, gpgmeSupport ? true
, gdbm ? null
, openssl ? null
, cyrus_sasl ? null
, gpgme ? null
, withSidebar ? false
, aclocal ? null
, headerCache ? true
, sslSupport ? true
, saslSupport ? true
, gpgmeSupport ? true
, imapSupport ? true
, withSidebar ? false
, withTrash ? false
}:
assert headerCache -> gdbm != null;
assert sslSupport -> openssl != null;
assert saslSupport -> cyrus_sasl != null;
assert gpgmeSupport -> gpgme != null;
assert headerCache -> gdbm != null;
assert sslSupport -> openssl != null;
assert saslSupport -> cyrus_sasl != null;
assert gpgmeSupport -> gpgme != null;
with stdenv.lib;
let
version = "1.6.0";
in
stdenv.mkDerivation rec {
name = "mutt${stdenv.lib.optionalString withSidebar "-with-sidebar"}-${version}";
name = "mutt-${version}";
version = "1.6.2";
src = fetchurl {
url = "http://ftp.mutt.org/pub/mutt/mutt-${version}.tar.gz";
sha256 = "06bc2drbgalkk68rzg7hq2v5m5qgjxff5357wg0419dpi8ivdbr9";
url = "http://ftp.mutt.org/pub/mutt/${name}.tar.gz";
sha256 = "13hxmji7v9m2agmvzrs7gzx8s3c9jiwrv7pbkr7z1kc6ckq2xl65";
};
buildInputs = with stdenv.lib;
buildInputs =
[ ncurses which perl ]
++ optional headerCache gdbm
++ optional sslSupport openssl
++ optional saslSupport cyrus_sasl
++ optional gpgmeSupport gpgme;
nativeBuildInputs = stdenv.lib.optional withSidebar autoreconfHook;
++ optional headerCache gdbm
++ optional sslSupport openssl
++ optional saslSupport cyrus_sasl
++ optional gpgmeSupport gpgme
++ optional withSidebar autoreconfHook;
configureFlags = [
"--with-mailpath=" "--enable-smtp"
(enableFeature headerCache "hcache")
(enableFeature gpgmeSupport "gpgme")
(enableFeature imapSupport "imap")
(enableFeature withSidebar "sidebar")
"--enable-smtp"
"--enable-pop"
"--enable-imap"
"--with-mailpath="
# Look in $PATH at runtime, instead of hardcoding /usr/bin/sendmail
"ac_cv_path_SENDMAIL=sendmail"
@ -45,36 +53,22 @@ stdenv.mkDerivation rec {
# This allows calls with "-d N", that output debug info into ~/.muttdebug*
"--enable-debug"
"--enable-pop" "--enable-imap"
# The next allows building mutt without having anything setgid
# set by the installer, and removing the need for the group 'mail'
# I set the value 'mailbox' because it is a default in the configure script
"--with-homespool=mailbox"
(if headerCache then "--enable-hcache" else "--disable-hcache")
(if sslSupport then "--with-ssl" else "--without-ssl")
(if imapSupport then "--enable-imap" else "--disable-imap")
(if saslSupport then "--with-sasl" else "--without-sasl")
(if gpgmeSupport then "--enable-gpgme" else "--disable-gpgme")
];
] ++ optional sslSupport "--with-ssl"
++ optional saslSupport "--with-sasl";
# Adding the sidebar
patches = stdenv.lib.optional withSidebar [
./trash-folder.patch
./sidebar.patch
./sidebar-dotpathsep.patch
./sidebar-utf8.patch
./sidebar-newonly.patch
./sidebar-delimnullwide.patch
./sidebar-compose.patch
./sidebar-new.patch
];
patches =
optional withTrash ./trash.patch ++
optional withSidebar ./sidebar.patch;
meta = with stdenv.lib; {
meta = {
description = "A small but very powerful text-based mail client";
homepage = http://www.mutt.org;
license = stdenv.lib.licenses.gpl2Plus;
license = licenses.gpl2Plus;
platforms = platforms.unix;
maintainers = with maintainers; [ the-kenny ];
maintainers = with maintainers; [ the-kenny rnhmjoj ];
};
}

View file

@ -1,40 +0,0 @@
From: Evgeni Golov <evgeni@debian.org>
Date: Fri, 14 Mar 2014 08:54:47 +0100
Subject: sidebar-compose
draw_sidebar sets SidebarWidth to 0 when sidebar_visible is false.
However, if you start mutt in compose mode, draw_sidebar won't be
called until the next redraw and your header lines will be off by
the width of the sidebar, even when you did not want a sidebar at
all.
Can be tested with:
HOME=/ LC_ALL=C mutt -e 'unset sidebar_visible' -s test recipient
Closes: #502627
Gbp-Pq: Topic mutt-patched
---
compose.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/compose.c b/compose.c
index b63695f..0fa6df2 100644
--- a/compose.c
+++ b/compose.c
@@ -32,6 +32,7 @@
#include "mailbox.h"
#include "sort.h"
#include "charset.h"
+#include "sidebar.h"
#ifdef MIXMASTER
#include "remailer.h"
@@ -248,6 +249,7 @@ static void draw_envelope_addr (int line, ADDRESS *addr)
static void draw_envelope (HEADER *msg, char *fcc)
{
+ draw_sidebar (MENU_COMPOSE);
draw_envelope_addr (HDR_FROM, msg->env->from);
draw_envelope_addr (HDR_TO, msg->env->to);
draw_envelope_addr (HDR_CC, msg->env->cc);

View file

@ -1,38 +0,0 @@
From: Evgeni Golov <sargentd@die-welt.net>
Date: Wed, 5 Mar 2014 17:46:07 +0100
Subject: sidebar-delimnullwide
SidebarDelim can be NULL and strlen(NULL) is a bad idea, as it will segfault.
Wrap it with NONULL().
While at it, change strlen to mbstowcs for better utf8 support.
Closes: #696145, #663883
Gbp-Pq: Topic mutt-patched
---
sidebar.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/sidebar.c b/sidebar.c
index 51a25ca..c3ea338 100644
--- a/sidebar.c
+++ b/sidebar.c
@@ -88,7 +88,7 @@ char *make_sidebar_entry(char *box, int size, int new, int flagged)
int box_len, box_bytes;
int int_len;
int right_offset = 0;
- int delim_len = strlen(SidebarDelim);
+ int delim_len = mbstowcs(NULL, NONULL(SidebarDelim), 0);
static char *entry;
right_width = left_width = 0;
@@ -178,7 +178,7 @@ int draw_sidebar(int menu) {
#ifndef USE_SLANG_CURSES
attr_t attrs;
#endif
- short delim_len = strlen(SidebarDelim);
+ short delim_len = mbstowcs(NULL, NONULL(SidebarDelim), 0);
short color_pair;
static bool initialized = false;

View file

@ -1,98 +0,0 @@
From: Fabian Groffen <grobian@gentoo.org>
Date: Tue, 4 Mar 2014 21:12:15 +0100
Subject: sidebar-dotpathsep
Make path separators for sidebar folders configurable.
When using IMAP, a '.' is often used as path separator, hence make the
path separators configurable through sidebar_delim_chars variable.
It defaults to "/." to work for both mboxes as well as IMAP folders. It
can be set to only "/" or "." or whichever character desired as needed.
Gbp-Pq: Topic mutt-patched
---
globals.h | 1 +
init.h | 8 ++++++++
sidebar.c | 31 ++++++++++++++++++++++++-------
3 files changed, 33 insertions(+), 7 deletions(-)
diff --git a/globals.h b/globals.h
index 004c795..602f932 100644
--- a/globals.h
+++ b/globals.h
@@ -119,6 +119,7 @@ WHERE char *SendCharset;
WHERE char *Sendmail;
WHERE char *Shell;
WHERE char *SidebarDelim;
+WHERE char *SidebarDelimChars INITVAL (NULL);
WHERE char *Signature;
WHERE char *SimpleSearch;
#if USE_SMTP
diff --git a/init.h b/init.h
index c664e5f..166671b 100644
--- a/init.h
+++ b/init.h
@@ -2051,6 +2051,14 @@ struct option_t MuttVars[] = {
** .pp
** The width of the sidebar.
*/
+ { "sidebar_delim_chars", DT_STR, R_NONE, UL &SidebarDelimChars, UL "/." },
+ /*
+ ** .pp
+ ** This contains the list of characters which you would like to treat
+ ** as folder separators for displaying paths in the sidebar. If
+ ** you're not using IMAP folders, you probably prefer setting this to "/"
+ ** alone.
+ */
{ "pgp_use_gpg_agent", DT_BOOL, R_NONE, OPTUSEGPGAGENT, 0},
/*
** .pp
diff --git a/sidebar.c b/sidebar.c
index 6098c2a..4356ffc 100644
--- a/sidebar.c
+++ b/sidebar.c
@@ -249,20 +249,37 @@ int draw_sidebar(int menu) {
// calculate depth of current folder and generate its display name with indented spaces
int sidebar_folder_depth = 0;
char *sidebar_folder_name;
- sidebar_folder_name = basename(tmp->path);
+ int i;
+ sidebar_folder_name = tmp->path;
+ /* disregard a trailing separator, so strlen() - 2
+ * https://bugs.gentoo.org/show_bug.cgi?id=373197#c16 */
+ for (i = strlen(sidebar_folder_name) - 2; i >= 0; i--) {
+ if (SidebarDelimChars &&
+ strchr(SidebarDelimChars, sidebar_folder_name[i]))
+ {
+ sidebar_folder_name += i + 1;
+ break;
+ }
+ }
if ( maildir_is_prefix ) {
char *tmp_folder_name;
- int i;
+ int lastsep = 0;
tmp_folder_name = tmp->path + strlen(Maildir);
- for (i = 0; i < strlen(tmp->path) - strlen(Maildir); i++) {
- if (tmp_folder_name[i] == '/') sidebar_folder_depth++;
- }
+ for (i = 0; i < strlen(tmp_folder_name) - 1; i++) {
+ if (SidebarDelimChars &&
+ strchr(SidebarDelimChars, tmp_folder_name[i]))
+ {
+ sidebar_folder_depth++;
+ lastsep = i + 1;
+ }
+ }
if (sidebar_folder_depth > 0) {
- sidebar_folder_name = malloc(strlen(basename(tmp->path)) + sidebar_folder_depth + 1);
+ tmp_folder_name += lastsep; /* basename */
+ sidebar_folder_name = malloc(strlen(tmp_folder_name) + sidebar_folder_depth + 1);
for (i=0; i < sidebar_folder_depth; i++)
sidebar_folder_name[i]=' ';
sidebar_folder_name[i]=0;
- strncat(sidebar_folder_name, basename(tmp->path), strlen(basename(tmp->path)) + sidebar_folder_depth);
+ strncat(sidebar_folder_name, tmp_folder_name, strlen(tmp_folder_name) + sidebar_folder_depth);
}
}
printw( "%.*s", SidebarWidth - delim_len + 1,

View file

@ -1,97 +0,0 @@
From 355399bde98203af59d20821f9e840fc056bd383 Mon Sep 17 00:00:00 2001
From: Julius Haertl <jus@bitgrid.net>
Date: Tue, 9 Sep 2014 22:31:49 +0200
Subject: Patch for sidebar iteration functionality
sidebar-new will move the selected folder to the next with new messages.
If the end is reached, it will start at the top.
Useful macros would be:
macro index <esc>a "<sidebar-new><sidebar-open>"
macro pager <esc>a "<exit><sidebar-new><sidebar-open>"
---
OPS | 1 +
curs_main.c | 1 +
functions.h | 2 ++
pager.c | 1 +
sidebar.c | 10 ++++++++++
5 files changed, 15 insertions(+)
diff --git a/OPS b/OPS
index 1ed9c96..3ffb82a 100644
--- a/OPS
+++ b/OPS
@@ -187,3 +187,4 @@ OP_SIDEBAR_PREV "go to previous mailbox"
OP_SIDEBAR_OPEN "open hilighted mailbox"
OP_SIDEBAR_NEXT_NEW "go down to next mailbox with new mail"
OP_SIDEBAR_PREV_NEW "go to previous mailbox with new mail"
+OP_SIDEBAR_NEW "iterate though mailboxes with new mail"
diff --git a/curs_main.c b/curs_main.c
index acb106d..2e35f90 100644
--- a/curs_main.c
+++ b/curs_main.c
@@ -2328,6 +2328,7 @@ int mutt_index_menu (void)
case OP_SIDEBAR_PREV:
case OP_SIDEBAR_NEXT_NEW:
case OP_SIDEBAR_PREV_NEW:
+ case OP_SIDEBAR_NEW:
scroll_sidebar(op, menu->menu);
break;
default:
diff --git a/functions.h b/functions.h
index 363b4d5..1485080 100644
--- a/functions.h
+++ b/functions.h
@@ -176,6 +176,7 @@ const struct binding_t OpMain[] = { /* map: index */
{ "sidebar-prev", OP_SIDEBAR_PREV, NULL },
{ "sidebar-next-new", OP_SIDEBAR_NEXT_NEW, NULL},
{ "sidebar-prev-new", OP_SIDEBAR_PREV_NEW, NULL},
+ { "sidebar-new", OP_SIDEBAR_NEW, NULL },
{ "sidebar-open", OP_SIDEBAR_OPEN, NULL },
{ NULL, 0, NULL }
};
@@ -287,6 +288,7 @@ const struct binding_t OpPager[] = { /* map: pager */
{ "sidebar-prev", OP_SIDEBAR_PREV, NULL },
{ "sidebar-next-new", OP_SIDEBAR_NEXT_NEW, NULL},
{ "sidebar-prev-new", OP_SIDEBAR_PREV_NEW, NULL},
+ { "sidebar-new", OP_SIDEBAR_NEW, NULL },
{ "sidebar-open", OP_SIDEBAR_OPEN, NULL },
{ NULL, 0, NULL }
};
diff --git a/pager.c b/pager.c
index 8d64fe1..696e55c 100644
--- a/pager.c
+++ b/pager.c
@@ -2791,6 +2791,7 @@ search_next:
case OP_SIDEBAR_PREV:
case OP_SIDEBAR_NEXT_NEW:
case OP_SIDEBAR_PREV_NEW:
+ case OP_SIDEBAR_NEW:
scroll_sidebar(ch, MENU_PAGER);
break;
diff --git a/sidebar.c b/sidebar.c
index c3ea338..eb8ecd2 100644
--- a/sidebar.c
+++ b/sidebar.c
@@ -429,6 +429,16 @@ void scroll_sidebar(int op, int menu)
CurBuffy = CurBuffy->next;
}
break;
+ case OP_SIDEBAR_NEW:
+ if ( (tmp = exist_next_new()) == NULL)
+ tmp = TopBuffy;
+ if ( tmp->msg_unread == 0 ) {
+ CurBuffy = tmp;
+ tmp = exist_next_new();
+ }
+ if ( tmp != NULL )
+ CurBuffy = tmp;
+ break;
default:
return;
}
--
2.6.0.rc0.2.g7662973.dirty

View file

@ -1,198 +0,0 @@
From: Steve Kemp <steve@steve.org.uk>
Date: Tue, 4 Mar 2014 22:07:06 +0100
Subject: sidebar-newonly
patches written by Steve Kemp, it adds two new functionalities to the sidebar,
so only the mailbox with new messages will be shown (and/or) selected
See Debian bug http://bugs.debian.org/532510
Gbp-Pq: Topic mutt-patched
---
OPS | 2 ++
curs_main.c | 2 ++
functions.h | 4 ++++
init.h | 5 +++++
mutt.h | 2 ++
pager.c | 2 ++
sidebar.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
7 files changed, 70 insertions(+), 2 deletions(-)
diff --git a/OPS b/OPS
index b036db9..1ed9c96 100644
--- a/OPS
+++ b/OPS
@@ -185,3 +185,5 @@ OP_SIDEBAR_SCROLL_DOWN "scroll the mailbox pane down 1 page"
OP_SIDEBAR_NEXT "go down to next mailbox"
OP_SIDEBAR_PREV "go to previous mailbox"
OP_SIDEBAR_OPEN "open hilighted mailbox"
+OP_SIDEBAR_NEXT_NEW "go down to next mailbox with new mail"
+OP_SIDEBAR_PREV_NEW "go to previous mailbox with new mail"
diff --git a/curs_main.c b/curs_main.c
index ea530a6..acb106d 100644
--- a/curs_main.c
+++ b/curs_main.c
@@ -2326,6 +2326,8 @@ int mutt_index_menu (void)
case OP_SIDEBAR_SCROLL_DOWN:
case OP_SIDEBAR_NEXT:
case OP_SIDEBAR_PREV:
+ case OP_SIDEBAR_NEXT_NEW:
+ case OP_SIDEBAR_PREV_NEW:
scroll_sidebar(op, menu->menu);
break;
default:
diff --git a/functions.h b/functions.h
index ef8937a..363b4d5 100644
--- a/functions.h
+++ b/functions.h
@@ -174,6 +174,8 @@ const struct binding_t OpMain[] = { /* map: index */
{ "sidebar-scroll-down", OP_SIDEBAR_SCROLL_DOWN, NULL },
{ "sidebar-next", OP_SIDEBAR_NEXT, NULL },
{ "sidebar-prev", OP_SIDEBAR_PREV, NULL },
+ { "sidebar-next-new", OP_SIDEBAR_NEXT_NEW, NULL},
+ { "sidebar-prev-new", OP_SIDEBAR_PREV_NEW, NULL},
{ "sidebar-open", OP_SIDEBAR_OPEN, NULL },
{ NULL, 0, NULL }
};
@@ -283,6 +285,8 @@ const struct binding_t OpPager[] = { /* map: pager */
{ "sidebar-scroll-down", OP_SIDEBAR_SCROLL_DOWN, NULL },
{ "sidebar-next", OP_SIDEBAR_NEXT, NULL },
{ "sidebar-prev", OP_SIDEBAR_PREV, NULL },
+ { "sidebar-next-new", OP_SIDEBAR_NEXT_NEW, NULL},
+ { "sidebar-prev-new", OP_SIDEBAR_PREV_NEW, NULL},
{ "sidebar-open", OP_SIDEBAR_OPEN, NULL },
{ NULL, 0, NULL }
};
diff --git a/init.h b/init.h
index 166671b..a5d4238 100644
--- a/init.h
+++ b/init.h
@@ -2059,6 +2059,11 @@ struct option_t MuttVars[] = {
** you're not using IMAP folders, you probably prefer setting this to "/"
** alone.
*/
+ {"sidebar_newmail_only", DT_BOOL, R_BOTH, OPTSIDEBARNEWMAILONLY, 0 },
+ /*
+ ** .pp
+ ** Show only new mail in the sidebar.
+ */
{ "pgp_use_gpg_agent", DT_BOOL, R_NONE, OPTUSEGPGAGENT, 0},
/*
** .pp
diff --git a/mutt.h b/mutt.h
index 5f25406..d73e514 100644
--- a/mutt.h
+++ b/mutt.h
@@ -529,6 +529,8 @@ enum
OPTDONTHANDLEPGPKEYS, /* (pseudo) used to extract PGP keys */
OPTUNBUFFEREDINPUT, /* (pseudo) don't use key buffer */
+ OPTSIDEBARNEWMAILONLY,
+
OPTMAX
};
diff --git a/pager.c b/pager.c
index 5cfcb75..8d64fe1 100644
--- a/pager.c
+++ b/pager.c
@@ -2789,6 +2789,8 @@ search_next:
case OP_SIDEBAR_SCROLL_DOWN:
case OP_SIDEBAR_NEXT:
case OP_SIDEBAR_PREV:
+ case OP_SIDEBAR_NEXT_NEW:
+ case OP_SIDEBAR_PREV_NEW:
scroll_sidebar(ch, MENU_PAGER);
break;
diff --git a/sidebar.c b/sidebar.c
index 8f58f85..51a25ca 100644
--- a/sidebar.c
+++ b/sidebar.c
@@ -269,8 +269,21 @@ int draw_sidebar(int menu) {
SETCOLOR(MT_COLOR_NEW);
else if ( tmp->msg_flagged > 0 )
SETCOLOR(MT_COLOR_FLAGGED);
- else
- SETCOLOR(MT_COLOR_NORMAL);
+ else {
+ /* make sure the path is either:
+ 1. Containing new mail.
+ 2. The inbox.
+ 3. The current box.
+ */
+ if ((option (OPTSIDEBARNEWMAILONLY)) &&
+ ( (tmp->msg_unread <= 0) &&
+ ( tmp != Incoming ) &&
+ Context &&
+ ( strcmp( tmp->path, Context->path ) != 0 ) ) )
+ continue;
+ else
+ SETCOLOR(MT_COLOR_NORMAL);
+ }
move( lines, 0 );
if ( Context && !strcmp( tmp->path, Context->path ) ) {
@@ -336,6 +349,29 @@ int draw_sidebar(int menu) {
return 0;
}
+BUFFY * exist_next_new()
+{
+ BUFFY *tmp = CurBuffy;
+ if(tmp == NULL) return NULL;
+ while (tmp->next != NULL)
+ {
+ tmp = tmp->next;
+ if(tmp->msg_unread) return tmp;
+ }
+ return NULL;
+}
+
+BUFFY * exist_prev_new()
+{
+ BUFFY *tmp = CurBuffy;
+ if(tmp == NULL) return NULL;
+ while (tmp->prev != NULL)
+ {
+ tmp = tmp->prev;
+ if(tmp->msg_unread) return tmp;
+ }
+ return NULL;
+}
void set_buffystats(CONTEXT* Context)
{
@@ -352,18 +388,33 @@ void set_buffystats(CONTEXT* Context)
void scroll_sidebar(int op, int menu)
{
+ BUFFY *tmp;
if(!SidebarWidth) return;
if(!CurBuffy) return;
switch (op) {
case OP_SIDEBAR_NEXT:
+ if (!option (OPTSIDEBARNEWMAILONLY)) {
if ( CurBuffy->next == NULL ) return;
CurBuffy = CurBuffy->next;
break;
+ }
+ case OP_SIDEBAR_NEXT_NEW:
+ if ( (tmp = exist_next_new()) == NULL)
+ return;
+ else CurBuffy = tmp;
+ break;
case OP_SIDEBAR_PREV:
+ if (!option (OPTSIDEBARNEWMAILONLY)) {
if ( CurBuffy->prev == NULL ) return;
CurBuffy = CurBuffy->prev;
break;
+ }
+ case OP_SIDEBAR_PREV_NEW:
+ if ( (tmp = exist_prev_new()) == NULL)
+ return;
+ else CurBuffy = tmp;
+ break;
case OP_SIDEBAR_SCROLL_UP:
CurBuffy = TopBuffy;
if ( CurBuffy != Incoming ) {

View file

@ -1,132 +0,0 @@
From: Antonio Radici <antonio@debian.org>
Date: Tue, 4 Mar 2014 15:39:14 +0100
Subject: sidebar-utf8
This patch fixes a problem with utf-8 strings and the sidebar,
it rewrites entirely make_sidebar_entry so it also fixes some
segfaults due to misallocations and overflows.
See:
http://bugs.debian.org/584581
http://bugs.debian.org/603287
Gbp-Pq: Topic mutt-patched
---
sidebar.c | 97 +++++++++++++++++++++++++++++++++++++++++++--------------------
1 file changed, 67 insertions(+), 30 deletions(-)
diff --git a/sidebar.c b/sidebar.c
index 4356ffc..8f58f85 100644
--- a/sidebar.c
+++ b/sidebar.c
@@ -30,6 +30,7 @@
#include <libgen.h>
#include "keymap.h"
#include <stdbool.h>
+#include <wchar.h>
/*BUFFY *CurBuffy = 0;*/
static BUFFY *TopBuffy = 0;
@@ -82,36 +83,72 @@ void calc_boundaries (int menu)
char *make_sidebar_entry(char *box, int size, int new, int flagged)
{
- static char *entry = 0;
- char *c;
- int i = 0;
- int delim_len = strlen(SidebarDelim);
-
- c = realloc(entry, SidebarWidth - delim_len + 2);
- if ( c ) entry = c;
- entry[SidebarWidth - delim_len + 1] = 0;
- for (; i < SidebarWidth - delim_len + 1; entry[i++] = ' ' );
- i = strlen(box);
- strncpy( entry, box, i < (SidebarWidth - delim_len + 1) ? i : (SidebarWidth - delim_len + 1) );
-
- if (size == -1)
- sprintf(entry + SidebarWidth - delim_len - 3, "?");
- else if ( new ) {
- if (flagged > 0) {
- sprintf(
- entry + SidebarWidth - delim_len - 5 - quick_log10(size) - quick_log10(new) - quick_log10(flagged),
- "% d(%d)[%d]", size, new, flagged);
- } else {
- sprintf(
- entry + SidebarWidth - delim_len - 3 - quick_log10(size) - quick_log10(new),
- "% d(%d)", size, new);
- }
- } else if (flagged > 0) {
- sprintf( entry + SidebarWidth - delim_len - 3 - quick_log10(size) - quick_log10(flagged), "% d[%d]", size, flagged);
- } else {
- sprintf( entry + SidebarWidth - delim_len - 1 - quick_log10(size), "% d", size);
- }
- return entry;
+ char int_store[20]; // up to 64 bits integers
+ int right_width, left_width;
+ int box_len, box_bytes;
+ int int_len;
+ int right_offset = 0;
+ int delim_len = strlen(SidebarDelim);
+ static char *entry;
+
+ right_width = left_width = 0;
+ box_len = box_bytes = 0;
+
+ // allocate an entry big enough to contain SidebarWidth wide chars
+ entry = malloc((SidebarWidth*4)+1); // TODO: error check
+
+ // determine the right space (i.e.: how big are the numbers that we want to print)
+ if ( size > 0 ) {
+ int_len = snprintf(int_store, sizeof(int_store), "%d", size);
+ right_width += int_len;
+ } else {
+ right_width = 1; // to represent 0
+ }
+ if ( new > 0 ) {
+ int_len = snprintf(int_store, sizeof(int_store), "%d", new);
+ right_width += int_len + 2; // 2 is for ()
+ }
+ if ( flagged > 0 ) {
+ int_len = snprintf(int_store, sizeof(int_store), "%d", flagged);
+ right_width += int_len + 2; // 2 is for []
+ }
+
+ // determine how much space we have for *box and its padding (if any)
+ left_width = SidebarWidth - right_width - 1 - delim_len; // 1 is for the space
+ //fprintf(stdout, "left_width: %d right_width: %d\n", left_width, right_width);
+ // right side overflow case
+ if ( left_width <= 0 ) {
+ snprintf(entry, SidebarWidth*4, "%-*.*s ...", SidebarWidth-4-delim_len, SidebarWidth-4-delim_len, box);
+ return entry;
+ }
+ right_width -= delim_len;
+
+ // to support utf-8 chars we need to add enough space padding in case there
+ // are less chars than bytes in *box
+ box_len = mbstowcs(NULL, box, 0);
+ box_bytes = strlen(box);
+ // debug
+ //fprintf(stdout, "box_len: %d box_bytes: %d (diff: %d)\n", box_len, box_bytes, (box_bytes-box_len));
+ // if there is less string than the space we allow, then we will add the
+ // spaces
+ if ( box_len != -1 && box_len < left_width ) {
+ left_width += (box_bytes - box_len);
+ }
+ // otherwise sprintf will truncate the string for us (therefore, no else case)
+
+ // print the sidebar entry (without new and flagged messages, at the moment)
+ //fprintf(stdout, "left_width: %d right_width: %d\n", left_width, right_width);
+ right_offset = snprintf(entry, SidebarWidth*4, "%-*.*s %d", left_width, left_width, box, size);
+
+ // then pad new and flagged messages if any
+ if ( new > 0 ) {
+ right_offset += snprintf(entry+right_offset, SidebarWidth*4-right_offset, "(%d)", new);
+ }
+ if ( flagged > 0 ) {
+ right_offset += snprintf(entry+right_offset, SidebarWidth*4-right_offset, "[%d]", flagged);
+ }
+
+ return entry;
}
void set_curbuffy(char buf[LONG_STRING])

File diff suppressed because it is too large Load diff

View file

@ -1,316 +0,0 @@
From: Cedric Duval <cedricduval@free.fr>
Date: Thu, 27 Feb 2014 12:27:41 +0100
Subject: trash-folder
With this patch, if the trash variable is set to a path (unset by default), the
deleted mails will be moved to a trash folder instead of being irremediably
purged when syncing the mailbox.
For instance, set trash="~/Mail/trash" will cause every deleted mail to go to
this folder.
Note that the append to the trash folder doesn't occur until the resync is
done. This allows you to change your mind and undo deletes, and thus the moves
to the trash folder are unnecessary.
Notes
* You might also want to have a look at the purge message feature below
which is related to this patch.
* IMAP is now supported. To retain the previous behavior, add this to your
muttrc:
folder-hook ^imap:// 'unset trash'
FAQ
Every once in a while, someone asks what are the advantages of this patch over
a macro based solution. Here's an attempt to answer this question:
* The folder history doesn't clutter up with unwanted trash entries.
* Delayed move to the trash allows to change one's mind.
* No need to treat the case of "normal folders" and trash folders
separately with folder-hooks, and to create two sets of macros (one for
the index, one for the pager).
* Works not only with delete-message, but also with every deletion
functions like delete-pattern, delete-thread or delete-subthread.
To sum up, it's more integrated and transparent to the user.
* Patch last synced with upstream:
- Date: 2007-02-15
- File: http://cedricduval.free.fr/mutt/patches/download/patch-1.5.5.1.cd.trash_folder.3.4
* Changes made:
- Updated to 1.5.13:
- structure of _mutt_save_message changed (commands.c)
- context of option (OPTCONFIRMAPPEND) changed (muttlib.c)
- Fixed indentation of "appended" in mutt.h.
Signed-off-by: Matteo F. Vescovi <mfvescovi@gmail.com>
Gbp-Pq: Topic features
---
commands.c | 1 +
flags.c | 19 +++++++++++++++++-
globals.h | 1 +
imap/message.c | 2 ++
init.h | 10 ++++++++++
mutt.h | 3 +++
muttlib.c | 4 +++-
mx.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
postpone.c | 3 +++
9 files changed, 103 insertions(+), 2 deletions(-)
diff --git a/commands.c b/commands.c
index 5dbd100..7fd014b 100644
--- a/commands.c
+++ b/commands.c
@@ -720,6 +720,7 @@ int _mutt_save_message (HEADER *h, CONTEXT *ctx, int delete, int decode, int dec
if (option (OPTDELETEUNTAG))
mutt_set_flag (Context, h, M_TAG, 0);
}
+ mutt_set_flag (Context, h, M_APPENDED, 1);
return 0;
}
diff --git a/flags.c b/flags.c
index f0f3d81..dfa6a50 100644
--- a/flags.c
+++ b/flags.c
@@ -65,7 +65,13 @@ void _mutt_set_flag (CONTEXT *ctx, HEADER *h, int flag, int bf, int upd_ctx)
{
h->deleted = 0;
update = 1;
- if (upd_ctx) ctx->deleted--;
+ if (upd_ctx)
+ {
+ ctx->deleted--;
+ if (h->appended)
+ ctx->appended--;
+ }
+ h->appended = 0; /* when undeleting, also reset the appended flag */
#ifdef USE_IMAP
/* see my comment above */
if (ctx->magic == M_IMAP)
@@ -87,6 +93,17 @@ void _mutt_set_flag (CONTEXT *ctx, HEADER *h, int flag, int bf, int upd_ctx)
}
break;
+ case M_APPENDED:
+ if (bf)
+ {
+ if (!h->appended)
+ {
+ h->appended = 1;
+ if (upd_ctx) ctx->appended++;
+ }
+ }
+ break;
+
case M_NEW:
if (!mutt_bit_isset(ctx->rights,M_ACL_SEEN))
diff --git a/globals.h b/globals.h
index e77030c..6a1b8da 100644
--- a/globals.h
+++ b/globals.h
@@ -144,6 +144,7 @@ WHERE char *Tochars;
WHERE char *TSStatusFormat;
WHERE char *TSIconFormat;
WHERE short TSSupported;
+WHERE char *TrashPath;
WHERE char *Username;
WHERE char *Visual;
diff --git a/imap/message.c b/imap/message.c
index 3877381..039fda6 100644
--- a/imap/message.c
+++ b/imap/message.c
@@ -884,6 +884,7 @@ int imap_copy_messages (CONTEXT* ctx, HEADER* h, char* dest, int delete)
if (ctx->hdrs[n]->tagged)
{
mutt_set_flag (ctx, ctx->hdrs[n], M_DELETE, 1);
+ mutt_set_flag (ctx, ctx->hdrs[n], M_APPENDED, 1);
if (option (OPTDELETEUNTAG))
mutt_set_flag (ctx, ctx->hdrs[n], M_TAG, 0);
}
@@ -891,6 +892,7 @@ int imap_copy_messages (CONTEXT* ctx, HEADER* h, char* dest, int delete)
else
{
mutt_set_flag (ctx, h, M_DELETE, 1);
+ mutt_set_flag (ctx, h, M_APPENDED, 1);
if (option (OPTDELETEUNTAG))
mutt_set_flag (ctx, h, M_TAG, 0);
}
diff --git a/init.h b/init.h
index 6b49341..d3206f9 100644
--- a/init.h
+++ b/init.h
@@ -3341,6 +3341,16 @@ struct option_t MuttVars[] = {
** provided that ``$$ts_enabled'' has been set. This string is identical in
** formatting to the one used by ``$$status_format''.
*/
+ { "trash", DT_PATH, R_NONE, UL &TrashPath, 0 },
+ /*
+ ** .pp
+ ** If set, this variable specifies the path of the trash folder where the
+ ** mails marked for deletion will be moved, instead of being irremediably
+ ** purged.
+ ** .pp
+ ** NOTE: When you delete a message in the trash folder, it is really
+ ** deleted, so that you have a way to clean the trash.
+ */
#ifdef USE_SOCKET
{ "tunnel", DT_STR, R_NONE, UL &Tunnel, UL 0 },
/*
diff --git a/mutt.h b/mutt.h
index f8565fa..29bb6c2 100644
--- a/mutt.h
+++ b/mutt.h
@@ -185,6 +185,7 @@ enum
M_DELETE,
M_UNDELETE,
M_DELETED,
+ M_APPENDED,
M_FLAG,
M_TAG,
M_UNTAG,
@@ -713,6 +714,7 @@ typedef struct header
unsigned int mime : 1; /* has a MIME-Version header? */
unsigned int flagged : 1; /* marked important? */
unsigned int tagged : 1;
+ unsigned int appended : 1; /* has been saved */
unsigned int deleted : 1;
unsigned int changed : 1;
unsigned int attach_del : 1; /* has an attachment marked for deletion */
@@ -885,6 +887,7 @@ typedef struct _context
int new; /* how many new messages? */
int unread; /* how many unread messages? */
int deleted; /* how many deleted messages */
+ int appended; /* how many saved messages? */
int flagged; /* how many flagged messages */
int msgnotreadyet; /* which msg "new" in pager, -1 if none */
diff --git a/muttlib.c b/muttlib.c
index 02067cc..0fd9766 100644
--- a/muttlib.c
+++ b/muttlib.c
@@ -1505,7 +1505,9 @@ int mutt_save_confirm (const char *s, struct stat *st)
if (magic > 0 && !mx_access (s, W_OK))
{
- if (option (OPTCONFIRMAPPEND))
+ if (option (OPTCONFIRMAPPEND) &&
+ (!TrashPath || (mutt_strcmp (s, TrashPath) != 0)))
+ /* if we're appending to the trash, there's no point in asking */
{
snprintf (tmp, sizeof (tmp), _("Append messages to %s?"), s);
if ((rc = mutt_yesorno (tmp, M_YES)) == M_NO)
diff --git a/mx.c b/mx.c
index 4c5cb07..c0a6d30 100644
--- a/mx.c
+++ b/mx.c
@@ -776,6 +776,53 @@ static int sync_mailbox (CONTEXT *ctx, int *index_hint)
return rc;
}
+/* move deleted mails to the trash folder */
+static int trash_append (CONTEXT *ctx)
+{
+ CONTEXT *ctx_trash;
+ int i = 0;
+ struct stat st, stc;
+
+ if (!TrashPath || !ctx->deleted ||
+ (ctx->magic == M_MAILDIR && option (OPTMAILDIRTRASH)))
+ return 0;
+
+ for (;i < ctx->msgcount && (!ctx->hdrs[i]->deleted ||
+ ctx->hdrs[i]->appended); i++);
+ if (i == ctx->msgcount)
+ return 0; /* nothing to be done */
+
+ if (mutt_save_confirm (TrashPath, &st) != 0)
+ {
+ mutt_error _("message(s) not deleted");
+ return -1;
+ }
+
+ if (lstat (ctx->path, &stc) == 0 && stc.st_ino == st.st_ino
+ && stc.st_dev == st.st_dev && stc.st_rdev == st.st_rdev)
+ return 0; /* we are in the trash folder: simple sync */
+
+ if ((ctx_trash = mx_open_mailbox (TrashPath, M_APPEND, NULL)) != NULL)
+ {
+ for (i = 0 ; i < ctx->msgcount ; i++)
+ if (ctx->hdrs[i]->deleted && !ctx->hdrs[i]->appended
+ && mutt_append_message (ctx_trash, ctx, ctx->hdrs[i], 0, 0) == -1)
+ {
+ mx_close_mailbox (ctx_trash, NULL);
+ return -1;
+ }
+
+ mx_close_mailbox (ctx_trash, NULL);
+ }
+ else
+ {
+ mutt_error _("Can't open trash folder");
+ return -1;
+ }
+
+ return 0;
+}
+
/* save changes and close mailbox */
int mx_close_mailbox (CONTEXT *ctx, int *index_hint)
{
@@ -912,6 +959,7 @@ int mx_close_mailbox (CONTEXT *ctx, int *index_hint)
if (mutt_append_message (&f, ctx, ctx->hdrs[i], 0, CH_UPDATE_LEN) == 0)
{
mutt_set_flag (ctx, ctx->hdrs[i], M_DELETE, 1);
+ mutt_set_flag (ctx, ctx->hdrs[i], M_APPENDED, 1);
}
else
{
@@ -936,6 +984,14 @@ int mx_close_mailbox (CONTEXT *ctx, int *index_hint)
return 0;
}
+ /* copy mails to the trash before expunging */
+ if (purge && ctx->deleted && mutt_strcmp(ctx->path, TrashPath))
+ if (trash_append (ctx) != 0)
+ {
+ ctx->closing = 0;
+ return -1;
+ }
+
#ifdef USE_IMAP
/* allow IMAP to preserve the deleted flag across sessions */
if (ctx->magic == M_IMAP)
@@ -1133,6 +1189,12 @@ int mx_sync_mailbox (CONTEXT *ctx, int *index_hint)
msgcount = ctx->msgcount;
deleted = ctx->deleted;
+ if (purge && ctx->deleted && mutt_strcmp(ctx->path, TrashPath))
+ {
+ if (trash_append (ctx) == -1)
+ return -1;
+ }
+
#ifdef USE_IMAP
if (ctx->magic == M_IMAP)
rc = imap_sync_mailbox (ctx, purge, index_hint);
diff --git a/postpone.c b/postpone.c
index a703161..7a4cbb1 100644
--- a/postpone.c
+++ b/postpone.c
@@ -277,6 +277,9 @@ int mutt_get_postponed (CONTEXT *ctx, HEADER *hdr, HEADER **cur, char *fcc, size
/* finished with this message, so delete it. */
mutt_set_flag (PostContext, h, M_DELETE, 1);
+ /* and consider it saved, so that it won't be moved to the trash folder */
+ mutt_set_flag (PostContext, h, M_APPENDED, 1);
+
/* update the count for the status display */
PostCount = PostContext->msgcount - PostContext->deleted;

View file

@ -0,0 +1,797 @@
diff -urN mutt-1.6.1/commands.c mutt-1.6.1-trash/commands.c
--- mutt-1.6.1/commands.c 2016-06-12 18:43:00.397447512 +0100
+++ mutt-1.6.1-trash/commands.c 2016-06-12 18:43:04.892517610 +0100
@@ -720,6 +720,7 @@
if (option (OPTDELETEUNTAG))
mutt_set_flag (Context, h, M_TAG, 0);
}
+ mutt_set_flag (Context, h, M_APPENDED, 1);
return 0;
}
diff -urN mutt-1.6.1/curs_main.c mutt-1.6.1-trash/curs_main.c
--- mutt-1.6.1/curs_main.c 2016-06-12 18:43:00.399447544 +0100
+++ mutt-1.6.1-trash/curs_main.c 2016-06-12 18:43:04.895517656 +0100
@@ -1919,6 +1919,7 @@
MAYBE_REDRAW (menu->redraw);
break;
+ case OP_PURGE_MESSAGE:
case OP_DELETE:
CHECK_MSGCOUNT;
@@ -1930,6 +1931,7 @@
if (tag)
{
mutt_tag_set_flag (M_DELETE, 1);
+ mutt_tag_set_flag (M_PURGED, (op != OP_PURGE_MESSAGE) ? 0 : 1);
if (option (OPTDELETEUNTAG))
mutt_tag_set_flag (M_TAG, 0);
menu->redraw = REDRAW_INDEX;
@@ -1937,6 +1939,8 @@
else
{
mutt_set_flag (Context, CURHDR, M_DELETE, 1);
+ mutt_set_flag (Context, CURHDR, M_PURGED,
+ (op != OP_PURGE_MESSAGE) ? 0 : 1);
if (option (OPTDELETEUNTAG))
mutt_set_flag (Context, CURHDR, M_TAG, 0);
if (option (OPTRESOLVE))
@@ -2242,11 +2246,13 @@
if (tag)
{
mutt_tag_set_flag (M_DELETE, 0);
+ mutt_tag_set_flag (M_PURGED, 0);
menu->redraw = REDRAW_INDEX;
}
else
{
mutt_set_flag (Context, CURHDR, M_DELETE, 0);
+ mutt_set_flag (Context, CURHDR, M_PURGED, 0);
if (option (OPTRESOLVE) && menu->current < Context->vcount - 1)
{
menu->current++;
@@ -2268,9 +2274,11 @@
CHECK_ACL(M_ACL_DELETE, _("Cannot undelete message(s)"));
rc = mutt_thread_set_flag (CURHDR, M_DELETE, 0,
- op == OP_UNDELETE_THREAD ? 0 : 1);
+ op == OP_UNDELETE_THREAD ? 0 : 1)
+ + mutt_thread_set_flag (CURHDR, M_PURGED, 0,
+ (op == OP_UNDELETE_THREAD) ? 0 : 1);
- if (rc != -1)
+ if (rc > -1)
{
if (option (OPTRESOLVE))
{
diff -urN mutt-1.6.1/doc/manual.xml.head mutt-1.6.1-trash/doc/manual.xml.head
--- mutt-1.6.1/doc/manual.xml.head 2016-06-12 18:43:00.402447590 +0100
+++ mutt-1.6.1-trash/doc/manual.xml.head 2016-06-12 18:43:04.901517750 +0100
@@ -7467,6 +7467,16 @@
</sect2>
+<sect2 id="mutt-patches">
+<title>Mutt Patches</title>
+<para>
+Mutt may also be <quote>patched</quote> to support smaller features.
+These patches should add a free-form string to the end Mutt's version string.
+Running <literal>mutt -v</literal> might show:
+<screen>patch-1.6.1.sidebar.20160502</screen>
+</para>
+</sect2>
+
<sect2 id="url-syntax">
<title>URL Syntax</title>
@@ -8081,6 +8091,175 @@
</sect1>
+<sect1 id="trash-folder">
+ <title>Trash Folder Patch</title>
+ <subtitle>Automatically move "deleted" emails to a trash bin</subtitle>
+
+ <sect2 id="trash-folder-patch">
+ <title>Patch</title>
+
+ <para>
+ To check if Mutt supports <quote>Trash Folder</quote>, look for
+ <quote>patch-trash</quote> in the mutt version.
+ See: <xref linkend="mutt-patches"/>.
+ </para>
+
+ If IMAP is enabled, this patch will use it
+
+ <itemizedlist>
+ <title>Dependencies:</title>
+ <listitem><para>mutt-1.6.1</para></listitem>
+ <listitem><para>IMAP support</para></listitem>
+ </itemizedlist>
+
+ <para>This patch is part of the <ulink url="http://www.neomutt.org/">NeoMutt Project</ulink>.</para>
+ </sect2>
+
+ <sect2 id="trash-folder-intro">
+ <title>Introduction</title>
+
+ <para>
+ In Mutt, when you <quote>delete</quote> an email it is first marked
+ deleted. The email isn't really gone until
+ <link linkend="index-map">&lt;sync-mailbox&gt;</link> is called.
+ This happens when the user leaves the folder, or the function is called
+ manually.
+ </para>
+
+ <para>
+ After <literal>&lt;sync-mailbox&gt;</literal> has been called the email is gone forever.
+ </para>
+
+ <para>
+ The <link linkend="trash">$trash</link> variable defines a folder in
+ which to keep old emails. As before, first you mark emails for
+ deletion. When &lt;sync-mailbox&gt; is called the emails are moved to
+ the trash folder.
+ </para>
+
+ <para>
+ The <literal>$trash</literal> path can be either a full directory,
+ or be relative to the <link linkend="folder">$folder</link>
+ variable, like the <literal>mailboxes</literal> command.
+ </para>
+
+ <note>
+ Emails deleted from the trash folder are gone forever.
+ </note>
+ </sect2>
+
+ <sect2 id="trash-folder-variables">
+ <title>Variables</title>
+ <table id="table-trash-variables">
+ <title>Trash Variables</title>
+ <tgroup cols="3">
+ <thead>
+ <row>
+ <entry>Name</entry>
+ <entry>Type</entry>
+ <entry>Default</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>trash</entry>
+ <entry>string</entry>
+ <entry>(none)</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </sect2>
+
+ <sect2 id="trash-folder-functions">
+ <title>Functions</title>
+ <table id="table-trash-functions">
+ <title>Trash Functions</title>
+ <tgroup cols="4">
+ <thead>
+ <row>
+ <entry>Menus</entry>
+ <entry>Default Key</entry>
+ <entry>Function</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>index,pager</entry>
+ <entry>(none)</entry>
+ <entry><literal>&lt;purge-message&gt;</literal></entry>
+ <entry>really delete the current entry, bypassing the trash folder</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </sect2>
+
+<!--
+ <sect2 id="trash-folder-commands">
+ <title>Commands</title>
+ <para>None</para>
+ </sect2>
+
+ <sect2 id="trash-folder-colors">
+ <title>Colors</title>
+ <para>None</para>
+ </sect2>
+
+ <sect2 id="trash-folder-sort">
+ <title>Sort</title>
+ <para>None</para>
+ </sect2>
+-->
+
+ <sect2 id="trash-folder-muttrc">
+ <title>Muttrc</title>
+<screen>
+<emphasis role="comment"># Example Mutt config file for the 'trash' feature.
+
+# This feature defines a new 'trash' folder.
+# When mail is deleted it will be moved to this folder.
+
+# Folder in which to put deleted emails</emphasis>
+set trash='+Trash'
+set trash='/home/flatcap/Mail/Trash'
+
+<emphasis role="comment"># The default delete key 'd' will move an email to the 'trash' folder
+# Bind 'D' to REALLY delete an email</emphasis>
+bind index D purge-message
+
+<emphasis role="comment"># Note: Deleting emails from the 'trash' folder will REALLY delete them.
+
+# vim: syntax=muttrc</emphasis>
+</screen>
+ </sect2>
+
+ <sect2 id="trash-folder-see-also">
+ <title>See Also</title>
+
+ <itemizedlist>
+ <listitem><para><ulink url="http://www.neomutt.org/">NeoMutt Project</ulink></para></listitem>
+ <listitem><para><link linkend="folder-hook">folder-hook</link></para></listitem>
+ </itemizedlist>
+ </sect2>
+
+ <sect2 id="trash-folder-known-bugs">
+ <title>Known Bugs</title>
+ <para>None</para>
+ </sect2>
+
+ <sect2 id="trash-folder-credits">
+ <title>Credits</title>
+ <itemizedlist>
+ <listitem><para>Cedric Duval <email>cedricduval@free.fr</email></para></listitem>
+ <listitem><para>Benjamin Kuperman <email>kuperman@acm.org</email></para></listitem>
+ <listitem><para>Paul Miller <email>paul@voltar.org</email></para></listitem>
+ <listitem><para>Richard Russon <email>rich@flatcap.org</email></para></listitem>
+ </itemizedlist>
+ </sect2>
+</sect1>
+
</chapter>
<chapter id="security">
diff -urN mutt-1.6.1/doc/muttrc.trash mutt-1.6.1-trash/doc/muttrc.trash
--- mutt-1.6.1/doc/muttrc.trash 1970-01-01 01:00:00.000000000 +0100
+++ mutt-1.6.1-trash/doc/muttrc.trash 2016-06-12 18:43:04.768515676 +0100
@@ -0,0 +1,16 @@
+# Example Mutt config file for the 'trash' feature.
+
+# This feature defines a new 'trash' folder.
+# When mail is deleted it will be moved to this folder.
+
+# Folder in which to put deleted emails
+set trash='+Trash'
+set trash='/home/flatcap/Mail/Trash'
+
+# The default delete key 'd' will move an email to the 'trash' folder
+# Bind 'D' to REALLY delete an email
+bind index D purge-message
+
+# Note: Deleting emails from the 'trash' folder will REALLY delete them.
+
+# vim: syntax=muttrc
diff -urN mutt-1.6.1/doc/vimrc.trash mutt-1.6.1-trash/doc/vimrc.trash
--- mutt-1.6.1/doc/vimrc.trash 1970-01-01 01:00:00.000000000 +0100
+++ mutt-1.6.1-trash/doc/vimrc.trash 2016-06-12 18:43:04.769515692 +0100
@@ -0,0 +1,7 @@
+" Vim syntax file for the mutt trash patch
+
+syntax keyword muttrcVarStr contained skipwhite trash nextgroup=muttrcVarEqualsIdxFmt
+
+syntax match muttrcFunction contained "\<purge-message\>"
+
+" vim: syntax=vim
diff -urN mutt-1.6.1/flags.c mutt-1.6.1-trash/flags.c
--- mutt-1.6.1/flags.c 2016-06-12 18:43:00.403447606 +0100
+++ mutt-1.6.1-trash/flags.c 2016-06-12 18:43:04.902517766 +0100
@@ -65,7 +65,13 @@
{
h->deleted = 0;
update = 1;
- if (upd_ctx) ctx->deleted--;
+ if (upd_ctx) {
+ ctx->deleted--;
+ if (h->appended) {
+ ctx->appended--;
+ }
+ }
+ h->appended = 0; /* when undeleting, also reset the appended flag */
#ifdef USE_IMAP
/* see my comment above */
if (ctx->magic == M_IMAP)
@@ -87,6 +93,27 @@
}
break;
+ case M_APPENDED:
+ if (bf) {
+ if (!h->appended) {
+ h->appended = 1;
+ if (upd_ctx) {
+ ctx->appended++;
+ }
+ }
+ }
+ break;
+
+ case M_PURGED:
+ if (bf) {
+ if (!h->purged) {
+ h->purged = 1;
+ }
+ } else if (h->purged) {
+ h->purged = 0;
+ }
+ break;
+
case M_NEW:
if (!mutt_bit_isset(ctx->rights,M_ACL_SEEN))
diff -urN mutt-1.6.1/functions.h mutt-1.6.1-trash/functions.h
--- mutt-1.6.1/functions.h 2016-06-12 18:43:00.403447606 +0100
+++ mutt-1.6.1-trash/functions.h 2016-06-12 18:43:04.902517766 +0100
@@ -121,6 +121,7 @@
{ "toggle-write", OP_TOGGLE_WRITE, "%" },
{ "next-thread", OP_MAIN_NEXT_THREAD, "\016" },
{ "next-subthread", OP_MAIN_NEXT_SUBTHREAD, "\033n" },
+ { "purge-message", OP_PURGE_MESSAGE, NULL },
{ "query", OP_QUERY, "Q" },
{ "quit", OP_QUIT, "q" },
{ "reply", OP_REPLY, "r" },
@@ -213,6 +214,7 @@
{ "print-message", OP_PRINT, "p" },
{ "previous-thread", OP_MAIN_PREV_THREAD, "\020" },
{ "previous-subthread",OP_MAIN_PREV_SUBTHREAD, "\033p" },
+ { "purge-message", OP_PURGE_MESSAGE, NULL },
{ "quit", OP_QUIT, "Q" },
{ "exit", OP_EXIT, "q" },
{ "reply", OP_REPLY, "r" },
diff -urN mutt-1.6.1/globals.h mutt-1.6.1-trash/globals.h
--- mutt-1.6.1/globals.h 2016-06-12 18:43:00.403447606 +0100
+++ mutt-1.6.1-trash/globals.h 2016-06-12 18:43:04.903517781 +0100
@@ -141,6 +141,7 @@
WHERE char *Status;
WHERE char *Tempdir;
WHERE char *Tochars;
+WHERE char *TrashPath;
WHERE char *TSStatusFormat;
WHERE char *TSIconFormat;
WHERE short TSSupported;
diff -urN mutt-1.6.1/imap/imap.c mutt-1.6.1-trash/imap/imap.c
--- mutt-1.6.1/imap/imap.c 2016-06-12 18:43:00.405447637 +0100
+++ mutt-1.6.1-trash/imap/imap.c 2016-06-12 18:43:04.905517812 +0100
@@ -888,6 +888,12 @@
if (hdrs[n]->deleted != HEADER_DATA(hdrs[n])->deleted)
match = invert ^ hdrs[n]->deleted;
break;
+ case M_EXPIRED: /* imap_fast_trash version of M_DELETED */
+ if (hdrs[n]->purged)
+ break;
+ if (hdrs[n]->deleted != HEADER_DATA(hdrs[n])->deleted)
+ match = invert ^ (hdrs[n]->deleted && !hdrs[n]->appended);
+ break;
case M_FLAG:
if (hdrs[n]->flagged != HEADER_DATA(hdrs[n])->flagged)
match = invert ^ hdrs[n]->flagged;
@@ -2038,3 +2044,53 @@
return -1;
}
+
+/**
+ * imap_fast_trash - XXX
+ */
+int
+imap_fast_trash (void)
+{
+ if ((Context->magic == M_IMAP) && mx_is_imap (TrashPath)) {
+ IMAP_MBOX mx;
+ IMAP_DATA *idata = (IMAP_DATA *) Context->data;
+ char mbox[LONG_STRING];
+ char mmbox[LONG_STRING];
+ int rc;
+ dprint (1, (debugfile, "[itf] trashcan seems to be on imap.\n"));
+
+ if (imap_parse_path (TrashPath, &mx) == 0) {
+ if (mutt_account_match (&(idata->conn->account), &(mx.account))) {
+ dprint (1, (debugfile, "[itf] trashcan seems to be on the same account.\n"));
+
+ imap_fix_path (idata, mx.mbox, mbox, sizeof (mbox));
+ if (!*mbox)
+ strfcpy (mbox, "INBOX", sizeof (mbox));
+ imap_munge_mbox_name (idata, mmbox, sizeof (mmbox), mbox);
+
+ rc = imap_exec_msgset (idata, "UID COPY", mmbox, M_EXPIRED, 0, 0);
+ if (rc == 0) {
+ dprint (1, (debugfile, "imap_copy_messages: No messages del-tagged\n"));
+ rc = -1;
+ goto old_way;
+ } else if (rc < 0) {
+ dprint (1, (debugfile, "could not queue copy\n"));
+ goto old_way;
+ } else {
+ mutt_message (_("Copying %d messages to %s..."), rc, mbox);
+ return 0;
+ }
+ } else {
+ dprint (1, (debugfile, "[itf] trashcan seems to be on a different account.\n"));
+ }
+old_way:
+ FREE(&mx.mbox); /* we probably only need to free this when the parse works */
+ } else {
+ dprint (1, (debugfile, "[itf] failed to parse TrashPath.\n"));
+ }
+
+ dprint (1, (debugfile, "[itf] giving up and trying old fasioned way.\n"));
+ }
+
+ return 1;
+}
diff -urN mutt-1.6.1/imap/imap.h mutt-1.6.1-trash/imap/imap.h
--- mutt-1.6.1/imap/imap.h 2016-06-12 18:43:00.405447637 +0100
+++ mutt-1.6.1-trash/imap/imap.h 2016-06-12 18:43:04.774515769 +0100
@@ -72,4 +72,7 @@
int imap_account_match (const ACCOUNT* a1, const ACCOUNT* a2);
+/* trash */
+int imap_fast_trash (void);
+
#endif
diff -urN mutt-1.6.1/imap/message.c mutt-1.6.1-trash/imap/message.c
--- mutt-1.6.1/imap/message.c 2016-06-12 18:43:00.406447652 +0100
+++ mutt-1.6.1-trash/imap/message.c 2016-06-12 18:43:04.906517828 +0100
@@ -886,6 +886,7 @@
if (ctx->hdrs[n]->tagged)
{
mutt_set_flag (ctx, ctx->hdrs[n], M_DELETE, 1);
+ mutt_set_flag (ctx, ctx->hdrs[n], M_APPENDED, 1);
if (option (OPTDELETEUNTAG))
mutt_set_flag (ctx, ctx->hdrs[n], M_TAG, 0);
}
@@ -893,6 +894,7 @@
else
{
mutt_set_flag (ctx, h, M_DELETE, 1);
+ mutt_set_flag (ctx, h, M_APPENDED, 1);
if (option (OPTDELETEUNTAG))
mutt_set_flag (ctx, h, M_TAG, 0);
}
diff -urN mutt-1.6.1/init.h mutt-1.6.1-trash/init.h
--- mutt-1.6.1/init.h 2016-06-12 18:43:00.408447684 +0100
+++ mutt-1.6.1-trash/init.h 2016-06-12 18:43:04.909517875 +0100
@@ -3419,6 +3419,16 @@
** provided that ``$$ts_enabled'' has been set. This string is identical in
** formatting to the one used by ``$$status_format''.
*/
+ { "trash", DT_PATH, R_NONE, UL &TrashPath, 0 },
+ /*
+ ** .pp
+ ** If set, this variable specifies the path of the trash folder where the
+ ** mails marked for deletion will be moved, instead of being irremediably
+ ** purged.
+ ** .pp
+ ** NOTE: When you delete a message in the trash folder, it is really
+ ** deleted, so that you have a way to clean the trash.
+ */
#ifdef USE_SOCKET
{ "tunnel", DT_STR, R_NONE, UL &Tunnel, UL 0 },
/*
diff -urN mutt-1.6.1/mutt.h mutt-1.6.1-trash/mutt.h
--- mutt-1.6.1/mutt.h 2016-06-12 18:43:00.410447715 +0100
+++ mutt-1.6.1-trash/mutt.h 2016-06-12 18:43:04.912517922 +0100
@@ -182,6 +182,8 @@
M_DELETE,
M_UNDELETE,
M_DELETED,
+ M_APPENDED,
+ M_PURGED,
M_FLAG,
M_TAG,
M_UNTAG,
@@ -719,6 +721,8 @@
unsigned int mime : 1; /* has a MIME-Version header? */
unsigned int flagged : 1; /* marked important? */
unsigned int tagged : 1;
+ unsigned int appended : 1; /* has been saved */
+ unsigned int purged : 1; /* bypassing the trash folder */
unsigned int deleted : 1;
unsigned int changed : 1;
unsigned int attach_del : 1; /* has an attachment marked for deletion */
@@ -891,6 +895,7 @@
int new; /* how many new messages? */
int unread; /* how many unread messages? */
int deleted; /* how many deleted messages */
+ int appended; /* how many saved messages? */
int flagged; /* how many flagged messages */
int msgnotreadyet; /* which msg "new" in pager, -1 if none */
diff -urN mutt-1.6.1/muttlib.c mutt-1.6.1-trash/muttlib.c
--- mutt-1.6.1/muttlib.c 2016-06-12 18:43:00.411447731 +0100
+++ mutt-1.6.1-trash/muttlib.c 2016-06-12 18:43:04.913517937 +0100
@@ -1511,7 +1511,9 @@
if (magic > 0 && !mx_access (s, W_OK))
{
- if (option (OPTCONFIRMAPPEND))
+ if (option (OPTCONFIRMAPPEND) &&
+ (!TrashPath || (mutt_strcmp (s, TrashPath) != 0)))
+ /* if we're appending to the trash, there's no point in asking */
{
snprintf (tmp, sizeof (tmp), _("Append messages to %s?"), s);
if ((rc = mutt_yesorno (tmp, M_YES)) == M_NO)
diff -urN mutt-1.6.1/mx.c mutt-1.6.1-trash/mx.c
--- mutt-1.6.1/mx.c 2016-06-12 18:43:00.411447731 +0100
+++ mutt-1.6.1-trash/mx.c 2016-06-12 18:43:04.914517953 +0100
@@ -776,6 +776,62 @@
return rc;
}
+/**
+ * trash_append - XXX
+ *
+ * move deleted mails to the trash folder
+ */
+static int trash_append (CONTEXT *ctx)
+{
+ CONTEXT *ctx_trash;
+ int i = 0;
+ struct stat st, stc;
+
+ if (!TrashPath || !ctx->deleted ||
+ ((ctx->magic == M_MAILDIR) && option (OPTMAILDIRTRASH))) {
+ return 0;
+ }
+
+ for (; i < ctx->msgcount && (!ctx->hdrs[i]->deleted || ctx->hdrs[i]->appended); i++);
+ /* nothing */
+
+ if (i == ctx->msgcount)
+ return 0; /* nothing to be done */
+
+ if (mutt_save_confirm (TrashPath, &st) != 0) {
+ mutt_error _("message(s) not deleted");
+ return -1;
+ }
+
+ if (lstat (ctx->path, &stc) == 0 && stc.st_ino == st.st_ino
+ && stc.st_dev == st.st_dev && stc.st_rdev == st.st_rdev) {
+ return 0; /* we are in the trash folder: simple sync */
+ }
+
+#ifdef USE_IMAP
+ if (!imap_fast_trash())
+ return 0;
+#endif
+
+ if ((ctx_trash = mx_open_mailbox (TrashPath, M_APPEND, NULL)) != NULL) {
+ for (i = 0 ; i < ctx->msgcount ; i++) {
+ if (ctx->hdrs[i]->deleted && !ctx->hdrs[i]->appended
+ && !ctx->hdrs[i]->purged
+ && mutt_append_message (ctx_trash, ctx, ctx->hdrs[i], 0, 0) == -1) {
+ mx_close_mailbox (ctx_trash, NULL);
+ return -1;
+ }
+ }
+
+ mx_close_mailbox (ctx_trash, NULL);
+ } else {
+ mutt_error _("Can't open trash folder");
+ return -1;
+ }
+
+ return 0;
+}
+
/* save changes and close mailbox */
int mx_close_mailbox (CONTEXT *ctx, int *index_hint)
{
@@ -912,6 +968,7 @@
if (mutt_append_message (&f, ctx, ctx->hdrs[i], 0, CH_UPDATE_LEN) == 0)
{
mutt_set_flag (ctx, ctx->hdrs[i], M_DELETE, 1);
+ mutt_set_flag (ctx, ctx->hdrs[i], M_APPENDED, 1);
}
else
{
@@ -936,6 +993,14 @@
return 0;
}
+ /* copy mails to the trash before expunging */
+ if (purge && ctx->deleted && mutt_strcmp (ctx->path, TrashPath)) {
+ if (trash_append (ctx) != 0) {
+ ctx->closing = 0;
+ return -1;
+ }
+ }
+
#ifdef USE_IMAP
/* allow IMAP to preserve the deleted flag across sessions */
if (ctx->magic == M_IMAP)
@@ -1140,6 +1205,12 @@
msgcount = ctx->msgcount;
deleted = ctx->deleted;
+ if (purge && ctx->deleted && mutt_strcmp (ctx->path, TrashPath)) {
+ if (trash_append (ctx) == -1) {
+ return -1;
+ }
+ }
+
#ifdef USE_IMAP
if (ctx->magic == M_IMAP)
rc = imap_sync_mailbox (ctx, purge, index_hint);
diff -urN mutt-1.6.1/OPS mutt-1.6.1-trash/OPS
--- mutt-1.6.1/OPS 2016-06-12 18:43:00.389447388 +0100
+++ mutt-1.6.1-trash/OPS 2016-06-12 18:43:04.883517469 +0100
@@ -142,6 +142,7 @@
OP_PREV_LINE "scroll up one line"
OP_PREV_PAGE "move to the previous page"
OP_PRINT "print the current entry"
+OP_PURGE_MESSAGE "really delete the current entry, bypassing the trash folder"
OP_QUERY "query external program for addresses"
OP_QUERY_APPEND "append new query results to current results"
OP_QUIT "save changes to mailbox and quit"
diff -urN mutt-1.6.1/pager.c mutt-1.6.1-trash/pager.c
--- mutt-1.6.1/pager.c 2016-06-12 18:43:00.412447746 +0100
+++ mutt-1.6.1-trash/pager.c 2016-06-12 18:43:04.915517968 +0100
@@ -2351,6 +2351,7 @@
MAYBE_REDRAW (redraw);
break;
+ case OP_PURGE_MESSAGE:
case OP_DELETE:
CHECK_MODE(IsHeader (extra));
CHECK_READONLY;
@@ -2358,6 +2359,8 @@
CHECK_ACL(M_ACL_DELETE, _("Cannot delete message"));
mutt_set_flag (Context, extra->hdr, M_DELETE, 1);
+ mutt_set_flag (Context, extra->hdr, M_PURGED,
+ ch != OP_PURGE_MESSAGE ? 0 : 1);
if (option (OPTDELETEUNTAG))
mutt_set_flag (Context, extra->hdr, M_TAG, 0);
redraw = REDRAW_STATUS | REDRAW_INDEX;
@@ -2688,6 +2691,7 @@
CHECK_ACL(M_ACL_DELETE, _("Cannot undelete message"));
mutt_set_flag (Context, extra->hdr, M_DELETE, 0);
+ mutt_set_flag (Context, extra->hdr, M_PURGED, 0);
redraw = REDRAW_STATUS | REDRAW_INDEX;
if (option (OPTRESOLVE))
{
@@ -2704,9 +2708,11 @@
CHECK_ACL(M_ACL_DELETE, _("Cannot undelete message(s)"));
r = mutt_thread_set_flag (extra->hdr, M_DELETE, 0,
+ ch == OP_UNDELETE_THREAD ? 0 : 1)
+ + mutt_thread_set_flag (extra->hdr, M_PURGED, 0,
ch == OP_UNDELETE_THREAD ? 0 : 1);
- if (r != -1)
+ if (r > -1)
{
if (option (OPTRESOLVE))
{
diff -urN mutt-1.6.1/PATCHES mutt-1.6.1-trash/PATCHES
--- mutt-1.6.1/PATCHES 2016-06-12 18:43:00.395447481 +0100
+++ mutt-1.6.1-trash/PATCHES 2016-06-12 18:43:04.889517563 +0100
@@ -0,0 +1 @@
+patch-trash-neo-20160612
diff -urN mutt-1.6.1/pattern.c mutt-1.6.1-trash/pattern.c
--- mutt-1.6.1/pattern.c 2016-06-12 18:43:00.413447762 +0100
+++ mutt-1.6.1-trash/pattern.c 2016-06-12 18:43:04.916517984 +0100
@@ -1367,8 +1367,9 @@
{
switch (op)
{
- case M_DELETE:
case M_UNDELETE:
+ mutt_set_flag (Context, Context->hdrs[Context->v2r[i]], M_PURGED, 0);
+ case M_DELETE:
mutt_set_flag (Context, Context->hdrs[Context->v2r[i]], M_DELETE,
(op == M_DELETE));
break;
diff -urN mutt-1.6.1/postpone.c mutt-1.6.1-trash/postpone.c
--- mutt-1.6.1/postpone.c 2016-06-12 18:43:00.414447777 +0100
+++ mutt-1.6.1-trash/postpone.c 2016-06-12 18:43:04.917518000 +0100
@@ -277,6 +277,9 @@
/* finished with this message, so delete it. */
mutt_set_flag (PostContext, h, M_DELETE, 1);
+ /* and consider it saved, so that it won't be moved to the trash folder */
+ mutt_set_flag (PostContext, h, M_APPENDED, 1);
+
/* update the count for the status display */
PostCount = PostContext->msgcount - PostContext->deleted;
diff -urN mutt-1.6.1/README.trash mutt-1.6.1-trash/README.trash
--- mutt-1.6.1/README.trash 1970-01-01 01:00:00.000000000 +0100
+++ mutt-1.6.1-trash/README.trash 2016-06-12 18:43:04.748515364 +0100
@@ -0,0 +1,74 @@
+Trash Folder Patch
+==================
+
+ Automatically move "deleted" emails to a trash bin
+
+Patch
+-----
+
+ To check if Mutt supports "Trash Folder", look for "patch-trash" in the
+ mutt version.
+
+ If IMAP is enabled, this patch will use it
+
+ Dependencies
+ * mutt-1.6.1
+ * IMAP support
+
+Introduction
+------------
+
+ In Mutt, when you "delete" an email it is first marked deleted. The email
+ isn't really gone until <sync-mailbox> is called. This happens when the
+ user leaves the folder, or the function is called manually.
+
+ After '<sync-mailbox>' has been called the email is gone forever.
+
+ The $trash variable defines a folder in which to keep old emails. As
+ before, first you mark emails for deletion. When <sync-mailbox> is called
+ the emails are moved to the trash folder.
+
+ The '$trash' path can be either a full directory, or be relative to the
+ $folder variable, like the 'mailboxes' command.
+
+ > Note
+ >
+ > Emails deleted from the trash folder are gone forever.
+
+Variables
+---------
+
+ Trash Variables
+
+ | Name | Type | Default |
+ |-------|--------|---------|
+ | trash | string | (none) |
+
+Functions
+---------
+
+ Trash Functions
+
+ | Menus | Default Key | Function | Description |
+ |-------------|-------------|-------------------|-------------------------------------------------------------|
+ | index,pager | (none) | '<purge-message>' | really delete the current entry, bypassing the trash folder |
+
+See Also
+--------
+
+ * NeoMutt project
+ * folder-hook
+
+Known Bugs
+----------
+
+ None
+
+Credits
+-------
+
+ * Cedric Duval <cedricduval@free.fr>
+ * Benjamin Kuperman <kuperman@acm.org>
+ * Paul Miller <paul@voltar.org>
+ * Richard Russon <rich@flatcap.org>
+