···1-From: Cedric Duval <cedricduval@free.fr>
2-Date: Thu, 27 Feb 2014 12:27:41 +0100
3-Subject: trash-folder
4-5-With this patch, if the trash variable is set to a path (unset by default), the
6-deleted mails will be moved to a trash folder instead of being irremediably
7-purged when syncing the mailbox.
8-9-For instance, set trash="~/Mail/trash" will cause every deleted mail to go to
10-this folder.
11-12-Note that the append to the trash folder doesn't occur until the resync is
13-done. This allows you to change your mind and undo deletes, and thus the moves
14-to the trash folder are unnecessary.
15-16-Notes
17-18- * You might also want to have a look at the purge message feature below
19- which is related to this patch.
20- * IMAP is now supported. To retain the previous behavior, add this to your
21- muttrc:
22- folder-hook ^imap:// 'unset trash'
23-24-FAQ
25-26-Every once in a while, someone asks what are the advantages of this patch over
27-a macro based solution. Here's an attempt to answer this question:
28-29- * The folder history doesn't clutter up with unwanted trash entries.
30- * Delayed move to the trash allows to change one's mind.
31- * No need to treat the case of "normal folders" and trash folders
32- separately with folder-hooks, and to create two sets of macros (one for
33- the index, one for the pager).
34- * Works not only with delete-message, but also with every deletion
35- functions like delete-pattern, delete-thread or delete-subthread.
36-37-To sum up, it's more integrated and transparent to the user.
38-39-* Patch last synced with upstream:
40- - Date: 2007-02-15
41- - File: http://cedricduval.free.fr/mutt/patches/download/patch-1.5.5.1.cd.trash_folder.3.4
42-43-* Changes made:
44- - Updated to 1.5.13:
45- - structure of _mutt_save_message changed (commands.c)
46- - context of option (OPTCONFIRMAPPEND) changed (muttlib.c)
47- - Fixed indentation of "appended" in mutt.h.
48-49-Signed-off-by: Matteo F. Vescovi <mfvescovi@gmail.com>
50-51-Gbp-Pq: Topic features
52----
53- commands.c | 1 +
54- flags.c | 19 +++++++++++++++++-
55- globals.h | 1 +
56- imap/message.c | 2 ++
57- init.h | 10 ++++++++++
58- mutt.h | 3 +++
59- muttlib.c | 4 +++-
60- mx.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
61- postpone.c | 3 +++
62- 9 files changed, 103 insertions(+), 2 deletions(-)
63-64-diff --git a/commands.c b/commands.c
65-index 5dbd100..7fd014b 100644
66---- a/commands.c
67-+++ b/commands.c
68-@@ -720,6 +720,7 @@ int _mutt_save_message (HEADER *h, CONTEXT *ctx, int delete, int decode, int dec
69- if (option (OPTDELETEUNTAG))
70- mutt_set_flag (Context, h, M_TAG, 0);
71- }
72-+ mutt_set_flag (Context, h, M_APPENDED, 1);
73-74- return 0;
75- }
76-diff --git a/flags.c b/flags.c
77-index f0f3d81..dfa6a50 100644
78---- a/flags.c
79-+++ b/flags.c
80-@@ -65,7 +65,13 @@ void _mutt_set_flag (CONTEXT *ctx, HEADER *h, int flag, int bf, int upd_ctx)
81- {
82- h->deleted = 0;
83- update = 1;
84-- if (upd_ctx) ctx->deleted--;
85-+ if (upd_ctx)
86-+ {
87-+ ctx->deleted--;
88-+ if (h->appended)
89-+ ctx->appended--;
90-+ }
91-+ h->appended = 0; /* when undeleting, also reset the appended flag */
92- #ifdef USE_IMAP
93- /* see my comment above */
94- if (ctx->magic == M_IMAP)
95-@@ -87,6 +93,17 @@ void _mutt_set_flag (CONTEXT *ctx, HEADER *h, int flag, int bf, int upd_ctx)
96- }
97- break;
98-99-+ case M_APPENDED:
100-+ if (bf)
101-+ {
102-+ if (!h->appended)
103-+ {
104-+ h->appended = 1;
105-+ if (upd_ctx) ctx->appended++;
106-+ }
107-+ }
108-+ break;
109-+
110- case M_NEW:
111-112- if (!mutt_bit_isset(ctx->rights,M_ACL_SEEN))
113-diff --git a/globals.h b/globals.h
114-index e77030c..6a1b8da 100644
115---- a/globals.h
116-+++ b/globals.h
117-@@ -144,6 +144,7 @@ WHERE char *Tochars;
118- WHERE char *TSStatusFormat;
119- WHERE char *TSIconFormat;
120- WHERE short TSSupported;
121-+WHERE char *TrashPath;
122- WHERE char *Username;
123- WHERE char *Visual;
124-125-diff --git a/imap/message.c b/imap/message.c
126-index 3877381..039fda6 100644
127---- a/imap/message.c
128-+++ b/imap/message.c
129-@@ -884,6 +884,7 @@ int imap_copy_messages (CONTEXT* ctx, HEADER* h, char* dest, int delete)
130- if (ctx->hdrs[n]->tagged)
131- {
132- mutt_set_flag (ctx, ctx->hdrs[n], M_DELETE, 1);
133-+ mutt_set_flag (ctx, ctx->hdrs[n], M_APPENDED, 1);
134- if (option (OPTDELETEUNTAG))
135- mutt_set_flag (ctx, ctx->hdrs[n], M_TAG, 0);
136- }
137-@@ -891,6 +892,7 @@ int imap_copy_messages (CONTEXT* ctx, HEADER* h, char* dest, int delete)
138- else
139- {
140- mutt_set_flag (ctx, h, M_DELETE, 1);
141-+ mutt_set_flag (ctx, h, M_APPENDED, 1);
142- if (option (OPTDELETEUNTAG))
143- mutt_set_flag (ctx, h, M_TAG, 0);
144- }
145-diff --git a/init.h b/init.h
146-index 6b49341..d3206f9 100644
147---- a/init.h
148-+++ b/init.h
149-@@ -3341,6 +3341,16 @@ struct option_t MuttVars[] = {
150- ** provided that ``$$ts_enabled'' has been set. This string is identical in
151- ** formatting to the one used by ``$$status_format''.
152- */
153-+ { "trash", DT_PATH, R_NONE, UL &TrashPath, 0 },
154-+ /*
155-+ ** .pp
156-+ ** If set, this variable specifies the path of the trash folder where the
157-+ ** mails marked for deletion will be moved, instead of being irremediably
158-+ ** purged.
159-+ ** .pp
160-+ ** NOTE: When you delete a message in the trash folder, it is really
161-+ ** deleted, so that you have a way to clean the trash.
162-+ */
163- #ifdef USE_SOCKET
164- { "tunnel", DT_STR, R_NONE, UL &Tunnel, UL 0 },
165- /*
166-diff --git a/mutt.h b/mutt.h
167-index f8565fa..29bb6c2 100644
168---- a/mutt.h
169-+++ b/mutt.h
170-@@ -185,6 +185,7 @@ enum
171- M_DELETE,
172- M_UNDELETE,
173- M_DELETED,
174-+ M_APPENDED,
175- M_FLAG,
176- M_TAG,
177- M_UNTAG,
178-@@ -713,6 +714,7 @@ typedef struct header
179- unsigned int mime : 1; /* has a MIME-Version header? */
180- unsigned int flagged : 1; /* marked important? */
181- unsigned int tagged : 1;
182-+ unsigned int appended : 1; /* has been saved */
183- unsigned int deleted : 1;
184- unsigned int changed : 1;
185- unsigned int attach_del : 1; /* has an attachment marked for deletion */
186-@@ -885,6 +887,7 @@ typedef struct _context
187- int new; /* how many new messages? */
188- int unread; /* how many unread messages? */
189- int deleted; /* how many deleted messages */
190-+ int appended; /* how many saved messages? */
191- int flagged; /* how many flagged messages */
192- int msgnotreadyet; /* which msg "new" in pager, -1 if none */
193-194-diff --git a/muttlib.c b/muttlib.c
195-index 02067cc..0fd9766 100644
196---- a/muttlib.c
197-+++ b/muttlib.c
198-@@ -1505,7 +1505,9 @@ int mutt_save_confirm (const char *s, struct stat *st)
199-200- if (magic > 0 && !mx_access (s, W_OK))
201- {
202-- if (option (OPTCONFIRMAPPEND))
203-+ if (option (OPTCONFIRMAPPEND) &&
204-+ (!TrashPath || (mutt_strcmp (s, TrashPath) != 0)))
205-+ /* if we're appending to the trash, there's no point in asking */
206- {
207- snprintf (tmp, sizeof (tmp), _("Append messages to %s?"), s);
208- if ((rc = mutt_yesorno (tmp, M_YES)) == M_NO)
209-diff --git a/mx.c b/mx.c
210-index 4c5cb07..c0a6d30 100644
211---- a/mx.c
212-+++ b/mx.c
213-@@ -776,6 +776,53 @@ static int sync_mailbox (CONTEXT *ctx, int *index_hint)
214- return rc;
215- }
216-217-+/* move deleted mails to the trash folder */
218-+static int trash_append (CONTEXT *ctx)
219-+{
220-+ CONTEXT *ctx_trash;
221-+ int i = 0;
222-+ struct stat st, stc;
223-+
224-+ if (!TrashPath || !ctx->deleted ||
225-+ (ctx->magic == M_MAILDIR && option (OPTMAILDIRTRASH)))
226-+ return 0;
227-+
228-+ for (;i < ctx->msgcount && (!ctx->hdrs[i]->deleted ||
229-+ ctx->hdrs[i]->appended); i++);
230-+ if (i == ctx->msgcount)
231-+ return 0; /* nothing to be done */
232-+
233-+ if (mutt_save_confirm (TrashPath, &st) != 0)
234-+ {
235-+ mutt_error _("message(s) not deleted");
236-+ return -1;
237-+ }
238-+
239-+ if (lstat (ctx->path, &stc) == 0 && stc.st_ino == st.st_ino
240-+ && stc.st_dev == st.st_dev && stc.st_rdev == st.st_rdev)
241-+ return 0; /* we are in the trash folder: simple sync */
242-+
243-+ if ((ctx_trash = mx_open_mailbox (TrashPath, M_APPEND, NULL)) != NULL)
244-+ {
245-+ for (i = 0 ; i < ctx->msgcount ; i++)
246-+ if (ctx->hdrs[i]->deleted && !ctx->hdrs[i]->appended
247-+ && mutt_append_message (ctx_trash, ctx, ctx->hdrs[i], 0, 0) == -1)
248-+ {
249-+ mx_close_mailbox (ctx_trash, NULL);
250-+ return -1;
251-+ }
252-+
253-+ mx_close_mailbox (ctx_trash, NULL);
254-+ }
255-+ else
256-+ {
257-+ mutt_error _("Can't open trash folder");
258-+ return -1;
259-+ }
260-+
261-+ return 0;
262-+}
263-+
264- /* save changes and close mailbox */
265- int mx_close_mailbox (CONTEXT *ctx, int *index_hint)
266- {
267-@@ -912,6 +959,7 @@ int mx_close_mailbox (CONTEXT *ctx, int *index_hint)
268- if (mutt_append_message (&f, ctx, ctx->hdrs[i], 0, CH_UPDATE_LEN) == 0)
269- {
270- mutt_set_flag (ctx, ctx->hdrs[i], M_DELETE, 1);
271-+ mutt_set_flag (ctx, ctx->hdrs[i], M_APPENDED, 1);
272- }
273- else
274- {
275-@@ -936,6 +984,14 @@ int mx_close_mailbox (CONTEXT *ctx, int *index_hint)
276- return 0;
277- }
278-279-+ /* copy mails to the trash before expunging */
280-+ if (purge && ctx->deleted && mutt_strcmp(ctx->path, TrashPath))
281-+ if (trash_append (ctx) != 0)
282-+ {
283-+ ctx->closing = 0;
284-+ return -1;
285-+ }
286-+
287- #ifdef USE_IMAP
288- /* allow IMAP to preserve the deleted flag across sessions */
289- if (ctx->magic == M_IMAP)
290-@@ -1133,6 +1189,12 @@ int mx_sync_mailbox (CONTEXT *ctx, int *index_hint)
291- msgcount = ctx->msgcount;
292- deleted = ctx->deleted;
293-294-+ if (purge && ctx->deleted && mutt_strcmp(ctx->path, TrashPath))
295-+ {
296-+ if (trash_append (ctx) == -1)
297-+ return -1;
298-+ }
299-+
300- #ifdef USE_IMAP
301- if (ctx->magic == M_IMAP)
302- rc = imap_sync_mailbox (ctx, purge, index_hint);
303-diff --git a/postpone.c b/postpone.c
304-index a703161..7a4cbb1 100644
305---- a/postpone.c
306-+++ b/postpone.c
307-@@ -277,6 +277,9 @@ int mutt_get_postponed (CONTEXT *ctx, HEADER *hdr, HEADER **cur, char *fcc, size
308- /* finished with this message, so delete it. */
309- mutt_set_flag (PostContext, h, M_DELETE, 1);
310-311-+ /* and consider it saved, so that it won't be moved to the trash folder */
312-+ mutt_set_flag (PostContext, h, M_APPENDED, 1);
313-+
314- /* update the count for the status display */
315- PostCount = PostContext->msgcount - PostContext->deleted;
316-