]> git.llucax.com Git - software/mutt-debian.git/blob - upstream/extra-patches/edit-threads
Import mutt_1.5.9-2
[software/mutt-debian.git] / upstream / extra-patches / edit-threads
1 # vi: ft=diff
2 This is the edit threads patch by Cedric Duval <cedricduval+web@free.fr>.
3
4 The home page for this patch is:
5
6   http://cedricduval.free.fr/mutt/patches/#threads
7
8 * Patch last synced with upstream:
9   - Date: 2004-08-10
10   - File: http://cedricduval.free.fr/mutt/patches/download/patch-1.5.5.1.cd.edit_threads.9.5
11
12 * Changes made:
13   - modified mutt.h part to apply cleanly.
14   - removed diffs for the following files: acconfig.h, configure,
15     configure.in, config.h.in.
16
17 == END PATCH
18 diff -pruN mutt-1.5.5.1-orig/OPS mutt-1.5.5.1/OPS
19 --- mutt-1.5.5.1-orig/OPS       Wed Nov  5 10:41:31 2003
20 +++ mutt-1.5.5.1/OPS    Tue Nov 11 02:52:33 2003
21 @@ -96,6 +96,7 @@ OP_LAST_ENTRY "move to the last entry"
22  OP_LIST_REPLY "reply to specified mailing list"
23  OP_MACRO "execute a macro"
24  OP_MAIL "compose a new mail message"
25 +OP_MAIN_BREAK_THREAD "break the thread in two"
26  OP_MAIN_CHANGE_FOLDER "open a different folder"
27  OP_MAIN_CHANGE_FOLDER_READONLY "open a different folder in read only mode"
28  OP_MAIN_CLEAR_FLAG "clear a status flag from a message"
29 @@ -105,6 +106,7 @@ OP_MAIN_FETCH_MAIL "retrieve mail from P
30  OP_MAIN_FIRST_MESSAGE "move to the first message"
31  OP_MAIN_LAST_MESSAGE "move to the last message"
32  OP_MAIN_LIMIT "show only messages matching a pattern"
33 +OP_MAIN_LINK_THREADS "link tagged message to the current one"
34  OP_MAIN_NEXT_NEW "jump to the next new message"
35  OP_MAIN_NEXT_NEW_THEN_UNREAD "jump to the next new or unread message"
36  OP_MAIN_NEXT_SUBTHREAD "jump to the next subthread"
37 diff -pruN mutt-1.5.5.1-orig/copy.c mutt-1.5.5.1/copy.c
38 --- mutt-1.5.5.1-orig/copy.c    Wed Nov  5 10:41:31 2003
39 +++ mutt-1.5.5.1/copy.c Tue Nov 11 02:52:33 2003
40 @@ -95,6 +95,12 @@ mutt_copy_hdr (FILE *in, FILE *out, long
41             (ascii_strncasecmp ("Content-Length:", buf, 15) == 0 ||
42              ascii_strncasecmp ("Lines:", buf, 6) == 0))
43           continue;
44 +       if ((flags & CH_UPDATE_REFS) &&
45 +           ascii_strncasecmp ("References:", buf, 11) == 0)
46 +         continue;
47 +       if ((flags & CH_UPDATE_IRT) &&
48 +           ascii_strncasecmp ("In-Reply-To:", buf, 12) == 0)
49 +         continue;
50         ignore = 0;
51        }
52  
53 @@ -193,6 +199,12 @@ mutt_copy_hdr (FILE *in, FILE *out, long
54              ascii_strncasecmp ("type:", buf + 8, 5) == 0)) ||
55            ascii_strncasecmp ("mime-version:", buf, 13) == 0))
56         continue;
57 +      if ((flags & CH_UPDATE_REFS) &&
58 +         ascii_strncasecmp ("References:", buf, 11) == 0)
59 +       continue;
60 +      if ((flags & CH_UPDATE_IRT) &&
61 +         ascii_strncasecmp ("In-Reply-To:", buf, 12) == 0)
62 +       continue;
63  
64        /* Find x -- the array entry where this header is to be saved */
65        if (flags & CH_REORDER)
66 @@ -326,6 +338,8 @@ mutt_copy_hdr (FILE *in, FILE *out, long
67         CH_XMIT         ignore Lines: and Content-Length:
68         CH_WEED         do header weeding
69         CH_NOQFROM      ignore ">From " line
70 +       CH_UPDATE_IRT   update the In-Reply-To: header
71 +       CH_UPDATE_REFS  update the References: header
72  
73     prefix
74         string to use if CH_PREFIX is set
75 @@ -335,6 +349,9 @@ int
76  mutt_copy_header (FILE *in, HEADER *h, FILE *out, int flags, const char *prefix)
77  {
78    char buffer[SHORT_STRING];
79 +
80 +  flags |= (h->irt_changed ? CH_UPDATE_IRT : 0)
81 +         | (h->refs_changed ? CH_UPDATE_REFS : 0);
82    
83    if (mutt_copy_hdr (in, out, h->offset, h->content->offset, flags, prefix) == -1)
84      return (-1);
85 @@ -358,7 +375,56 @@ mutt_copy_header (FILE *in, HEADER *h, F
86    if (flags & CH_UPDATE)
87    {
88      if ((flags & CH_NOSTATUS) == 0)
89 +#ifdef IMAP_EDIT_THREADS
90 +#define NEW_ENV new_env
91 +#else
92 +#define NEW_ENV env
93 +#endif
94      {
95 +      if (h->irt_changed && h->NEW_ENV->in_reply_to)
96 +      {
97 +       LIST *listp = h->NEW_ENV->in_reply_to;
98 +
99 +       if (fputs ("In-Reply-To: ", out) == EOF)
100 +         return (-1);
101 +
102 +       for (; listp; listp = listp->next)
103 +         if ((fputs (listp->data, out) == EOF) || (fputc (' ', out) == EOF))
104 +           return (-1);
105 +
106 +       if (fputc ('\n', out) == EOF)
107 +         return (-1);
108 +      }
109 +
110 +      if (h->refs_changed && h->NEW_ENV->references)
111 +      {
112 +       LIST *listp = h->NEW_ENV->references, *refs = NULL, *t;
113 +
114 +       if (fputs ("References: ", out) == EOF)
115 +         return (-1);
116 +
117 +       /* Mutt stores references in reverse order, thus we create
118 +        * a reordered refs list that we can put in the headers */
119 +       for (; listp; listp = listp->next, refs = t)
120 +       {
121 +         t = (LIST *)safe_malloc (sizeof (LIST));
122 +         t->data = listp->data;
123 +         t->next = refs;
124 +       }
125 +
126 +       for (; refs; refs = refs->next)
127 +         if ((fputs (refs->data, out) == EOF) || (fputc (' ', out) == EOF))
128 +           return (-1);
129 +
130 +       /* clearing refs from memory */
131 +       for (t = refs; refs; refs = t->next, t = refs)
132 +         safe_free ((void **)&refs);
133 +
134 +       if (fputc ('\n', out) == EOF)
135 +         return (-1);
136 +      }
137 +#undef NEW_ENV
138 +
139        if (h->old || h->read)
140        {
141         if (fputs ("Status: ", out) == EOF)
142 diff -pruN mutt-1.5.5.1-orig/curs_main.c mutt-1.5.5.1/curs_main.c
143 --- mutt-1.5.5.1-orig/curs_main.c       Wed Nov  5 10:41:31 2003
144 +++ mutt-1.5.5.1/curs_main.c    Tue Nov 11 02:52:33 2003
145 @@ -930,6 +930,11 @@ CHECK_IMAP_ACL(IMAP_ACL_DELETE);
146         else
147         {
148           mutt_set_flag (Context, CURHDR, M_TAG, !CURHDR->tagged);
149 +
150 +         Context->last_tag = CURHDR->tagged ? CURHDR :
151 +           ((Context->last_tag == CURHDR && !CURHDR->tagged)
152 +            ? NULL : Context->last_tag);
153 +
154           menu->redraw = REDRAW_STATUS;
155           if (option (OPTRESOLVE) && menu->current < Context->vcount - 1)
156           {
157 @@ -1162,6 +1167,89 @@ CHECK_IMAP_ACL(IMAP_ACL_DELETE);
158           }
159           done = 1;
160         }
161 +       break;
162 +
163 +      case OP_MAIN_BREAK_THREAD:
164 +
165 +       CHECK_MSGCOUNT;
166 +        CHECK_VISIBLE;
167 +       CHECK_READONLY;
168 +
169 +        if ((Sort & SORT_MASK) != SORT_THREADS)
170 +         mutt_error _("Threading is not enabled.");
171 +
172 +#if defined (USE_IMAP) && ! defined (IMAP_EDIT_THREADS)
173 +       else if (Context->magic == M_IMAP)
174 +         mutt_error _("Compile Mutt with --enable-imap-edit-threads for break-thread support");
175 +#endif
176 +
177 +       else
178 +       {
179 +         {
180 +           HEADER *oldcur = CURHDR;
181 +
182 +           mutt_break_thread (CURHDR);
183 +           mutt_sort_headers (Context, 1);
184 +           menu->current = oldcur->virtual;
185 +         }
186 +
187 +         Context->changed = 1;
188 +         mutt_message _("Thread broken");
189 +
190 +         if (menu->menu == MENU_PAGER)
191 +         {
192 +           op = OP_DISPLAY_MESSAGE;
193 +           continue;
194 +         }
195 +         else
196 +           menu->redraw |= REDRAW_INDEX;
197 +       }
198 +
199 +         break;
200 +
201 +      case OP_MAIN_LINK_THREADS:
202 +
203 +       CHECK_MSGCOUNT;
204 +        CHECK_VISIBLE;
205 +       CHECK_READONLY;
206 +
207 +        if ((Sort & SORT_MASK) != SORT_THREADS)
208 +         mutt_error _("Threading is not enabled.");
209 +
210 +#if defined (USE_IMAP) && ! defined (IMAP_EDIT_THREADS)
211 +       else if (Context->magic == M_IMAP)
212 +         mutt_error _("Compile Mutt with --enable-imap-edit-threads for link-threads support");
213 +#endif
214 +
215 +       else if (!CURHDR->env->message_id)
216 +         mutt_error _("No Message-ID: header available to link thread");
217 +       else if (!tag && (!Context->last_tag || !Context->last_tag->tagged))
218 +         mutt_error _("First, please tag a message to be linked here");
219 +       else 
220 +       {
221 +         HEADER *oldcur = CURHDR;
222 +
223 +         if (mutt_link_threads (CURHDR, tag ? NULL : Context->last_tag,
224 +                                Context))
225 +         {
226 +           mutt_sort_headers (Context, 1);
227 +           menu->current = oldcur->virtual;
228 +           
229 +           Context->changed = 1;
230 +           mutt_message _("Threads linked");
231 +         }
232 +         else
233 +           mutt_error _("No thread linked");
234 +       }
235 +
236 +       if (menu->menu == MENU_PAGER)
237 +       {
238 +         op = OP_DISPLAY_MESSAGE;
239 +         continue;
240 +       }
241 +       else
242 +         menu->redraw |= REDRAW_STATUS | REDRAW_INDEX;
243 +
244         break;
245  
246        case OP_EDIT_TYPE:
247 diff -pruN mutt-1.5.5.1-orig/doc/manual.sgml.head mutt-1.5.5.1/doc/manual.sgml.head
248 --- mutt-1.5.5.1-orig/doc/manual.sgml.head      Wed Nov  5 10:41:34 2003
249 +++ mutt-1.5.5.1/doc/manual.sgml.head   Tue Nov 11 02:52:33 2003
250 @@ -2170,8 +2170,43 @@ used a threaded news client, this is the
251  with large volume mailing lists easier because you can easily delete
252  uninteresting threads and quickly find topics of value.
253  
254 +<sect1>Editing threads
255 +<p>
256 +Mutt has the ability to dynamically restructure threads that are broken
257 +either by misconfigured software or bad behaviour from some
258 +correspondents. This allows to clean your mailboxes formats) from these
259 +annoyances which make it hard to follow a discussion.
260 +
261 +If you want to use these functions with IMAP, you need to compile Mutt
262 +with the <em/--enable-imap-edit-threads/ configure flag.
263 +
264 +<sect2>Linking threads
265 +<p>
266 +
267 +Some mailers tend to "forget" to correctly set the "In-Reply-To:" and
268 +"References:" headers when replying to a message. This results in broken
269 +discussions because Mutt has not enough information to guess the correct
270 +threading.
271 +You can fix this by tagging the reply, then moving to the parent message
272 +and using the ``link-threads'' function (bound to & by default). The
273 +reply will then be connected to this "parent" message.
274 +
275 +You can also connect multiple childs at once, tagging them and using the
276 +tag-prefix command (';') or the auto_tag option.
277 +
278 +<sect2>Breaking threads
279 +<p>
280 +
281 +On mailing lists, some people are in the bad habit of starting a new
282 +discussion by hitting "reply" to any message from the list and changing
283 +the subject to a totally unrelated one.
284 +You can fix such threads by using the ``break-thread'' function (bound
285 +by default to #), which will turn the subthread starting from the
286 +current message into a whole different thread.
287 +
288  <sect1>Delivery Status Notification (DSN) Support
289  <p>
290 +
291  RFC1894 defines a set of MIME content types for relaying information
292  about the status of electronic mail messages.  These can be thought of as
293  ``return receipts.'' Berkeley sendmail 8.8.x currently has some command
294 diff -pruN mutt-1.5.5.1-orig/functions.h mutt-1.5.5.1/functions.h
295 --- mutt-1.5.5.1-orig/functions.h       Wed Nov  5 10:41:31 2003
296 +++ mutt-1.5.5.1/functions.h    Tue Nov 11 02:52:33 2003
297 @@ -69,6 +69,7 @@ struct binding_t OpGeneric[] = {
298  struct binding_t OpMain[] = {
299    { "create-alias",            OP_CREATE_ALIAS,                "a" },
300    { "bounce-message",          OP_BOUNCE_MESSAGE,              "b" },
301 +  { "break-thread",            OP_MAIN_BREAK_THREAD,           "#" },
302    { "change-folder",           OP_MAIN_CHANGE_FOLDER,          "c" },
303    { "change-folder-readonly",  OP_MAIN_CHANGE_FOLDER_READONLY, "\033c" },
304    { "collapse-thread",         OP_MAIN_COLLAPSE_THREAD,        "\033v" },
305 @@ -95,6 +96,7 @@ struct binding_t OpMain[] = {
306    { "next-undeleted",          OP_MAIN_NEXT_UNDELETED,         "j" },
307    { "previous-undeleted",      OP_MAIN_PREV_UNDELETED,         "k" },
308    { "limit",                   OP_MAIN_LIMIT,                  "l" },
309 +  { "link-threads",            OP_MAIN_LINK_THREADS,           "&" },
310    { "list-reply",              OP_LIST_REPLY,                  "L" },
311    { "mail",                    OP_MAIL,                        "m" },
312    { "toggle-new",              OP_TOGGLE_NEW,                  "N" },
313 @@ -153,6 +155,7 @@ struct binding_t OpMain[] = {
314  };
315  
316  struct binding_t OpPager[] = {
317 +  { "break-thread",    OP_MAIN_BREAK_THREAD,           "#" },
318    { "create-alias",    OP_CREATE_ALIAS,                "a" },
319    { "bounce-message",  OP_BOUNCE_MESSAGE,              "b" },
320    { "change-folder",   OP_MAIN_CHANGE_FOLDER,          "c" },
321 @@ -175,6 +178,7 @@ struct binding_t OpPager[] = {
322    { "next-entry",      OP_NEXT_ENTRY,                  "J" },
323    { "previous-undeleted",OP_MAIN_PREV_UNDELETED,       "k" },
324    { "previous-entry",  OP_PREV_ENTRY,                  "K" },
325 +  { "link-threads",    OP_MAIN_LINK_THREADS,           "&" },
326    { "list-reply",      OP_LIST_REPLY,                  "L" },
327    { "redraw-screen",   OP_REDRAW,                      "\014" },
328    { "mail",            OP_MAIL,                        "m" },
329 diff -pruN mutt-1.5.5.1-orig/imap/imap.c mutt-1.5.5.1/imap/imap.c
330 --- mutt-1.5.5.1-orig/imap/imap.c       Wed Nov  5 10:41:36 2003
331 +++ mutt-1.5.5.1/imap/imap.c    Tue Nov 11 02:52:33 2003
332 @@ -980,9 +980,11 @@ int imap_sync_mailbox (CONTEXT* ctx, int
333        mutt_buffer_addstr (&cmd, "UID STORE ");
334        mutt_buffer_addstr (&cmd, uid);
335  
336 -      /* if attachments have been deleted we delete the message and reupload
337 -       * it. This works better if we're expunging, of course. */
338 -      if (ctx->hdrs[n]->attach_del)
339 +      /* if the message has been rethreaded or attachments have been deleted
340 +       * we delete the message and reupload it.
341 +       * This works better if we're expunging, of course. */
342 +      if (ctx->hdrs[n]->refs_changed || ctx->hdrs[n]->irt_changed ||
343 +         ctx->hdrs[n]->attach_del)
344        {
345         dprint (3, (debugfile, "imap_sync_mailbox: Attachments to be deleted, falling back to _mutt_save_message\n"));
346         if (!appendctx)
347 diff -pruN mutt-1.5.5.1-orig/main.c mutt-1.5.5.1/main.c
348 --- mutt-1.5.5.1-orig/main.c    Tue Mar  4 08:49:48 2003
349 +++ mutt-1.5.5.1/main.c Tue Nov 11 02:52:33 2003
350 @@ -228,6 +228,12 @@ static void show_version (void)
351          "-USE_IMAP  "
352  #endif
353  
354 +#ifdef IMAP_EDIT_THREADS
355 +        "+IMAP_EDIT_THREADS  "
356 +#else
357 +        "-IMAP_EDIT_THREADS  "
358 +#endif
359 +
360  #ifdef USE_GSS
361         "+USE_GSS  "
362  #else
363 diff -pruN mutt-1.5.5.1-orig/mh.c mutt-1.5.5.1/mh.c
364 --- mutt-1.5.5.1-orig/mh.c      Wed Nov  5 10:41:32 2003
365 +++ mutt-1.5.5.1/mh.c   Tue Nov 11 02:52:33 2003
366 @@ -1220,7 +1220,7 @@ static int mh_sync_message (CONTEXT * ct
367  {
368    HEADER *h = ctx->hdrs[msgno];
369  
370 -  if (h->attach_del)
371 +  if (h->attach_del || h->refs_changed || h->irt_changed)
372      if (mh_rewrite_message (ctx, msgno) != 0)
373        return -1;
374  
375 @@ -1231,9 +1231,9 @@ static int maildir_sync_message (CONTEXT
376  {
377    HEADER *h = ctx->hdrs[msgno];
378  
379 -  if (h->attach_del)
380 +  if (h->attach_del || h->refs_changed || h->irt_changed)
381    {
382 -    /* when doing attachment deletion, fall back to the MH case. */
383 +    /* when doing attachment deletion/rethreading, fall back to the MH case. */
384      if (mh_rewrite_message (ctx, msgno) != 0)
385        return (-1);
386    }
387 diff -pruN mutt-1.5.5.1-orig/mutt.h mutt-1.5.5.1/mutt.h
388 --- mutt-1.5.5.1-orig/mutt.h    Wed Nov  5 10:41:32 2003
389 +++ mutt-1.5.5.1/mutt.h Tue Nov 11 02:52:33 2003
390 @@ -92,6 +92,8 @@
391  #define CH_WEED_DELIVERED (1<<13) /* weed eventual Delivered-To headers */
392  #define CH_FORCE_FROM  (1<<14) /* give CH_FROM precedence over CH_WEED? */
393  #define CH_NOQFROM     (1<<15) /* give CH_FROM precedence over CH_WEED? */
394 +#define CH_UPDATE_IRT  (1<<16) /* update In-Reply-To: */
395 +#define CH_UPDATE_REFS (1<<17) /* update References: */
396  
397  /* flags for mutt_enter_string() */
398  #define  M_ALIAS   1      /* do alias "completion" by calling up the alias-menu */
399 @@ -506,8 +508,9 @@ typedef struct list_t
400  
401  #define mutt_new_list() safe_calloc (1, sizeof (LIST))
402  void mutt_free_list (LIST **);
403  void mutt_free_rx_list (RX_LIST **);
404  void mutt_free_spam_list (SPAM_LIST **);
405 +LIST *mutt_copy_list (LIST *);
406  int mutt_matches_ignore (const char *, LIST *);
407  
408  /* add an element to a list */
409 @@ -647,6 +650,8 @@ typedef struct header
410    unsigned int subject_changed : 1;    /* used for threading */
411    unsigned int threaded : 1;           /* used for threading */
412    unsigned int display_subject : 1;    /* used for threading */
413 +  unsigned int irt_changed : 1; /* In-Reply-To changed to link/break threads */
414 +  unsigned int refs_changed : 1; /* References changed to break thread */
415    unsigned int recip_valid : 1;        /* is_recipient is valid */
416    unsigned int active : 1;             /* message is not to be removed */
417    unsigned int trash : 1;              /* message is marked as trashed on disk.
418 @@ -687,6 +692,10 @@ typedef struct header
419    char *tree;                  /* character string to print thread tree */
420    struct thread *thread;
421  
422 +#ifdef IMAP_EDIT_THREADS
423 +  ENVELOPE *new_env;   /* envelope information for rethreading */
424 +#endif
425 +
426  #ifdef MIXMASTER
427    LIST *chain;
428  #endif
429 @@ -752,6 +761,7 @@ typedef struct
430    char *pattern;                /* limit pattern string */
431    pattern_t *limit_pattern;     /* compiled limit pattern */
432    HEADER **hdrs;
433 +  HEADER *last_tag;            /* last tagged msg. used to link threads */
434    THREAD *tree;                        /* top of thread tree */
435    HASH *id_hash;               /* hash table by msg id */
436    HASH *subj_hash;             /* hash table by subject */
437 diff -pruN mutt-1.5.5.1-orig/mx.c mutt-1.5.5.1/mx.c
438 --- mutt-1.5.5.1-orig/mx.c      Wed Nov  5 10:41:32 2003
439 +++ mutt-1.5.5.1/mx.c   Tue Nov 11 02:52:33 2003
440 @@ -1161,6 +1161,8 @@ int mx_sync_mailbox (CONTEXT *ctx, int *
441          ctx->deleted = 0;
442        }
443      }
444 +    else if (ctx->last_tag && ctx->last_tag->deleted)
445 +      ctx->last_tag = NULL; /* reset last tagged msg now useless */
446    }
447  
448    /* really only for IMAP - imap_sync_mailbox results in a call to
449 diff -pruN mutt-1.5.5.1-orig/pager.c mutt-1.5.5.1/pager.c
450 --- mutt-1.5.5.1-orig/pager.c   Wed Nov  5 10:41:32 2003
451 +++ mutt-1.5.5.1/pager.c        Tue Nov 11 02:52:33 2003
452 @@ -2481,6 +2481,11 @@ CHECK_IMAP_ACL(IMAP_ACL_WRITE);
453        case OP_TAG:
454         CHECK_MODE(IsHeader (extra));
455         mutt_set_flag (Context, extra->hdr, M_TAG, !extra->hdr->tagged);
456 +
457 +       Context->last_tag = extra->hdr->tagged ? extra->hdr :
458 +         ((Context->last_tag == extra->hdr && !extra->hdr->tagged)
459 +          ? NULL : Context->last_tag);
460 +
461         redraw = REDRAW_STATUS | REDRAW_INDEX;
462         if (option (OPTRESOLVE))
463         {
464 diff -pruN mutt-1.5.5.1-orig/protos.h mutt-1.5.5.1/protos.h
465 --- mutt-1.5.5.1-orig/protos.h  Wed Nov  5 10:41:33 2003
466 +++ mutt-1.5.5.1/protos.h       Tue Nov 11 02:52:33 2003
467 @@ -146,6 +146,7 @@ void mutt_block_signals (void);
468  void mutt_block_signals_system (void);
469  void mutt_body_handler (BODY *, STATE *);
470  int  mutt_bounce_message (FILE *fp, HEADER *, ADDRESS *);
471 +void mutt_break_thread (HEADER *);
472  void mutt_buffy (char *, size_t);
473  int  mutt_buffy_list (void);
474  void mutt_canonical_charset (char *, size_t, const char *);
475 @@ -286,6 +287,7 @@ int mutt_is_list_recipient (int, ADDRESS
476  int mutt_is_subscribed_list (ADDRESS *);
477  int mutt_is_text_part (BODY *);
478  int mutt_is_valid_mailbox (const char *);
479 +int mutt_link_threads (HEADER *, HEADER *, CONTEXT *);
480  int mutt_lookup_mime_type (BODY *, const char *);
481  int mutt_messages_in_thread (CONTEXT *, HEADER *, int);
482  int mutt_multi_choice (char *prompt, char *letters);
483 diff -pruN mutt-1.5.5.1-orig/thread.c mutt-1.5.5.1/thread.c
484 --- mutt-1.5.5.1-orig/thread.c  Wed Nov  5 10:41:34 2003
485 +++ mutt-1.5.5.1/thread.c       Tue Nov 11 02:52:33 2003
486 @@ -1333,3 +1333,105 @@ HASH *mutt_make_subj_hash (CONTEXT *ctx)
487  
488    return hash;
489  }
490 +
491 +static void clean_references (THREAD *brk, THREAD *cur)
492 +{
493 +  THREAD *p;
494 +  LIST *ref = NULL;
495 +  int done = 0;
496 +
497 +  for (; cur; cur = cur->next, done = 0)
498 +  {
499 +    /* parse subthread recursively */
500 +    clean_references (brk, cur->child);
501 +
502 +    if (!cur->message)
503 +      break; /* skip pseudo-message */
504 +
505 +    /* Looking for the first bad reference according to the new threading.
506 +     * Optimal since Mutt stores the references in reverse order, and the
507 +     * first loop should match immediatly for mails respecting RFC2822. */
508 +    for (p = brk; !done && p; p = p->parent)
509 +      for (ref = cur->message->env->references; p->message && ref; ref = ref->next)
510 +       if (!mutt_strcasecmp (ref->data, p->message->env->message_id))
511 +       {
512 +         done = 1;
513 +         break;
514 +       }
515 +
516 +    if (done)
517 +    {
518 +      HEADER *h = cur->message;
519 +
520 +      /* clearing the References: header from obsolete Message-Id(s) */
521 +      mutt_free_list (&ref->next);
522 +
523 +#ifdef IMAP_EDIT_THREADS
524 +      if (h->new_env)
525 +       mutt_free_list (&h->new_env->references);
526 +      else
527 +       h->new_env = mutt_new_envelope ();
528 +
529 +      h->new_env->references = mutt_copy_list (h->env->references);
530 +#endif
531 +
532 +      h->refs_changed = h->changed = 1;
533 +    }
534 +  }
535 +}
536 +
537 +void mutt_break_thread (HEADER *hdr)
538 +{
539 +  mutt_free_list (&hdr->env->in_reply_to);
540 +  mutt_free_list (&hdr->env->references);
541 +  hdr->irt_changed = hdr->refs_changed = hdr->changed = 1;
542 +
543 +#ifdef IMAP_EDIT_THREADS
544 +  if (hdr->new_env)
545 +  {
546 +    mutt_free_list (&hdr->new_env->in_reply_to);
547 +    mutt_free_list (&hdr->new_env->references);
548 +  }
549 +  else
550 +    hdr->new_env = mutt_new_envelope ();
551 +#endif
552 +
553 +  clean_references (hdr->thread, hdr->thread->child);
554 +}
555 +
556 +static int link_threads (HEADER *parent, HEADER *child, CONTEXT *ctx)
557 +{
558 +  if (child == parent)
559 +    return 0;
560 +
561 +  mutt_break_thread (child);
562 +
563 +  child->env->in_reply_to = mutt_new_list ();
564 +  child->env->in_reply_to->data = safe_strdup (parent->env->message_id);
565 +
566 +#ifdef IMAP_EDIT_THREADS
567 +  child->new_env->in_reply_to = mutt_new_list ();
568 +  child->new_env->in_reply_to->data = safe_strdup (parent->env->message_id);
569 +#endif
570 +  
571 +  mutt_set_flag (ctx, child, M_TAG, 0);
572 +  
573 +  child->irt_changed = child->changed = 1;
574 +  return 1;
575 +}
576 +
577 +int mutt_link_threads (HEADER *cur, HEADER *last, CONTEXT *ctx)
578 +{
579 +  int i, changed = 0;
580 +
581 +  if (!last)
582 +  {
583 +    for (i = 0; i < ctx->vcount; i++)
584 +      if (ctx->hdrs[Context->v2r[i]]->tagged)
585 +       changed |= link_threads (cur, ctx->hdrs[Context->v2r[i]], ctx);
586 +  }
587 +  else
588 +    changed = link_threads (cur, last, ctx);
589 +
590 +  return changed;
591 +}
592 diff -pruN mutt-1.5.5.1-orig/PATCHES mutt-1.5.5.1/PATCHES
593 --- mutt-1.5.5.1-orig/PATCHES   Tue Apr 15 15:18:34 2003
594 +++ mutt-1.5.5.1/PATCHES        Tue Nov 11 02:52:33 2003
595 @@ -1,0 +1 @@
596 +patch-1.5.5.1.cd.edit_threads.9.5