summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKevin McCarthy <kevin@8t8.us>2017-09-13 15:48:16 -0700
committerKevin McCarthy <kevin@8t8.us>2017-09-13 15:48:16 -0700
commit19a17aaeff13103dc0981ffe100c16993f42293d (patch)
treec2e761693ea7cb40325e8908bea64d5443a91c3a
parent0139a67dafc24f4c57b84cd8972a27814fe016fd (diff)
Change imap copy/save and trash to sync flags, excluding deleted. (closes #3966) (closes #3860)
imap_copy_messages() uses a helper to sync the flags before performing a server-side copy. However, it had a bug that the "deleted" flag on a local message, if set, will be propagated to the copy too. Change the copy sync helper to ignore the deleted flag. Then, change the imap trash function to use the same helper. Thanks to Anton Lindqvist for his excellent bug report, suggested fixes, and help testing.
-rw-r--r--imap/imap.c61
-rw-r--r--imap/imap_private.h2
-rw-r--r--imap/message.c4
3 files changed, 49 insertions, 18 deletions
diff --git a/imap/imap.c b/imap/imap.c
index d156e440..e757c688 100644
--- a/imap/imap.c
+++ b/imap/imap.c
@@ -1051,8 +1051,9 @@ out:
return rc;
}
-/* returns 0 if mutt's flags match cached server flags */
-static int compare_flags (HEADER* h)
+/* returns 0 if mutt's flags match cached server flags:
+ * EXCLUDING the deleted flag. */
+static int compare_flags_for_copy (HEADER* h)
{
IMAP_HEADER_DATA* hd = (IMAP_HEADER_DATA*)h->data;
@@ -1064,24 +1065,28 @@ static int compare_flags (HEADER* h)
return 1;
if (h->replied != hd->replied)
return 1;
- if (h->deleted != hd->deleted)
- return 1;
return 0;
}
-/* Update the IMAP server to reflect the flags a single message. */
-int imap_sync_message (IMAP_DATA *idata, HEADER *hdr, BUFFER *cmd,
+/* Update the IMAP server to reflect the flags for a single message before
+ * performing a "UID COPY".
+ * NOTE: This does not sync the "deleted" flag state, because it is not
+ * desirable to propagate that flag into the copy.
+ */
+int imap_sync_message_for_copy (IMAP_DATA *idata, HEADER *hdr, BUFFER *cmd,
int *err_continue)
{
char flags[LONG_STRING];
char uid[11];
- hdr->changed = 0;
-
- if (!compare_flags (hdr))
+ if (!compare_flags_for_copy (hdr))
{
- idata->ctx->changed--;
+ if (hdr->deleted == HEADER_DATA(hdr)->deleted)
+ {
+ hdr->changed = 0;
+ idata->ctx->changed--;
+ }
return 0;
}
@@ -1100,8 +1105,8 @@ int imap_sync_message (IMAP_DATA *idata, HEADER *hdr, BUFFER *cmd,
"\\Flagged ", flags, sizeof (flags));
imap_set_flag (idata, MUTT_ACL_WRITE, hdr->replied,
"\\Answered ", flags, sizeof (flags));
- imap_set_flag (idata, MUTT_ACL_DELETE, hdr->deleted,
- "\\Deleted ", flags, sizeof (flags));
+ imap_set_flag (idata, MUTT_ACL_DELETE, HEADER_DATA(hdr)->deleted,
+ "\\Deleted ", flags, sizeof (flags));
/* now make sure we don't lose custom tags */
if (mutt_bit_isset (idata->ctx->rights, MUTT_ACL_WRITE))
@@ -1117,7 +1122,8 @@ int imap_sync_message (IMAP_DATA *idata, HEADER *hdr, BUFFER *cmd,
imap_set_flag (idata, MUTT_ACL_WRITE, 1, "Old ", flags, sizeof (flags));
imap_set_flag (idata, MUTT_ACL_WRITE, 1, "\\Flagged ", flags, sizeof (flags));
imap_set_flag (idata, MUTT_ACL_WRITE, 1, "\\Answered ", flags, sizeof (flags));
- imap_set_flag (idata, MUTT_ACL_DELETE, 1, "\\Deleted ", flags, sizeof (flags));
+ imap_set_flag (idata, MUTT_ACL_DELETE, !HEADER_DATA(hdr)->deleted,
+ "\\Deleted ", flags, sizeof (flags));
mutt_remove_trailing_ws (flags);
@@ -1139,11 +1145,18 @@ int imap_sync_message (IMAP_DATA *idata, HEADER *hdr, BUFFER *cmd,
*err_continue = imap_continue ("imap_sync_message: STORE failed",
idata->buf);
if (*err_continue != MUTT_YES)
+ {
+ hdr->active = 1;
return -1;
+ }
}
hdr->active = 1;
- idata->ctx->changed--;
+ if (hdr->deleted == HEADER_DATA(hdr)->deleted)
+ {
+ hdr->changed = 0;
+ idata->ctx->changed--;
+ }
return 0;
}
@@ -2123,9 +2136,11 @@ int imap_fast_trash (CONTEXT* ctx, char* dest)
char mbox[LONG_STRING];
char mmbox[LONG_STRING];
char prompt[LONG_STRING];
- int rc;
+ int n, rc;
IMAP_MBOX mx;
int triedcreate = 0;
+ BUFFER *sync_cmd = NULL;
+ int err_continue = MUTT_NO;
idata = (IMAP_DATA*) ctx->data;
@@ -2148,6 +2163,21 @@ int imap_fast_trash (CONTEXT* ctx, char* dest)
strfcpy (mbox, "INBOX", sizeof (mbox));
imap_munge_mbox_name (idata, mmbox, sizeof (mmbox), mbox);
+ sync_cmd = mutt_buffer_new ();
+ for (n = 0; n < ctx->msgcount; n++)
+ {
+ if (ctx->hdrs[n]->active && ctx->hdrs[n]->changed &&
+ ctx->hdrs[n]->deleted && !ctx->hdrs[n]->purge)
+ {
+ rc = imap_sync_message_for_copy (idata, ctx->hdrs[n], sync_cmd, &err_continue);
+ if (rc < 0)
+ {
+ dprint (1, (debugfile, "imap_fast_trash: could not sync\n"));
+ goto out;
+ }
+ }
+ }
+
/* loop in case of TRYCREATE */
do
{
@@ -2201,6 +2231,7 @@ int imap_fast_trash (CONTEXT* ctx, char* dest)
rc = 0;
out:
+ mutt_buffer_free (&sync_cmd);
FREE (&mx.mbox);
return rc < 0 ? -1 : rc;
diff --git a/imap/imap_private.h b/imap/imap_private.h
index b85c1280..0c28dfbb 100644
--- a/imap/imap_private.h
+++ b/imap/imap_private.h
@@ -249,7 +249,7 @@ IMAP_DATA* imap_conn_find (const ACCOUNT* account, int flags);
int imap_read_literal (FILE* fp, IMAP_DATA* idata, long bytes, progress_t*);
void imap_expunge_mailbox (IMAP_DATA* idata);
void imap_logout (IMAP_DATA** idata);
-int imap_sync_message (IMAP_DATA *idata, HEADER *hdr, BUFFER *cmd,
+int imap_sync_message_for_copy (IMAP_DATA *idata, HEADER *hdr, BUFFER *cmd,
int *err_continue);
int imap_has_flag (LIST* flag_list, const char* flag);
diff --git a/imap/message.c b/imap/message.c
index 4ec1c01e..8282ec10 100644
--- a/imap/message.c
+++ b/imap/message.c
@@ -953,7 +953,7 @@ int imap_copy_messages (CONTEXT* ctx, HEADER* h, char* dest, int delete)
if (ctx->hdrs[n]->tagged && ctx->hdrs[n]->active &&
ctx->hdrs[n]->changed)
{
- rc = imap_sync_message (idata, ctx->hdrs[n], &sync_cmd, &err_continue);
+ rc = imap_sync_message_for_copy (idata, ctx->hdrs[n], &sync_cmd, &err_continue);
if (rc < 0)
{
dprint (1, (debugfile, "imap_copy_messages: could not sync\n"));
@@ -984,7 +984,7 @@ int imap_copy_messages (CONTEXT* ctx, HEADER* h, char* dest, int delete)
if (h->active && h->changed)
{
- rc = imap_sync_message (idata, h, &sync_cmd, &err_continue);
+ rc = imap_sync_message_for_copy (idata, h, &sync_cmd, &err_continue);
if (rc < 0)
{
dprint (1, (debugfile, "imap_copy_messages: could not sync\n"));