<<< Date Index >>>     <<< Thread Index >>>

[PATCH] Fetching thread from other folders



I use gmail as my imap e-mail server. I'd like to keep only new
e-mails on my inbox and have the rest archived. Sometimes I get an
answer to an old thread and I want to check out the other messages in
that thread. Because of that I created this patch. It allows for the
user to set a base_folder, from which emails will be fetched (this is
set in .muttrc). There are two new commands: fetch-child-message and
fetch-parent-message. Which will copy the proper email from the base
folder.

I made my modifications on top of the patches applied on mutt 1.5.18
in debian lenny. I think it probably can be easily applied on newer
versions even without the patches the debian maintainer applies. If
you think this patch is useful and you are having trouble applying it,
just drop me an email. I'm attaching it instead of pasting it on the
email because I only have web e-mail access where I am right now.
diff --git a/OPS b/OPS
index 312a84d..2d1443d 100644
--- a/OPS
+++ b/OPS
@@ -115,6 +115,8 @@ OP_MAIN_NEXT_THREAD "jump to the next thread"
 OP_MAIN_NEXT_UNDELETED "move to the next undeleted message"
 OP_MAIN_NEXT_UNREAD "jump to the next unread message"
 OP_MAIN_PARENT_MESSAGE "jump to parent message in thread"
+OP_FETCH_PARENT "fetch parent message from an alternative mailbox"
+OP_FETCH_CHILD "fetch child messages from an alternative mailbox"
 OP_MAIN_PREV_THREAD "jump to previous thread"
 OP_MAIN_PREV_SUBTHREAD "jump to previous subthread"
 OP_MAIN_PREV_UNDELETED "move to the previous undeleted message"
diff --git a/configure b/configure
index add8143..3337495 100755
--- a/configure
+++ b/configure
@@ -3240,13 +3240,13 @@ if test "$ac_test_CFLAGS" = set; then
   CFLAGS=$ac_save_CFLAGS
 elif test $ac_cv_prog_cc_g = yes; then
   if test "$GCC" = yes; then
-    CFLAGS="-g -O2"
+    CFLAGS="-g"
   else
     CFLAGS="-g"
   fi
 else
   if test "$GCC" = yes; then
-    CFLAGS="-O2"
+    CFLAGS=""
   else
     CFLAGS=
   fi
diff --git a/curs_main.c b/curs_main.c
index 59e736a..53002f6 100644
--- a/curs_main.c
+++ b/curs_main.c
@@ -2190,32 +2190,46 @@ int mutt_index_menu (void)
        break;
 
       case OP_VERSION:
-       mutt_version ();
-       break;
+        mutt_version ();
+        break;
 
       case OP_BUFFY_LIST:
-       mutt_buffy_list ();
-       break;
+        mutt_buffy_list ();
+        break;
 
       case OP_VIEW_ATTACHMENTS:
-       CHECK_MSGCOUNT;
+        CHECK_MSGCOUNT;
         CHECK_VISIBLE;
-       mutt_view_attachments (CURHDR);
-       if (CURHDR->attach_del)
-         Context->changed = 1;
-       menu->redraw = REDRAW_FULL;
-       break;
+        mutt_view_attachments (CURHDR);
+        if (CURHDR->attach_del)
+         Context->changed = 1;
+        menu->redraw = REDRAW_FULL;
+        break;
 
       case OP_END_COND:
-       break;
+        break;
 
       case OP_WHAT_KEY:
-       mutt_what_key();
-       break;
+        mutt_what_key();
+        break;
+
+#ifdef USE_IMAP
+      case OP_FETCH_PARENT:
+        imap_fetch_parent(Context, CURHDR);
+        menu->redraw = REDRAW_FULL;
+
+        break;
+
+      case OP_FETCH_CHILD:
+        imap_fetch_child(Context, CURHDR);
+        menu->redraw = REDRAW_FULL;
+
+        break;
+#endif
 
       default:
-       if (menu->menu == MENU_MAIN)
-         km_error_key (MENU_MAIN);
+        if (menu->menu == MENU_MAIN)
+          km_error_key (MENU_MAIN);
     }
 
     if (menu->menu == MENU_PAGER)
diff --git a/functions.h b/functions.h
index 6a46946..ea18df8 100644
--- a/functions.h
+++ b/functions.h
@@ -159,6 +159,10 @@ struct binding_t OpMain[] = { /* map: index */
   { "next-unread",             OP_MAIN_NEXT_UNREAD,            NULL },
   { "previous-unread",         OP_MAIN_PREV_UNREAD,            NULL },
   { "parent-message",          OP_MAIN_PARENT_MESSAGE,         "P" },
+#ifdef USE_IMAP
+  { "fetch-parent-message",    OP_FETCH_PARENT,                NULL},
+  { "fetch-child-message",     OP_FETCH_CHILD,                 NULL},
+#endif
 
 
   { "extract-keys",            OP_EXTRACT_KEYS,                "\013" },
diff --git a/globals.h b/globals.h
index 72d6e40..369c3ef 100644
--- a/globals.h
+++ b/globals.h
@@ -63,6 +63,7 @@ WHERE char *ImapHeaders;
 WHERE char *ImapLogin INITVAL (NULL);
 WHERE char *ImapPass INITVAL (NULL);
 WHERE char *ImapUser INITVAL (NULL);
+WHERE char *BaseFolder INITVAL (NULL);
 #endif
 WHERE char *Inbox;
 WHERE char *Ispell;
diff --git a/imap/imap.c b/imap/imap.c
index fec2029..254f5f6 100644
--- a/imap/imap.c
+++ b/imap/imap.c
@@ -1998,3 +1998,138 @@ int imap_complete(char* dest, size_t dlen, char* path) {
   
   return -1;
 }
+
+static int alldigits(char *buf)
+{
+  while (*buf) {
+    if (!isdigit(*buf))
+      return 0;
+    ++buf;
+  }
+  return 1;
+}
+
+#define STR_SZ 1000
+/* maximum number of in_reply_to messages */
+#define MAX_MSG 30
+static int digits_only(char *str)
+{
+  while (*str) {
+    if (!isdigit(*str))
+      return 0;
+    ++str;
+  }
+
+  return 1;
+}
+
+static unsigned int parse_ids(char *str, unsigned int ids[MAX_MSG])
+{
+  char *num;
+  unsigned int len = 0, i = 0;
+
+  if (!strncmp(str, "* ", 2)) {
+    for (; *str && !isdigit(*str); ++str);
+    num = strtok(str, " ");
+    if (num && digits_only(num)) {
+      ++len;
+      i = 0;
+      ids[i] = atoi(num);
+      while ((num = strtok(NULL, " ")) && digits_only(num)) {
+        ++len;
+        ++i;
+        ids[i] = atoi(num);
+                               if (len >= MAX_MSG) break;
+      }
+    }
+  }
+
+  return len;
+}
+
+int imap_fetch_parent(CONTEXT *ctx, HEADER *hdr)
+{
+  LIST *r;
+  int rc;
+  unsigned int orig_count, i, len, ids[MAX_MSG];
+  IMAP_DATA *idata = (IMAP_DATA*)ctx->data;
+  char cmd[STR_SZ], buf[21];
+
+  orig_count = idata->newMailCount;
+
+  snprintf(cmd, STR_SZ, "SELECT %s", BaseFolder);
+  cmd[STR_SZ-1] = 0;
+  if (imap_exec(idata, cmd, IMAP_CMD_FAIL_OK) < 0)
+    return -1;
+  idata->newMailCount = orig_count;
+
+  len = 0;
+  for (i = 0, r = hdr->env->in_reply_to; r && i<MAX_MSG; r = r->next, ++i) {
+    snprintf(cmd, STR_SZ, "UID SEARCH HEADER Message-ID %s", r->data);
+    cmd[STR_SZ-1] = 0;
+    imap_cmd_start(idata, cmd);
+    rc = imap_cmd_step(idata);
+    len = parse_ids(idata->buf, ids);
+    while (rc == IMAP_CMD_CONTINUE)
+      rc = imap_cmd_step(idata);
+  }
+
+  for (i = 0; i < len; ++i) {
+    snprintf(cmd, STR_SZ, "UID COPY %u %s", ids[i], idata->mailbox);
+    cmd[STR_SZ-1] = 0;
+    if (imap_exec(idata, cmd, IMAP_CMD_FAIL_OK) < 0)
+      return -1;
+  }
+
+  snprintf(cmd, STR_SZ, "SELECT %s", idata->mailbox);
+  cmd[STR_SZ] = 0;
+  if (imap_exec(idata, cmd, IMAP_CMD_FAIL_OK) < 0)
+    return -1;
+
+  return 0;
+}
+
+int imap_fetch_child(CONTEXT *ctx, HEADER *hdr)
+{
+  LIST *r;
+  int rc;
+  unsigned int orig_count, i, len, ids[MAX_MSG];
+  IMAP_DATA *idata = (IMAP_DATA*)ctx->data;
+  char cmd[STR_SZ], buf[21], *msgid;
+
+  orig_count = idata->newMailCount;
+
+  snprintf(cmd, STR_SZ, "SELECT %s", BaseFolder);
+  cmd[STR_SZ-1] = 0;
+  if (imap_exec(idata, cmd, IMAP_CMD_FAIL_OK) < 0)
+    return -1;
+  idata->newMailCount = orig_count;
+
+  len = 0;
+  msgid = hdr->env->message_id;
+  if (msgid) {
+    snprintf(cmd, STR_SZ, "UID SEARCH HEADER References %s", msgid);
+    cmd[STR_SZ-1] = 0;
+    imap_cmd_start(idata, cmd);
+    rc = imap_cmd_step(idata);
+    len = parse_ids(idata->buf, ids);
+    while (rc == IMAP_CMD_CONTINUE)
+      rc = imap_cmd_step(idata);
+  }
+
+  for (i = 0; i < len; ++i) {
+    snprintf(cmd, STR_SZ, "UID COPY %u %s", ids[i], idata->mailbox);
+    cmd[STR_SZ-1] = 0;
+    if (imap_exec(idata, cmd, IMAP_CMD_FAIL_OK) < 0)
+      return -1;
+  }
+
+  snprintf(cmd, STR_SZ, "SELECT %s", idata->mailbox);
+  cmd[STR_SZ] = 0;
+  if (imap_exec(idata, cmd, IMAP_CMD_FAIL_OK) < 0)
+    return -1;
+
+  return 0;
+}
+#undef STR_SZ
+#undef MAX_MSG
diff --git a/imap/imap.h b/imap/imap.h
index ed59566..7e95414 100644
--- a/imap/imap.h
+++ b/imap/imap.h
@@ -48,6 +48,11 @@ int imap_complete (char* dest, size_t dlen, char* path);
 void imap_allow_reopen (CONTEXT *ctx);
 void imap_disallow_reopen (CONTEXT *ctx);
 
+int imap_fetch_parent(CONTEXT *ctx, HEADER *hdr);
+int imap_fetch_child(CONTEXT *ctx, HEADER *hdr);
+int imap_set_force_check(CONTEXT *ctx);
+int imap_unset_force_check(CONTEXT *ctx);
+
 /* browse.c */
 int imap_browse (char* path, struct browser_state* state);
 int imap_mailbox_state (const char* path, struct mailbox_state* state);
diff --git a/init.h b/init.h
index e26c455..2cc7eda 100644
--- a/init.h
+++ b/init.h
@@ -976,6 +976,14 @@ struct option_t MuttVars[] = {
   ** .pp
   ** This variable defaults to your user name on the local machine.
   */
+  { "base_folder",     DT_STR,  R_NONE, UL &BaseFolder, UL "\"[Gmail]/All 
Mail\""},
+  /*
+  ** .pp
+  ** The name base folder from where to copy all parent and child messages.
+  ** .pp
+  ** This variable defaults to "[Gmail]/All Mail", the gmail folder which has
+  ** all the e-mails the user has sent and received.
+  */
 #endif
   { "implicit_autoview", DT_BOOL,R_NONE, OPTIMPLICITAUTOVIEW, 0},
   /*