patch.
OP_VIEW_ATTACH "view attachment using mailcap entry if necessary"
OP_VIEW_ATTACHMENTS "show MIME attachments"
OP_MAIN_SHOW_LIMIT "show currently active limit pattern"
+OP_MAIN_COLLAPSE_THREAD "collapse/uncollapse current thread"
+OP_MAIN_COLLAPSE_ALL "collapse/uncollapse all threads"
#define CURHDR Context->hdrs[Context->v2r[menu->current]]
#define OLDHDR Context->hdrs[Context->v2r[menu->oldcurrent]]
+#define UNREAD(h) mutt_thread_contains_unread (Context, h)
extern const char *ReleaseDate;
}
}
- _mutt_make_string (s, l, NONULL (HdrFmt), Context, h, flag);
+ _mutt_make_string (s, l, NONULL (HdrFmt), Context, h, flag | M_FORMAT_INDEX);
}
int index_color (int index_no)
if (Context && !attach_msg)
{
+ int check;
/* check for new mail in the mailbox. If nonzero, then something has
* changed about the file (either we got new mail or the file was
* modified underneath us.)
*/
index_hint = (Context->vcount) ? CURHDR->index : 0;
- if ((i = mx_check_mailbox (Context, &index_hint)) < 0)
+ if ((check = mx_check_mailbox (Context, &index_hint)) < 0)
{
if (!Context->path)
{
set_option (OPTSEARCHINVALID);
}
- else if (i == M_NEW_MAIL || i == M_REOPENED)
+ else if (check == M_NEW_MAIL || check == M_REOPENED)
{
+ int *save_new;
+
/* take note of the current message */
if (oldcount)
{
* they will be visible in the limited view */
if (Context->pattern)
{
- #define this_body Context->hdrs[i]->content
- if (oldcount)
- for (i = oldcount; i < Context->msgcount; i++)
+#define THIS_BODY Context->hdrs[j]->content
+ if (oldcount || check == M_REOPENED)
+ for (j = (check == M_REOPENED) ? 0 : oldcount; j < Context->msgcount; j++)
{
if (mutt_pattern_exec (Context->limit_pattern,
M_MATCH_FULL_ADDRESS,
- Context, Context->hdrs[i]))
+ Context, Context->hdrs[j]))
{
- Context->hdrs[i]->virtual = Context->vcount;
- Context->v2r[Context->vcount] = i;
- Context->vcount++;
- Context->vsize+=this_body->length + this_body->offset -
- this_body->hdr_offset;
+ Context->hdrs[j]->virtual = Context->vcount;
+ Context->v2r[Context->vcount] = j;
+ Context->hdrs[j]->limited = 1;
+ Context->vcount++;
+ Context->vsize += THIS_BODY->length + THIS_BODY->offset - THIS_BODY->hdr_offset;
}
}
- #undef this_body
+#undef THIS_BODY
+ }
+
+ /* save the list of new messages */
+ if (oldcount && check != M_REOPENED)
+ {
+ save_new = (int *) safe_malloc (sizeof (int) * (Context->msgcount - oldcount));
+ for (j = oldcount; j < Context->msgcount; j++)
+ save_new[j-oldcount] = Context->hdrs[j]->index;
}
/* if the mailbox was reopened, need to rethread from scratch */
- mutt_sort_headers (Context, (i == M_REOPENED));
+ set_option (OPTSORTCOLLAPSE);
+ mutt_sort_headers (Context, (check == M_REOPENED));
+ unset_option (OPTSORTCOLLAPSE);
+
+ /* uncollapse threads with new mail */
+ if ((Sort & SORT_MASK) == SORT_THREADS)
+ {
+ if (check == M_REOPENED)
+ {
+ HEADER *h;
+
+ h = Context->tree;
+ Context->collapsed = 0;
+
+ while (h)
+ {
+ mutt_uncollapse_thread (Context, h);
+ h = h->next;
+ }
+ mutt_set_virtual (Context);
+ }
+ else if (oldcount)
+ {
+ for (j = 0; j < Context->msgcount - oldcount; j++)
+ {
+ int k;
+
+ for (k = 0; k < Context->msgcount; k++)
+ {
+ HEADER *h = Context->hdrs[k];
+ if (h->index == save_new[j] && (!Context->pattern || h->limited))
+ mutt_uncollapse_thread (Context, h);
+ }
+ }
+ FREE (&save_new);
+ mutt_set_virtual (Context);
+ }
+ }
menu->current = -1;
if (oldcount)
{
- int j;
-
/* restore the current message to the message it was pointing to */
for (j = 0; j < Context->vcount; j++)
if (Context->hdrs[Context->v2r[j]]->index == menu->oldcurrent)
menu->current = ci_first_message ();
/* notify the user of new mail */
- if (i == M_REOPENED)
+ if (check == M_REOPENED)
mutt_error ("Mailbox was externally modified. Flags may be wrong.");
else
{
toggle_option (OPTWEED);
unset_option (OPTNEEDRESORT);
-
+ if ((Sort & SORT_MASK) == SORT_THREADS && CURHDR->collapsed)
+ {
+ mutt_uncollapse_thread (Context, CURHDR);
+ mutt_set_virtual (Context);
+ if (option (OPTUNCOLLAPSEJUMPNEW))
+ menu->current = mutt_thread_next_new (Context, CURHDR);
+ }
+
if ((op = mutt_display_message (CURHDR, attach_msg_status)) == -1)
{
unset_option (OPTNEEDRESORT);
menu->current = -1;
for (j = 0; j != Context->vcount; j++)
{
+#define CUR Context->hdrs[Context->v2r[i]]
if (op == OP_MAIN_NEXT_NEW || op == OP_MAIN_NEXT_UNREAD)
{
i++;
}
}
- if (! Context->hdrs[Context->v2r[i]]->deleted &&
- ! Context->hdrs[Context->v2r[i]]->read)
+ if ((!CUR->deleted && !CUR->read) ||
+ (CUR->collapsed && !CUR->deleted && UNREAD (CUR)))
{
if (op == OP_MAIN_NEXT_UNREAD || op == OP_MAIN_PREV_UNREAD ||
- ! Context->hdrs[Context->v2r[i]]->old)
+ !CUR->old)
{
menu->current = i;
break;
}
}
}
+#undef CUR
if (menu->current == -1)
{
+ char *tmp = "";
menu->current = menu->oldcurrent;
- mutt_error ((op == OP_MAIN_NEXT_NEW || op == OP_MAIN_PREV_NEW) ?
- "No new messages." : "No unread messages.");
+ if (Context->pattern)
+ tmp = " in this limited view";
+ mutt_error ("%s%s.", (op == OP_MAIN_NEXT_NEW || op == OP_MAIN_PREV_NEW) ? "No new messages" : "No unread messages", NONULL (tmp));
}
else if (menu->menu == MENU_PAGER)
{
}
break;
+ case OP_MAIN_COLLAPSE_THREAD:
+ CHECK_MSGCOUNT;
+
+ if (CURHDR->collapsed)
+ {
+ menu->current = mutt_uncollapse_thread (Context, CURHDR);
+ mutt_set_virtual (Context);
+ if (option (OPTUNCOLLAPSEJUMPNEW))
+ menu->current = mutt_thread_next_new (Context, CURHDR);
+ }
+ else if (option (OPTCOLLAPSENEW) || !UNREAD (CURHDR))
+ {
+ menu->current = mutt_collapse_thread (Context, CURHDR);
+ mutt_set_virtual (Context);
+ }
+ else
+ {
+ mutt_error ("Thread contains unread messages.");
+ break;
+ }
+
+ menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
+
+ break;
+
+ case OP_MAIN_COLLAPSE_ALL:
+ CHECK_MSGCOUNT;
+
+ if ((Sort & SORT_MASK) != SORT_THREADS)
+ {
+ mutt_error ("Threading is not enabled.");
+ break;
+ }
+
+ {
+ HEADER *h, *base;
+ int final;
+
+ if (CURHDR->collapsed)
+ final = mutt_uncollapse_thread (Context, CURHDR);
+ else if (option (OPTCOLLAPSENEW) || !UNREAD (CURHDR))
+ final = mutt_collapse_thread (Context, CURHDR);
+ else
+ final = CURHDR->virtual;
+
+ base = Context->hdrs[Context->v2r[final]];
+
+ h = Context->tree;
+ Context->collapsed = !Context->collapsed;
+ while (h)
+ {
+ if (h->collapsed != Context->collapsed)
+ {
+ if (h->collapsed)
+ mutt_uncollapse_thread (Context, h);
+ else if (option (OPTCOLLAPSENEW) || !UNREAD (h))
+ mutt_collapse_thread (Context, h);
+ }
+ h = h->next;
+ }
+
+ mutt_set_virtual (Context);
+ for (j = 0; j < Context->vcount; j++)
+ {
+ if (Context->hdrs[Context->v2r[j]]->index == base->index)
+ {
+ menu->current = j;
+ break;
+ }
+ }
+
+ menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
+ break;
+ }
+
/* --------------------------------------------------------------------
* These functions are invoked directly from the internal-pager
*/
{ "bounce-message", OP_BOUNCE_MESSAGE, "b" },
{ "change-folder", OP_MAIN_CHANGE_FOLDER, "c" },
{ "change-folder-readonly", OP_MAIN_CHANGE_FOLDER_READONLY, "\033c" },
+ { "collapse-thread", OP_MAIN_COLLAPSE_THREAD, "\033v" },
+ { "collapse-all", OP_MAIN_COLLAPSE_ALL, "\033V" },
{ "copy-message", OP_COPY_MESSAGE, "C" },
{ "decode-copy", OP_DECODE_COPY, "\033C" },
{ "decode-save", OP_DECODE_SAVE, "\033s" },
#include "mutt.h"
#include "mutt_curses.h"
-
+#include "sort.h"
#ifdef _PGPPATH
char fmt[SHORT_STRING], buf2[SHORT_STRING], ch, *p;
int do_locales, i;
int optional = (flags & M_FORMAT_OPTIONAL);
+ int threads = ((Sort & SORT_MASK) == SORT_THREADS);
+ int is_index = (flags & M_FORMAT_INDEX);
+#define NEW (threads && hdr->collapsed && hdr->num_hidden > 1 && mutt_thread_contains_unread (ctx, hdr))
size_t len;
hdr = hfi->hdr;
break;
case 's':
- snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
- if (flags & M_FORMAT_TREE)
+
+ snprintf (fmt, sizeof (fmt), "%s%%%ss", threads && is_index ? " " : "", prefix);
+ if (threads && is_index && hdr->collapsed && hdr->num_hidden > 1)
+ snprintf (dest, destlen, "%2d %s", hdr->num_hidden, NONULL(hdr->env->subject));
+ else if (flags & M_FORMAT_TREE)
{
if (flags & M_FORMAT_FORCESUBJ)
{
- snprintf (buf2, sizeof (buf2), "%s%s", hdr->tree,
- hdr->env->subject ? hdr->env->subject : "");
+ snprintf (buf2, sizeof (buf2), "%s%s", hdr->tree, NONULL (hdr->env->subject));
snprintf (dest, destlen, fmt, buf2);
}
else
snprintf (dest, destlen, fmt, hdr->tree);
}
else
- {
- snprintf (dest, destlen, fmt, hdr->env->subject ? hdr->env->subject : "");
- }
+ snprintf (dest, destlen, fmt, NONULL (hdr->env->subject));
break;
case 'S':
snprintf (buf2, sizeof (buf2),
"%c%c%c",
(hdr->read && (ctx && ctx->msgnotreadyet != hdr->msgno))
- ? (hdr->replied ? 'r' : ' ') : (hdr->old ? 'O' : 'N'),
+ ? (NEW ? 'n' : (hdr->replied ? 'r' : ' ')) : (hdr->old ? 'O' : (NEW ? 'n' : 'N')),
hdr->deleted ? 'D' : (hdr->attach_del ? 'd' : ch),
hdr->tagged ? '*' :
(hdr->flagged ? '!' :
mutt_FormatString (dest, destlen, elsestring, hdr_format_str, (unsigned long) hfi, flags);
return (src);
+#undef NEW
}
void
{ "beep_new", DT_BOOL, R_NONE, OPTBEEPNEW, 0 },
{ "charset", DT_STR, R_NONE, UL &Charset, UL "iso-8859-1" },
{ "check_new", DT_BOOL, R_NONE, OPTCHECKNEW, 1 },
+ { "collapse_new", DT_BOOL, R_NONE, OPTCOLLAPSENEW, 1 },
+ { "uncollapse_jump_new", DT_BOOL, R_NONE, OPTUNCOLLAPSEJUMPNEW, 0 },
+ { "auto_collapse", DT_BOOL, R_NONE, OPTAUTOCOLLAPSE, 0 },
{ "confirmappend", DT_BOOL, R_NONE, OPTCONFIRMAPPEND, 1 },
{ "confirmcreate", DT_BOOL, R_NONE, OPTCONFIRMCREATE, 1 },
{ "copy", DT_QUAD, R_NONE, OPT_COPY, M_YES },
{
save_sort = Sort;
Sort = SORT_ORDER;
+ set_option (OPTSORTCOLLAPSE);
mutt_sort_headers (ctx, 0);
+ unset_option (OPTSORTCOLLAPSE);
}
/* need to open the file for writing in such a way that it does not truncate
Sort = save_sort;
/* if the mailbox was reopened, the thread tree will be invalid so make
* sure to start threading from scratch. */
+ set_option (OPTSORTCOLLAPSE);
mutt_sort_headers (ctx, (need_sort == M_REOPENED));
+ unset_option (OPTSORTCOLLAPSE);
}
return (-1);
M_FORMAT_MAKEPRINT = (1<<2), /* make sure that all chars are printable */
M_FORMAT_OPTIONAL = (1<<3),
M_FORMAT_STAT_FILE = (1<<4), /* used by mutt_attach_fmt */
- M_FORMAT_ARROWCURSOR = (1<<5) /* reserve space for arrow_cursor */
+ M_FORMAT_ARROWCURSOR = (1<<5), /* reserve space for arrow_cursor */
+ M_FORMAT_INDEX = (1<<6) /* this is a main index entry */
} format_flag;
/* types for mutt_add_hook() */
#define M_TREE_HIDDEN 9
#define M_TREE_MAX 10
+#define M_THREAD_COLLAPSE (1<<0)
+#define M_THREAD_UNCOLLAPSE (1<<1)
+#define M_THREAD_GET_HIDDEN (1<<2)
+#define M_THREAD_UNREAD (1<<3)
+#define M_THREAD_NEXT_NEW (1<<4)
+
enum
{
/* modes for mutt_view_attachment() */
OPTASKBCC,
OPTASKCC,
OPTATTACHSPLIT,
+ OPTAUTOCOLLAPSE,
OPTAUTOEDIT,
OPTAUTOTAG,
OPTBEEP,
OPTBEEPNEW,
OPTCHECKNEW,
+ OPTCOLLAPSENEW,
OPTCONFIRMAPPEND,
OPTCONFIRMCREATE,
OPTEDITHDRS,
OPTSUSPEND,
OPTTHOROUGHSRC,
OPTTILDE,
+ OPTUNCOLLAPSEJUMPNEW,
OPTUSE8BITMIME,
OPTUSEDOMAIN,
OPTUSEFROM,
OPTWRAP,
OPTWRAPSEARCH,
OPTWRITEBCC, /* write out a bcc header? */
-
+
/* PGP options */
#ifdef _PGPPATH
OPTFORCEREDRAWPAGER, /* (pseudo) used to force a redraw in the pager */
OPTSORTSUBTHREADS, /* (pseudo) used when $sort_aux changes */
OPTNEEDRESCORE, /* (pseudo) set when the `score' command is used */
+ OPTSORTCOLLAPSE, /* (pseudo) used by mutt_sort_headers() */
#ifdef _PGPPATH
OPTPGPCHECKTRUST, /* (pseudo) used by pgp_select_key () */
unsigned int searched : 1;
unsigned int matched : 1;
+ /* the following are used to support collapsing threads */
+ unsigned int collapsed : 1; /* is this message part of a collapsed thread? */
+ unsigned int limited : 1; /* is this message in a limited view? */
+ size_t num_hidden; /* number of hidden messages in this view */
+
int pair; /* color-pair to use when displaying in the index */
time_t date_sent; /* time when the message was sent (UTC) */
unsigned int setgid : 1;
unsigned int quiet : 1; /* inhibit status messages? */
unsigned int revsort : 1; /* mailbox sorted in reverse? */
+ unsigned int collapsed : 1; /* are all threads collapsed? */
} CONTEXT;
typedef struct attachptr
ctx->path = safe_strdup (path);
ctx->msgnotreadyet = -1;
+ ctx->collapsed = 0;
if (flags & M_QUIET)
ctx->quiet = 1;
#undef this_body
ctx->msgcount = j;
+ set_option (OPTSORTCOLLAPSE);
mutt_sort_headers (ctx, 1); /* rethread from scratch */
+ unset_option (OPTSORTCOLLAPSE);
}
return (rc);
if (op == M_LIMIT)
{
for (i = 0; i < Context->msgcount; i++)
+ {
Context->hdrs[i]->virtual = -1;
+ Context->hdrs[i]->limited = 0;
+ Context->hdrs[i]->collapsed = 0;
+ Context->hdrs[i]->num_hidden = 0;
+ }
Context->vcount = 0;
Context->vsize = 0;
+ Context->collapsed = 0;
}
-#define this_body Context->hdrs[i]->content
+#define THIS_BODY Context->hdrs[i]->content
for (i = 0; i < Context->msgcount; i++)
if (mutt_pattern_exec (pat, M_MATCH_FULL_ADDRESS, Context, Context->hdrs[i]))
break;
case M_LIMIT:
Context->hdrs[i]->virtual = Context->vcount;
+ Context->hdrs[i]->limited = 1;
Context->v2r[Context->vcount] = i;
Context->vcount++;
- Context->vsize+=this_body->length + this_body->offset -
- this_body->hdr_offset;
+ Context->vsize+=THIS_BODY->length + THIS_BODY->offset -
+ THIS_BODY->hdr_offset;
break;
}
}
-#undef this_body
+#undef THIS_BODY
mutt_clear_error ();
if (op == M_LIMIT)
{
+ Context->collapsed = 0;
safe_free ((void **) &Context->pattern);
if (Context->limit_pattern)
mutt_pattern_free (&Context->limit_pattern);
for (i = 0; i < Context->msgcount; i++)
{
Context->hdrs[i]->virtual = i;
+ Context->hdrs[i]->limited = 0;
+ Context->hdrs[i]->num_hidden = 0;
+ Context->hdrs[i]->collapsed = 0;
Context->v2r[i] = i;
}
#define mutt_previous_subthread(x) _mutt_aside_thread(x,0,1)
int _mutt_aside_thread (HEADER *, short, short);
+#define mutt_collapse_thread(x,y) _mutt_traverse_thread (x,y,M_THREAD_COLLAPSE)
+#define mutt_uncollapse_thread(x,y) _mutt_traverse_thread (x,y,M_THREAD_UNCOLLAPSE)
+#define mutt_get_hidden(x,y)_mutt_traverse_thread (x,y,M_THREAD_GET_HIDDEN)
+#define mutt_thread_contains_unread(x,y) _mutt_traverse_thread (x,y,M_THREAD_UNREAD)
+#define mutt_thread_next_new(x,y) _mutt_traverse_thread(x,y,M_THREAD_NEXT_NEW)
+int _mutt_traverse_thread (CONTEXT *ctx, HEADER *hdr, int flag);
+
#define ISSPACE(c) isspace((unsigned char)c)
#define mutt_new_parameter() safe_calloc (1, sizeof (PARAMETER))
void mutt_body_handler (BODY *, STATE *);
void mutt_bounce_message (HEADER *, ADDRESS *);
void mutt_buffy (char *);
-void mutt_check_rescore (CONTEXT *ctx);
+void mutt_check_rescore (CONTEXT *);
void mutt_clear_error (void);
void mutt_create_alias (ENVELOPE *, ADDRESS *);
void mutt_decode_attachment (BODY *, STATE *);
void mutt_update_tree (ATTACHPTR **, short);
void mutt_version (void);
void mutt_view_attachments (HEADER *);
+void mutt_set_virtual (CONTEXT *);
int mutt_addr_is_user (ADDRESS *);
int mutt_alias_complete (char *, size_t);
{
int i;
sort_t *sortfunc;
+ int collapse = (option (OPTSORTCOLLAPSE)) ? 0 : 1;
unset_option (OPTNEEDRESORT);
/* adjust the virtual message numbers */
ctx->vcount = 0;
+ if (collapse)
+ ctx->collapsed = 0;
for (i = 0; i < ctx->msgcount; i++)
{
- if (ctx->hdrs[i]->virtual != -1)
+ HEADER *cur = ctx->hdrs[i];
+ if (cur->virtual != -1 || (collapse && cur->collapsed && (!ctx->pattern || cur->limited)))
{
- ctx->hdrs[i]->virtual = ctx->vcount;
+ cur->virtual = ctx->vcount;
ctx->v2r[ctx->vcount] = i;
ctx->vcount++;
}
- ctx->hdrs[i]->msgno = i;
+ cur->msgno = i;
+ cur->num_hidden = mutt_get_hidden (ctx, cur);
+ if (collapse)
+ cur->collapsed = 0;
}
mutt_cache_index_colors(ctx);
*/
#include "mutt.h"
+#include "mutt_curses.h"
+#include "mutt_menu.h"
#include "sort.h"
+#include "mailbox.h"
+#include "copy.h"
+#include "mx.h"
+#include <sys/stat.h>
+#include <utime.h>
+
+#ifdef BUFFY_SIZE
+#include "buffy.h"
+#endif
#include <string.h>
#include <ctype.h>
}
/* Determines whether to display a message's subject. */
-static int need_display_subject (HEADER *tree)
+static int need_display_subject (CONTEXT *ctx, HEADER *tree)
{
HEADER *tmp;
return (1);
for (tmp = tree->prev; tmp; tmp = tmp->prev)
{
- if (tmp->virtual >= 0)
+ if (tmp->virtual >= 0 || (tmp->collapsed && (!ctx->pattern || tmp->limited)))
{
if (!tmp->subject_changed)
return (0);
}
for (tmp = tree->parent; tmp; tmp = tmp->parent)
{
- if (tmp->virtual >= 0)
+ if (tmp->virtual >= 0 || (tmp->collapsed && (!ctx->pattern || tmp->limited)))
return (0);
else if (tmp->subject_changed)
return (1);
/* determines whether a later sibling or the child of a later
sibling is displayed. */
-int is_next_displayed (HEADER *tree)
+static int is_next_displayed (CONTEXT *ctx, HEADER *tree)
{
int depth = 0;
FOREVER
{
- if (tree->virtual >= 0)
+ if (tree->virtual >= 0 || (tree->collapsed && (!ctx->pattern || tree->limited)))
return (1);
if (tree->child)
FOREVER
{
- if (tree->virtual >= 0)
- tree->display_subject = need_display_subject (tree);
+ if (tree->virtual >= 0 || (tree->collapsed && (!ctx->pattern || tree->limited)))
+ tree->display_subject = need_display_subject (ctx, tree);
if (depth >= max_depth)
safe_realloc ((void **) &pfx,
safe_free ((void **) &tree->tree);
if (!depth)
{
- if (tree->virtual >= 0)
+ if (tree->virtual >= 0 || (tree->collapsed && (!ctx->pattern || tree->limited)))
tree->tree = safe_strdup ("");
}
else
{
myarrow = arrow + (depth - start_depth - (start_depth ? 0 : 1)) * 2;
- nextdisp = is_next_displayed (tree);
+ nextdisp = is_next_displayed (ctx, tree);
if (depth && start_depth == depth)
myarrow[0] = nextdisp ? M_TREE_LTEE : corner;
else
myarrow[0] = M_TREE_HIDDEN;
myarrow[1] = tree->fake_thread ? M_TREE_STAR : M_TREE_HLINE;
- if (tree->virtual >= 0)
+ if (tree->virtual >= 0 || (tree->collapsed && (!ctx->pattern || tree->limited)))
{
myarrow[2] = M_TREE_RARROW;
myarrow[3] = 0;
}
- if (tree->virtual >= 0)
+ if (tree->virtual >= 0 || (tree->collapsed && (!ctx->pattern || tree->limited)))
{
tree->tree = safe_malloc ((2 + depth * 2) * sizeof (char));
if (start_depth > 1)
mypfx[1] = M_TREE_SPACE;
}
depth++;
- if (tree->virtual >= 0)
+ if (tree->virtual >= 0 || (tree->collapsed && (!ctx->pattern || tree->limited)))
start_depth = depth;
tree = tree->child;
}
{
while (!tree->next && tree->parent)
{
- if (tree->virtual >= 0)
+ if (tree->virtual >= 0 || (tree->collapsed && (!ctx->pattern || tree->limited)))
start_depth = depth;
tree = tree->parent;
if (start_depth == depth)
start_depth--;
depth--;
}
- if (tree->virtual >= 0)
+ if (tree->virtual >= 0 || (tree->collapsed && (!ctx->pattern || tree->limited)))
start_depth = depth;
if ((tree = tree->next) == NULL)
break;
return (tmp->virtual);
}
+
+void mutt_set_virtual (CONTEXT *ctx)
+{
+ int i;
+
+ ctx->vcount = 0;
+ ctx->vsize = 0;
+
+#define THIS_BODY cur->content
+ for (i = 0; i < ctx->msgcount; i++)
+ {
+ HEADER *cur = ctx->hdrs[i];
+ if (cur->virtual != -1)
+ {
+ cur->virtual = ctx->vcount;
+ ctx->v2r[ctx->vcount] = i;
+ ctx->vcount++;
+ ctx->vsize += THIS_BODY->length + THIS_BODY->offset - THIS_BODY->hdr_offset;
+ cur->num_hidden = mutt_get_hidden (ctx, cur);
+ }
+ }
+#undef THIS_BODY
+}
+
+int _mutt_traverse_thread (CONTEXT *ctx, HEADER *cur, int flag)
+{
+ HEADER *roothdr = NULL, *top;
+ int final, reverse = (Sort & SORT_REVERSE), minmsgno;
+ int num_hidden = 0, unread = 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))
+ {
+ mutt_error ("Threading is not enabled.");
+ return (cur->virtual);
+ }
+
+ final = cur->virtual;
+ while (cur->parent)
+ cur = cur->parent;
+ top = cur;
+ minmsgno = cur->msgno;
+
+
+ if (!cur->read && CHECK_LIMIT)
+ {
+ unread = 1;
+ if (cur->msgno < min_unread_msgno)
+ {
+ min_unread = cur->virtual;
+ min_unread_msgno = cur->msgno;
+ }
+ }
+
+ if (cur->virtual == -1 && CHECK_LIMIT)
+ num_hidden++;
+
+ if (flag & (M_THREAD_COLLAPSE | M_THREAD_UNCOLLAPSE))
+ {
+ cur->collapsed = flag & M_THREAD_COLLAPSE;
+ if (cur->virtual != -1)
+ {
+ roothdr = cur;
+ if (flag & M_THREAD_COLLAPSE)
+ final = roothdr->virtual;
+ }
+ }
+
+ if ((cur = cur->child) == NULL)
+ {
+ /* return value depends on action requested */
+ if (flag & (M_THREAD_COLLAPSE | M_THREAD_UNCOLLAPSE))
+ return (final);
+ else if (flag & M_THREAD_UNREAD)
+ return (unread);
+ else if (flag & M_THREAD_GET_HIDDEN)
+ return (num_hidden);
+ else if (flag & M_THREAD_NEXT_NEW)
+ return (min_unread);
+ }
+
+ FOREVER
+ {
+ if (flag & (M_THREAD_COLLAPSE | M_THREAD_UNCOLLAPSE))
+ {
+ 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)
+ {
+ unread = 1;
+ if (cur->msgno < min_unread_msgno)
+ {
+ min_unread = cur->virtual;
+ min_unread_msgno = cur->msgno;
+ }
+ }
+
+ if (cur->virtual == -1 && CHECK_LIMIT)
+ num_hidden++;
+
+ if (cur->child)
+ cur = cur->child;
+ else if (cur->next)
+ cur = cur->next;
+ else
+ {
+ int done = 0;
+ while (!cur->next)
+ {
+ cur = cur->parent;
+ if (cur == top)
+ {
+ done = 1;
+ break;
+ }
+ }
+ if (done)
+ break;
+ cur = cur->next;
+ }
+ }
+
+ /* return value depends on action requested */
+ if (flag & (M_THREAD_COLLAPSE | M_THREAD_UNCOLLAPSE))
+ return (final);
+ else if (flag & M_THREAD_UNREAD)
+ return (unread);
+ else if (flag & M_THREAD_GET_HIDDEN)
+ return (num_hidden+1);
+ else if (flag & M_THREAD_NEXT_NEW)
+ return (min_unread);
+
+ return (0);
+#undef CHECK_LIMIT
+}
+