From: Kevin McCarthy Date: Mon, 18 Jul 2016 02:31:09 +0000 (-0700) Subject: Add the trash folder patch. X-Git-Tag: neomutt-20160822~76 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=2f764c5637a057e05a75af6cc528eff31cd307c4;p=neomutt Add the trash folder patch. This is based on the trash folder patch by Cedric Duval. Modifications to the original patch are: * Use a flag called M_PURGE instead of M_APPENDED. The same flag is then used in the following "purge" patch instead of adding a different flag. * Removed the counter in context. The existing context->deleted is all that's needed. * Removed the "auto unset M_PURGE" when M_DELETED is unset inside _mutt_set_flag(), although this is convenient, it easily leads to header->purge not being reset in a few situations. * Reset purge flag along with the deleted flag if $delete is answered no. * Set M_PURGE on an edited message. (edit_one_message()) * Preserve purge flag in mutt_reopen_mailbox() * Turn off OPTCONFIRMAPPEND when saving to the trash, rather than hardcoding it off in mutt_save_confirm(). That way, normal save to the folder will respect the option. --- diff --git a/commands.c b/commands.c index c5811bd45..2202a6733 100644 --- a/commands.c +++ b/commands.c @@ -717,6 +717,7 @@ int _mutt_save_message (HEADER *h, CONTEXT *ctx, int delete, int decode, int dec if (delete) { mutt_set_flag (Context, h, MUTT_DELETE, 1); + mutt_set_flag (Context, h, MUTT_PURGE, 1); if (option (OPTDELETEUNTAG)) mutt_set_flag (Context, h, MUTT_TAG, 0); } diff --git a/curs_main.c b/curs_main.c index d0ff0aa6a..8c291bdfd 100644 --- a/curs_main.c +++ b/curs_main.c @@ -2273,11 +2273,13 @@ int mutt_index_menu (void) if (tag) { mutt_tag_set_flag (MUTT_DELETE, 0); + mutt_tag_set_flag (MUTT_PURGE, 0); menu->redraw = REDRAW_INDEX; } else { mutt_set_flag (Context, CURHDR, MUTT_DELETE, 0); + mutt_set_flag (Context, CURHDR, MUTT_PURGE, 0); if (option (OPTRESOLVE) && menu->current < Context->vcount - 1) { menu->current++; @@ -2300,7 +2302,9 @@ int mutt_index_menu (void) rc = mutt_thread_set_flag (CURHDR, MUTT_DELETE, 0, op == OP_UNDELETE_THREAD ? 0 : 1); - + if (rc != -1) + rc = mutt_thread_set_flag (CURHDR, MUTT_PURGE, 0, + op == OP_UNDELETE_THREAD ? 0 : 1); if (rc != -1) { if (option (OPTRESOLVE)) diff --git a/editmsg.c b/editmsg.c index 57d8b1ca1..356810a00 100644 --- a/editmsg.c +++ b/editmsg.c @@ -200,6 +200,7 @@ static int edit_one_message (CONTEXT *ctx, HEADER *cur) if (rc == 0) { mutt_set_flag (Context, cur, MUTT_DELETE, 1); + mutt_set_flag (Context, cur, MUTT_PURGE, 1); mutt_set_flag (Context, cur, MUTT_READ, 1); if (option (OPTDELETEUNTAG)) diff --git a/flags.c b/flags.c index 82e486471..3e8025137 100644 --- a/flags.c +++ b/flags.c @@ -87,6 +87,20 @@ void _mutt_set_flag (CONTEXT *ctx, HEADER *h, int flag, int bf, int upd_ctx) } break; + case MUTT_PURGE: + + if (!mutt_bit_isset(ctx->rights,MUTT_ACL_DELETE)) + return; + + if (bf) + { + if (!h->purge && !ctx->readonly) + h->purge = 1; + } + else if (h->purge) + h->purge = 0; + break; + case MUTT_NEW: if (!mutt_bit_isset(ctx->rights,MUTT_ACL_SEEN)) @@ -345,6 +359,13 @@ int mutt_change_flag (HEADER *h, int bf) { case 'd': case 'D': + if (!bf) + { + if (h) + mutt_set_flag (Context, h, MUTT_PURGE, bf); + else + mutt_tag_set_flag (MUTT_PURGE, bf); + } flag = MUTT_DELETE; break; diff --git a/globals.h b/globals.h index d2b6124d4..af38a43c7 100644 --- a/globals.h +++ b/globals.h @@ -147,6 +147,7 @@ WHERE char *StChars; WHERE char *Status; WHERE char *Tempdir; WHERE char *Tochars; +WHERE char *TrashPath; WHERE char *TSStatusFormat; WHERE char *TSIconFormat; WHERE short TSSupported; diff --git a/imap/message.c b/imap/message.c index 088278084..5ce585868 100644 --- a/imap/message.c +++ b/imap/message.c @@ -902,6 +902,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], MUTT_DELETE, 1); + mutt_set_flag (ctx, ctx->hdrs[n], MUTT_PURGE, 1); if (option (OPTDELETEUNTAG)) mutt_set_flag (ctx, ctx->hdrs[n], MUTT_TAG, 0); } @@ -909,6 +910,7 @@ int imap_copy_messages (CONTEXT* ctx, HEADER* h, char* dest, int delete) else { mutt_set_flag (ctx, h, MUTT_DELETE, 1); + mutt_set_flag (ctx, h, MUTT_PURGE, 1); if (option (OPTDELETEUNTAG)) mutt_set_flag (ctx, h, MUTT_TAG, 0); } diff --git a/init.h b/init.h index 2f582025a..02073557e 100644 --- a/init.h +++ b/init.h @@ -3553,6 +3553,16 @@ struct option_t MuttVars[] = { ** by \fIyou\fP. The sixth character is used to indicate when a mail ** was sent to a mailing-list you subscribe to. */ + { "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. + */ {"ts_icon_format", DT_STR, R_BOTH, UL &TSIconFormat, UL "M%?n?AIL&ail?"}, /* ** .pp diff --git a/mbox.c b/mbox.c index 12d423641..36dd81e73 100644 --- a/mbox.c +++ b/mbox.c @@ -1265,6 +1265,7 @@ int mutt_reopen_mailbox (CONTEXT *ctx, int *index_hint) mutt_set_flag (ctx, ctx->hdrs[i], MUTT_READ, old_hdrs[j]->read); } mutt_set_flag (ctx, ctx->hdrs[i], MUTT_DELETE, old_hdrs[j]->deleted); + mutt_set_flag (ctx, ctx->hdrs[i], MUTT_PURGE, old_hdrs[j]->purge); mutt_set_flag (ctx, ctx->hdrs[i], MUTT_TAG, old_hdrs[j]->tagged); /* we don't need this header any more */ diff --git a/mutt.h b/mutt.h index ce04a68a6..bd90a49b4 100644 --- a/mutt.h +++ b/mutt.h @@ -181,6 +181,7 @@ enum MUTT_UNREAD, MUTT_DELETE, MUTT_UNDELETE, + MUTT_PURGE, MUTT_DELETED, MUTT_FLAG, MUTT_TAG, @@ -728,6 +729,7 @@ typedef struct header unsigned int flagged : 1; /* marked important? */ unsigned int tagged : 1; unsigned int deleted : 1; + unsigned int purge : 1; /* skip trash folder when deleting */ unsigned int changed : 1; unsigned int attach_del : 1; /* has an attachment marked for deletion */ unsigned int old : 1; diff --git a/mx.c b/mx.c index fe956aac1..07f3b4080 100644 --- a/mx.c +++ b/mx.c @@ -797,6 +797,65 @@ 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; + struct stat st, stc; + int opt_confappend, rc; + + if (!TrashPath || !ctx->deleted || + (ctx->magic == MUTT_MAILDIR && option (OPTMAILDIRTRASH))) + return 0; + + for (i = 0; i < ctx->msgcount; i++) + if (ctx->hdrs[i]->deleted && (!ctx->hdrs[i]->purge)) + break; + if (i == ctx->msgcount) + return 0; /* nothing to be done */ + + /* avoid the "append messages" prompt */ + opt_confappend = option (OPTCONFIRMAPPEND); + if (opt_confappend) + unset_option (OPTCONFIRMAPPEND); + rc = mutt_save_confirm (TrashPath, &st); + if (opt_confappend) + set_option (OPTCONFIRMAPPEND); + if (rc != 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, MUTT_APPEND, NULL)) != NULL) + { + /* continue from initial scan above */ + for (; i < ctx->msgcount ; i++) + if (ctx->hdrs[i]->deleted && (!ctx->hdrs[i]->purge)) + { + if (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) { @@ -939,6 +998,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], MUTT_DELETE, 1); + mutt_set_flag (ctx, ctx->hdrs[i], MUTT_PURGE, 1); } else { @@ -962,7 +1022,17 @@ int mx_close_mailbox (CONTEXT *ctx, int *index_hint) mx_fastclose_mailbox (ctx); 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 == MUTT_IMAP) @@ -979,7 +1049,10 @@ int mx_close_mailbox (CONTEXT *ctx, int *index_hint) if (!purge) { for (i = 0; i < ctx->msgcount; i++) + { ctx->hdrs[i]->deleted = 0; + ctx->hdrs[i]->purge = 0; + } ctx->deleted = 0; } @@ -1159,7 +1232,10 @@ int mx_sync_mailbox (CONTEXT *ctx, int *index_hint) if (ctx->magic != MUTT_IMAP) { for (i = 0 ; i < ctx->msgcount ; i++) + { ctx->hdrs[i]->deleted = 0; + ctx->hdrs[i]->purge = 0; + } ctx->deleted = 0; } } @@ -1172,6 +1248,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) != 0) + return -1; + } + #ifdef USE_IMAP if (ctx->magic == MUTT_IMAP) rc = imap_sync_mailbox (ctx, purge, index_hint); diff --git a/pager.c b/pager.c index e6ee9392e..f8113aea5 100644 --- a/pager.c +++ b/pager.c @@ -2743,6 +2743,7 @@ search_next: CHECK_ACL(MUTT_ACL_DELETE, _("Cannot undelete message")); mutt_set_flag (Context, extra->hdr, MUTT_DELETE, 0); + mutt_set_flag (Context, extra->hdr, MUTT_PURGE, 0); redraw = REDRAW_STATUS | REDRAW_INDEX; if (option (OPTRESOLVE)) { @@ -2760,7 +2761,9 @@ search_next: r = mutt_thread_set_flag (extra->hdr, MUTT_DELETE, 0, ch == OP_UNDELETE_THREAD ? 0 : 1); - + if (r != -1) + r = mutt_thread_set_flag (extra->hdr, MUTT_PURGE, 0, + ch == OP_UNDELETE_THREAD ? 0 : 1); if (r != -1) { if (option (OPTRESOLVE)) diff --git a/pattern.c b/pattern.c index ef3cf01a4..85d38b5f4 100644 --- a/pattern.c +++ b/pattern.c @@ -1367,8 +1367,10 @@ int mutt_pattern_func (int op, char *prompt) { switch (op) { + case MUTT_UNDELETE: + mutt_set_flag (Context, Context->hdrs[Context->v2r[i]], MUTT_PURGE, + 0); case MUTT_DELETE: - case MUTT_UNDELETE: mutt_set_flag (Context, Context->hdrs[Context->v2r[i]], MUTT_DELETE, (op == MUTT_DELETE)); break; diff --git a/postpone.c b/postpone.c index 9e19da2cd..525a72fda 100644 --- a/postpone.c +++ b/postpone.c @@ -178,6 +178,7 @@ static HEADER *select_msg (void) { case OP_DELETE: case OP_UNDELETE: + /* should deleted draft messages be saved in the trash folder? */ mutt_set_flag (PostContext, PostContext->hdrs[menu->current], MUTT_DELETE, (i == OP_DELETE) ? 1 : 0); PostCount = PostContext->msgcount - PostContext->deleted; if (option (OPTRESOLVE) && menu->current < menu->max - 1) @@ -276,6 +277,7 @@ 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, MUTT_DELETE, 1); + mutt_set_flag (PostContext, h, MUTT_PURGE, 1); /* update the count for the status display */ PostCount = PostContext->msgcount - PostContext->deleted;