File mutt-1.9.0-1.9.1.patch of Package mutt

---
 imap/command.c      |   47 +++++++++++++++++++++++-------
 imap/imap.c         |   79 +++++++++++++++++++++++++++++++++++++++-------------
 imap/imap_private.h |    2 -
 imap/message.c      |    6 +--
 4 files changed, 99 insertions(+), 35 deletions(-)

--- imap/command.c
+++ imap/command.c	2017-10-24 14:15:49.011057645 +0000
@@ -146,6 +146,7 @@ static void cmd_handle_fatal(struct Imap
   if ((idata->state >= IMAP_SELECTED) && (idata->reopen & IMAP_REOPEN_ALLOW))
   {
     mx_fastclose_mailbox(idata->ctx);
+    mutt_socket_close(idata->conn);
     mutt_error(_("Mailbox closed"));
     mutt_sleep(1);
     idata->state = IMAP_DISCONNECTED;
@@ -257,7 +258,7 @@ static void cmd_parse_expunge(struct Ima
  */
 static void cmd_parse_fetch(struct ImapData *idata, char *s)
 {
-  unsigned int msn;
+  unsigned int msn, uid;
   struct Header *h = NULL;
 
   mutt_debug(3, "Handling FETCH\n");
@@ -288,19 +289,41 @@ static void cmd_parse_fetch(struct ImapD
   }
   s++;
 
-  if (mutt_strncasecmp("FLAGS", s, 5) != 0)
+  while (*s)
   {
-    mutt_debug(2, "Only handle FLAGS updates\n");
-    return;
-  }
+    SKIPWS (s);
 
-  /* If server flags could conflict with mutt's flags, reopen the mailbox. */
-  if (h->changed)
-    idata->reopen |= IMAP_EXPUNGE_PENDING;
-  else
-  {
-    imap_set_flags(idata, h, s);
-    idata->check_status = IMAP_FLAGS_PENDING;
+    if (mutt_strncasecmp ("FLAGS", s, 5) == 0)
+    {
+      /* If server flags could conflict with mutt's flags, reopen the mailbox. */
+      if (h->changed)
+        idata->reopen |= IMAP_EXPUNGE_PENDING;
+      else
+      {
+        imap_set_flags (idata, h, s);
+        idata->check_status = IMAP_FLAGS_PENDING;
+      }
+      return;
+    }
+    else if (mutt_strncasecmp ("UID", s, 3) == 0)
+    {
+      s += 3;
+      SKIPWS (s);
+      uid = (unsigned int) atoi (s);
+      if (uid != HEADER_DATA(h)->uid)
+      {
+        mutt_debug(2, "FETCH UID vs MSN mismatch.  Skipping update.\n");
+        return;
+      }
+      s = imap_next_word (s);
+    }
+    else if (*s == ')')
+      s++; /* end of request */
+    else if (*s)
+    {
+      mutt_debug(2, "Only handle FLAGS updates\n");
+      return;
+    }
   }
 }
 
--- imap/imap.c
+++ imap/imap.c	2017-10-24 14:27:08.002351735 +0000
@@ -318,7 +318,26 @@ void imap_expunge_mailbox(struct ImapDat
       imap_free_header_data((struct ImapHeaderData **) &h->data);
     }
     else
+    {
       h->index = i;
+      /* Mutt has several places where it turns off h->active as a
+       * hack.  For example to avoid FLAG updates, or to exclude from
+       * imap_exec_msgset.
+       *
+       * Unfortunately, when a reopen is allowed and the IMAP_EXPUNGE_PENDING
+       * flag becomes set (e.g. a flag update to a modified header),
+       * this function will be called by imap_cmd_finish().
+       *
+       * The mx_update_tables() will free and remove these "inactive" headers,
+       * despite that an EXPUNGE was not received for them.
+       * This would result in memory leaks and segfaults due to dangling
+       * pointers in the msn_index and uid_hash.
+       *
+       * So this is another hack to work around the hacks.  We don't want to
+       * remove the messages, so make sure active is on.
+       */
+      h->active = 1;
+    }
   }
 
 #ifdef USE_HCACHE
@@ -1094,7 +1113,7 @@ out:
  * compare_flags - Compare local flags against the server
  * @retval 0 if mutt's flags match cached server flags
  */
-static bool compare_flags(struct Header *h)
+static bool compare_flags_for_copy(struct Header *h)
 {
   struct ImapHeaderData *hd = (struct ImapHeaderData *) h->data;
 
@@ -1106,16 +1125,17 @@ static bool compare_flags(struct Header
     return true;
   if (h->replied != hd->replied)
     return true;
-  if (h->deleted != hd->deleted)
-    return true;
 
   return false;
 }
 
 /**
- * imap_sync_message - Update server to reflect the flags of a single message
+ * imap_sync_message -  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(struct ImapData *idata, struct Header *hdr,
+int imap_sync_message_for_copy(struct ImapData *idata, struct Header *hdr,
                       struct Buffer *cmd, int *err_continue)
 {
   char flags[LONG_STRING];
@@ -1123,9 +1143,13 @@ int imap_sync_message(struct ImapData *i
 
   hdr->changed = false;
 
-  if (!compare_flags(hdr))
+  if (!compare_flags_for_copy(hdr))
   {
-    idata->ctx->changed = false;
+    if (hdr->deleted == HEADER_DATA(hdr)->deleted)
+    {
+      hdr->changed = 0;
+      idata->ctx->changed = false;
+    }
     return 0;
   }
 
@@ -1140,7 +1164,7 @@ int imap_sync_message(struct ImapData *i
   imap_set_flag(idata, MUTT_ACL_WRITE, hdr->old, "Old ", flags, sizeof(flags));
   imap_set_flag(idata, MUTT_ACL_WRITE, hdr->flagged, "\\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))
@@ -1156,7 +1180,7 @@ int imap_sync_message(struct ImapData *i
     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);
 
@@ -1178,11 +1202,17 @@ int imap_sync_message(struct ImapData *i
   {
     *err_continue = imap_continue("imap_sync_message: STORE failed", idata->buf);
     if (*err_continue != MUTT_YES)
+    {
+      hdr->active = 1;
       return -1;
+    }
   }
 
-  hdr->active = true;
-  idata->ctx->changed = false;
+  if (hdr->deleted == HEADER_DATA(hdr)->deleted)
+  {
+    hdr->active = true;
+    idata->ctx->changed = false;
+  }
 
   return 0;
 }
@@ -1637,7 +1667,7 @@ int imap_buffy_check(int force, int chec
     {
       /* Send commands to previous server. Sorting the buffy list
        * may prevent some infelicitous interleavings */
-      if (imap_exec(lastdata, NULL, IMAP_CMD_FAIL_OK) == -1)
+      if (imap_exec(lastdata, NULL, IMAP_CMD_FAIL_OK | IMAP_CMD_POLL) == -1)
         mutt_debug(1, "Error polling mailboxes\n");
 
       lastdata = NULL;
@@ -2214,9 +2244,11 @@ int imap_fast_trash(struct Context *ctx,
   char mbox[LONG_STRING];
   char mmbox[LONG_STRING];
   char prompt[LONG_STRING];
-  int rc;
+  int n, rc;
   struct ImapMbox mx;
   bool triedcreate = false;
+  struct Buffer *sync_cmd = NULL;
+  int err_continue = MUTT_NO;
 
   idata = ctx->data;
 
@@ -2238,16 +2270,24 @@ int imap_fast_trash(struct Context *ctx,
     strfcpy(mbox, "INBOX", sizeof(mbox));
   imap_munge_mbox_name(idata, mmbox, sizeof(mmbox), mbox);
 
-  /* loop in case of TRYCREATE */
-  do
+  sync_cmd = mutt_buffer_new ();
+  for (n = 0; n < ctx->msgcount; n++)
   {
-    rc = imap_exec_msgset(idata, "UID STORE", "+FLAGS.SILENT (\\Seen)", MUTT_TRASH, 0, 0);
-    if (rc < 0)
+    if (ctx->hdrs[n]->active && ctx->hdrs[n]->changed &&
+        ctx->hdrs[n]->deleted && !ctx->hdrs[n]->purge)
     {
-      mutt_debug(1, "imap_fast_trash: Unable to mark messages as seen\n");
-      goto out;
+      rc = imap_sync_message_for_copy (idata, ctx->hdrs[n], sync_cmd, &err_continue);
+      if (rc < 0)
+      {
+        mutt_debug(1, "imap_fast_trash: could not sync\n");
+        goto out;
+      }
     }
+  }
 
+  /* loop in case of TRYCREATE */
+  do
+  {
     rc = imap_exec_msgset(idata, "UID COPY", mmbox, MUTT_TRASH, 0, 0);
     if (!rc)
     {
@@ -2297,6 +2337,7 @@ int imap_fast_trash(struct Context *ctx,
   rc = 0;
 
 out:
+  mutt_buffer_free (&sync_cmd);
   FREE(&mx.mbox);
 
   return rc < 0 ? -1 : rc;
--- imap/imap_private.h
+++ imap/imap_private.h	2017-10-24 14:15:49.015057570 +0000
@@ -279,7 +279,7 @@ struct ImapData *imap_conn_find(const st
 int imap_read_literal(FILE *fp, struct ImapData *idata, long bytes, struct Progress *pbar);
 void imap_expunge_mailbox(struct ImapData *idata);
 void imap_logout(struct ImapData **idata);
-int imap_sync_message(struct ImapData *idata, struct Header *hdr, struct Buffer *cmd, int *err_continue);
+int imap_sync_message_for_copy(struct ImapData *idata, struct Header *hdr, struct Buffer *cmd, int *err_continue);
 bool imap_has_flag(struct ListHead *flag_list, const char *flag);
 
 /* auth.c */
--- imap/message.c
+++ imap/message.c	2017-10-24 14:15:49.015057570 +0000
@@ -1261,7 +1261,7 @@ int imap_copy_messages(struct Context *c
 
         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)
           {
             mutt_debug(1, "imap_copy_messages: could not sync\n");
@@ -1292,7 +1292,7 @@ int imap_copy_messages(struct Context *c
 
       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)
         {
           mutt_debug(1, "imap_copy_messages: could not sync\n");
@@ -1444,7 +1444,7 @@ char *imap_set_flags(struct ImapData *id
   hd = h->data;
   newh.data = hd;
 
-  mutt_debug(2, "imap_fetch_message: parsing FLAGS\n");
+  mutt_debug(2, "imap_set_flags: parsing FLAGS\n");
   if ((s = msg_parse_flags(&newh, s)) == NULL)
     return NULL;
 
openSUSE Build Service is sponsored by