Way cool, Thanks Cedric.  I will check it out this week and provide
feedback.

Lou

On 08/07/01 03:18 PM, Cedric Duval sat at the `puter and typed:
> Hi Zack, David, Andre, Ken, Chris and Louis  :-)
> 
> Here is the patch to edit threads.
> 
> Two new commands to achieve this:
> * link-threads (bound by default to &).
>   To connect replies to a mail, tag these replies and go onto the
>   "parent" message. Then hit the & (link-threads) key.
> 
> * break-thread (bound by default to #).
>   To make a new thread from a subthread, go onto the message where it
>   has to be broken. Then hit the # key.
> 
> (The changes will appear when you resync the mailbox)
> 
> I would be glad if you could do some testing, or bring some suggestions.
> (ask me if you need help patching Mutt)
> If no issue arises, I will soon propose this patch to the mutt-dev list,
> keeping my fingers crossed that this feature will be considered useful!
> 
> Thanks,
> Cedric.
> 
> PS: I still have to write a small section for the Mutt manual. Not my
>     prefered part of the work, since I'm not a fluent writer in English!
>     No one interested? Never mind, I get down to work!  ;-)
> 

> diff -pruN mutt-1.3.20.orig/OPS mutt-1.3.20/OPS
> --- mutt-1.3.20.orig/OPS      Sat Jan 27 14:07:59 2001
> +++ mutt-1.3.20/OPS   Tue Aug  7 15:14:54 2001
> @@ -94,6 +94,7 @@ OP_LAST_ENTRY "move to the last entry"
>  OP_LIST_REPLY "reply to specified mailing list"
>  OP_MACRO "execute a macro"
>  OP_MAIL "compose a new mail message"
> +OP_MAIN_BREAK_THREAD "break the thread in two"
>  OP_MAIN_CHANGE_FOLDER "open a different folder"
>  OP_MAIN_CHANGE_FOLDER_READONLY "open a different folder in read only mode"
>  OP_MAIN_CLEAR_FLAG "clear a status flag from a message"
> @@ -103,6 +104,7 @@ OP_MAIN_FETCH_MAIL "retrieve mail from P
>  OP_MAIN_FIRST_MESSAGE "move to the first message"
>  OP_MAIN_LAST_MESSAGE "move to the last message"
>  OP_MAIN_LIMIT "show only messages matching a pattern"
> +OP_MAIN_LINK_THREADS "link tagged messages to the current one"
>  OP_MAIN_NEXT_NEW "jump to the next new message"
>  OP_MAIN_NEXT_SUBTHREAD "jump to the next subthread"
>  OP_MAIN_NEXT_THREAD "jump to the next thread"
> diff -pruN mutt-1.3.20.orig/copy.c mutt-1.3.20/copy.c
> --- mutt-1.3.20.orig/copy.c   Fri May 11 16:04:24 2001
> +++ mutt-1.3.20/copy.c        Tue Aug  7 15:14:54 2001
> @@ -91,6 +91,12 @@ mutt_copy_hdr (FILE *in, FILE *out, long
>           (ascii_strncasecmp ("Content-Length:", buf, 15) == 0 ||
>            ascii_strncasecmp ("Lines:", buf, 6) == 0))
>         continue;
> +     if ((flags & CH_UPDATE_REFS) &&
> +         ascii_strncasecmp ("References:", buf, 11) == 0)
> +       continue;
> +     if ((flags & CH_UPDATE_IRT) &&
> +         ascii_strncasecmp ("In-Reply-To:", buf, 12) == 0)
> +       continue;
>       ignore = 0;
>        }
>  
> @@ -167,6 +173,12 @@ mutt_copy_hdr (FILE *in, FILE *out, long
>            ascii_strncasecmp ("type:", buf + 8, 5) == 0)) ||
>          ascii_strncasecmp ("mime-version:", buf, 13) == 0))
>       continue;
> +      if ((flags & CH_UPDATE_REFS) &&
> +       ascii_strncasecmp ("References:", buf, 11) == 0)
> +     continue;
> +      if ((flags & CH_UPDATE_IRT) &&
> +       ascii_strncasecmp ("In-Reply-To:", buf, 12) == 0)
> +     continue;
>  
>        /* Find x -- the array entry where this header is to be saved */
>        if (flags & CH_REORDER)
> @@ -276,6 +288,8 @@ mutt_copy_hdr (FILE *in, FILE *out, long
>       CH_UPDATE_LEN   write new Content-Length: and Lines:
>       CH_XMIT         ignore Lines: and Content-Length:
>       CH_WEED         do header weeding
> +     CH_UPDATE_IRT   update the In-Reply-To: header
> +     CH_UPDATE_REFS  update the References: header
>  
>     prefix
>       string to use if CH_PREFIX is set
> @@ -285,6 +299,9 @@ int
>  mutt_copy_header (FILE *in, HEADER *h, FILE *out, int flags, const char *prefix)
>  {
>    char buffer[SHORT_STRING];
> +
> +  flags |= (h->irt_changed ? CH_UPDATE_IRT : 0)
> +         | (h->refs_changed ? CH_UPDATE_REFS : 0);
>    
>    if (mutt_copy_hdr (in, out, h->offset, h->content->offset, flags, prefix) == -1)
>      return (-1);
> @@ -309,6 +326,49 @@ mutt_copy_header (FILE *in, HEADER *h, F
>    {
>      if ((flags & CH_NOSTATUS) == 0)
>      {
> +      if (h->irt_changed && h->env->in_reply_to)
> +      {
> +     LIST *listp = h->env->in_reply_to;
> +
> +     if (fputs ("In-Reply-To: ", out) == EOF)
> +       return (-1);
> +
> +     for (; listp; listp = listp->next)
> +       if ((fputs (listp->data, out) == EOF) || (fputc (' ', out) == EOF))
> +         return (-1);
> +
> +     if (fputc ('\n', out) == EOF)
> +       return (-1);
> +      }
> +
> +      if (h->refs_changed && h->env->references)
> +      {
> +     LIST *listp = h->env->references, *refs = NULL, *t;
> +
> +     if (fputs ("References: ", out) == EOF)
> +       return (-1);
> +
> +     /* Mutt stores references in reverse order, thus we create
> +      * a reordered refs list that we can put in the headers */
> +     for (; listp; listp = listp->next, refs = t)
> +     {
> +       t = (LIST *)safe_malloc (sizeof (LIST));
> +       t->data = listp->data;
> +       t->next = refs;
> +     }
> +
> +     for (; refs; refs = refs->next)
> +       if ((fputs (refs->data, out) == EOF) || (fputc (' ', out) == EOF))
> +         return (-1);
> +
> +     /* clearing refs from memory */
> +     for (t = refs; refs; refs = t->next, t = refs)
> +       safe_free ((void **)&refs);
> +
> +     if (fputc ('\n', out) == EOF)
> +       return (-1);
> +      }
> +
>        if (h->old || h->read)
>        {
>       if (fputs ("Status: ", out) == EOF)
> diff -pruN mutt-1.3.20.orig/curs_main.c mutt-1.3.20/curs_main.c
> --- mutt-1.3.20.orig/curs_main.c      Thu Jul 19 16:49:51 2001
> +++ mutt-1.3.20/curs_main.c   Tue Aug  7 15:14:54 2001
> @@ -1179,6 +1179,64 @@ int mutt_index_menu (void)
>       else
>         menu->redraw = REDRAW_MOTION;
>       break;
> +     
> +      case OP_MAIN_LINK_THREADS:
> +
> +     CHECK_MSGCOUNT;
> +        CHECK_VISIBLE;
> +     CHECK_READONLY;
> +
> +     if (!CURHDR->env->message_id)
> +       mutt_error _("No Message-ID: header available to link thread");
> +     else
> +     {
> +       int changed = 0;
> +
> +       for (i = 0; i < Context->vcount; i++)
> +       {
> +         HEADER *hdr = Context->hdrs[Context->v2r[i]];
> +
> +         if (i != menu->current && hdr->tagged)
> +         {
> +           mutt_free_list (&hdr->env->in_reply_to);
> +           hdr->env->in_reply_to = mutt_new_list ();
> +           hdr->env->in_reply_to->data =
> +             safe_strdup (CURHDR->env->message_id);
> +
> +           mutt_set_flag (Context, hdr, M_TAG, 0);
> +
> +           hdr->irt_changed = hdr->changed = 1;
> +           changed = 1;
> +         }
> +       }
> +
> +       if (changed)
> +       {
> +         Context->changed = 1;
> +         mutt_message _("Threads linked");
> +         menu->redraw |= REDRAW_STATUS | REDRAW_INDEX;
> +       }
> +       else
> +         mutt_error _("No thread linked");
> +     }
> +     break;
> +
> +      case OP_MAIN_BREAK_THREAD:
> +
> +     CHECK_MSGCOUNT;
> +        CHECK_VISIBLE;
> +     CHECK_READONLY;
> +
> +     mutt_free_list (&CURHDR->env->in_reply_to);
> +     mutt_free_list (&CURHDR->env->references);
> +     CURHDR->irt_changed = CURHDR->refs_changed = CURHDR->changed = 1;
> +     Context->changed = 1;
> +
> +     /* cleaning References: for obsolete Message-Ids */
> +     mutt_break_thread (CURHDR, CURHDR->child);
> +     
> +     mutt_message _("Thread broken");
> +     break;
>  
>        case OP_COPY_MESSAGE:
>        case OP_SAVE:
> diff -pruN mutt-1.3.20.orig/functions.h mutt-1.3.20/functions.h
> --- mutt-1.3.20.orig/functions.h      Tue Feb 13 16:00:26 2001
> +++ mutt-1.3.20/functions.h   Tue Aug  7 15:14:54 2001
> @@ -66,6 +66,7 @@ struct binding_t OpGeneric[] = {
>  struct binding_t OpMain[] = {
>    { "create-alias",          OP_CREATE_ALIAS,                "a" },
>    { "bounce-message",                OP_BOUNCE_MESSAGE,              "b" },
> +  { "break-thread",          OP_MAIN_BREAK_THREAD,           "#" },
>    { "change-folder",         OP_MAIN_CHANGE_FOLDER,          "c" },
>    { "change-folder-readonly",        OP_MAIN_CHANGE_FOLDER_READONLY, "\033c" },
>    { "collapse-thread",               OP_MAIN_COLLAPSE_THREAD,        "\033v" },
> @@ -92,6 +93,7 @@ struct binding_t OpMain[] = {
>    { "next-undeleted",                OP_MAIN_NEXT_UNDELETED,         "j" },
>    { "previous-undeleted",    OP_MAIN_PREV_UNDELETED,         "k" },
>    { "limit",                 OP_MAIN_LIMIT,                  "l" },
> +  { "link-threads",          OP_MAIN_LINK_THREADS,           "&" },
>    { "list-reply",            OP_LIST_REPLY,                  "L" },
>    { "mail",                  OP_MAIL,                        "m" },
>    { "toggle-new",            OP_TOGGLE_NEW,                  "N" },
> diff -pruN mutt-1.3.20.orig/mutt.h mutt-1.3.20/mutt.h
> --- mutt-1.3.20.orig/mutt.h   Fri Jun 29 12:05:50 2001
> +++ mutt-1.3.20/mutt.h        Tue Aug  7 15:14:54 2001
> @@ -81,6 +81,8 @@
>  #define CH_NOLEN     (1<<12) /* don't write Content-Length: and Lines: */
>  #define CH_WEED_DELIVERED (1<<13) /* weed eventual Delivered-To headers */
>  #define CH_FORCE_FROM        (1<<14) /* give CH_FROM precedence over CH_WEED? */
> +#define CH_UPDATE_IRT        (1<<15) /* update In-Reply-To: */
> +#define CH_UPDATE_REFS       (1<<16) /* update References: */
>  
>  /* flags for mutt_enter_string() */
>  #define  M_ALIAS   1      /* do alias "completion" by calling up the alias-menu */
> @@ -616,6 +618,8 @@ typedef struct header
>    unsigned int display_subject : 1; /* used for threading */
>    unsigned int fake_thread : 1;     /* no ref matched, but subject did */
>    unsigned int threaded : 1;        /* message has been threaded */
> +  unsigned int irt_changed : 1; /* In-Reply-To changed to link/break threads */
> +  unsigned int refs_changed : 1; /* References changed to break thread */
>    unsigned int recip_valid : 1;  /* is_recipient is valid */
>    unsigned int active : 1;       /* message is not to be removed */
>    
> diff -pruN mutt-1.3.20.orig/protos.h mutt-1.3.20/protos.h
> --- mutt-1.3.20.orig/protos.h Tue Jul  3 21:31:16 2001
> +++ mutt-1.3.20/protos.h      Tue Aug  7 15:14:54 2001
> @@ -146,6 +146,7 @@ void mutt_block_signals (void);
>  void mutt_block_signals_system (void);
>  void mutt_body_handler (BODY *, STATE *);
>  void mutt_bounce_message (FILE *fp, HEADER *, ADDRESS *);
> +void mutt_break_thread (HEADER *, HEADER *);
>  void mutt_buffy (char *, size_t);
>  void mutt_canonical_charset (char *, size_t, const char *);
>  void mutt_check_rescore (CONTEXT *);
> diff -pruN mutt-1.3.20.orig/thread.c mutt-1.3.20/thread.c
> --- mutt-1.3.20.orig/thread.c Thu Apr 26 00:06:58 2001
> +++ mutt-1.3.20/thread.c      Tue Aug  7 15:14:54 2001
> @@ -999,3 +999,35 @@ int mutt_msgno_in_thread (HEADER *cur)
>    } 
>    /* not reached */
>  }
> +
> +void mutt_break_thread (HEADER *brk, HEADER *cur)
> +{
> +  HEADER *p;
> +  LIST *ref;
> +  int done = 0;
> +
> +  for (; cur; cur = cur->next, done = 0)
> +  {
> +    /* parse subthread recursively */
> +    mutt_break_thread (brk, cur->child);
> +
> +    /* Looking for the first bad reference according to the new threading.
> +     * Optimal since Mutt stores the references in reverse order, and the
> +     * first loop should match immediatly for mails respecting RFC2822. */
> +    for (p = brk; !done && p; p = p->parent)
> +      for (ref = cur->env->references; ref; ref = ref->next)
> +     if (!mutt_strcasecmp (ref->data, p->env->message_id))
> +     {
> +       done = 1;
> +       break;
> +     }
> +
> +    if (done)
> +    {
> +      /* clearing the References: header from obsolete Message-Id(s) */
> +      mutt_free_list (&ref->next);
> +
> +      cur->refs_changed = cur->changed = 1;
> +    }
> +  }
> +}


-- 
Louis LeBlanc       [EMAIL PROTECTED]
Fully Funded Hobbyist, KeySlapper Extrordinaire :)
http://acadia.ne.mediaone.net                 ԿԬ

Hurewitz's Memory Principle:
  The chance of forgetting something is directly proportional
  to... to... uh.....

Reply via email to