X-Git-Url: http://git.madism.org/?p=apps%2Fmadmutt.git;a=blobdiff_plain;f=thread.c;h=e34c543ea88bf62b1d547c15eff7f8780dc22eab;hp=998cd6c17f18a379a3abdcbfcc4d681e1a67290f;hb=f3cbb9f51357972f6e74244494236a41dc4d84cd;hpb=3d937534e7b1ee723f86594b5e4c64c95158a933 diff --git a/thread.c b/thread.c index 998cd6c..e34c543 100644 --- a/thread.c +++ b/thread.c @@ -1,34 +1,24 @@ /* + * Copyright notice from original mutt: * Copyright (C) 1996-2002 Michael R. Elkins * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. - */ + * This file is part of mutt-ng, see http://www.muttng.org/. + * It's licensed under the GNU General Public License, + * please see the file GPL in the top level source directory. + */ + +#include #include "mutt.h" #include "sort.h" - -#include -#include +#include "thread.h" #define VISIBLE(hdr, ctx) (hdr->virtual >= 0 || (hdr->collapsed && (!ctx->pattern || hdr->limited))) /* determine whether a is a descendant of b */ -static int is_descendant (THREAD *a, THREAD *b) +static int is_descendant (THREAD * a, THREAD * b) { - while (a) - { + while (a) { if (a == b) return (1); a = a->parent; @@ -37,7 +27,7 @@ static int is_descendant (THREAD *a, THREAD *b) } /* Determines whether to display a message's subject. */ -static int need_display_subject (CONTEXT *ctx, HEADER *hdr) +static int need_display_subject (CONTEXT * ctx, HEADER * hdr) { THREAD *tmp, *tree = hdr->thread; @@ -51,29 +41,25 @@ static int need_display_subject (CONTEXT *ctx, HEADER *hdr) /* if our subject is different from that of our closest previously displayed * sibling, display the subject */ - for (tmp = tree->prev; tmp; tmp = tmp->prev) - { + for (tmp = tree->prev; tmp; tmp = tmp->prev) { hdr = tmp->message; - if (hdr && VISIBLE (hdr, ctx)) - { + if (hdr && VISIBLE (hdr, ctx)) { if (hdr->subject_changed) - return (1); + return (1); else - break; + break; } } - + /* if there is a parent-to-child subject change anywhere between us and our * closest displayed ancestor, display the subject */ - for (tmp = tree->parent; tmp; tmp = tmp->parent) - { + for (tmp = tree->parent; tmp; tmp = tmp->parent) { hdr = tmp->message; - if (hdr) - { + if (hdr) { if (VISIBLE (hdr, ctx)) - return (0); + return (0); else if (hdr->subject_changed) - return (1); + return (1); } } @@ -81,13 +67,12 @@ static int need_display_subject (CONTEXT *ctx, HEADER *hdr) return (1); } -static void linearize_tree (CONTEXT *ctx) +static void linearize_tree (CONTEXT * ctx) { THREAD *tree = ctx->tree; HEADER **array = ctx->hdrs + (Sort & SORT_REVERSE ? ctx->msgcount - 1 : 0); - while (tree) - { + while (tree) { while (!tree->message) tree = tree->child; @@ -96,17 +81,14 @@ static void linearize_tree (CONTEXT *ctx) if (tree->child) tree = tree->child; - else - { - while (tree) - { - if (tree->next) - { - tree = tree->next; - break; - } - else - tree = tree->parent; + else { + while (tree) { + if (tree->next) { + tree = tree->next; + break; + } + else + tree = tree->parent; } } } @@ -119,11 +101,13 @@ static void linearize_tree (CONTEXT *ctx) * skip parts of the tree in mutt_draw_tree() if we've decided here that we * don't care about them any more. */ -static void calculate_visibility (CONTEXT *ctx, int *max_depth) +static void calculate_visibility (CONTEXT * ctx, int *max_depth) { THREAD *tmp, *tree = ctx->tree; - int hide_top_missing = option (OPTHIDETOPMISSING) && !option (OPTHIDEMISSING); - int hide_top_limited = option (OPTHIDETOPLIMITED) && !option (OPTHIDELIMITED); + int hide_top_missing = option (OPTHIDETOPMISSING) + && !option (OPTHIDEMISSING); + int hide_top_limited = option (OPTHIDETOPLIMITED) + && !option (OPTHIDELIMITED); int depth = 0; /* we walk each level backwards to make it easier to compute next_subtree_visible */ @@ -131,89 +115,78 @@ static void calculate_visibility (CONTEXT *ctx, int *max_depth) tree = tree->next; *max_depth = 0; - FOREVER - { + for (;;) { if (depth > *max_depth) *max_depth = depth; tree->subtree_visible = 0; - if (tree->message) - { - FREE (&tree->message->tree); - if (VISIBLE (tree->message, ctx)) - { - tree->deep = 1; - tree->visible = 1; - tree->message->display_subject = need_display_subject (ctx, tree->message); - for (tmp = tree; tmp; tmp = tmp->parent) - { - if (tmp->subtree_visible) - { - tmp->deep = 1; - tmp->subtree_visible = 2; - break; - } - else - tmp->subtree_visible = 1; - } + if (tree->message) { + p_delete(&tree->message->tree); + if (VISIBLE (tree->message, ctx)) { + tree->deep = 1; + tree->visible = 1; + tree->message->display_subject = + need_display_subject (ctx, tree->message); + for (tmp = tree; tmp; tmp = tmp->parent) { + if (tmp->subtree_visible) { + tmp->deep = 1; + tmp->subtree_visible = 2; + break; + } + else + tmp->subtree_visible = 1; + } } - else - { - tree->visible = 0; - tree->deep = !option (OPTHIDELIMITED); + else { + tree->visible = 0; + tree->deep = !option (OPTHIDELIMITED); } } - else - { + else { tree->visible = 0; tree->deep = !option (OPTHIDEMISSING); } - tree->next_subtree_visible = tree->next && (tree->next->next_subtree_visible - || tree->next->subtree_visible); - if (tree->child) - { + tree->next_subtree_visible = tree->next + && (tree->next->next_subtree_visible || tree->next->subtree_visible); + if (tree->child) { depth++; tree = tree->child; while (tree->next) - tree = tree->next; + tree = tree->next; } else if (tree->prev) tree = tree->prev; - else - { - while (tree && !tree->prev) - { - depth--; - tree = tree->parent; + else { + while (tree && !tree->prev) { + depth--; + tree = tree->parent; } if (!tree) - break; + break; else - tree = tree->prev; + tree = tree->prev; } } - + /* now fix up for the OPTHIDETOP* options if necessary */ - if (hide_top_limited || hide_top_missing) - { + if (hide_top_limited || hide_top_missing) { tree = ctx->tree; - FOREVER - { - if (!tree->visible && tree->deep && tree->subtree_visible < 2 - && ((tree->message && hide_top_limited) || (!tree->message && hide_top_missing))) - tree->deep = 0; + for (;;) { + if (!tree->visible && tree->deep && tree->subtree_visible < 2 + && ((tree->message && hide_top_limited) + || (!tree->message && hide_top_missing))) + tree->deep = 0; if (!tree->deep && tree->child && tree->subtree_visible) - tree = tree->child; + tree = tree->child; else if (tree->next) - tree = tree->next; - else - { - while (tree && !tree->next) - tree = tree->parent; - if (!tree) - break; - else - tree = tree->next; + tree = tree->next; + else { + while (tree && !tree->next) + tree = tree->parent; + if (!tree) + break; + else + tree = tree->next; } } } @@ -227,173 +200,156 @@ static void calculate_visibility (CONTEXT *ctx, int *max_depth) * graphics chars on terminals which don't support them (see the man page * for curs_addch). */ -void mutt_draw_tree (CONTEXT *ctx) +void mutt_draw_tree (CONTEXT * ctx) { char *pfx = NULL, *mypfx = NULL, *arrow = NULL, *myarrow = NULL, *new_tree; char corner = (Sort & SORT_REVERSE) ? M_TREE_ULCORNER : M_TREE_LLCORNER; char vtee = (Sort & SORT_REVERSE) ? M_TREE_BTEE : M_TREE_TTEE; - int depth = 0, start_depth = 0, max_depth = 0, width = option (OPTNARROWTREE) ? 1 : 2; + int depth = 0, start_depth = 0, max_depth = 0, width = + option (OPTNARROWTREE) ? 1 : 2; THREAD *nextdisp = NULL, *pseudo = NULL, *parent = NULL, *tree = ctx->tree; /* Do the visibility calculations and free the old thread chars. * From now on we can simply ignore invisible subtrees */ calculate_visibility (ctx, &max_depth); - pfx = safe_malloc (width * max_depth + 2); - arrow = safe_malloc (width * max_depth + 2); - while (tree) - { - if (depth) - { + pfx = p_new(char, width * max_depth + 2); + arrow = p_new(char, width * max_depth + 2); + while (tree) { + if (depth) { myarrow = arrow + (depth - start_depth - (start_depth ? 0 : 1)) * width; if (depth && start_depth == depth) - myarrow[0] = nextdisp ? M_TREE_LTEE : corner; + myarrow[0] = nextdisp ? M_TREE_LTEE : corner; else if (parent->message && !option (OPTHIDELIMITED)) - myarrow[0] = M_TREE_HIDDEN; + myarrow[0] = M_TREE_HIDDEN; else if (!parent->message && !option (OPTHIDEMISSING)) - myarrow[0] = M_TREE_MISSING; + myarrow[0] = M_TREE_MISSING; else - myarrow[0] = vtee; + myarrow[0] = vtee; if (width == 2) - myarrow[1] = pseudo ? M_TREE_STAR - : (tree->duplicate_thread ? M_TREE_EQUALS : M_TREE_HLINE); - if (tree->visible) - { - myarrow[width] = M_TREE_RARROW; - myarrow[width + 1] = 0; - new_tree = safe_malloc ((2 + depth * width)); - if (start_depth > 1) - { - strncpy (new_tree, pfx, (start_depth - 1) * width); - strfcpy (new_tree + (start_depth - 1) * width, - arrow, (1 + depth - start_depth) * width + 2); - } - else - strfcpy (new_tree, arrow, 2 + depth * width); - tree->message->tree = new_tree; + myarrow[1] = pseudo ? M_TREE_STAR + : (tree->duplicate_thread ? M_TREE_EQUALS : M_TREE_HLINE); + if (tree->visible) { + myarrow[width] = M_TREE_RARROW; + myarrow[width + 1] = 0; + new_tree = p_new(char, (2 + depth * width)); + if (start_depth > 1) { + memcpy(new_tree, pfx, (start_depth - 1) * width); + m_strcpy(new_tree + (start_depth - 1) * width, + (1 + depth - start_depth) * width + 2, arrow); + } + else + m_strcpy(new_tree, 2 + depth * width, arrow); + tree->message->tree = new_tree; } } - if (tree->child && depth) - { + if (tree->child && depth) { mypfx = pfx + (depth - 1) * width; mypfx[0] = nextdisp ? M_TREE_VLINE : M_TREE_SPACE; if (width == 2) - mypfx[1] = M_TREE_SPACE; + mypfx[1] = M_TREE_SPACE; } parent = tree; nextdisp = NULL; pseudo = NULL; - do - { - if (tree->child && tree->subtree_visible) - { - if (tree->deep) - depth++; - if (tree->visible) - start_depth = depth; - tree = tree->child; - - /* we do this here because we need to make sure that the first child thread - * of the old tree that we deal with is actually displayed if any are, - * or we might set the parent variable wrong while going through it. */ - while (!tree->subtree_visible && tree->next) - tree = tree->next; + do { + if (tree->child && tree->subtree_visible) { + if (tree->deep) + depth++; + if (tree->visible) + start_depth = depth; + tree = tree->child; + + /* we do this here because we need to make sure that the first child thread + * of the old tree that we deal with is actually displayed if any are, + * or we might set the parent variable wrong while going through it. */ + while (!tree->subtree_visible && tree->next) + tree = tree->next; } - else - { - while (!tree->next && tree->parent) - { - if (tree == pseudo) - pseudo = NULL; - if (tree == nextdisp) - nextdisp = NULL; - if (tree->visible) - start_depth = depth; - tree = tree->parent; - if (tree->deep) - { - if (start_depth == depth) - start_depth--; - depth--; - } - } - if (tree == pseudo) - pseudo = NULL; - if (tree == nextdisp) - nextdisp = NULL; - if (tree->visible) - start_depth = depth; - tree = tree->next; - if (!tree) - break; + else { + while (!tree->next && tree->parent) { + if (tree == pseudo) + pseudo = NULL; + if (tree == nextdisp) + nextdisp = NULL; + if (tree->visible) + start_depth = depth; + tree = tree->parent; + if (tree->deep) { + if (start_depth == depth) + start_depth--; + depth--; + } + } + if (tree == pseudo) + pseudo = NULL; + if (tree == nextdisp) + nextdisp = NULL; + if (tree->visible) + start_depth = depth; + tree = tree->next; + if (!tree) + break; } if (!pseudo && tree->fake_thread) - pseudo = tree; + pseudo = tree; if (!nextdisp && tree->next_subtree_visible) - nextdisp = tree; + nextdisp = tree; } while (!tree->deep); } - FREE (&pfx); - FREE (&arrow); + p_delete(&pfx); + p_delete(&arrow); } /* since we may be trying to attach as a pseudo-thread a THREAD that * has no message, we have to make a list of all the subjects of its * most immediate existing descendants. we also note the earliest * date on any of the parents and put it in *dateptr. */ -static LIST *make_subject_list (THREAD *cur, time_t *dateptr) +static string_list_t *make_subject_list (THREAD * cur, time_t * dateptr) { THREAD *start = cur; ENVELOPE *env; time_t thisdate; - LIST *curlist, *oldlist, *newlist, *subjects = NULL; + string_list_t *curlist, *oldlist, *newlist, *subjects = NULL; int rc = 0; - - FOREVER - { + + for (;;) { while (!cur->message) cur = cur->child; - if (dateptr) - { + if (dateptr) { thisdate = option (OPTTHREADRECEIVED) - ? cur->message->received : cur->message->date_sent; + ? cur->message->received : cur->message->date_sent; if (!*dateptr || thisdate < *dateptr) - *dateptr = thisdate; + *dateptr = thisdate; } env = cur->message->env; if (env->real_subj && - ((env->real_subj != env->subject) || (!option (OPTSORTRE)))) - { + ((env->real_subj != env->subject) || (!option (OPTSORTRE)))) { for (curlist = subjects, oldlist = NULL; - curlist; oldlist = curlist, curlist = curlist->next) - { - rc = mutt_strcmp (env->real_subj, curlist->data); - if (rc >= 0) - break; + curlist; oldlist = curlist, curlist = curlist->next) { + rc = m_strcmp(env->real_subj, curlist->data); + if (rc >= 0) + break; } - if (!curlist || rc > 0) - { - newlist = safe_calloc (1, sizeof (LIST)); - newlist->data = env->real_subj; - if (oldlist) - { - newlist->next = oldlist->next; - oldlist->next = newlist; - } - else - { - newlist->next = subjects; - subjects = newlist; - } + if (!curlist || rc > 0) { + newlist = p_new(string_list_t, 1); + newlist->data = env->real_subj; + if (oldlist) { + newlist->next = oldlist->next; + oldlist->next = newlist; + } + else { + newlist->next = subjects; + subjects = newlist; + } } } - while (!cur->next && cur != start) - { + while (!cur->next && cur != start) { cur = cur->parent; } if (cur == start) @@ -408,42 +364,40 @@ static LIST *make_subject_list (THREAD *cur, time_t *dateptr) * if there are multiple matches, the one which was sent the latest, but * before the current message, is used. */ -static THREAD *find_subject (CONTEXT *ctx, THREAD *cur) +static THREAD *find_subject (CONTEXT * ctx, THREAD * cur) { struct hash_elem *ptr; THREAD *tmp, *last = NULL; int hash; - LIST *subjects = NULL, *oldlist; - time_t date = 0; + string_list_t *subjects = NULL, *oldlist; + time_t date = 0; subjects = make_subject_list (cur, &date); - while (subjects) - { + while (subjects) { hash = hash_string ((unsigned char *) subjects->data, - ctx->subj_hash->nelem); - for (ptr = ctx->subj_hash->table[hash]; ptr; ptr = ptr->next) - { + ctx->subj_hash->nelem); + for (ptr = ctx->subj_hash->table[hash]; ptr; ptr = ptr->next) { tmp = ((HEADER *) ptr->data)->thread; - if (tmp != cur && /* don't match the same message */ - !tmp->fake_thread && /* don't match pseudo threads */ - tmp->message->subject_changed && /* only match interesting replies */ - !is_descendant (tmp, cur) && /* don't match in the same thread */ - (date >= (option (OPTTHREADRECEIVED) ? - tmp->message->received : - tmp->message->date_sent)) && - (!last || - (option (OPTTHREADRECEIVED) ? - (last->message->received < tmp->message->received) : - (last->message->date_sent < tmp->message->date_sent))) && - tmp->message->env->real_subj && - mutt_strcmp (subjects->data, tmp->message->env->real_subj) == 0) - last = tmp; /* best match so far */ + if (tmp != cur && /* don't match the same message */ + !tmp->fake_thread && /* don't match pseudo threads */ + tmp->message->subject_changed && /* only match interesting replies */ + !is_descendant (tmp, cur) && /* don't match in the same thread */ + (date >= (option (OPTTHREADRECEIVED) ? + tmp->message->received : + tmp->message->date_sent)) && + (!last || + (option (OPTTHREADRECEIVED) ? + (last->message->received < tmp->message->received) : + (last->message->date_sent < tmp->message->date_sent))) && + tmp->message->env->real_subj && + m_strcmp(subjects->data, tmp->message->env->real_subj) == 0) + last = tmp; /* best match so far */ } oldlist = subjects; subjects = subjects->next; - FREE (&oldlist); + p_delete(&oldlist); } return (last); } @@ -451,7 +405,7 @@ static THREAD *find_subject (CONTEXT *ctx, THREAD *cur) /* remove cur and its descendants from their current location. * also make sure ancestors of cur no longer are sorted by the * fact that cur is their descendant. */ -static void unlink_message (THREAD **old, THREAD *cur) +static void unlink_message (THREAD ** old, THREAD * cur) { THREAD *tmp; @@ -463,16 +417,15 @@ static void unlink_message (THREAD **old, THREAD *cur) if (cur->next) cur->next->prev = cur->prev; - if (cur->sort_key) - { + if (cur->sort_key) { for (tmp = cur->parent; tmp && tmp->sort_key == cur->sort_key; - tmp = tmp->parent) + tmp = tmp->parent) tmp->sort_key = NULL; } } /* add cur as a prior sibling of *new, with parent newparent */ -static void insert_message (THREAD **new, THREAD *newparent, THREAD *cur) +static void insert_message (THREAD ** new, THREAD * newparent, THREAD * cur) { if (*new) (*new)->prev = cur; @@ -484,7 +437,7 @@ static void insert_message (THREAD **new, THREAD *newparent, THREAD *cur) } /* thread by subject things that didn't get threaded by message-id */ -static void pseudo_threads (CONTEXT *ctx) +static void pseudo_threads (CONTEXT * ctx) { THREAD *tree = ctx->tree, *top = tree; THREAD *tmp, *cur, *parent, *curchild, *nextchild; @@ -492,52 +445,45 @@ static void pseudo_threads (CONTEXT *ctx) if (!ctx->subj_hash) ctx->subj_hash = mutt_make_subj_hash (ctx); - while (tree) - { + while (tree) { cur = tree; tree = tree->next; - if ((parent = find_subject (ctx, cur)) != NULL) - { + if ((parent = find_subject (ctx, cur)) != NULL) { cur->fake_thread = 1; unlink_message (&top, cur); insert_message (&parent->child, parent, cur); parent->sort_children = 1; tmp = cur; - FOREVER - { - while (!tmp->message) - tmp = tmp->child; - - /* if the message we're attaching has pseudo-children, they - * need to be attached to its parent, so move them up a level. - * but only do this if they have the same real subject as the - * parent, since otherwise they rightly belong to the message - * we're attaching. */ - if (tmp == cur - || !mutt_strcmp (tmp->message->env->real_subj, - parent->message->env->real_subj)) - { - tmp->message->subject_changed = 0; - - for (curchild = tmp->child; curchild; ) - { - nextchild = curchild->next; - if (curchild->fake_thread) - { - unlink_message (&tmp->child, curchild); - insert_message (&parent->child, parent, curchild); - } - curchild = nextchild; - } - } - - while (!tmp->next && tmp != cur) - { - tmp = tmp->parent; - } - if (tmp == cur) - break; - tmp = tmp->next; + for (;;) { + while (!tmp->message) + tmp = tmp->child; + + /* if the message we're attaching has pseudo-children, they + * need to be attached to its parent, so move them up a level. + * but only do this if they have the same real subject as the + * parent, since otherwise they rightly belong to the message + * we're attaching. */ + if (tmp == cur + || !m_strcmp(tmp->message->env->real_subj, + parent->message->env->real_subj)) { + tmp->message->subject_changed = 0; + + for (curchild = tmp->child; curchild;) { + nextchild = curchild->next; + if (curchild->fake_thread) { + unlink_message (&tmp->child, curchild); + insert_message (&parent->child, parent, curchild); + } + curchild = nextchild; + } + } + + while (!tmp->next && tmp != cur) { + tmp = tmp->parent; + } + if (tmp == cur) + break; + tmp = tmp->next; } } } @@ -545,45 +491,43 @@ static void pseudo_threads (CONTEXT *ctx) } -void mutt_clear_threads (CONTEXT *ctx) +void mutt_clear_threads (CONTEXT * ctx) { int i; - for (i = 0; i < ctx->msgcount; i++) - { + for (i = 0; i < ctx->msgcount; i++) { ctx->hdrs[i]->thread = NULL; ctx->hdrs[i]->threaded = 0; } ctx->tree = NULL; if (ctx->thread_hash) - hash_destroy (&ctx->thread_hash, *free); + hash_destroy (&ctx->thread_hash, free); } -int compare_threads (const void *a, const void *b) +static int compare_threads (const void *a, const void *b) { static sort_t *sort_func = NULL; if (a || b) return ((*sort_func) (&(*((THREAD **) a))->sort_key, - &(*((THREAD **) b))->sort_key)); + &(*((THREAD **) b))->sort_key)); /* a hack to let us reset sort_func even though we can't * have extra arguments because of qsort */ - else - { + else { sort_func = NULL; sort_func = mutt_get_sort_func (Sort); return (sort_func ? 1 : 0); } } -THREAD *mutt_sort_subthreads (THREAD *thread, int init) +THREAD *mutt_sort_subthreads (THREAD * thread, int init) { THREAD **array, *sort_key, *top, *tmp; HEADER *oldsort_key; int i, array_size, sort_top = 0; - + /* we put things into the array backwards to save some cycles, * but we want to have to move less stuff around if we're * resorting, so we sort backwards and then put them back @@ -595,112 +539,100 @@ THREAD *mutt_sort_subthreads (THREAD *thread, int init) top = thread; - array = safe_calloc ((array_size = 256), sizeof (THREAD *)); - while (1) - { - if (init || !thread->sort_key) - { + array = p_new(THREAD *, (array_size = 256)); + while (1) { + if (init || !thread->sort_key) { thread->sort_key = NULL; if (thread->parent) thread->parent->sort_children = 1; else - sort_top = 1; + sort_top = 1; } - if (thread->child) - { + if (thread->child) { thread = thread->child; continue; } - else - { + else { /* if it has no children, it must be real. sort it on its own merits */ thread->sort_key = thread->message; - if (thread->next) - { - thread = thread->next; - continue; + if (thread->next) { + thread = thread->next; + continue; } } - while (!thread->next) - { + while (!thread->next) { /* if it has siblings and needs to be sorted, sort it... */ - if (thread->prev && (thread->parent ? thread->parent->sort_children : sort_top)) - { - /* put them into the array */ - for (i = 0; thread; i++, thread = thread->prev) - { - if (i >= array_size) - safe_realloc (&array, (array_size *= 2) * sizeof (THREAD *)); - - array[i] = thread; - } - - qsort ((void *) array, i, sizeof (THREAD *), *compare_threads); - - /* attach them back together. make thread the last sibling. */ - thread = array[0]; - thread->next = NULL; - array[i - 1]->prev = NULL; - - if (thread->parent) - thread->parent->child = array[i - 1]; - else - top = array[i - 1]; - - while (--i) - { - array[i - 1]->prev = array[i]; - array[i]->next = array[i - 1]; - } + if (thread->prev + && (thread->parent ? thread->parent->sort_children : sort_top)) { + /* put them into the array */ + for (i = 0; thread; i++, thread = thread->prev) { + if (i >= array_size) + p_realloc(&array, array_size *= 2); + + array[i] = thread; + } + + qsort ((void *) array, i, sizeof (THREAD *), compare_threads); + + /* attach them back together. make thread the last sibling. */ + thread = array[0]; + thread->next = NULL; + array[i - 1]->prev = NULL; + + if (thread->parent) + thread->parent->child = array[i - 1]; + else + top = array[i - 1]; + + while (--i) { + array[i - 1]->prev = array[i]; + array[i]->next = array[i - 1]; + } } - if (thread->parent) - { - tmp = thread; - thread = thread->parent; - - if (!thread->sort_key || thread->sort_children) - { - /* make sort_key the first or last sibling, as appropriate */ - sort_key = (!(Sort & SORT_LAST) ^ !(Sort & SORT_REVERSE)) ? thread->child : tmp; - - /* we just sorted its children */ - thread->sort_children = 0; - - oldsort_key = thread->sort_key; - thread->sort_key = thread->message; - - if (Sort & SORT_LAST) - { - if (!thread->sort_key - || ((((Sort & SORT_REVERSE) ? 1 : -1) - * compare_threads ((void *) &thread, - (void *) &sort_key)) - > 0)) - thread->sort_key = sort_key->sort_key; - } - else if (!thread->sort_key) - thread->sort_key = sort_key->sort_key; - - /* if its sort_key has changed, we need to resort it and siblings */ - if (oldsort_key != thread->sort_key) - { - if (thread->parent) - thread->parent->sort_children = 1; - else - sort_top = 1; - } - } + if (thread->parent) { + tmp = thread; + thread = thread->parent; + + if (!thread->sort_key || thread->sort_children) { + /* make sort_key the first or last sibling, as appropriate */ + sort_key = + (!(Sort & SORT_LAST) ^ !(Sort & SORT_REVERSE)) ? thread-> + child : tmp; + + /* we just sorted its children */ + thread->sort_children = 0; + + oldsort_key = thread->sort_key; + thread->sort_key = thread->message; + + if (Sort & SORT_LAST) { + if (!thread->sort_key || ((((Sort & SORT_REVERSE) ? 1 : -1) + * compare_threads ((void *) &thread, + (void *) &sort_key)) + > 0)) + thread->sort_key = sort_key->sort_key; + } + else if (!thread->sort_key) + thread->sort_key = sort_key->sort_key; + + /* if its sort_key has changed, we need to resort it and siblings */ + if (oldsort_key != thread->sort_key) { + if (thread->parent) + thread->parent->sort_children = 1; + else + sort_top = 1; + } + } } - else - { - Sort ^= SORT_REVERSE; - FREE (&array); - return (top); + else { + Sort ^= SORT_REVERSE; + p_delete(&array); + return (top); } } @@ -708,14 +640,13 @@ THREAD *mutt_sort_subthreads (THREAD *thread, int init) } } -static void check_subjects (CONTEXT *ctx, int init) +static void check_subjects (CONTEXT * ctx, int init) { HEADER *cur; THREAD *tmp; int i; - for (i = 0; i < ctx->msgcount; i++) - { + for (i = 0; i < ctx->msgcount; i++) { cur = ctx->hdrs[i]; if (cur->thread->check_subject) cur->thread->check_subject = 0; @@ -724,36 +655,36 @@ static void check_subjects (CONTEXT *ctx, int init) /* figure out which messages have subjects different than their parents' */ tmp = cur->thread->parent; - while (tmp && !tmp->message) - { + while (tmp && !tmp->message) { tmp = tmp->parent; } if (!tmp) cur->subject_changed = 1; else if (cur->env->real_subj && tmp->message->env->real_subj) - cur->subject_changed = mutt_strcmp (cur->env->real_subj, - tmp->message->env->real_subj) ? 1 : 0; + cur->subject_changed = m_strcmp(cur->env->real_subj, + tmp->message->env-> + real_subj) ? 1 : 0; else cur->subject_changed = (cur->env->real_subj - || tmp->message->env->real_subj) ? 1 : 0; + || tmp->message->env->real_subj) ? 1 : 0; } } -void mutt_sort_threads (CONTEXT *ctx, int init) +void mutt_sort_threads (CONTEXT * ctx, int init) { HEADER *cur; int i, oldsort, using_refs = 0; THREAD *thread, *new, *tmp, top; - LIST *ref = NULL; - + string_list_t *ref = NULL; + /* set Sort to the secondary method to support the set sort_aux=reverse-* * settings. The sorting functions just look at the value of * SORT_REVERSE */ oldsort = Sort; Sort = SortAux; - + if (!ctx->thread_hash) init = 1; @@ -772,101 +703,89 @@ void mutt_sort_threads (CONTEXT *ctx, int init) * exists. otherwise, if there is a THREAD that already has a message, thread * new message as an identical child. if we didn't attach the message to a * THREAD, make a new one for it. */ - for (i = 0; i < ctx->msgcount; i++) - { + for (i = 0; i < ctx->msgcount; i++) { cur = ctx->hdrs[i]; - if (!cur->thread) - { + if (!cur->thread) { if ((!init || option (OPTDUPTHREADS)) && cur->env->message_id) - thread = hash_find (ctx->thread_hash, cur->env->message_id); + thread = hash_find (ctx->thread_hash, cur->env->message_id); else - thread = NULL; - - if (thread && !thread->message) - { - /* this is a message which was missing before */ - thread->message = cur; - cur->thread = thread; - thread->check_subject = 1; - - /* mark descendants as needing subject_changed checked */ - for (tmp = (thread->child ? thread->child : thread); tmp != thread; ) - { - while (!tmp->message) - tmp = tmp->child; - tmp->check_subject = 1; - while (!tmp->next && tmp != thread) - tmp = tmp->parent; - if (tmp != thread) - tmp = tmp->next; - } - - if (thread->parent) - { - /* remove threading info above it based on its children, which we'll - * recalculate based on its headers. make sure not to leave - * dangling missing messages. note that we haven't kept track - * of what info came from its children and what from its siblings' - * children, so we just remove the stuff that's definitely from it */ - do - { - tmp = thread->parent; - unlink_message (&tmp->child, thread); - thread->parent = NULL; - thread->sort_key = NULL; - thread->fake_thread = 0; - thread = tmp; - } while (thread != &top && !thread->child && !thread->message); - } + thread = NULL; + + if (thread && !thread->message) { + /* this is a message which was missing before */ + thread->message = cur; + cur->thread = thread; + thread->check_subject = 1; + + /* mark descendants as needing subject_changed checked */ + for (tmp = (thread->child ? thread->child : thread); tmp != thread;) { + while (!tmp->message) + tmp = tmp->child; + tmp->check_subject = 1; + while (!tmp->next && tmp != thread) + tmp = tmp->parent; + if (tmp != thread) + tmp = tmp->next; + } + + if (thread->parent) { + /* remove threading info above it based on its children, which we'll + * recalculate based on its headers. make sure not to leave + * dangling missing messages. note that we haven't kept track + * of what info came from its children and what from its siblings' + * children, so we just remove the stuff that's definitely from it */ + do { + tmp = thread->parent; + unlink_message (&tmp->child, thread); + thread->parent = NULL; + thread->sort_key = NULL; + thread->fake_thread = 0; + thread = tmp; + } while (thread != &top && !thread->child && !thread->message); + } } - else - { - new = (option (OPTDUPTHREADS) ? thread : NULL); - - thread = safe_calloc (1, sizeof (THREAD)); - thread->message = cur; - thread->check_subject = 1; - cur->thread = thread; - hash_insert (ctx->thread_hash, - cur->env->message_id ? cur->env->message_id : "", - thread, 1); - - if (new) - { - if (new->duplicate_thread) - new = new->parent; - - thread = cur->thread; - - insert_message (&new->child, new, thread); - thread->duplicate_thread = 1; - thread->message->threaded = 1; - } + else { + new = (option (OPTDUPTHREADS) ? thread : NULL); + + thread = p_new(THREAD, 1); + thread->message = cur; + thread->check_subject = 1; + cur->thread = thread; + hash_insert (ctx->thread_hash, + cur->env->message_id ? cur->env->message_id : "", + thread, 1); + + if (new) { + if (new->duplicate_thread) + new = new->parent; + + thread = cur->thread; + + insert_message (&new->child, new, thread); + thread->duplicate_thread = 1; + thread->message->threaded = 1; + } } } - else - { + else { /* unlink pseudo-threads because they might be children of newly * arrived messages */ thread = cur->thread; - for (new = thread->child; new; ) - { - tmp = new->next; - if (new->fake_thread) - { - unlink_message (&thread->child, new); - insert_message (&top.child, &top, new); - new->fake_thread = 0; - } - new = tmp; + for (new = thread->child; new;) { + tmp = new->next; + if (new->fake_thread) { + unlink_message (&thread->child, new); + insert_message (&top.child, &top, new); + new->fake_thread = 0; + } + new = tmp; } } } /* thread by references */ - for (i = 0; i < ctx->msgcount; i++) - { + for (i = 0; i < ctx->msgcount; i++) { cur = ctx->hdrs[i]; if (cur->threaded) continue; @@ -875,64 +794,57 @@ void mutt_sort_threads (CONTEXT *ctx, int init) thread = cur->thread; using_refs = 0; - while (1) - { - if (using_refs == 0) - { - /* look at the beginning of in-reply-to: */ - if ((ref = cur->env->in_reply_to) != NULL) - using_refs = 1; - else - { - ref = cur->env->references; - using_refs = 2; - } + while (1) { + if (using_refs == 0) { + /* look at the beginning of in-reply-to: */ + if ((ref = cur->env->in_reply_to) != NULL) + using_refs = 1; + else { + ref = cur->env->references; + using_refs = 2; + } } - else if (using_refs == 1) - { - /* if there's no references header, use all the in-reply-to: - * data that we have. otherwise, use the first reference - * if it's different than the first in-reply-to, otherwise use - * the second reference (since at least eudora puts the most - * recent reference in in-reply-to and the rest in references) - */ - if (!cur->env->references) - ref = ref->next; - else - { - if (mutt_strcmp (ref->data, cur->env->references->data)) - ref = cur->env->references; - else - ref = cur->env->references->next; - - using_refs = 2; - } + else if (using_refs == 1) { + /* if there's no references header, use all the in-reply-to: + * data that we have. otherwise, use the first reference + * if it's different than the first in-reply-to, otherwise use + * the second reference (since at least eudora puts the most + * recent reference in in-reply-to and the rest in references) + */ + if (!cur->env->references) + ref = ref->next; + else { + if (m_strcmp(ref->data, cur->env->references->data)) + ref = cur->env->references; + else + ref = cur->env->references->next; + + using_refs = 2; + } } else - ref = ref->next; /* go on with references */ - + ref = ref->next; /* go on with references */ + if (!ref) - break; + break; - if ((new = hash_find (ctx->thread_hash, ref->data)) == NULL) - { - new = safe_calloc (1, sizeof (THREAD)); - hash_insert (ctx->thread_hash, ref->data, new, 1); + if ((new = hash_find (ctx->thread_hash, ref->data)) == NULL) { + new = p_new(THREAD, 1); + hash_insert (ctx->thread_hash, ref->data, new, 1); } - else - { - if (new->duplicate_thread) - new = new->parent; - if (is_descendant (new, thread)) /* no loops! */ - break; + else { + if (new->duplicate_thread) + new = new->parent; + if (is_descendant (new, thread)) /* no loops! */ + continue; } if (thread->parent) - unlink_message (&top.child, thread); + unlink_message (&top.child, thread); insert_message (&new->child, new, thread); thread = new; if (thread->message || (thread->parent && thread->parent != &top)) - break; + break; } if (!thread->parent) @@ -940,8 +852,7 @@ void mutt_sort_threads (CONTEXT *ctx, int init) } /* detach everything from the temporary top node */ - for (thread = top.child; thread; thread = thread->next) - { + for (thread = top.child; thread; thread = thread->next) { thread->parent = NULL; } ctx->tree = top.child; @@ -951,13 +862,12 @@ void mutt_sort_threads (CONTEXT *ctx, int init) if (!option (OPTSTRICTTHREADS)) pseudo_threads (ctx); - if (ctx->tree) - { + if (ctx->tree) { ctx->tree = mutt_sort_subthreads (ctx->tree, init); /* restore the oldsort order. */ Sort = oldsort; - + /* Put the list into an array. */ linearize_tree (ctx); @@ -966,7 +876,7 @@ void mutt_sort_threads (CONTEXT *ctx, int init) } } -static HEADER *find_virtual (THREAD *cur, int reverse) +static HEADER *find_virtual (THREAD * cur, int reverse) { THREAD *top; @@ -980,27 +890,23 @@ static HEADER *find_virtual (THREAD *cur, int reverse) while (reverse && cur->next) cur = cur->next; - FOREVER - { + for (;;) { if (cur->message && cur->message->virtual >= 0) return (cur->message); - if (cur->child) - { + if (cur->child) { cur = cur->child; while (reverse && cur->next) - cur = cur->next; + cur = cur->next; } else if (reverse ? cur->prev : cur->next) cur = reverse ? cur->prev : cur->next; - else - { - while (!(reverse ? cur->prev : cur->next)) - { - cur = cur->parent; - if (cur == top) - return (NULL); + else { + while (!(reverse ? cur->prev : cur->next)) { + cur = cur->parent; + if (cur == top) + return (NULL); } cur = reverse ? cur->prev : cur->next; } @@ -1008,55 +914,47 @@ static HEADER *find_virtual (THREAD *cur, int reverse) } } -int _mutt_aside_thread (HEADER *hdr, short dir, short subthreads) +int _mutt_aside_thread (HEADER * hdr, short dir, short subthreads) { THREAD *cur; HEADER *tmp; - if ((Sort & SORT_MASK) != SORT_THREADS) - { + if ((Sort & SORT_MASK) != SORT_THREADS) { mutt_error _("Threading is not enabled."); + return (hdr->virtual); } cur = hdr->thread; - if (!subthreads) - { + if (!subthreads) { while (cur->parent) cur = cur->parent; } - else - { - if ((dir != 0) ^ ((Sort & SORT_REVERSE) != 0)) - { + else { + if ((dir != 0) ^ ((Sort & SORT_REVERSE) != 0)) { while (!cur->next && cur->parent) - cur = cur->parent; + cur = cur->parent; } - else - { + else { while (!cur->prev && cur->parent) - cur = cur->parent; + cur = cur->parent; } } - if ((dir != 0) ^ ((Sort & SORT_REVERSE) != 0)) - { - do - { + if ((dir != 0) ^ ((Sort & SORT_REVERSE) != 0)) { + do { cur = cur->next; if (!cur) - return (-1); + return (-1); tmp = find_virtual (cur, 0); } while (!tmp); } - else - { - do - { + else { + do { cur = cur->prev; if (!cur) - return (-1); + return (-1); tmp = find_virtual (cur, 1); } while (!tmp); } @@ -1064,35 +962,34 @@ int _mutt_aside_thread (HEADER *hdr, short dir, short subthreads) return (tmp->virtual); } -int mutt_parent_message (CONTEXT *ctx, HEADER *hdr) +int mutt_parent_message (CONTEXT * ctx, HEADER * hdr) { THREAD *thread; - if ((Sort & SORT_MASK) != SORT_THREADS) - { + if ((Sort & SORT_MASK) != SORT_THREADS) { mutt_error _("Threading is not enabled."); + return (hdr->virtual); } - for (thread = hdr->thread->parent; thread; thread = thread->parent) - { - if ((hdr = thread->message) != NULL) - { + for (thread = hdr->thread->parent; thread; thread = thread->parent) { + if ((hdr = thread->message) != NULL) { if (VISIBLE (hdr, ctx)) - return (hdr->virtual); - else - { - mutt_error _("Parent message is not visible in this limited view."); - return (-1); + return (hdr->virtual); + else { + mutt_error _("Parent message is not visible in this limited view."); + + return (-1); } } } - + mutt_error _("Parent message is not available."); + return (-1); } -void mutt_set_virtual (CONTEXT *ctx) +void mutt_set_virtual (CONTEXT * ctx) { int i; HEADER *cur; @@ -1100,31 +997,31 @@ void mutt_set_virtual (CONTEXT *ctx) ctx->vcount = 0; ctx->vsize = 0; - for (i = 0; i < ctx->msgcount; i++) - { + for (i = 0; i < ctx->msgcount; i++) { cur = ctx->hdrs[i]; - if (cur->virtual >= 0) - { + if (cur->virtual >= 0) { cur->virtual = ctx->vcount; ctx->v2r[ctx->vcount] = i; ctx->vcount++; - ctx->vsize += cur->content->length + cur->content->offset - cur->content->hdr_offset; + ctx->vsize += + cur->content->length + cur->content->offset - + cur->content->hdr_offset; cur->num_hidden = mutt_get_hidden (ctx, cur); } } } -int _mutt_traverse_thread (CONTEXT *ctx, HEADER *cur, int flag) +int _mutt_traverse_thread (CONTEXT * ctx, HEADER * cur, int flag) { THREAD *thread, *top; HEADER *roothdr = NULL; int final, reverse = (Sort & SORT_REVERSE), minmsgno; int num_hidden = 0, new = 0, old = 0; int min_unread_msgno = INT_MAX, min_unread = cur->virtual; + #define CHECK_LIMIT (!ctx->pattern || cur->limited) - if ((Sort & SORT_MASK) != SORT_THREADS && !(flag & M_THREAD_GET_HIDDEN)) - { + if ((Sort & SORT_MASK) != SORT_THREADS && !(flag & M_THREAD_GET_HIDDEN)) { mutt_error (_("Threading is not enabled.")); return (cur->virtual); } @@ -1139,14 +1036,12 @@ int _mutt_traverse_thread (CONTEXT *ctx, HEADER *cur, int flag) cur = thread->message; minmsgno = cur->msgno; - if (!cur->read && CHECK_LIMIT) - { + if (!cur->read && CHECK_LIMIT) { if (cur->old) old = 2; else new = 1; - if (cur->msgno < min_unread_msgno) - { + if (cur->msgno < min_unread_msgno) { min_unread = cur->virtual; min_unread_msgno = cur->msgno; } @@ -1155,20 +1050,17 @@ int _mutt_traverse_thread (CONTEXT *ctx, HEADER *cur, int flag) if (cur->virtual == -1 && CHECK_LIMIT) num_hidden++; - if (flag & (M_THREAD_COLLAPSE | M_THREAD_UNCOLLAPSE)) - { - cur->pair = 0; /* force index entry's color to be re-evaluated */ + if (flag & (M_THREAD_COLLAPSE | M_THREAD_UNCOLLAPSE)) { + cur->pair = 0; /* force index entry's color to be re-evaluated */ cur->collapsed = flag & M_THREAD_COLLAPSE; - if (cur->virtual != -1) - { + if (cur->virtual != -1) { roothdr = cur; if (flag & M_THREAD_COLLAPSE) - final = roothdr->virtual; + final = roothdr->virtual; } } - if (thread == top && (thread = thread->child) == NULL) - { + if (thread == top && (thread = thread->child) == NULL) { /* return value depends on action requested */ if (flag & (M_THREAD_COLLAPSE | M_THREAD_UNCOLLAPSE)) return (final); @@ -1179,78 +1071,68 @@ int _mutt_traverse_thread (CONTEXT *ctx, HEADER *cur, int flag) else if (flag & M_THREAD_NEXT_UNREAD) return (min_unread); } - - FOREVER - { + + for (;;) { cur = thread->message; - if (cur) - { - if (flag & (M_THREAD_COLLAPSE | M_THREAD_UNCOLLAPSE)) - { - cur->pair = 0; /* force index entry's color to be re-evaluated */ - cur->collapsed = flag & M_THREAD_COLLAPSE; - if (!roothdr && CHECK_LIMIT) - { - roothdr = cur; - if (flag & M_THREAD_COLLAPSE) - final = roothdr->virtual; - } - - if (reverse && (flag & M_THREAD_COLLAPSE) && (cur->msgno < minmsgno) && CHECK_LIMIT) - { - minmsgno = cur->msgno; - final = cur->virtual; - } - - if (flag & M_THREAD_COLLAPSE) - { - if (cur != roothdr) - cur->virtual = -1; - } - else - { - if (CHECK_LIMIT) - cur->virtual = cur->msgno; - } + if (cur) { + if (flag & (M_THREAD_COLLAPSE | M_THREAD_UNCOLLAPSE)) { + cur->pair = 0; /* force index entry's color to be re-evaluated */ + cur->collapsed = flag & M_THREAD_COLLAPSE; + if (!roothdr && CHECK_LIMIT) { + roothdr = cur; + if (flag & M_THREAD_COLLAPSE) + final = roothdr->virtual; + } + + if (reverse && (flag & M_THREAD_COLLAPSE) && (cur->msgno < minmsgno) + && CHECK_LIMIT) { + minmsgno = cur->msgno; + final = cur->virtual; + } + + if (flag & M_THREAD_COLLAPSE) { + if (cur != roothdr) + cur->virtual = -1; + } + else { + if (CHECK_LIMIT) + cur->virtual = cur->msgno; + } } - if (!cur->read && CHECK_LIMIT) - { - if (cur->old) - old = 2; - else - new = 1; - if (cur->msgno < min_unread_msgno) - { - min_unread = cur->virtual; - min_unread_msgno = cur->msgno; - } + if (!cur->read && CHECK_LIMIT) { + if (cur->old) + old = 2; + else + new = 1; + if (cur->msgno < min_unread_msgno) { + min_unread = cur->virtual; + min_unread_msgno = cur->msgno; + } } if (cur->virtual == -1 && CHECK_LIMIT) - num_hidden++; + num_hidden++; } if (thread->child) thread = thread->child; else if (thread->next) thread = thread->next; - else - { + else { int done = 0; - while (!thread->next) - { - thread = thread->parent; - if (thread == top) - { - done = 1; - break; - } + + while (!thread->next) { + thread = thread->parent; + if (thread == top) { + done = 1; + break; + } } if (done) - break; + break; thread = thread->next; } } @@ -1261,7 +1143,7 @@ int _mutt_traverse_thread (CONTEXT *ctx, HEADER *cur, int flag) else if (flag & M_THREAD_UNREAD) return ((old && new) ? new : (old ? old : new)); else if (flag & M_THREAD_GET_HIDDEN) - return (num_hidden+1); + return (num_hidden + 1); else if (flag & M_THREAD_NEXT_UNREAD) return (min_unread); @@ -1273,7 +1155,7 @@ int _mutt_traverse_thread (CONTEXT *ctx, HEADER *cur, int flag) /* if flag is 0, we want to know how many messages * are in the thread. if flag is 1, we want to know * our position in the thread. */ -int mutt_messages_in_thread (CONTEXT *ctx, HEADER *hdr, int flag) +int mutt_messages_in_thread (CONTEXT * ctx, HEADER * hdr, int flag) { THREAD *threads[2]; int i, rc; @@ -1287,25 +1169,28 @@ int mutt_messages_in_thread (CONTEXT *ctx, HEADER *hdr, int flag) threads[1] = flag ? hdr->thread : threads[0]->next; - for (i = 0; i < ((flag || !threads[1]) ? 1 : 2); i++) - { + for (i = 0; i < ((flag || !threads[1]) ? 1 : 2); i++) { while (!threads[i]->message) threads[i] = threads[i]->child; - } + } if (Sort & SORT_REVERSE) - rc = threads[0]->message->msgno - (threads[1] ? threads[1]->message->msgno : -1); + rc = + threads[0]->message->msgno - + (threads[1] ? threads[1]->message->msgno : -1); else - rc = (threads[1] ? threads[1]->message->msgno : ctx->msgcount) - threads[0]->message->msgno; - + rc = + (threads[1] ? threads[1]->message->msgno : ctx->msgcount) - + threads[0]->message->msgno; + if (flag) rc += 1; - + return (rc); } -HASH *mutt_make_id_hash (CONTEXT *ctx) +HASH *mutt_make_id_hash (CONTEXT * ctx) { int i; HEADER *hdr; @@ -1313,8 +1198,7 @@ HASH *mutt_make_id_hash (CONTEXT *ctx) hash = hash_create (ctx->msgcount * 2); - for (i = 0; i < ctx->msgcount; i++) - { + for (i = 0; i < ctx->msgcount; i++) { hdr = ctx->hdrs[i]; if (hdr->env->message_id) hash_insert (hash, hdr->env->message_id, hdr, 0); @@ -1323,7 +1207,7 @@ HASH *mutt_make_id_hash (CONTEXT *ctx) return hash; } -HASH *mutt_make_subj_hash (CONTEXT *ctx) +HASH *mutt_make_subj_hash (CONTEXT * ctx) { int i; HEADER *hdr; @@ -1331,8 +1215,7 @@ HASH *mutt_make_subj_hash (CONTEXT *ctx) hash = hash_create (ctx->msgcount * 2); - for (i = 0; i < ctx->msgcount; i++) - { + for (i = 0; i < ctx->msgcount; i++) { hdr = ctx->hdrs[i]; if (hdr->env->real_subj) hash_insert (hash, hdr->env->real_subj, hdr, 1); @@ -1341,104 +1224,97 @@ HASH *mutt_make_subj_hash (CONTEXT *ctx) return hash; } -static void clean_references (THREAD *brk, THREAD *cur) +static void clean_references (THREAD * tbrk, THREAD * cur) { THREAD *p; - LIST *ref = NULL; + string_list_t *ref = NULL; int done = 0; - for (; cur; cur = cur->next, done = 0) - { + for (; cur; cur = cur->next, done = 0) { /* parse subthread recursively */ - clean_references (brk, cur->child); + clean_references (tbrk, cur->child); if (!cur->message) - break; /* skip pseudo-message */ + break; /* skip pseudo-message */ /* 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->message->env->references; p->message && ref; ref = ref->next) - if (!mutt_strcasecmp (ref->data, p->message->env->message_id)) - { - done = 1; - break; - } - - if (done) - { + for (p = tbrk; !done && p; p = p->parent) + for (ref = cur->message->env->references; p->message && ref; + ref = ref->next) + if (!m_strcasecmp(ref->data, p->message->env->message_id)) { + done = 1; + break; + } + + if (done) { HEADER *h = cur->message; - /* clearing the References: header from obsolete Message-Id(s) */ - mutt_free_list (&ref->next); - -#ifdef IMAP_EDIT_THREADS - if (h->new_env) - mutt_free_list (&h->new_env->references); - else - h->new_env = mutt_new_envelope (); - - h->new_env->references = mutt_copy_list (h->env->references); -#endif + /* clearing the References: header from obsolete Message-ID(s) */ + string_list_wipe(&ref->next); - h->refs_changed = h->changed = 1; + h->env->refs_changed = h->changed = 1; } } } -void mutt_break_thread (HEADER *hdr) +void mutt_break_thread (HEADER * hdr) { - mutt_free_list (&hdr->env->in_reply_to); - mutt_free_list (&hdr->env->references); - hdr->irt_changed = hdr->refs_changed = hdr->changed = 1; - -#ifdef IMAP_EDIT_THREADS - if (hdr->new_env) - { - mutt_free_list (&hdr->new_env->in_reply_to); - mutt_free_list (&hdr->new_env->references); - } - else - hdr->new_env = mutt_new_envelope (); -#endif - + string_list_wipe(&hdr->env->in_reply_to); + string_list_wipe(&hdr->env->references); + hdr->env->irt_changed = hdr->env->refs_changed = hdr->changed = 1; clean_references (hdr->thread, hdr->thread->child); } -static int link_threads (HEADER *parent, HEADER *child, CONTEXT *ctx) +static int link_threads (HEADER * parent, HEADER * child, CONTEXT * ctx) { if (child == parent) return 0; mutt_break_thread (child); - child->env->in_reply_to = mutt_new_list (); - child->env->in_reply_to->data = safe_strdup (parent->env->message_id); + child->env->in_reply_to = string_item_new(); + child->env->in_reply_to->data = m_strdup(parent->env->message_id); -#ifdef IMAP_EDIT_THREADS - child->new_env->in_reply_to = mutt_new_list (); - child->new_env->in_reply_to->data = safe_strdup (parent->env->message_id); -#endif - mutt_set_flag (ctx, child, M_TAG, 0); - - child->irt_changed = child->changed = 1; + + child->env->irt_changed = child->changed = 1; return 1; } -int mutt_link_threads (HEADER *cur, HEADER *last, CONTEXT *ctx) +int mutt_link_threads (HEADER * cur, HEADER * last, CONTEXT * ctx) { int i, changed = 0; - if (!last) - { + if (!last) { for (i = 0; i < ctx->vcount; i++) if (ctx->hdrs[Context->v2r[i]]->tagged) - changed |= link_threads (cur, ctx->hdrs[Context->v2r[i]], ctx); + changed |= link_threads (cur, ctx->hdrs[Context->v2r[i]], ctx); } else changed = link_threads (cur, last, ctx); return changed; } + +void mutt_adjust_subject (ENVELOPE* e) { + regmatch_t pmatch[1]; + + if (e && e->subject) { + if (regexec (ReplyRegexp.rx, e->subject, 1, pmatch, 0) == 0) + e->real_subj = e->subject + pmatch[0].rm_eo; + else + e->real_subj = e->subject; + } +} + +void mutt_adjust_all_subjects (void) { + int i = 0; + + if (!Context || !Context->msgcount) + return; + + for (i = 0; i < Context->msgcount; i++) + mutt_adjust_subject (Context->hdrs[i]->env); +}