diff -u -r alpine-0.98+dfsg/alpine/arg.c alpine-0.98+dfsg+fancythread-clean/alpine/arg.c --- alpine-0.98+dfsg/alpine/arg.c 2007-03-23 17:53:15.000000000 +0100 +++ alpine-0.98+dfsg+fancythread-clean/alpine/arg.c 2007-04-30 00:09:05.000000000 +0200 @@ -52,6 +52,7 @@ static char args_err_missing_passfile[] = N_("missing argument for option \"-passfile\""); static char args_err_non_abs_passfile[] = N_("argument to \"-passfile\" should be fully-qualified"); static char args_err_missing_sort[] = N_("missing argument for option \"-sort\""); +static char args_err_missing_thread_sort[] = N_("missing argument for option \"-threadsort\""); static char args_err_missing_flag_arg[] = N_("missing argument for flag \"%c\""); static char args_err_missing_flag_num[] = N_("Non numeric argument for flag \"%c\""); static char args_err_missing_debug_num[] = N_("Non numeric argument for \"%s\""); @@ -95,6 +96,7 @@ N_(" -z \t\tSuspend - allow use of ^Z suspension"), N_(" -r \t\tRestricted - can only send mail to oneself"), N_(" -sort \tSort - Specify sort order of folder:"), +N_(" -threadsort \tSort - Specify sort order of thread index screen:"), N_("\t\t\tarrival, subject, threaded, orderedsubject, date,"), N_("\t\t\tfrom, size, score, to, cc, /reverse"), N_(" -i\t\tIndex - Go directly to index, bypassing main menu"), @@ -186,6 +188,7 @@ char *cmd_list = NULL; char *debug_str = NULL; char *sort = NULL; + char *threadsort = NULL; char *pinerc_file = NULL; char *ab_sort_descrip = NULL; char *lc = NULL; @@ -379,6 +382,18 @@ goto Loop; } + else if(strcmp(*av, "threadsort") == 0){ + if(--ac){ + threadsort = *++av; + COM_THREAD_SORT_KEY = cpystr(threadsort); + } + else{ + display_args_err(args_err_missing_thread_sort, NULL, 1); + ++usage; + } + + goto Loop; + } else if(strcmp(*av, "url") == 0){ if(args->action == aaFolder && !args->data.folder){ args->action = aaURL; diff -u -r alpine-0.98+dfsg/alpine/confscroll.c alpine-0.98+dfsg+fancythread-clean/alpine/confscroll.c --- alpine-0.98+dfsg/alpine/confscroll.c 2007-03-13 23:16:32.000000000 +0100 +++ alpine-0.98+dfsg+fancythread-clean/alpine/confscroll.c 2007-04-29 22:42:31.000000000 +0200 @@ -135,7 +135,7 @@ char *radio_pretty_value(struct pine *, CONF_S *); char *sigfile_pretty_value(struct pine *, CONF_S *); char *color_pretty_value(struct pine *, CONF_S *); -char *sort_pretty_value(struct pine *, CONF_S *); +char *sort_pretty_value(struct pine *, CONF_S *, int); COLOR_PAIR *sample_color(struct pine *, struct variable *); COLOR_PAIR *sampleexc_color(struct pine *, struct variable *); void clear_feature(char ***, char *); @@ -291,7 +291,8 @@ CONF_S *ctmp; if(!(cl && *cl && - ((*cl)->var == &ps->vars[V_SORT_KEY] || + (((*cl)->var == &ps->vars[V_SORT_KEY]) || + ((*cl)->var == &ps->vars[V_THREAD_SORT_KEY]) || standard_radio_var(ps, (*cl)->var) || (*cl)->var == startup_ptr))) return; @@ -2829,7 +2830,7 @@ } set_current_val((*cl)->var, TRUE, TRUE); - if(decode_sort(ps->VAR_SORT_KEY, &def_sort, &def_sort_rev) != -1){ + if(decode_sort(ps->VAR_SORT_KEY, &def_sort, &def_sort_rev,0) != -1){ ps->def_sort = def_sort; ps->def_sort_rev = def_sort_rev; } @@ -2838,6 +2839,37 @@ ps->mangled_body = 1; /* BUG: redraw it all for now? */ rv = 1; } + else if((*cl)->var == &ps->vars[V_THREAD_SORT_KEY]){ + SortOrder thread_def_sort; + int thread_def_sort_rev; + + thread_def_sort_rev = (*cl)->varmem >= (short) EndofList; + thread_def_sort = (SortOrder) ((*cl)->varmem - (thread_def_sort_rev + * EndofList)); + sprintf(tmp_20k_buf, "%s%s", sort_name(thread_def_sort), + (thread_def_sort_rev) ? "/Reverse" : ""); + + if((*cl)->var->cmdline_val.p) + fs_give((void **)&(*cl)->var->cmdline_val.p); + + if(apval){ + if(*apval) + fs_give((void **)apval); + + *apval = cpystr(tmp_20k_buf); + } + + set_current_val((*cl)->var, TRUE, TRUE); + if(decode_sort(ps->VAR_THREAD_SORT_KEY, &thread_def_sort, + &thread_def_sort_rev, 1) != -1){ + ps->thread_def_sort = thread_def_sort; + ps->thread_def_sort_rev = thread_def_sort_rev; + } + + set_radio_pretty_vals(ps, cl); + ps->mangled_body = 1; /* BUG: redraw it all for now? */ + rv = 1; + } else q_status_message(SM_ORDER | SM_DING, 3, 6, "Programmer botch! Unknown radiobutton type."); @@ -3692,7 +3724,9 @@ else if(standard_radio_var(ps, v) || v == startup_ptr) return(radio_pretty_value(ps, cl)); else if(v == &ps->vars[V_SORT_KEY]) - return(sort_pretty_value(ps, cl)); + return(sort_pretty_value(ps, cl, 0)); + else if(v == &ps->vars[V_THREAD_SORT_KEY]) + return(sort_pretty_value(ps, cl, 1)); else if(v == &ps->vars[V_SIGNATURE_FILE]) return(sigfile_pretty_value(ps, cl)); else if(v == &ps->vars[V_USE_ONLY_DOMAIN_NAME]) @@ -4173,14 +4207,14 @@ char * -sort_pretty_value(struct pine *ps, CONF_S *cl) +sort_pretty_value(struct pine *ps, CONF_S *cl, int thread) { - return(generalized_sort_pretty_value(ps, cl, 1)); + return(generalized_sort_pretty_value(ps, cl, 1, thread)); } char * -generalized_sort_pretty_value(struct pine *ps, CONF_S *cl, int default_ok) +generalized_sort_pretty_value(struct pine *ps, CONF_S *cl, int default_ok, int thread) { char tmp[6*MAXPATH]; char *pvalnorm, *pvalexc, *pval; @@ -4230,7 +4264,7 @@ } else if(fixed){ pval = v->fixed_val.p; - decode_sort(pval, &var_sort, &var_sort_rev); + decode_sort(pval, &var_sort, &var_sort_rev, thread); is_the_one = (var_sort_rev == line_sort_rev && var_sort == line_sort); utf8_snprintf(tmp, sizeof(tmp), "(%c) %s%-*w%*s%s", @@ -4241,9 +4275,9 @@ is_the_one ? " (value is fixed)" : ""); } else if(is_set_for_this_level){ - decode_sort(pval, &var_sort, &var_sort_rev); + decode_sort(pval, &var_sort, &var_sort_rev, thread); is_the_one = (var_sort_rev == line_sort_rev && var_sort == line_sort); - decode_sort(pvalexc, &exc_sort, &exc_sort_rev); + decode_sort(pvalexc, &exc_sort, &exc_sort_rev, thread); the_exc_one = (editing_normal_which_isnt_except && pvalexc && exc_sort_rev == line_sort_rev && exc_sort == line_sort); utf8_snprintf(tmp, sizeof(tmp), "(%c) %s%-*w%*s%s", @@ -4261,7 +4295,7 @@ } else{ if(pvalexc){ - decode_sort(pvalexc, &exc_sort, &exc_sort_rev); + decode_sort(pvalexc, &exc_sort, &exc_sort_rev, thread); is_the_one = (exc_sort_rev == line_sort_rev && exc_sort == line_sort); utf8_snprintf(tmp, sizeof(tmp), "( ) %s%-*w%*s%s", @@ -4272,7 +4306,7 @@ } else{ pval = v->current_val.p; - decode_sort(pval, &var_sort, &var_sort_rev); + decode_sort(pval, &var_sort, &var_sort_rev, thread); is_the_one = ((pval || default_ok) && var_sort_rev == line_sort_rev && var_sort == line_sort); @@ -4485,6 +4519,18 @@ cl->value = pretty_value(ps, cl); } + if (f->id == F_ENHANCED_THREAD && ps->mail_stream + && SORT_IS_THREADED(ps->msgmap)){ + refresh_sort(ps->mail_stream, ps->msgmap, SRT_NON); + if (COLL_THRDS()) /* sortring by thread destroys collapsed info */ + kolapse_thread(ps, ps->mail_stream, ps->msgmap,'[', 0); + if(SEP_THRDINDX() && SORT_IS_THREADED(ps->msgmap) + && sp_viewing_a_thread(ps->mail_stream)){ + unview_thread(ps, ps->mail_stream, ps->msgmap); + view_thread(ps, ps->mail_stream, ps->msgmap, 0); + ps_global->next_screen = SCREEN_FUN_NULL; + } + } } @@ -5366,9 +5412,15 @@ else if(revert && var == &ps->vars[V_SORT_KEY]){ int def_sort_rev; - decode_sort(VAR_SORT_KEY, &ps->def_sort, &def_sort_rev); + decode_sort(VAR_SORT_KEY, &ps->def_sort, &def_sort_rev, 0); ps->def_sort_rev = def_sort_rev; } + else if(revert && var == &ps->vars[V_THREAD_SORT_KEY]){ + int thread_def_sort_rev; + + decode_sort(VAR_THREAD_SORT_KEY, &ps->thread_def_sort, &thread_def_sort_rev, 1); + ps->thread_def_sort_rev = thread_def_sort_rev; + } else if(var == &ps->vars[V_THREAD_MORE_CHAR] || var == &ps->vars[V_THREAD_EXP_CHAR] || var == &ps->vars[V_THREAD_LASTREPLY_CHAR]){ diff -u -r alpine-0.98+dfsg/alpine/confscroll.h alpine-0.98+dfsg+fancythread-clean/alpine/confscroll.h --- alpine-0.98+dfsg/alpine/confscroll.h 2006-09-22 22:06:05.000000000 +0200 +++ alpine-0.98+dfsg+fancythread-clean/alpine/confscroll.h 2007-04-29 21:14:00.000000000 +0200 @@ -90,7 +90,7 @@ int checkbox_tool(struct pine *, int, CONF_S **, unsigned); int radiobutton_tool(struct pine *, int, CONF_S **, unsigned); int yesno_tool(struct pine *, int, CONF_S **, unsigned); -char *generalized_sort_pretty_value(struct pine *, CONF_S *, int); +char *generalized_sort_pretty_value(struct pine *, CONF_S *, int, int); #endif /* PINE_CONFSCROLL_INCLUDED */ diff -u -r alpine-0.98+dfsg/alpine/keymenu.c alpine-0.98+dfsg+fancythread-clean/alpine/keymenu.c --- alpine-0.98+dfsg/alpine/keymenu.c 2007-02-22 20:48:09.000000000 +0100 +++ alpine-0.98+dfsg+fancythread-clean/alpine/keymenu.c 2007-04-29 21:11:22.000000000 +0200 @@ -583,10 +583,23 @@ RCOMPOSE_MENU, HOMEKEY_MENU, ENDKEY_MENU, - NULL_MENU, + {"K",N_("Sort Thread"),{MC_SORTHREAD,1,{'k'}},KS_NONE}, /* TRANSLATORS: toggles a collapsed view or an expanded view of a message thread on and off */ {"/",N_("Collapse/Expand"),{MC_COLLAPSE,1,{'/'}},KS_NONE}, + {"{",N_("Collapse All"),{MC_KOLAPSE,1,{'{'}},KS_NONE}, + {"}",N_("Expand All"), {MC_EXPTHREAD,1,{'}'}},KS_NONE}, + + HELP_MENU, + OTHER_MENU, + {")",N_("Next Threa"),{MC_NEXTHREAD,1,{')'}},KS_NONE}, + {"(",N_("Prev Threa"),{MC_PRETHREAD,1,{'('}},KS_NONE}, + {"^D",N_("Delete Thr"),{MC_DELTHREAD,1,{ctrl('D')}},KS_NONE}, + {"^U",N_("Undel Thre"),{MC_UNDTHREAD,1,{ctrl('U')}},KS_NONE}, + {"^T",N_("Select Thr"),{MC_SELTHREAD,1,{ctrl('T')}},KS_NONE}, + NULL_MENU, + {"[",N_("Close Thre"),{MC_CTHREAD,1,{'['}},KS_NONE}, + {"]",N_("Open Threa"),{MC_OTHREAD,1,{']'}},KS_NONE}, NULL_MENU, NULL_MENU}; INST_KEY_MENU(index_keymenu, index_keys); @@ -661,9 +674,22 @@ RCOMPOSE_MENU, HOMEKEY_MENU, ENDKEY_MENU, - NULL_MENU, + {"]",N_("Open Threa"),{MC_OTHREAD,1,{']'}},KS_NONE}, {"/",N_("Collapse/Expand"),{MC_COLLAPSE,1,{'/'}},KS_NONE}, + {")",N_("Next Threa"),{MC_NEXTHREAD,1,{')'}},KS_NONE}, + {"(",N_("Prev Threa"),{MC_PRETHREAD,1,{'('}},KS_NONE}, + + HELP_MENU, + OTHER_MENU, NULL_MENU, + NULL_MENU, + {"^D",N_("Delete Thr"),{MC_DELTHREAD,1,{ctrl('D')}},KS_NONE}, + {"^U",N_("Undel Thre"),{MC_UNDTHREAD,1,{ctrl('U')}},KS_NONE}, + {"^T",N_("Select Thr"),{MC_SELTHREAD,1,{ctrl('T')}},KS_NONE}, + NULL_MENU, + NULL_MENU, + NULL_MENU, + {"K",N_("Sort Thread"),{MC_SORTHREAD,1,{'k'}},KS_NONE}, NULL_MENU}; INST_KEY_MENU(thread_keymenu, thread_keys); @@ -803,11 +829,11 @@ ENDKEY_MENU, RCOMPOSE_MENU, {"A",N_("TogglePreferPlain"),{MC_TOGGLE,1,{'a'}},KS_NONE}, - NULL_MENU, - NULL_MENU, - NULL_MENU, - NULL_MENU, - NULL_MENU, + {"(",N_("Prev Threa"),{MC_PRETHREAD,1,{'('}},KS_NONE}, + {")",N_("Next Threa"),{MC_NEXTHREAD,1,{')'}},KS_NONE}, + {"^D",N_("Delete Thr"),{MC_DELTHREAD,1,{ctrl('D')}},KS_NONE}, + {"^U",N_("Undel Thre"),{MC_UNDTHREAD,1,{ctrl('U')}},KS_NONE}, + {"^T",N_("selcT Thre"),{MC_SELTHREAD,1,{ctrl('T')}},KS_NONE}, NULL_MENU}; INST_KEY_MENU(view_keymenu, view_keys); diff -u -r alpine-0.98+dfsg/alpine/keymenu.h alpine-0.98+dfsg+fancythread-clean/alpine/keymenu.h --- alpine-0.98+dfsg/alpine/keymenu.h 2007-01-23 01:09:18.000000000 +0100 +++ alpine-0.98+dfsg+fancythread-clean/alpine/keymenu.h 2007-04-29 22:57:59.000000000 +0200 @@ -210,6 +210,19 @@ #define MC_NOT 799 #define MC_COLLAPSE 800 #define MC_CHK_RECENT 801 +#define MC_PRETHREAD 802 +#define MC_CTHREAD 803 +#define MC_OTHREAD 804 +#define MC_DELTHREAD 805 +#define MC_UNDTHREAD 806 +#define MC_SELTHREAD 807 +#define MC_SSUTHREAD 808 +#define MC_DSUTHREAD 809 +#define MC_USUTHREAD 810 +#define MC_SORTHREAD 811 +#define MC_NEXTHREAD 812 +#define MC_KOLAPSE 813 +#define MC_EXPTHREAD 814 /* diff -u -r alpine-0.98+dfsg/alpine/mailcmd.c alpine-0.98+dfsg+fancythread-clean/alpine/mailcmd.c --- alpine-0.98+dfsg/alpine/mailcmd.c 2007-03-26 20:18:35.000000000 +0200 +++ alpine-0.98+dfsg+fancythread-clean/alpine/mailcmd.c 2007-04-30 00:09:52.000000000 +0200 @@ -99,7 +99,7 @@ char *choose_a_rule(int); int select_by_keyword(MAILSTREAM *, SEARCHSET **); char *choose_a_keyword(void); -int select_sort(struct pine *, int, SortOrder *, int *); +int select_sort(struct pine *, int, SortOrder *, int *, int); void free_list_sel(LIST_SEL_S **); int print_index(struct pine *, MSGNO_S *, int); @@ -1296,7 +1296,7 @@ if(any_messages(msgmap, NULL, NULL)){ if(any_lflagged(msgmap, MN_SLCT) > 0L){ if(apply_command(state, stream, msgmap, 0, - AC_NONE, question_line)){ + AC_NONE, question_line, 1)){ if(F_ON(F_AUTO_UNSELECT, state)){ agg_select_all(stream, msgmap, NULL, 0); unzoom_index(state, stream, msgmap); @@ -1314,18 +1314,23 @@ /*-------- Sort command -------*/ case MC_SORT : + case MC_SORTHREAD : { int were_threading = THREADING(); SortOrder sort = mn_get_sort(msgmap); int rev = mn_get_revsort(msgmap); + int thread = (command == MC_SORT) ? 0 : 1; dprint((1,"MAIL_CMD: sort\n")); - if(select_sort(state, question_line, &sort, &rev)){ + if(select_sort(state, question_line, &sort, &rev,thread)){ /* $ command reinitializes threading collapsed/expanded info */ if(SORT_IS_THREADED(msgmap) && !SEP_THRDINDX()) erase_threading_info(stream, msgmap); - sort_folder(stream, msgmap, sort, rev, SRT_VRB|SRT_MAN); + if (command == MC_SORTHREAD) + ps_global->thread_cur_sort = sort; + sort = (command == MC_SORT) ? sort : SortThread; + sort_folder(stream, msgmap, sort, rev, SRT_VRB|SRT_MAN, 1); } state->mangled_footer = 1; @@ -2895,6 +2900,10 @@ if(SORT_IS_THREADED(msgmap)) refresh_sort(stream, msgmap, SRT_NON); + if (msgmap->nmsgs + && F_ON(F_ENHANCED_THREAD, state) && COLL_THRDS()) + kolapse_thread(state, stream, msgmap, '[', 0); + state->mangled_body = 1; state->mangled_header = 1; q_status_message2(SM_ORDER, 0, 4, @@ -2985,6 +2994,9 @@ */ if(SORT_IS_THREADED(msgmap)) refresh_sort(stream, msgmap, SRT_NON); + if (msgmap->nmsgs + && F_ON(F_ENHANCED_THREAD, state) && COLL_THRDS()) + kolapse_thread(state, stream, msgmap, '[', 0); } else{ if(del_count) @@ -6352,7 +6364,7 @@ ----*/ int apply_command(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap, - UCS preloadkeystroke, int flags, int q_line) + UCS preloadkeystroke, int flags, int q_line, int display) { int i = 8, /* number of static entries in sel_opts3 */ rv = 0, @@ -6504,9 +6516,19 @@ collapse_or_expand(state, stream, msgmap, F_ON(F_SLASH_COLL_ENTIRE, ps_global) ? 0L - : mn_get_cur(msgmap)); + : mn_get_cur(msgmap), + display); break; + case '[' : + collapse_this_thread(state, stream, msgmap, display, 0); + break; + + case ']' : + expand_this_thread(state, stream, msgmap, display, 0); + break; + + case ':' : select_thread_stmp(state, stream, msgmap); break; @@ -7994,10 +8016,10 @@ Returns 0 if it was cancelled, 1 otherwise. ----*/ int -select_sort(struct pine *state, int ql, SortOrder *sort, int *rev) +select_sort(struct pine *state, int ql, SortOrder *sort, int *rev, int thread) { char prompt[200], tmp[3], *p; - int s, i; + int s, i, j; int deefault = 'a', retval = 1; HelpType help; ESCKEY_S sorts[14]; @@ -8030,17 +8052,28 @@ strncpy(prompt, _("Choose type of sort, or 'R' to reverse current sort : "), sizeof(prompt)); - for(i = 0; state->sort_types[i] != EndofList; i++) { - sorts[i].rval = i; - p = sorts[i].label = sort_name(state->sort_types[i]); - while(*(p+1) && islower((unsigned char)*p)) - p++; - - sorts[i].ch = tolower((unsigned char)(tmp[0] = *p)); - sorts[i].name = cpystr(tmp); - - if(mn_get_sort(state->msgmap) == state->sort_types[i]) - deefault = sorts[i].rval; + for(i = 0, j = 0; state->sort_types[i] != EndofList; i++) { + sorts[i].rval = i; + sorts[i].name = cpystr(""); + sorts[i].label = ""; + sorts[i].ch = -2; + if (!thread || state->sort_types[i] == SortArrival + || state->sort_types[i] == SortThread + || state->sort_types[i] == SortScore){ + p = sorts[j].label = sort_name(state->sort_types[i]); + while(*(p+1) && islower((unsigned char)*p)) + p++; + sorts[j].ch = tolower((unsigned char)(tmp[0] = *p)); + sorts[j++].name = cpystr(tmp); + } + + if (thread){ + if (state->thread_def_sort == state->sort_types[i]) + deefault = sorts[j-1].rval; + } + else + if(mn_get_sort(state->msgmap) == state->sort_types[i]) + deefault = sorts[i].rval; } sorts[i].ch = 'r'; @@ -8065,7 +8098,7 @@ if(s == 'r') *rev = !mn_get_revsort(state->msgmap); else - *sort = state->sort_types[s]; + *sort = state->sort_types[thread ? (s == 0 ? 1 : 9) : s]; if(F_ON(F_SHOW_SORT, ps_global)) ps_global->mangled_header = 1; @@ -8442,3 +8475,126 @@ } #endif /* _WINDOWS */ + + +/* Extra Fancy Thread support */ + + +void +cmd_delete_this_thread(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap) +{ + unsigned long rawno, top, save_kolapsed; + PINETHRD_S *thrd = NULL, *nxthrd; + + if(!stream) + return; + + rawno = mn_m2raw(msgmap, mn_get_cur(msgmap)); + move_top_this_thread(stream, msgmap, rawno); + top = mn_m2raw(msgmap, mn_get_cur(msgmap)); + if(top) + thrd = fetch_thread(stream, top); + + if(!thrd) + return; + + save_kolapsed = this_thread_is_kolapsed(state, stream, msgmap, top); + collapse_this_thread(state, stream, msgmap, 0, 0); + thread_command(state, stream, msgmap, 'd', -FOOTER_ROWS(state), 1); + if (!save_kolapsed) + expand_this_thread(state, stream, msgmap, 0, 0); +} + +void +cmd_delete_thread(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap) +{ + unsigned long rawno, top, orig_top, topnxt, save_kolapsed; + PINETHRD_S *thrd = NULL, *nxthrd; + int done = 0, count; + + if(!stream) + return; + + rawno = mn_m2raw(msgmap, mn_get_cur(msgmap)); + move_top_thread(stream, msgmap, rawno); + top = orig_top = mn_m2raw(msgmap, mn_get_cur(msgmap)); + if(top) + thrd = fetch_thread(stream, top); + + if(!thrd) + return; + + while (!done){ + cmd_delete_this_thread(state, stream, msgmap); + if (F_OFF(F_ENHANCED_THREAD, state) + || (move_next_this_thread(state, stream, msgmap, 0) <= 0) + || !(top = mn_m2raw(msgmap, mn_get_cur(msgmap))) + || (orig_top != top_thread(stream, top))) + done++; + } + mn_set_cur(msgmap,mn_raw2m(msgmap, rawno)); + cmd_delete(state, msgmap, 0, MsgIndx); + count = count_thread(state, stream, msgmap, rawno); + q_status_message2(SM_ORDER, 0, 1, "%s message%s marked deleted", + int2string(count), plural(count)); +} + + + +void +cmd_undelete_this_thread(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap) +{ + unsigned long rawno; + int save_kolapsed; + + rawno = mn_m2raw(msgmap, mn_get_cur(msgmap)); + save_kolapsed = this_thread_is_kolapsed(state, stream, msgmap, rawno); + collapse_this_thread(state, stream, msgmap, 0, 0); + thread_command(state, stream, msgmap, 'u', -FOOTER_ROWS(state), 1); + if (!save_kolapsed) + expand_this_thread(state, stream, msgmap, 0, 0); +} + +void +cmd_undelete_thread(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap) +{ + PINETHRD_S *thrd = NULL; + unsigned long rawno, top, orig_top; + int done = 0, count; + + rawno = mn_m2raw(msgmap, mn_get_cur(msgmap)); + move_top_thread(stream, msgmap, rawno); + top = orig_top = mn_m2raw(msgmap, mn_get_cur(msgmap)); + if(top) + thrd = fetch_thread(stream, top); + + if(!thrd) + return; + + while (!done){ + cmd_undelete_this_thread(state, stream, msgmap); + if (F_OFF(F_ENHANCED_THREAD, state) + || (move_next_this_thread(state, stream, msgmap, 0) <= 0) + || !(top = mn_m2raw(msgmap, mn_get_cur(msgmap))) + || (orig_top != top_thread(stream, top))) + done++; + } + mn_set_cur(msgmap,mn_raw2m(msgmap, rawno)); + count = count_thread(state, stream, msgmap, rawno); + q_status_message2(SM_ORDER, 0, 1, "Deletion mark removed from %s message%s", + int2string(count), plural(count)); +} + +void +cmd_select_thread(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap) +{ + unsigned long rawno; + int save_kolapsed; + + rawno = mn_m2raw(msgmap, mn_get_cur(msgmap)); + save_kolapsed = thread_is_kolapsed(state, stream, msgmap, rawno); + collapse_thread(state, stream, msgmap, 0); + thread_command(state, stream, msgmap, ':', -FOOTER_ROWS(state), 1); + if (!save_kolapsed) + expand_thread(state, stream, msgmap, 0); +} diff -u -r alpine-0.98+dfsg/alpine/mailcmd.h alpine-0.98+dfsg+fancythread-clean/alpine/mailcmd.h --- alpine-0.98+dfsg/alpine/mailcmd.h 2007-03-08 00:16:56.000000000 +0100 +++ alpine-0.98+dfsg+fancythread-clean/alpine/mailcmd.h 2007-04-30 00:10:02.000000000 +0200 @@ -71,7 +71,7 @@ int ask_mailbox_reopen(struct pine *, int *); void visit_folder(struct pine *, char *, CONTEXT_S *, MAILSTREAM *, unsigned long); int select_by_current(struct pine *, MSGNO_S *, CmdWhere); -int apply_command(struct pine *, MAILSTREAM *, MSGNO_S *, UCS, int, int); +int apply_command(struct pine *, MAILSTREAM *, MSGNO_S *, UCS, int, int, int); char **choose_list_of_keywords(void); char **choose_list_of_charsets(void); char *choose_item_from_list(char **, char *, char *, HelpType, char *); @@ -80,6 +80,11 @@ int file_lister(char *, char *, size_t, char *, size_t, int, int); int read_msg_prompt(long, char *); void advance_cur_after_delete(struct pine *, MAILSTREAM *, MSGNO_S *, CmdWhere); +void cmd_delete_this_thread (struct pine *, MAILSTREAM *, MSGNO_S *); +void cmd_delete_thread (struct pine *, MAILSTREAM *, MSGNO_S *); +void cmd_undelete_this_thread (struct pine *, MAILSTREAM *, MSGNO_S *); +void cmd_undelete_thread (struct pine *, MAILSTREAM *, MSGNO_S *); +void cmd_select_thread (struct pine *, MAILSTREAM *, MSGNO_S *); #ifdef _WINDOWS int header_mode_callback(int, long); int zoom_mode_callback(int, long); diff -u -r alpine-0.98+dfsg/alpine/mailindx.c alpine-0.98+dfsg+fancythread-clean/alpine/mailindx.c --- alpine-0.98+dfsg/alpine/mailindx.c 2007-03-16 00:06:03.000000000 +0100 +++ alpine-0.98+dfsg+fancythread-clean/alpine/mailindx.c 2007-04-30 00:10:24.000000000 +0200 @@ -46,7 +46,6 @@ static OtherMenu what_keymenu = FirstMenu; - struct index_state *current_index_state = NULL; @@ -560,6 +559,7 @@ /*---------- Scroll line up ----------*/ case MC_CHARUP : +previtem: (void) process_cmd(state, stream, msgmap, MC_PREVITEM, (style == MsgIndex || style == MultiMsgIndex @@ -577,6 +577,7 @@ /*---------- Scroll line down ----------*/ case MC_CHARDOWN : +nextitem: /* * Special Page framing handling here. If we * did something that should scroll-by-a-line, frame @@ -794,6 +795,7 @@ case MC_THRDINDX : +mc_thrdindx: msgmap->top = msgmap->top_after_thrd; if(unview_thread(state, stream, msgmap)){ state->next_screen = mail_index_screen; @@ -844,7 +846,7 @@ && mp.col == id.plus_col && style != ThreadIndex){ collapse_or_expand(state, stream, msgmap, - mn_get_cur(msgmap)); + mn_get_cur(msgmap), 1); } else if (mp.doubleclick){ if(mp.button == M_BUTTON_LEFT){ @@ -945,9 +947,106 @@ bogus_command(ch, F_ON(F_USE_FK,state) ? "F1" : "?"); break; + case MC_CTHREAD : + if (SEP_THRDINDX()) + goto mc_thrdindx; + else + if (THREADING()){ + if (any_messages(ps_global->msgmap, NULL, + "to collapse a thread")) + collapse_thread(state, stream,msgmap, 1); + } + else + q_status_message(SM_ORDER, 0, 1, + "Command available in threaded mode only"); + break; + + case MC_OTHREAD : + if (SEP_THRDINDX()) + goto view_a_thread; + else + if (THREADING()){ + if (any_messages(ps_global->msgmap, NULL, "to expand a thread")) + expand_thread(state, stream,msgmap, 1); + } + else + q_status_message(SM_ORDER, 0, 1, + "Command available in threaded mode only"); + break; + + case MC_NEXTHREAD: + case MC_PRETHREAD: + if (THRD_INDX()){ + if (cmd == MC_NEXTHREAD) + goto nextitem; + else + goto previtem; + } + else + if (THREADING()){ + if (any_messages(ps_global->msgmap, NULL, + "to move to other thread")) + move_thread(state, stream, msgmap, + cmd == MC_NEXTHREAD ? 1 : -1); + } + else + q_status_message(SM_ORDER, 0, 1, + "Command available in threaded mode only"); + break; + + case MC_KOLAPSE: + case MC_EXPTHREAD: + if (SEP_THRDINDX()){ + q_status_message(SM_ORDER, 0, 1, + "Command not available in this screen"); + } + else{ + if (THREADING()){ + if (any_messages(ps_global->msgmap, NULL, + cmd == MC_KOLAPSE ? "to collapse" : "to expand")) + kolapse_thread(state, stream, msgmap, + (cmd == MC_KOLAPSE) ? '[' : ']', 1); + } + else + q_status_message(SM_ORDER, 0, 1, + "Command available in threaded mode only"); + } + break; + + case MC_DELTHREAD: + if (THREADING()){ + if (any_messages(ps_global->msgmap, NULL, "to delete")) + cmd_delete_thread(state, stream, msgmap); + } + else + q_status_message(SM_ORDER, 0, 1, + "Command available in threaded mode only"); + break; + + case MC_UNDTHREAD: + if (THREADING()){ + if (any_messages(ps_global->msgmap, NULL, "to undelete")) + cmd_undelete_thread(state, stream, msgmap); + } + else + q_status_message(SM_ORDER, 0, 1, + "Command available in threaded mode only"); + break; + + + case MC_SELTHREAD: + if (THREADING()){ + if (any_messages(ps_global->msgmap, NULL, "to undelete")) + cmd_select_thread(state, stream, msgmap); + } + else + q_status_message(SM_ORDER, 0, 1, + "Command available in threaded mode only"); + break; + case MC_COLLAPSE : - thread_command(state, stream, msgmap, ch, -FOOTER_ROWS(state)); + thread_command(state, stream, msgmap, ch, -FOOTER_ROWS(state), 1); break; case MC_DELETE : @@ -970,13 +1069,12 @@ if(rawno) thrd = fetch_thread(stream, rawno); - collapsed = thrd && thrd->next - && get_lflag(stream, NULL, rawno, MN_COLL); + collapsed = thread_is_kolapsed(ps_global, stream, msgmap, rawno); } if(collapsed){ thread_command(state, stream, msgmap, - ch, -FOOTER_ROWS(state)); + ch, -FOOTER_ROWS(state), 1); /* increment current */ if(cmd == MC_DELETE){ advance_cur_after_delete(state, stream, msgmap, @@ -2643,6 +2741,7 @@ n = mn_raw2m(msgs, thrd->rawno); while(thrd){ + unsigned long branch; if(!msgline_hidden(stream, msgs, n, 0) && (++m % lines_per_page) == 1L) t = n; @@ -2711,11 +2810,12 @@ /* n is the end of this thread */ while(thrd){ + unsigned long next = 0L, branch = 0L; n = mn_raw2m(msgs, thrd->rawno); - if(thrd->branch) - thrd = fetch_thread(stream, thrd->branch); - else if(thrd->next) - thrd = fetch_thread(stream, thrd->next); + if(branch = get_branch(stream,thrd)) + thrd = fetch_thread(stream, branch); + else if(next = get_next(stream,thrd)) + thrd = fetch_thread(stream, next); else thrd = NULL; } @@ -2823,7 +2923,7 @@ void thread_command(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap, - UCS preloadkeystroke, int q_line) + UCS preloadkeystroke, int q_line, int display) { PINETHRD_S *thrd = NULL; unsigned long rawno, save_branch; @@ -2872,7 +2972,7 @@ cancel_busy_cue(0); (void ) apply_command(state, stream, msgmap, preloadkeystroke, flags, - q_line); + q_line, display); /* restore the original flags */ copy_lflags(stream, msgmap, MN_STMP, MN_SLCT); diff -u -r alpine-0.98+dfsg/alpine/mailindx.h alpine-0.98+dfsg+fancythread-clean/alpine/mailindx.h --- alpine-0.98+dfsg/alpine/mailindx.h 2007-02-27 01:10:47.000000000 +0100 +++ alpine-0.98+dfsg+fancythread-clean/alpine/mailindx.h 2007-04-28 13:56:25.000000000 +0200 @@ -100,7 +100,7 @@ void paint_index_hline(MAILSTREAM *, long, ICE_S *); void setup_index_state(int); void warn_other_cmds(void); -void thread_command(struct pine *, MAILSTREAM *, MSGNO_S *, UCS, int); +void thread_command(struct pine *, MAILSTREAM *, MSGNO_S *, UCS, int, int); #ifdef _WINDOWS int index_sort_callback(int, long); void view_in_new_window(void); diff -u -r alpine-0.98+dfsg/alpine/mailview.c alpine-0.98+dfsg+fancythread-clean/alpine/mailview.c --- alpine-0.98+dfsg/alpine/mailview.c 2007-02-26 21:19:42.000000000 +0100 +++ alpine-0.98+dfsg+fancythread-clean/alpine/mailview.c 2007-04-29 21:12:48.000000000 +0200 @@ -3389,6 +3389,52 @@ print_to_printer(sparms); break; + case MC_NEXTHREAD: + case MC_PRETHREAD: + if (THREADING()){ + if (any_messages(ps_global->msgmap, NULL, + "to move to other thread")) + move_thread(ps_global, ps_global->mail_stream, ps_global->msgmap, + cmd == MC_NEXTHREAD ? 1 : -1); + done = 1; + } + else + q_status_message(SM_ORDER, 0, 1, + "Command available in threaded mode only"); + break; + + case MC_DELTHREAD: + if (THREADING()){ + if (any_messages(ps_global->msgmap, NULL, "to delete")) + cmd_delete_thread(ps_global, ps_global->mail_stream, ps_global->msgmap); + done = 1; + } + else + q_status_message(SM_ORDER, 0, 1, + "Command available in threaded mode only"); + break; + + case MC_UNDTHREAD: + if (THREADING()){ + if (any_messages(ps_global->msgmap, NULL, "to undelete")) + cmd_undelete_thread(ps_global, ps_global->mail_stream, ps_global->msgmap); + done = 1; + } + else + q_status_message(SM_ORDER, 0, 1, + "Command available in threaded mode only"); + break; + + case MC_SELTHREAD: + if (THREADING()){ + if (any_messages(ps_global->msgmap, NULL, "to undelete")) + cmd_select_thread(ps_global, ps_global->mail_stream, ps_global->msgmap); + done = 1; + } + else + q_status_message(SM_ORDER, 0, 1, + "Command available in threaded mode only"); + break; /* ------- First handle on Line ------ */ case MC_GOTOBOL : diff -u -r alpine-0.98+dfsg/alpine/roleconf.c alpine-0.98+dfsg+fancythread-clean/alpine/roleconf.c --- alpine-0.98+dfsg/alpine/roleconf.c 2007-01-23 01:09:18.000000000 +0100 +++ alpine-0.98+dfsg+fancythread-clean/alpine/roleconf.c 2007-04-29 22:44:03.000000000 +0200 @@ -4375,7 +4375,7 @@ pval = PVAL(&sort_act_var, ew); if(pval) - decode_sort(pval, &def_sort, &def_sort_rev); + decode_sort(pval, &def_sort, &def_sort_rev,0); /* allow user to set their default sort order */ new_confline(&ctmp)->var = &sort_act_var; @@ -4385,7 +4385,7 @@ ctmp->tool = role_sort_tool; ctmp->valoffset = rindent; ctmp->varmem = -1; - ctmp->value = generalized_sort_pretty_value(ps, ctmp, 0); + ctmp->value = generalized_sort_pretty_value(ps, ctmp, 0, 0); for(j = 0; j < 2; j++){ for(i = 0; ps->sort_types[i] != EndofList; i++){ @@ -4397,7 +4397,7 @@ ctmp->valoffset = rindent; ctmp->varmem = i + (j * EndofList); ctmp->value = generalized_sort_pretty_value(ps, ctmp, - 0); + 0, 0); } } @@ -5323,7 +5323,7 @@ (*result)->patgrp->stat_boy = PAT_STAT_EITHER; if(sort_act){ - decode_sort(sort_act, &def_sort, &def_sort_rev); + decode_sort(sort_act, &def_sort, &def_sort_rev, 0); (*result)->action->sort_is_set = 1; (*result)->action->sortorder = def_sort; (*result)->action->revsort = (def_sort_rev ? 1 : 0); diff -u -r alpine-0.98+dfsg/alpine/setup.c alpine-0.98+dfsg+fancythread-clean/alpine/setup.c --- alpine-0.98+dfsg/alpine/setup.c 2006-12-02 02:35:46.000000000 +0100 +++ alpine-0.98+dfsg+fancythread-clean/alpine/setup.c 2007-04-30 00:10:39.000000000 +0200 @@ -55,7 +55,7 @@ option_screen(struct pine *ps, int edit_exceptions) { char tmp[MAXPATH+1], *pval, **lval; - int i, j, ln = 0, readonly_warning = 0; + int i, j, ln = 0, lv, readonly_warning = 0; struct variable *vtmp; CONF_S *ctmpa = NULL, *ctmpb, *first_line = NULL; FEATURE_S *feature; @@ -250,7 +250,7 @@ ctmpa->flags |= CF_NOSELECT; ctmpa->value = cpystr("--- ----------------------"); - decode_sort(pval, &def_sort, &def_sort_rev); + decode_sort(pval, &def_sort, &def_sort_rev, 0); for(j = 0; j < 2; j++){ for(i = 0; ps->sort_types[i] != EndofList; i++){ @@ -265,6 +265,57 @@ } } } + else if(vtmp == &ps->vars[V_THREAD_SORT_KEY]){ /* radio case */ + SortOrder thread_def_sort; + int thread_def_sort_rev; + + ctmpa->flags |= CF_NOSELECT; + ctmpa->keymenu = &config_radiobutton_keymenu; + ctmpa->tool = NULL; + + /* put a nice delimiter before list */ + new_confline(&ctmpa)->var = NULL; + ctmpa->varnamep = ctmpb; + ctmpa->keymenu = &config_radiobutton_keymenu; + ctmpa->help = NO_HELP; + ctmpa->tool = radiobutton_tool; + ctmpa->valoffset = 12; + ctmpa->flags |= CF_NOSELECT; + ctmpa->value = cpystr("Set Thread Sort Options"); + + new_confline(&ctmpa)->var = NULL; + ctmpa->varnamep = ctmpb; + ctmpa->keymenu = &config_radiobutton_keymenu; + ctmpa->help = NO_HELP; + ctmpa->tool = radiobutton_tool; + ctmpa->valoffset = 12; + ctmpa->flags |= CF_NOSELECT; + ctmpa->value = cpystr("--- ----------------------"); + + /* find longest value's name */ + for(lv = 0, i = 0; ps->sort_types[i] != EndofList; i++) + if(lv < (j = strlen(sort_name(ps->sort_types[i])))) + lv = j; + + decode_sort(pval, &thread_def_sort, &thread_def_sort_rev, 1); + + for(j = 0; j < 2; j++){ + for(i = 0; ps->sort_types[i] != EndofList; i++){ + if (ps->sort_types[i] == SortArrival + || ps->sort_types[i] == SortThread + || ps->sort_types[i] == SortScore){ + new_confline(&ctmpa)->var = vtmp; + ctmpa->varnamep = ctmpb; + ctmpa->keymenu = &config_radiobutton_keymenu; + ctmpa->help = config_help(vtmp - ps->vars, 0); + ctmpa->tool = radiobutton_tool; + ctmpa->valoffset = 12; + ctmpa->varmem = i + (j * EndofList); + ctmpa->value = pretty_value(ps, ctmpa); + } + } + } + } else if(vtmp == &ps->vars[V_USE_ONLY_DOMAIN_NAME]){ /* yesno case */ ctmpa->keymenu = &config_yesno_keymenu; ctmpa->tool = yesno_tool; @@ -438,6 +489,15 @@ } } + pval = PVAL(&ps->vars[V_THREAD_SORT_KEY], ew); + if(vsave[V_THREAD_SORT_KEY].saved_user_val.p && pval + && strcmp(vsave[V_THREAD_SORT_KEY].saved_user_val.p, pval)){ + if(!mn_get_mansort(ps_global->msgmap)){ + clear_index_cache(); + reset_sort_order(SRT_VRB); + } + } + treat_color_vars_as_text = 0; free_saved_config(ps, &vsave, expose_hidden_config); #ifdef _WINDOWS Only in alpine-0.98+dfsg+fancythread-clean/: def_sort diff -u -r alpine-0.98+dfsg/pith/conf.c alpine-0.98+dfsg+fancythread-clean/pith/conf.c --- alpine-0.98+dfsg/pith/conf.c 2007-03-29 19:50:41.000000000 +0200 +++ alpine-0.98+dfsg+fancythread-clean/pith/conf.c 2007-04-30 00:11:33.000000000 +0200 @@ -47,6 +47,8 @@ #define TO_BAIL_THRESHOLD 60 +#define DF_THREAD_SORT_KEY "thread" + /* @@ -176,6 +178,8 @@ CONF_TXT_T cf_text_sort_key[] = "Sets presentation order of messages in Index. Choices:\n# Subject, From, Arrival, Date, Size, To, Cc, OrderedSubj, Score, and Thread.\n# Order may be reversed by appending /Reverse. Default: \"Arrival\"."; +CONF_TXT_T cf_text_thread_sort_key[] = "#Sets presentation order of threads in thread index. Choices:\n#arrival, and thread."; + CONF_TXT_T cf_text_addrbook_sort_rule[] = "Sets presentation order of address book entries. Choices: dont-sort,\n# fullname-with-lists-last, fullname, nickname-with-lists-last, nickname\n# Default: \"fullname-with-lists-last\"."; CONF_TXT_T cf_text_folder_sort_rule[] = "Sets presentation order of folder list entries. Choices: alphabetical,\n# alpha-with-dirs-last, alpha-with-dirs-first.\n# Default: \"alpha-with-directories-last\"."; @@ -481,6 +485,8 @@ cf_text_fcc_name_rule}, {"sort-key", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, cf_text_sort_key}, +{"thread-sort-key", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, + cf_text_thread_sort_key}, {"addrbook-sort-rule", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, cf_text_addrbook_sort_rule}, {"folder-sort-rule", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, @@ -1460,7 +1466,7 @@ register struct variable *vars = ps->vars; int obs_header_in_reply = 0, /* the obs_ variables are to */ obs_old_style_reply = 0, /* support backwards compatibility */ - obs_save_by_sender, i, def_sort_rev; + obs_save_by_sender, i, def_sort_rev, thread_def_sort_rev; long rvl; PINERC_S *fixedprc = NULL; FeatureLevel obs_feature_level; @@ -1484,6 +1490,7 @@ GLO_FEATURE_LEVEL = cpystr("sappling"); GLO_OLD_STYLE_REPLY = cpystr(DF_OLD_STYLE_REPLY); GLO_SORT_KEY = cpystr(DF_SORT_KEY); + GLO_THREAD_SORT_KEY = cpystr(DF_THREAD_SORT_KEY); GLO_SAVED_MSG_NAME_RULE = cpystr(DF_SAVED_MSG_NAME_RULE); GLO_FCC_RULE = cpystr(DF_FCC_RULE); GLO_AB_SORT_RULE = cpystr(DF_AB_SORT_RULE); @@ -2328,7 +2335,7 @@ set_current_val(&vars[V_ARCHIVED_FOLDERS], TRUE, TRUE); set_current_val(&vars[V_INCOMING_FOLDERS], TRUE, TRUE); set_current_val(&vars[V_SORT_KEY], TRUE, TRUE); - if(decode_sort(VAR_SORT_KEY, &ps->def_sort, &def_sort_rev) == -1){ + if(decode_sort(VAR_SORT_KEY, &ps->def_sort, &def_sort_rev, 0) == -1){ snprintf(tmp_20k_buf, SIZEOF_20KBUF, "Sort type \"%.200s\" is invalid", VAR_SORT_KEY); init_error(ps, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf); ps->def_sort = SortArrival; @@ -2337,6 +2344,17 @@ else ps->def_sort_rev = def_sort_rev; + set_current_val(&vars[V_THREAD_SORT_KEY], TRUE, TRUE); + if(decode_sort(VAR_THREAD_SORT_KEY, &ps->thread_def_sort, + &thread_def_sort_rev, 1) == -1){ + sprintf(tmp_20k_buf, "Sort type \"%s\" is invalid", VAR_THREAD_SORT_KEY); + init_error(ps, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf); + ps->thread_def_sort = SortThread; + ps->thread_def_sort_rev = 0; + } + else + ps->thread_def_sort_rev = thread_def_sort_rev; + cur_rule_value(&vars[V_SAVED_MSG_NAME_RULE], TRUE, TRUE); {NAMEVAL_S *v; int i; for(i = 0; v = save_msg_rules(i); i++) @@ -2752,6 +2770,8 @@ F_TAB_TO_NEW, h_config_tab_new_only, PREF_INDX}, {"thread-index-shows-important-color", F_COLOR_LINE_IMPORTANT, h_config_color_thrd_import, PREF_INDX}, + {"enhanced-fancy-thread-support", + F_ENHANCED_THREAD, h_config_enhanced_thread, PREF_INDX}, /* Viewer prefs */ {"enable-msg-view-addresses", @@ -7264,6 +7284,8 @@ return(h_config_fcc_rule); case V_SORT_KEY : return(h_config_sort_key); + case V_THREAD_SORT_KEY : + return(h_config_thread_sort_key); case V_AB_SORT_RULE : return(h_config_ab_sort_rule); case V_FLD_SORT_RULE : diff -u -r alpine-0.98+dfsg/pith/conf.h alpine-0.98+dfsg+fancythread-clean/pith/conf.h --- alpine-0.98+dfsg/pith/conf.h 2007-02-17 00:01:28.000000000 +0100 +++ alpine-0.98+dfsg+fancythread-clean/pith/conf.h 2007-04-29 22:51:47.000000000 +0200 @@ -141,6 +141,9 @@ #define VAR_SORT_KEY vars[V_SORT_KEY].current_val.p #define GLO_SORT_KEY vars[V_SORT_KEY].global_val.p #define COM_SORT_KEY vars[V_SORT_KEY].cmdline_val.p +#define VAR_THREAD_SORT_KEY vars[V_THREAD_SORT_KEY].current_val.p +#define GLO_THREAD_SORT_KEY vars[V_THREAD_SORT_KEY].global_val.p +#define COM_THREAD_SORT_KEY vars[V_THREAD_SORT_KEY].cmdline_val.p #define VAR_AB_SORT_RULE vars[V_AB_SORT_RULE].current_val.p #define GLO_AB_SORT_RULE vars[V_AB_SORT_RULE].global_val.p #define VAR_FLD_SORT_RULE vars[V_FLD_SORT_RULE].current_val.p diff -u -r alpine-0.98+dfsg/pith/conftype.h alpine-0.98+dfsg+fancythread-clean/pith/conftype.h --- alpine-0.98+dfsg/pith/conftype.h 2007-03-15 19:43:40.000000000 +0100 +++ alpine-0.98+dfsg+fancythread-clean/pith/conftype.h 2007-04-29 22:52:39.000000000 +0200 @@ -57,6 +57,7 @@ , V_SAVED_MSG_NAME_RULE , V_FCC_RULE , V_SORT_KEY + , V_THREAD_SORT_KEY , V_AB_SORT_RULE , V_FLD_SORT_RULE , V_GOTO_DEFAULT_RULE @@ -453,6 +454,7 @@ F_ALWAYS_SPELL_CHECK, F_QUELL_TIMEZONE, F_COLOR_LINE_IMPORTANT, + F_ENHANCED_THREAD, F_SLASH_COLL_ENTIRE, F_ENABLE_FULL_HDR_AND_TEXT, F_QUELL_FULL_HDR_RESET, diff -u -r alpine-0.98+dfsg/pith/flag.c alpine-0.98+dfsg+fancythread-clean/pith/flag.c --- alpine-0.98+dfsg/pith/flag.c 2006-10-26 19:23:46.000000000 +0200 +++ alpine-0.98+dfsg+fancythread-clean/pith/flag.c 2007-04-29 22:49:09.000000000 +0200 @@ -545,14 +545,15 @@ was_invisible = (mc->spare || mc->spare4) ? 1 : 0; + thrd = fetch_thread(stream, rawno); + if(chk_thrd_cnt = ((msgs->visible_threads >= 0L) && THRD_INDX_ENABLED() && (f & MN_HIDE) && (mc->spare != v))){ - thrd = fetch_thread(stream, rawno); if(thrd && thrd->top){ - if(thrd->top == thrd->rawno) + if(top_thread(stream,thrd->top) == thrd->rawno) topthrd = thrd; else - topthrd = fetch_thread(stream, thrd->top); + topthrd = fetch_thread(stream, top_thread(stream,thrd->top)); } if(topthrd){ diff -u -r alpine-0.98+dfsg/pith/indxtype.h alpine-0.98+dfsg+fancythread-clean/pith/indxtype.h --- alpine-0.98+dfsg/pith/indxtype.h 2007-03-15 19:43:40.000000000 +0100 +++ alpine-0.98+dfsg+fancythread-clean/pith/indxtype.h 2007-04-29 22:57:19.000000000 +0200 @@ -72,7 +72,7 @@ iSubject, iSubjKey, iSubjKeyInit, iSubjectText, iSubjKeyText, iSubjKeyInitText, iKey, iKeyInit, - iSize, iSizeComma, iSizeNarrow, iDescripSize, + iSize, iSizeComma, iSizeNarrow, iDescripSize, iSizeThread, iNewsAndTo, iToAndNews, iNewsAndRecips, iRecipsAndNews, iFromTo, iFromToNotNews, iFrom, iTo, iSender, iCc, iNews, iRecips, iCurNews, iArrow, diff -u -r alpine-0.98+dfsg/pith/mailindx.c alpine-0.98+dfsg+fancythread-clean/pith/mailindx.c --- alpine-0.98+dfsg/pith/mailindx.c 2007-03-30 02:16:53.000000000 +0200 +++ alpine-0.98+dfsg+fancythread-clean/pith/mailindx.c 2007-04-30 00:11:55.000000000 +0200 @@ -218,6 +218,7 @@ case iSTime: case iKSize: case iSize: + case iSizeThread: (*answer)[column].req_width = 7; break; case iS1Date: @@ -404,6 +405,7 @@ {"FROMORTONOTNEWS", iFromToNotNews, FOR_INDEX}, {"SIZE", iSize, FOR_INDEX}, {"SIZECOMMA", iSizeComma, FOR_INDEX}, + {"SIZETHREAD", iSizeThread, FOR_INDEX}, {"SIZENARROW", iSizeNarrow, FOR_INDEX}, {"KSIZE", iKSize, FOR_INDEX}, {"SUBJECT", iSubject, FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE}, @@ -849,7 +851,7 @@ */ static IndexColType fixed_ctypes[] = { iMessNo, iStatus, iFStatus, iIStatus, iDate, iSDate, iSDateTime, iSDateTime24, - iSTime, iLDate, + iSTime, iLDate, iSizeThread, iS1Date, iS2Date, iS3Date, iS4Date, iDateIso, iDateIsoS, iSDateIso, iSDateIsoS, iSDateS1, iSDateS2, iSDateS3, iSDateS4, @@ -1029,6 +1031,7 @@ case iTime12: case iSize: case iKSize: + case iSizeThread: cdesc->actual_length = 7; cdesc->adjustment = Right; break; @@ -1118,7 +1121,7 @@ cdesc->ctype != iNothing; cdesc++) if(cdesc->ctype == iSize || cdesc->ctype == iKSize || - cdesc->ctype == iSizeNarrow || + cdesc->ctype == iSizeNarrow || cdesc->ctype == iSizeThread || cdesc->ctype == iSizeComma || cdesc->ctype == iDescripSize){ if(cdesc->actual_length == 0){ if((fix=cdesc->width) > 0){ /* had this reserved */ @@ -1487,10 +1490,11 @@ /* find next thread which is visible */ do{ + unsigned long branch; if(mn_get_revsort(msgmap) && thrd->prevthd) thrd = fetch_thread(stream, thrd->prevthd); - else if(!mn_get_revsort(msgmap) && thrd->nextthd) - thrd = fetch_thread(stream, thrd->nextthd); + else if(!mn_get_revsort(msgmap) && thrd->branch) + thrd = fetch_thread(stream, thrd->branch); else thrd = NULL; } while(thrd @@ -1854,11 +1858,9 @@ free_ifield(&ice->ifield); /* is this a collapsed thread index line? */ + thrd = fetch_thread(idata->stream, idata->rawno); if(!idata->bogus && THREADING()){ - thrd = fetch_thread(idata->stream, idata->rawno); - collapsed = thrd && thrd->next - && get_lflag(idata->stream, NULL, - idata->rawno, MN_COLL); + collapsed = thrd && thread_is_kolapsed(ps_global, idata->stream, ps_global->msgmap, idata->rawno); } /* calculate contents of the required fields */ @@ -2313,7 +2315,31 @@ break; + case iSizeThread: + if (!THREADING()){ + goto getsize; + } else if (collapsed){ + l = count_flags_in_thread(idata->stream, thrd, F_NONE); + sprintf(str, "(%lu)", l); + } + else{ + thrd = fetch_thread(idata->stream, idata->rawno); + if(!thrd) + sprintf(str,"Error"); + else{ + long lengthb; + lengthb = get_length_branch(idata->stream, idata->rawno); + + if (lengthb > 0L) + sprintf(str,"(%lu)", lengthb); + else + sprintf(str," "); + } + } + break; + case iSize: +getsize: /* 0 ... 9999 */ if((l = fetch_size(idata)) < 10*1000L) snprintf(str, sizeof(str), "(%lu)", l); diff -u -r alpine-0.98+dfsg/pith/pattern.c alpine-0.98+dfsg+fancythread-clean/pith/pattern.c --- alpine-0.98+dfsg/pith/pattern.c 2007-03-30 02:16:53.000000000 +0200 +++ alpine-0.98+dfsg+fancythread-clean/pith/pattern.c 2007-04-29 23:06:19.000000000 +0200 @@ -1739,7 +1739,7 @@ SortOrder def_sort; int def_sort_rev; - if(decode_sort(p, &def_sort, &def_sort_rev) != -1){ + if(decode_sort(p, &def_sort, &def_sort_rev, 0) != -1){ action->sort_is_set = 1; action->sortorder = def_sort; action->revsort = (def_sort_rev ? 1 : 0); diff -u -r alpine-0.98+dfsg/pith/pine.hlp alpine-0.98+dfsg+fancythread-clean/pith/pine.hlp --- alpine-0.98+dfsg/pith/pine.hlp 2007-03-29 19:50:41.000000000 +0200 +++ alpine-0.98+dfsg+fancythread-clean/pith/pine.hlp 2007-04-29 23:05:41.000000000 +0200 @@ -3266,6 +3266,7 @@
  • OPTION: Signature-File
  • OPTION: SMTP-Server
  • OPTION: Sort-Key +
  • OPTION: Thread-Sort-Key
  • OPTION: Speller
  • OPTION: Ssh-Command
  • OPTION: Ssh-Open-Timeout @@ -5114,6 +5115,164 @@ <End of help on this topic> +======= h_thread_index_sort_arrival ======= + + +SORT OPTION: Arrival + + +

    SORT OPTION: Arrival

    + +The Arrival sort option arranges threads according to the last +time that a message was added to it. In this order the last thread +contains the most recent message in the folder. + +

    +<End of help on this topic> + + +======= h_thread_index_sort_date ======= + + +SORT OPTION: Date + + +

    SORT OPTION: Date

    + +The Date sort option in the THREAD INDEX screen is the same +as sorting by thread, the most likely thing is that you won't see Pine +sorting the folder, because it's already sorted. + +

    +On a folder like INBOX, sorting by "Date" should be almost +identical to sorting by "Arrival". + +

    +<End of help on this topic> + + +======= h_thread_index_sort_subj ======= + + +SORT OPTION: Subject + + +

    SORT OPTION: Subject

    + +The Subject sort option has not been defined yet. + +

    +<End of help on this topic> + + +======= h_thread_index_sort_ordsubj ======= + + +SORT OPTION: OrderedSubject + + +

    SORT OPTION: OrderedSubject

    + +The OrderedSubject sort option in the THREAD INDEX screen is +the same as sorting by Subject. + +

    +<End of help on this topic> + + +======= h_thread_index_sort_thread ======= + + +SORT OPTION: Thread + + +

    SORT OPTION: Thread

    + +The Thread sort option in the THREAD INDEX screen sorts all +messages by the proposed algorithm by Crispin and Murchison. In this +method of sorting once threads have been isolated they are sorted by the +date of their parents, or if that is missing, the first message in that +thread. + +

    +<End of help on this topic> + + +======= h_thread_index_sort_from ======= + + +SORT OPTION: From + + +

    SORT OPTION: From

    + +The From sort option has not been defined yet. + +

    +<End of help on this topic> + + +======= h_thread_index_sort_size ======= + + +SORT OPTION: Size + + +

    SORT OPTION: Size

    + +The Size sort option has not been defined yet. + +

    +<End of help on this topic> + + +======= h_thread_index_sort_score ======= + + +SORT OPTION: Score + + +

    SORT OPTION: Score

    + +The Score sort option means that threads are sorted according to +the maximum score of a message in that thread. A thread all of whose +messages contain a smaller score than a message in some other thread is +placed in an earlier place in the list of messages for that folder; that +is, threads with the highest scores appear at the bottom of the index +list. + +

    +<End of help on this topic> + + +======= h_thread_index_sort_to ======= + + +SORT OPTION: To + + +

    SORT OPTION: To

    + +The To sort option has not been defined yet. + +

    +<End of help on this topic> + + +======= h_thread_index_sort_cc ======= + + +SORT OPTION: Cc + + +

    SORT OPTION: Cc

    + +The Cc sort option has not been defined yet. + +

    +<End of help on this topic> + + ======= h_index_cmd_whereis ======= @@ -17911,6 +18070,14 @@

    +

    SIZETHREAD
    +
    +This token represents the total size of the thread for a collapsed thread +or the size of the branch for an expanded thread. The field is omitted for +messages that are not top of threads nor branches and it defaults to +the SIZE token when your folders is not sorted by thread. +
    +
    SIZENARROW
    This token represents the total size, in bytes, of the message. @@ -21085,6 +21252,45 @@ <End of help on this topic> +====== h_config_thread_sort_key ===== + + +OPTION: Thread-Sort-Key + + +

    OPTION: Thread-Sort-Key

    + +This option determines the order in which threads will be displayed. You +can choose from the options listed below. Each folder is sorted in one of +the sort orders displayed below first, then the thread containing the last +message of that sorted list is put at the end of the index. All messages +of that thread are "removed" from the sorted list and the +process is repeated with the remaining messages in that list. + +

    +

    + +

    Each type of sort may also be reversed. Normal default is by +"Thread". + +

    +

    +<End of help on this topic> + + ====== h_config_other_startup ===== @@ -28221,6 +28427,23 @@ <End of help on this topic> +====== h_config_enhanced_thread ===== + + +FEATURE: enhanced-fancy-thread-support + + +

    FEATURE: enhanced-fancy-thread-support

    + +If this option is set certain commands in Pine will operate in loose +threads too. For example, the command ^D marks a thread deleted, but if +this feature is set, it will remove all threads that share the same missing +parent with this thread. + +

    +<End of help on this topic> + + ====== h_config_news_cross_deletes ===== diff -u -r alpine-0.98+dfsg/pith/sequence.h alpine-0.98+dfsg+fancythread-clean/pith/sequence.h --- alpine-0.98+dfsg/pith/sequence.h 2006-09-22 22:06:05.000000000 +0200 +++ alpine-0.98+dfsg+fancythread-clean/pith/sequence.h 2007-04-30 00:12:41.000000000 +0200 @@ -17,6 +17,7 @@ #define PITH_SEQUENCE_INCLUDED +#include "../pith/state.h" #include "../pith/msgno.h" @@ -29,5 +30,4 @@ void restore_selected(MSGNO_S *); SEARCHSET *limiting_searchset(MAILSTREAM *, int); - #endif /* PITH_SEQUENCE_INCLUDED */ diff -u -r alpine-0.98+dfsg/pith/sort.c alpine-0.98+dfsg+fancythread-clean/pith/sort.c --- alpine-0.98+dfsg/pith/sort.c 2007-03-27 19:44:31.000000000 +0200 +++ alpine-0.98+dfsg+fancythread-clean/pith/sort.c 2007-04-28 16:03:53.000000000 +0200 @@ -86,7 +86,7 @@ ----*/ void sort_folder(MAILSTREAM *stream, MSGNO_S *msgmap, SortOrder new_sort, - int new_rev, unsigned int flags) + int new_rev, unsigned int flags, int first) { long raw_current, i, j; unsigned long *sort = NULL; @@ -96,6 +96,15 @@ int current_rev; MESSAGECACHE *mc; + if (first){ + if (new_sort == SortThread) + find_msgmap(stream, msgmap, flags, + ps_global->thread_cur_sort, new_rev); + else + sort_folder(stream, msgmap, new_sort, new_rev, flags, 0); + return; + } + dprint((2, "Sorting by %s%s\n", sort_name(new_sort), new_rev ? "/reverse" : "")); @@ -450,6 +459,7 @@ thrd = fetch_head_thread(stream); for(j = msgmap->max_thrdno; thrd && j >= 1L; j--){ + unsigned long branch; thrd->thrdno = j; if(thrd->nextthd) @@ -557,20 +567,20 @@ * argument also means arrival/reverse. */ int -decode_sort(char *sort_spec, SortOrder *def_sort, int *def_sort_rev) +decode_sort(char *sort_spec, SortOrder *def_sort, int *def_sort_rev, int thread) { char *sep; char *fix_this = NULL; - int x, reverse; + int x = 0, reverse; if(!sort_spec || !*sort_spec){ - *def_sort = SortArrival; + *def_sort = thread ? SortThread : SortArrival; *def_sort_rev = 0; return(0); } if(struncmp(sort_spec, "reverse", strlen(sort_spec)) == 0){ - *def_sort = SortArrival; + *def_sort = thread ? SortThread : SortArrival; *def_sort_rev = 1; return(0); } @@ -593,13 +603,19 @@ sort_spec, strlen(sort_spec)) == 0) break; + if (thread && ps_global->sort_types[x] != SortArrival + && ps_global->sort_types[x] != SortDate + && ps_global->sort_types[x] != SortThread) + for(x = 0; ps_global->sort_types[x] != EndofList; x++); + if(fix_this) *fix_this = '/'; if(ps_global->sort_types[x] == EndofList) return(-1); - *def_sort = ps_global->sort_types[x]; + *def_sort = (thread && ps_global->sort_types[x] == SortDate) + ? SortThread : ps_global->sort_types[x]; *def_sort_rev = reverse; return(0); } @@ -716,7 +732,9 @@ /* set default order */ the_sort_order = ps_global->def_sort; - sort_is_rev = ps_global->def_sort_rev; + sort_is_rev = the_sort_order == SortThread + ? (ps_global->thread_def_sort_rev + ps_global->def_sort_rev) % 2 + : ps_global->def_sort_rev; if(ps_global->mail_stream && nonempty_patterns(rflags, &pstate)){ for(pat = first_pattern(&pstate); pat; pat = next_pattern(&pstate)){ @@ -728,10 +746,16 @@ if(pat && pat->action && !pat->action->bogus && pat->action->sort_is_set){ the_sort_order = pat->action->sortorder; - sort_is_rev = pat->action->revsort; + sort_is_rev = the_sort_order == SortThread + ? (ps_global->thread_def_sort_rev + pat->action->revsort) % 2 + : pat->action->revsort; } } + if (ps_global->thread_cur_sort != SortArrival + && ps_global->thread_cur_sort != SortThread) + ps_global->thread_cur_sort = ps_global->thread_def_sort; + sort_folder(ps_global->mail_stream, ps_global->msgmap, - the_sort_order, sort_is_rev, flags); + the_sort_order, sort_is_rev, flags, 1); } diff -u -r alpine-0.98+dfsg/pith/sort.h alpine-0.98+dfsg+fancythread-clean/pith/sort.h --- alpine-0.98+dfsg/pith/sort.h 2006-09-22 22:06:05.000000000 +0200 +++ alpine-0.98+dfsg+fancythread-clean/pith/sort.h 2007-04-29 23:01:43.000000000 +0200 @@ -22,7 +22,7 @@ #define refresh_sort(S,M,F) sort_folder((S), (M), mn_get_sort(M), \ - mn_get_revsort(M), (F)) + mn_get_revsort(M), (F), 1) struct global_sort_data { MSGNO_S *msgmap; @@ -41,8 +41,8 @@ /* exported protoypes */ char *sort_name(SortOrder); -void sort_folder(MAILSTREAM *, MSGNO_S *, SortOrder, int, unsigned); -int decode_sort(char *, SortOrder *, int *); +void sort_folder(MAILSTREAM *, MSGNO_S *, SortOrder, int, unsigned, int); +int decode_sort(char *, SortOrder *, int *, int); void reset_sort_order(unsigned); diff -u -r alpine-0.98+dfsg/pith/state.c alpine-0.98+dfsg+fancythread-clean/pith/state.c --- alpine-0.98+dfsg/pith/state.c 2007-03-14 22:27:23.000000000 +0100 +++ alpine-0.98+dfsg+fancythread-clean/pith/state.c 2007-04-29 22:47:23.000000000 +0200 @@ -71,6 +71,7 @@ p = (struct pine *)fs_get(sizeof (struct pine)); memset((void *) p, 0, sizeof(struct pine)); p->def_sort = SortArrival; + p->thread_def_sort = SortDate; p->sort_types[0] = SortSubject; p->sort_types[1] = SortArrival; p->sort_types[2] = SortFrom; diff -u -r alpine-0.98+dfsg/pith/state.h alpine-0.98+dfsg+fancythread-clean/pith/state.h --- alpine-0.98+dfsg/pith/state.h 2007-03-23 17:53:15.000000000 +0100 +++ alpine-0.98+dfsg+fancythread-clean/pith/state.h 2007-04-29 23:03:28.000000000 +0200 @@ -134,6 +134,8 @@ unsigned unseen_in_view:1; unsigned start_in_context:1; /* start fldr_scrn in current cntxt */ unsigned def_sort_rev:1; /* true if reverse sort is default */ + unsigned thread_def_sort_rev:1; /* true if reverse sort is default in thread screen */ + unsigned msgmap_thread_def_sort_rev:1; /* true if reverse sort is being used in thread screen */ unsigned restricted:1; unsigned save_msg_rule:5; @@ -275,6 +277,9 @@ EditWhich ew_for_other_take; SortOrder def_sort, /* Default sort type */ + thread_def_sort, /* Default Sort Type in Thread Screen */ + thread_cur_sort, /* current sort style for threads */ + msgmap_thread_sort, sort_types[22]; int last_expire_year, last_expire_month; diff -u -r alpine-0.98+dfsg/pith/thread.c alpine-0.98+dfsg+fancythread-clean/pith/thread.c --- alpine-0.98+dfsg/pith/thread.c 2006-09-30 01:28:46.000000000 +0200 +++ alpine-0.98+dfsg+fancythread-clean/pith/thread.c 2007-04-30 00:13:19.000000000 +0200 @@ -26,6 +26,7 @@ #include "../pith/status.h" #include "../pith/news.h" +static int erase_thread_info = 1; /* * Keep track of the sort array and some of the thread structure @@ -41,7 +42,8 @@ * Internal prototypes */ struct pass_along *sort_thread_flatten(THREADNODE *, MAILSTREAM *, - struct pass_along *, PINETHRD_S *, unsigned); + struct pass_along *, PINETHRD_S *, unsigned, + int, long, long); void make_thrdflags_consistent(MAILSTREAM *, MSGNO_S *, PINETHRD_S *, int); THREADNODE *collapse_threadnode_tree(THREADNODE *); long calculate_visible_threads(MAILSTREAM *); @@ -97,20 +99,22 @@ set_flags_for_thread(MAILSTREAM *stream, MSGNO_S *msgmap, int f, PINETHRD_S *thrd, int v) { PINETHRD_S *nthrd, *bthrd; + unsigned long next = 0L, branch = 0L; if(!(stream && thrd && msgmap)) return; set_lflag(stream, msgmap, mn_raw2m(msgmap, thrd->rawno), f, v); - if(thrd->next){ + if(next = get_next(stream,thrd)){ + nthrd = fetch_thread(stream, next); nthrd = fetch_thread(stream, thrd->next); if(nthrd) set_flags_for_thread(stream, msgmap, f, nthrd, v); } - if(thrd->branch){ - bthrd = fetch_thread(stream, thrd->branch); + if(branch = get_branch(stream, thrd)){ + bthrd = fetch_thread(stream, branch); if(bthrd) set_flags_for_thread(stream, msgmap, f, bthrd, v); } @@ -124,7 +128,7 @@ MESSAGECACHE *mc; PINELT_S *peltp; - if(!(stream && stream->spare)) + if(!(stream && stream->spare) || !erase_thread_info) return; ps_global->view_skipped_index = 0; @@ -159,7 +163,7 @@ unsigned long msgno, rawno, set_in_thread, in_thread; int bail, this_is_vis; int un_view_thread = 0; - long raw_current; + long raw_current, branch; dprint((2, "sort_thread_callback\n")); @@ -178,9 +182,11 @@ * way. If the dummy node is at the top-level, then its children are * promoted to the top-level as separate threads. */ - collapsed_tree = collapse_threadnode_tree(tree); - (void) sort_thread_flatten(collapsed_tree, stream, thrd_flatten_array, - NULL, THD_TOP); + collapsed_tree = F_ON(F_ENHANCED_THREAD, ps_global) ? + copy_tree(tree) : collapse_threadnode_tree(tree); + (void) sort_thread_flatten(collapsed_tree, + stream, thrd_flatten_array, + NULL, THD_TOP, 0, 1L, 0L); mail_free_threadnode(&collapsed_tree); if(any_lflagged(g_sort.msgmap, MN_HIDE)) @@ -343,12 +349,14 @@ else{ thrd = fetch_head_thread(stream); while(thrd){ + unsigned long raw = thrd->rawno; + unsigned long top = top_thread(stream, raw); /* * The top-level threads aren't hidden by collapse. */ msgno = mn_raw2m(g_sort.msgmap, thrd->rawno); - if(msgno) - set_lflag(stream, g_sort.msgmap, msgno, MN_CHID, 0); + if(msgno && !get_lflag(stream, NULL,thrd->rawno, MN_COLL)) + set_lflag(stream, g_sort.msgmap, msgno, MN_CHID, 0); if(thrd->next){ PINETHRD_S *nthrd; @@ -362,10 +370,11 @@ MN_COLL)); } - if(thrd->nextthd) + while (thrd && top_thread(stream, thrd->rawno) == top + && thrd->nextthd) thrd = fetch_thread(stream, thrd->nextthd); - else - thrd = NULL; + if (!(thrd && thrd->nextthd)) + thrd = NULL; } } } @@ -382,10 +391,17 @@ collapse_threads(MAILSTREAM *stream, MSGNO_S *msgmap, PINETHRD_S *not_this_thread) { PINETHRD_S *thrd = NULL, *nthrd; - unsigned long msgno; + unsigned long msgno, branch; dprint((9, "collapse_threads\n")); +/* if(F_ON(F_ENHANCED_THREAD, ps_global)){*/ + kolapse_thread(ps_global, stream, msgmap, '[', 0); + if (not_this_thread) + expand_thread(ps_global, stream, msgmap, 0); + return; +/* }*/ + thrd = fetch_head_thread(stream); while(thrd){ if(thrd != not_this_thread){ @@ -417,7 +433,7 @@ int a_parent_is_collapsed) { PINETHRD_S *nthrd, *bthrd; - unsigned long msgno; + unsigned long msgno, next, branch; if(!thrd) return; @@ -435,8 +451,8 @@ set_lflag(stream, msgmap, msgno, MN_CHID, 0); } - if(thrd->next){ - nthrd = fetch_thread(stream, thrd->next); + if(next = get_next(stream, thrd)){ + nthrd = fetch_thread(stream, next); if(nthrd) make_thrdflags_consistent(stream, msgmap, nthrd, a_parent_is_collapsed @@ -445,8 +461,8 @@ MN_COLL)); } - if(thrd->branch){ - bthrd = fetch_thread(stream, thrd->branch); + if(branch = get_branch(stream, thrd)){ + bthrd = fetch_thread(stream, branch); if(bthrd) make_thrdflags_consistent(stream, msgmap, bthrd, a_parent_is_collapsed); @@ -458,7 +474,7 @@ calculate_visible_threads(MAILSTREAM *stream) { PINETHRD_S *thrd = NULL; - long vis = 0L; + long vis = 0L, branch; thrd = fetch_head_thread(stream); while(thrd){ @@ -476,42 +492,79 @@ struct pass_along * sort_thread_flatten(struct thread_node *node, MAILSTREAM *stream, - struct pass_along *entry, PINETHRD_S *thrd, unsigned int flags) + struct pass_along *entry, PINETHRD_S *thrd, unsigned int flags, + int adopted, long top, long threadno) { long n = 0L; - PINETHRD_S *newthrd = NULL; + PINETHRD_S *newthrd = NULL, *save_thread = NULL; if(node){ if(node->num){ /* holes happen */ n = (long) (entry - thrd_flatten_array); + if (adopted == 2) + top = node->num; + for(; n > 0; n--) if(thrd_flatten_array[n].rawno == node->num) break; /* duplicate */ - if(!n) - entry->rawno = node->num; - } - - /* - * Build a richer threading structure that will help us paint - * and operate on threads and subthreads. - */ - if(!n && node->num){ - newthrd = msgno_thread_info(stream, node->num, thrd, flags); - if(newthrd){ - entry->thrd = newthrd; - entry++; - - if(node->next) + if(!n){ + entry->rawno = node->num; + newthrd = msgno_thread_info(stream, node->num, thrd, flags); + if(newthrd){ + if (adopted == 2) + threadno = newthrd->thrdno; + if (adopted){ + newthrd->toploose = top; + newthrd->thrdno = threadno; + } + entry->thrd = newthrd; + entry++; + } + adopted = adopted ? 1 : 0; + if (node->next) entry = sort_thread_flatten(node->next, stream, entry, - newthrd, THD_NEXT); - + newthrd, THD_NEXT, adopted, top, + threadno); if(node->branch) entry = sort_thread_flatten(node->branch, stream, entry, - newthrd, - (flags == THD_TOP) ? THD_TOP - : THD_BRANCH); + newthrd, + (flags == THD_TOP) ? THD_TOP: THD_BRANCH, + adopted, top, threadno); + } + } + else{ + adopted = 2; + if(node->next) + entry = sort_thread_flatten(node->next, stream, entry, + thrd, THD_TOP, adopted, top, threadno); + adopted = 0; + if(node->branch){ + if(entry){ + struct pass_along *last_entry = entry; + int i = 0; + + /* + * Next moved up to replace "tree" in the tree. + * If next has no branches, then we want to branch off + * of next. If next has branches, we want to branch off + * of the last of those branches instead. + */ + last_entry--; + while(last_entry->thrd->parent) + last_entry--; + save_thread = last_entry->thrd; + last_entry += i+1; + + last_entry = sort_thread_flatten(node->branch, stream, entry, + save_thread, + (flags == THD_TOP) ? THD_TOP: THD_BRANCH, + adopted, top, threadno); + } + else + entry = sort_thread_flatten(node->branch, stream, entry, + NULL, THD_TOP, adopted, top, threadno); } } } @@ -519,6 +572,25 @@ return(entry); } +/* + * Make a copy of c-client's THREAD tree + */ +THREADNODE * +copy_tree(THREADNODE *tree) +{ + THREADNODE *newtree = NULL; + + if(tree){ + newtree = mail_newthreadnode(NULL); + newtree->num = tree->num; + if(tree->next) + newtree->next = copy_tree(tree->next); + + if(tree->branch) + newtree->branch = copy_tree(tree->branch); + } + return(newtree); +} /* * Make a copy of c-client's THREAD tree while eliminating dummy nodes. @@ -647,7 +719,7 @@ */ void collapse_or_expand(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap, - long unsigned int msgno) + long unsigned int msgno, int display) { int collapsed, adjust_current = 0; PINETHRD_S *thrd = NULL, *nthrd; @@ -700,7 +772,7 @@ if(!thrd) return; - collapsed = get_lflag(stream, NULL, thrd->rawno, MN_COLL) && thrd->next; + collapsed = this_thread_is_kolapsed(ps_global, stream, msgmap, thrd->rawno); if(collapsed){ msgno = mn_raw2m(msgmap, thrd->rawno); @@ -718,13 +790,13 @@ msgno = mn_raw2m(msgmap, thrd->rawno); if(msgno > 0L && msgno <= mn_get_total(msgmap)){ set_lflag(stream, msgmap, msgno, MN_COLL, 1); - if(nthrd = fetch_thread(stream, thrd->next)) + if((thrd->next) && (nthrd = fetch_thread(stream, thrd->next))) set_thread_subtree(stream, nthrd, msgmap, 1, MN_CHID); clear_index_cache_ent(stream, msgno, 0); } } - else + else if (display) q_status_message(SM_ORDER, 0, 1, _("No thread to collapse or expand on this line")); @@ -811,18 +883,19 @@ unsigned long rawno, count = 0; PINETHRD_S *nthrd, *bthrd; MESSAGECACHE *mc; + unsigned long next = 0L, branch = 0L; if(!thrd || !stream || thrd->rawno < 1L || thrd->rawno > stream->nmsgs) return count; - if(thrd->next){ - nthrd = fetch_thread(stream, thrd->next); + if(next = get_next(stream, thrd)){ + nthrd = fetch_thread(stream, next); if(nthrd) count += count_flags_in_thread(stream, nthrd, flags); } - if(thrd->branch){ - bthrd = fetch_thread(stream, thrd->branch); + if(branch = get_branch(stream, thrd)){ + bthrd = fetch_thread(stream, branch); if(bthrd) count += count_flags_in_thread(stream, bthrd, flags); } @@ -849,20 +922,20 @@ unsigned long count_lflags_in_thread(MAILSTREAM *stream, PINETHRD_S *thrd, MSGNO_S *msgmap, int flags) { - unsigned long rawno, count = 0; + unsigned long rawno, count = 0, next, branch; PINETHRD_S *nthrd, *bthrd; if(!thrd || !stream || thrd->rawno < 1L || thrd->rawno > stream->nmsgs) return count; - if(thrd->next){ - nthrd = fetch_thread(stream, thrd->next); + if(next = get_next(stream, thrd)){ + nthrd = fetch_thread(stream, next); if(nthrd) count += count_lflags_in_thread(stream, nthrd, msgmap, flags); } - if(thrd->branch){ - bthrd = fetch_thread(stream, thrd->branch); + if(branch = get_branch(stream, thrd)){ + bthrd = fetch_thread(stream, branch); if(bthrd) count += count_lflags_in_thread(stream, bthrd, msgmap,flags); } @@ -882,7 +955,7 @@ int thread_has_some_visible(MAILSTREAM *stream, PINETHRD_S *thrd) { - unsigned long rawno, count = 0; + unsigned long rawno, count = 0, next, branch; PINETHRD_S *nthrd, *bthrd; if(!thrd || !stream || thrd->rawno < 1L || thrd->rawno > stream->nmsgs) @@ -891,14 +964,14 @@ if(get_lflag(stream, NULL, thrd->rawno, MN_HIDE) == 0) return 1; - if(thrd->next){ - nthrd = fetch_thread(stream, thrd->next); + if(next = get_next(stream, thrd)){ + nthrd = fetch_thread(stream, next); if(nthrd && thread_has_some_visible(stream, nthrd)) return 1; } - if(thrd->branch){ - bthrd = fetch_thread(stream, thrd->branch); + if(branch = get_branch(stream, thrd)){ + bthrd = fetch_thread(stream, branch); if(bthrd && thread_has_some_visible(stream, bthrd)) return 1; } @@ -911,20 +984,21 @@ mark_msgs_in_thread(MAILSTREAM *stream, PINETHRD_S *thrd, MSGNO_S *msgmap) { int count = 0; + long next, branch; PINETHRD_S *nthrd, *bthrd; MESSAGECACHE *mc; if(!thrd || !stream || thrd->rawno < 1L || thrd->rawno > stream->nmsgs) return count; - if(thrd->next){ - nthrd = fetch_thread(stream, thrd->next); + if(next = get_next(stream, thrd)){ + nthrd = fetch_thread(stream, next); if(nthrd) count += mark_msgs_in_thread(stream, nthrd, msgmap); } - if(thrd->branch){ - bthrd = fetch_thread(stream, thrd->branch); + if(branch = get_branch(stream, thrd)){ + bthrd = fetch_thread(stream, branch); if(bthrd) count += mark_msgs_in_thread(stream, bthrd, msgmap); } @@ -958,7 +1032,7 @@ /* flags to set or clear */ /* set or clear? */ { - unsigned long rawno, msgno; + unsigned long rawno, msgno, next, branch; PINETHRD_S *nthrd, *bthrd; if(!thrd || !stream || thrd->rawno < 1L || thrd->rawno > stream->nmsgs) @@ -982,14 +1056,14 @@ if(msgno > 0L && flags == MN_CHID2 && v == 1) clear_index_cache_ent(stream, msgno, 0); - if(thrd->next){ - nthrd = fetch_thread(stream, thrd->next); + if(next = get_next(stream, thrd)){ + nthrd = fetch_thread(stream, next); if(nthrd) set_thread_lflags(stream, nthrd, msgmap, flags, v); } - if(thrd->branch){ - bthrd = fetch_thread(stream, thrd->branch); + if(branch = get_branch(stream,thrd)){ + bthrd = fetch_thread(stream, branch); if(bthrd) set_thread_lflags(stream, bthrd, msgmap, flags, v); } @@ -1070,19 +1144,20 @@ { char to_us = ' '; PINETHRD_S *nthrd, *bthrd; + unsigned long next = 0L, branch = 0L; MESSAGECACHE *mc; if(!thrd || !stream || thrd->rawno < 1L || thrd->rawno > stream->nmsgs) return to_us; - if(thrd->next){ - nthrd = fetch_thread(stream, thrd->next); + if(next = get_next(stream,thrd)){ + nthrd = fetch_thread(stream, next); if(nthrd) to_us = to_us_symbol_for_thread(stream, nthrd, consider_flagged); } - if(to_us == ' ' && thrd->branch){ - bthrd = fetch_thread(stream, thrd->branch); + if(to_us == ' ' && (branch = get_branch(stream, thrd))){ + bthrd = fetch_thread(stream, branch); if(bthrd) to_us = to_us_symbol_for_thread(stream, bthrd, consider_flagged); } @@ -1117,7 +1192,7 @@ break; } - if(to_us != '+' && resent_to_us(&idata)) + if(to_us != '+' && !idata.bogus && resent_to_us(&idata)) to_us = '+'; if(to_us == ' ' && F_ON(F_MARK_FOR_CC,ps_global)) @@ -1153,7 +1228,7 @@ /* flags to set or clear */ { int hiding; - unsigned long rawno, msgno; + unsigned long rawno, msgno, next, branch; PINETHRD_S *nthrd, *bthrd; hiding = (flags == MN_CHID) && v; @@ -1165,7 +1240,8 @@ set_lflag(stream, msgmap, msgno, flags, v); - if(thrd->next && (hiding || !get_lflag(stream,NULL,thrd->rawno,MN_COLL))){ + if(thrd->next + && (hiding || !get_lflag(stream,NULL,thrd->rawno,MN_COLL))){ nthrd = fetch_thread(stream, thrd->next); if(nthrd) set_thread_subtree(stream, nthrd, msgmap, v, flags); @@ -1205,8 +1281,8 @@ if(rawno) thrd = fetch_thread(stream, rawno); - if(thrd && thrd->top && thrd->top != thrd->rawno) - thrd = fetch_thread(stream, thrd->top); + if(thrd && thrd->top && top_thread(stream,thrd->top) != thrd->rawno) + thrd = fetch_thread(stream, top_thread(stream,thrd->top)); if(!thrd) return 0; @@ -1270,7 +1346,7 @@ thrd = fetch_thread(stream, rawno); if(thrd && thrd->top) - topthrd = fetch_thread(stream, thrd->top); + topthrd = fetch_thread(stream, top_thread(stream,thrd->top)); if(!topthrd) return 0; @@ -1376,6 +1452,7 @@ set_search_bit_for_thread(MAILSTREAM *stream, PINETHRD_S *thrd, struct search_set **msgset) { PINETHRD_S *nthrd, *bthrd; + unsigned long next, branch; if(!(stream && thrd)) return; @@ -1384,15 +1461,823 @@ && (!(msgset && *msgset) || in_searchset(*msgset, thrd->rawno))) mm_searched(stream, thrd->rawno); - if(thrd->next){ - nthrd = fetch_thread(stream, thrd->next); + if(next= get_next(stream, thrd)){ + nthrd = fetch_thread(stream, next); if(nthrd) set_search_bit_for_thread(stream, nthrd, msgset); } - if(thrd->branch){ - bthrd = fetch_thread(stream, thrd->branch); + if(branch = get_branch(stream, thrd)){ + bthrd = fetch_thread(stream, branch); if(bthrd) set_search_bit_for_thread(stream, bthrd, msgset); } } + +unsigned long +get_branch(stream,thrd) + MAILSTREAM *stream; + PINETHRD_S *thrd; +{ + PINETHRD_S *nthrd = NULL; + unsigned long top; + + if (thrd->toploose && thrd->nextthd) + nthrd = fetch_thread(stream, thrd->nextthd); + if (!nthrd) + return thrd->branch; + top = top_thread(stream, thrd->rawno); + return thrd->branch + ? thrd->branch + : (F_ON(F_ENHANCED_THREAD, ps_global) + ? (top == top_thread(stream, nthrd->rawno) ? thrd->nextthd : 0L) + : 0L); +} + +unsigned long +get_next(stream,thrd) + MAILSTREAM *stream; + PINETHRD_S *thrd; +{ + return thrd->next; +} + +long +get_length_branch(stream, rawno) +MAILSTREAM *stream; +long rawno; +{ + int branchp = 0, done = 0; + long top, count = 1L, raw; + PINETHRD_S *thrd, *pthrd = NULL, *nthrd; + + thrd = fetch_thread(stream, rawno); + + if (!thrd) + return -1L; + + top = thrd->top; + + if (thrd->parent) + pthrd = fetch_thread(stream, thrd->parent); + + if (thrd->rawno == top) + branchp++; + + if (!branchp && !pthrd){ /* what!!?? */ + raw = top; + while (!done){ + pthrd = fetch_thread(stream, raw); + if ((pthrd->next == rawno) || (pthrd->branch == rawno)) + done++; + else{ + if (pthrd->next) + raw = pthrd->next; + else if (pthrd->branch) + raw = pthrd->branch; + } + } + } + + if (pthrd && pthrd->next == thrd->rawno && thrd->branch) + branchp++; + + if (pthrd && pthrd->next && pthrd->next != thrd->rawno){ + nthrd = fetch_thread(stream, pthrd->next); + while (nthrd && nthrd->branch && nthrd->branch != thrd->rawno) + nthrd = fetch_thread(stream, nthrd->branch); + if(nthrd && nthrd->branch && nthrd->branch == thrd->rawno) + branchp++; + } + + if(branchp){ + int entry = 0; + while(thrd && thrd->next){ + entry = 1; + count++; + thrd = fetch_thread(stream, thrd->next); + if (thrd->branch) + break; + } + if (entry && thrd->branch) + count--; + } + return branchp ? (count ? count : 1L) : 0L; +} + +void +find_msgmap(MAILSTREAM *stream, MSGNO_S *msgmap, int flags, SortOrder ordersort, unsigned is_rev) +{ + int we_cancel; + long *old_arrival,*new_arrival; + long init_thread, end_thread, current; + long k = 1L, j, last_thread = 0L; + long i, tmsg, ntmsg, nthreads; + int nflags = (SRT_VRB | SRT_MAN); + char sort_msg[MAX_SCREEN_COLS+1] = {'\0'}; + PINETHRD_S *thrd, *tthrd, *nthrd; + + erase_thread_info = 0; + current = mn_m2raw(msgmap, mn_get_cur(msgmap)); + + sort_folder(stream, msgmap, ordersort, 0, nflags, 0); + + tmsg = mn_get_total(msgmap) + 1; + + if (tmsg <= 1) + return; + + old_arrival = (long *) fs_get(tmsg * sizeof(long)); + memset(old_arrival, 0, tmsg*sizeof(long)); + for (i= 1L;(i <= mn_get_total(msgmap)) && (old_arrival[i] = msgmap->sort[i]); i++); + + /* now sort by thread */ + sort_folder(stream, msgmap, SortThread, 0, nflags, 0); + ntmsg = mn_get_total(msgmap) + 1; + + if (tmsg != ntmsg){ /* oh oh, something happened,we better try again */ + fs_give((void **)&old_arrival); + find_msgmap(stream, msgmap, flags, ordersort, is_rev); + return; + } + + /* reconstruct the msgmap */ + + new_arrival = (long *) fs_get(tmsg * sizeof(long)); + memset(new_arrival, 0, tmsg*sizeof(long)); + i = mn_get_total(msgmap); + while (new_arrival[1] == 0){ /* think of this as (tmsg > 0) */ + int done = 0; + long n = mn_get_total(msgmap); + + init_thread = top_thread(stream, old_arrival[i]); + thrd = fetch_thread(stream, init_thread); + while ((new_arrival[n] != 0) && !done){ /* compare raw numbers */ + done = (new_arrival[n] == init_thread); + n--; + } + if (!done){ + k = 1L; + mn_set_cur(msgmap, mn_raw2m(msgmap, init_thread)); + if (move_next_thread(ps_global, stream, msgmap, 0) <= 0) + j = mn_get_total(msgmap) - mn_raw2m(msgmap, init_thread) + 1; + else + j = mn_get_cur(msgmap) - mn_raw2m(msgmap, init_thread); + end_thread = mn_raw2m(msgmap, init_thread) + j; + while (k <= j){ + new_arrival[tmsg - k] = msgmap->sort[end_thread - k]; + k++; + } + tmsg -= j; + } + i--; + } + relink_threads(stream, msgmap, new_arrival); + for (i = 1; (i <= mn_get_total(msgmap)) + && (msgmap->sort[i] = new_arrival[i]); i++); + msgno_reset_isort(msgmap); + + fs_give((void **)&new_arrival); + fs_give((void **)&old_arrival); + + + if(is_rev && (mn_get_total(msgmap) > 1L)){ + long *rev_sort; + long i = 1L, l = mn_get_total(msgmap); + + rev_sort = (long *) fs_get((mn_get_total(msgmap)+1L) * sizeof(long)); + memset(rev_sort, 0, (mn_get_total(msgmap)+1L)*sizeof(long)); + while (l > 0L){ + if (top_thread(stream, msgmap->sort[l]) == msgmap->sort[l]){ + long init_thread = msgmap->sort[l]; + long j, k; + + mn_set_cur(msgmap, mn_raw2m(msgmap, init_thread)); + if (move_next_thread(ps_global, stream, msgmap, 0) <= 0) + j = mn_get_total(msgmap) - mn_raw2m(msgmap, init_thread) + 1; + else + j = mn_get_cur(msgmap) - mn_raw2m(msgmap, init_thread); + for (k = 0L; (k < j) && (rev_sort[i+k] = msgmap->sort[l+k]); k++); + i += j; + } + l--; + } + relink_threads(stream, msgmap, rev_sort); + for (i = 1L; i <= mn_get_total(msgmap); i++) + msgmap->sort[i] = rev_sort[i]; + msgno_reset_isort(msgmap); + fs_give((void **)&rev_sort); + } + mn_reset_cur(msgmap, first_sorted_flagged(is_rev ? F_NONE : F_SRCHBACK, + stream, mn_raw2m(msgmap, current), FSF_SKIP_CHID)); + msgmap->top = -1L; + + sp_set_unsorted_newmail(ps_global->mail_stream, 0); + + for(i = 1L; i <= ps_global->mail_stream->nmsgs; i++) + mail_elt(ps_global->mail_stream, i)->spare7 = 0; + + mn_set_sort(msgmap, SortThread); + mn_set_revsort(msgmap, is_rev); + erase_thread_info = 1; + clear_index_cache(stream, 0); +} + +void +move_thread(state, stream, msgmap, direction) + struct pine *state; + MAILSTREAM *stream; + MSGNO_S *msgmap; + int direction; +{ + long new_cursor, old_cursor = mn_get_cur(msgmap); + int rv; + PINETHRD_S *thrd; + + rv = direction > 0 ? move_next_thread(state, stream, msgmap, 1): + move_prev_thread(state, stream, msgmap, 1); + if (rv > 0 && THRD_INDX_ENABLED()){ + new_cursor = mn_get_cur(msgmap); + mn_set_cur(msgmap, old_cursor); + unview_thread(state, stream, msgmap); + thrd = fetch_thread(stream,mn_m2raw(msgmap, new_cursor)); + mn_set_cur(msgmap, new_cursor); + view_thread(state, stream, msgmap, 1); + state->next_screen = SCREEN_FUN_NULL; + } +} + +void +relink_threads(stream, msgmap, new_arrival) + MAILSTREAM *stream; + MSGNO_S *msgmap; + long *new_arrival; +{ + long last_thread = 0L; + long i = 0L, j = 1L, k; + PINETHRD_S *thrd, *nthrd; + + while (j <= mn_get_total(msgmap)){ + i++; + thrd = fetch_thread(stream, new_arrival[j]); + if (!thrd) /* sort failed!, better leave from here now!!! */ + break; + thrd->prevthd = last_thread; + thrd->thrdno = i; + thrd->head = new_arrival[1]; + last_thread = thrd->rawno; + mn_set_cur(msgmap, mn_raw2m(msgmap,thrd->top)); + k = mn_get_cur(msgmap); + if (move_next_thread(ps_global, stream, msgmap, 0) <= 0) + j += mn_get_total(msgmap) + 1 - k; + else + j += mn_get_cur(msgmap) - k; + if (!thrd->toploose) + thrd->nextthd = (j <= mn_get_total(msgmap)) ? new_arrival[j] : 0L; + else{ + int done = 0; + while(thrd->nextthd && !done){ + thrd->thrdno = i; + thrd->head = new_arrival[1]; + if (thrd->nextthd) + nthrd = fetch_thread(stream, thrd->nextthd); + else + done++; + if(top_thread(stream, thrd->rawno) == top_thread(stream, nthrd->rawno)) + thrd = nthrd; + else + done++; + } + thrd->nextthd = (j <= mn_get_total(msgmap)) ? new_arrival[j] : 0L; + last_thread = thrd->rawno; + } + } +} + +void +kolapse_thread(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap, char ch, int display) +{ + PINETHRD_S *thrd = NULL; + unsigned long rawno; + int rv = 1, done = 0; + + if(!stream) + return; + + rawno = mn_m2raw(msgmap, mn_get_cur(msgmap)); + if(rawno) + thrd = fetch_thread(stream, rawno); + + if(!thrd) + return; + + clear_index_cache(stream, 0); + mn_set_cur(msgmap,1); /* go to the first message */ + while (!done){ + if (ch == '[') + collapse_thread(state, stream, msgmap, display); + else + expand_thread(state, stream, msgmap, display); + if ((rv = move_next_thread(state, stream, msgmap, 0)) <= 0) + done++; + } + + if (rv < 0){ + if (display) + q_status_message(SM_ORDER, 0, 1, (ch == '[') + ? "Error while collapsing thread" + : "Error while expanding thread"); + } + else + if(display) + q_status_message(SM_ORDER, 0, 1, (ch == '[') + ? "All threads collapsed. Use \"}\" to expand them" + : "All threads expanded. Use \"{\" to collapse them"); + + mn_set_cur(msgmap,mn_raw2m(msgmap, top_thread(stream,rawno))); +} + +int +move_next_this_thread(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap, int display) +{ + PINETHRD_S *thrd = NULL, *thrdnxt; + unsigned long rawno, top; + int rv = 1; + + if(!stream) + return -1; + + rawno = mn_m2raw(msgmap, mn_get_cur(msgmap)); + if(rawno) + thrd = fetch_thread(stream, rawno); + + if(!thrd) + return -1; + + top = top_thread(stream, rawno); + + thrdnxt = (top == rawno) ? fetch_thread(stream, top) : thrd; + if (thrdnxt->nextthd) + mn_set_cur(msgmap,mn_raw2m(msgmap, thrdnxt->nextthd)); + else{ + rv = 0; + if (display) + q_status_message(SM_ORDER, 0, 1, "No more Threads to advance"); + } + return rv; +} + +int +move_next_thread(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap, int display) +{ + int collapsed, rv = 1, done = 0; + PINETHRD_S *thrd = NULL; + unsigned long orig, orig_top, top; + + if(!stream) + return 0; + + orig = mn_m2raw(msgmap, mn_get_cur(msgmap)); + move_top_thread(stream, msgmap,orig); + top = orig_top = mn_m2raw(msgmap, mn_get_cur(msgmap)); + + if(top) + thrd = fetch_thread(stream, top); + + if(!thrd) + return 0; + + while (rv > 0 && !done){ + rv = move_next_this_thread(state, stream, msgmap, display); + if (F_OFF(F_ENHANCED_THREAD, state) + || !(top = mn_m2raw(msgmap, mn_get_cur(msgmap))) + || (orig_top != top_thread(stream, top))) + done++; + } + if (display){ + if (rv > 0 && SEP_THRDINDX()) + q_status_message(SM_ORDER, 0, 2, "Viewing next thread"); + if (!rv) + q_status_message(SM_ORDER, 0, 2, "No more threads to advance"); + } + if(rv <= 0){ + rv = 0; + mn_set_cur(msgmap, mn_raw2m(msgmap, orig)); + } + + return rv; +} + +int +move_prev_thread(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap, int display) +{ + PINETHRD_S *thrd = NULL; + unsigned long rawno, top; + int rv = 1; + + if(!stream) + return -1; + + rawno = mn_m2raw(msgmap, mn_get_cur(msgmap)); + if(rawno) + thrd = fetch_thread(stream, rawno); + + if(!thrd) + return -1; + + top = top_thread(stream, rawno); + + if (top != rawno) + mn_set_cur(msgmap,mn_raw2m(msgmap, top)); + else if (thrd->prevthd) + mn_set_cur(msgmap,mn_raw2m(msgmap, top_thread(stream,thrd->prevthd))); + else + rv = 0; + if (display){ + if (rv && SEP_THRDINDX()) + q_status_message(SM_ORDER, 0, 2, "Viewing previous thread"); + if (!rv) + q_status_message(SM_ORDER, 0, 2, "No more threads to go back"); + } + + return rv; +} + +/* + * This function assumes that it is called at a top of a thread in its + * first call + */ + +int +count_this_thread(stream, rawno) + MAILSTREAM *stream; + unsigned long rawno; +{ + unsigned long top, orig_top, topnxt; + PINETHRD_S *thrd = NULL; + int count = 1; + + if(!stream) + return 0; + + if(rawno) + thrd = fetch_thread(stream, rawno); + + if(!thrd) + return 0; + + if (thrd->next) + count += count_this_thread(stream, thrd->next); + + if (thrd->branch) + count += count_this_thread(stream, thrd->branch); + + return count; +} + +int +count_thread(state, stream, msgmap, rawno) + struct pine *state; + MAILSTREAM *stream; + MSGNO_S *msgmap; + long rawno; +{ + unsigned long top, orig, orig_top; + PINETHRD_S *thrd = NULL; + int done = 0, count = 0; + + if(!stream) + return 0; + + orig = mn_m2raw(msgmap, mn_get_cur(msgmap)); + move_top_thread(stream, msgmap,rawno); + top = orig_top = top_thread(stream, rawno); + if(top) + thrd = fetch_thread(stream, top); + + if(!thrd) + return 0; + + while (!done){ + count += count_this_thread(stream, top); + if (F_OFF(F_ENHANCED_THREAD, state) + || (move_next_this_thread(state, stream, msgmap, 0) <= 0) + || !(top = mn_m2raw(msgmap, mn_get_cur(msgmap))) + || (orig_top != top_thread(stream, top))) + done++; + } + mn_set_cur(msgmap,mn_raw2m(msgmap, orig)); + return count; +} + +void +expand_thread(state, stream, msgmap, display) + struct pine *state; + MAILSTREAM *stream; + MSGNO_S *msgmap; + int display; +{ + int collapsed, rv = 1, done = 0; + PINETHRD_S *thrd = NULL; + unsigned long orig, orig_top, top; + + if(!stream) + return; + + orig = mn_m2raw(msgmap, mn_get_cur(msgmap)); + top = orig_top = mn_m2raw(msgmap, mn_get_cur(msgmap)); + + if(top) + thrd = fetch_thread(stream, top); + + if(!thrd) + return; + + while (!done){ + expand_this_thread(state, stream, msgmap, display, 1); + if (F_OFF(F_ENHANCED_THREAD, state) + || (move_next_this_thread(state, stream, msgmap, 0) <= 0) + || !(top = mn_m2raw(msgmap, mn_get_cur(msgmap))) + || (orig_top != top_thread(stream, top))) + done++; + } + mn_set_cur(msgmap,mn_raw2m(msgmap, orig_top)); +} + +/* this function tells us if the thread (or branch in the case of loose threads) + * is collapsed + */ + +int +this_thread_is_kolapsed(state, stream, msgmap, rawmsgno) + struct pine *state; + MAILSTREAM *stream; + MSGNO_S *msgmap; + long rawmsgno; +{ + int collapsed; + PINETHRD_S *thrd = NULL; + unsigned long rawno, orig; + + if(!stream) + return -1; + + rawno = rawmsgno; + if(rawno) + thrd = fetch_thread(stream, rawno); + + if(!thrd) + return -1; + + collapsed = get_lflag(stream, NULL, rawno, MN_COLL | MN_CHID); + + if (!thrd->next){ + if (thrd->rawno != top_thread(stream, thrd->rawno)) + collapsed = get_lflag(stream, NULL, rawno, MN_CHID); + else + collapsed = get_lflag(stream, NULL, rawno, MN_COLL); + } + + return collapsed; +} + + +long +top_thread(MAILSTREAM *stream, long rawmsgno) +{ + PINETHRD_S *thrd = NULL; + unsigned long rawno; + + if(!stream) + return -1L; + + if(rawmsgno) + thrd = fetch_thread(stream, rawmsgno); + + if(!thrd) + return -1L; + + return F_ON(F_ENHANCED_THREAD, ps_global) + ? (thrd->toploose ? thrd->toploose : thrd->top) + : thrd->top; +} + +void +collapse_thread(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap, int display) +{ + int collapsed, rv = 1, done = 0; + PINETHRD_S *thrd = NULL; + unsigned long orig, orig_top, top; + + if(!stream) + return; + + expand_this_thread(state, stream, msgmap, display, 1); + orig = mn_m2raw(msgmap, mn_get_cur(msgmap)); + move_top_thread(stream, msgmap,orig); + top = orig_top = mn_m2raw(msgmap, mn_get_cur(msgmap)); + + if(top) + thrd = fetch_thread(stream, top); + + if(!thrd) + return; + + while (!done){ + collapse_this_thread(state, stream, msgmap, display, 1); + if (F_OFF(F_ENHANCED_THREAD, state) + || (move_next_this_thread(state, stream, msgmap, 0) <= 0) + || !(top = mn_m2raw(msgmap, mn_get_cur(msgmap))) + || (orig_top != top_thread(stream, top))) + done++; + } + mn_set_cur(msgmap,mn_raw2m(msgmap, orig_top)); +} + +int +expand_this_thread(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap, int display, int special) +{ + int collapsed, rv = 1, done = 0; + PINETHRD_S *thrd = NULL, *nthrd; + unsigned long rawno, orig, msgno; + + if(!stream) + return 0; + + orig = mn_m2raw(msgmap, mn_get_cur(msgmap)); + move_top_this_thread(stream, msgmap,orig); + rawno = mn_m2raw(msgmap, mn_get_cur(msgmap)); + + if(rawno) + thrd = fetch_thread(stream, rawno); + + if(!thrd) + return rv; + + collapsed = this_thread_is_kolapsed(state, stream, msgmap, rawno); + + if (special && !collapsed){ + collapse_this_thread(state, stream, msgmap, 0, 0); + collapsed = 1; + } + + clear_index_cache_ent(stream, mn_raw2m(msgmap,rawno), 0); + + if (collapsed && thrd->next){ + if (thrd->rawno == top_thread(stream, thrd->rawno)) + collapse_or_expand(state, stream, msgmap, mn_get_cur(msgmap), display); + else{ + set_lflag(stream, msgmap, mn_raw2m(msgmap,thrd->rawno), MN_COLL, 0); + set_thread_subtree(stream, thrd, msgmap, 0, MN_CHID); + } + } + else{ + if (collapsed && special + && ((F_OFF(F_ENHANCED_THREAD, state) && !thrd->next) + || F_ON(F_ENHANCED_THREAD, state))){ + if (thrd->toploose) + if (thrd->rawno != thrd->toploose) + set_lflag(stream, msgmap, mn_raw2m(msgmap,thrd->rawno),MN_CHID, 0); + else + set_lflag(stream, msgmap, mn_raw2m(msgmap,thrd->rawno),MN_COLL, 0); + } + else{ + rv = 0; + if (display) + q_status_message(SM_ORDER, 0, 1, "Thread already expanded"); + } + } + return rv; +} + +void +move_top_thread(MAILSTREAM *stream, MSGNO_S *msgmap, long rawmsgno) +{ + mn_set_cur(msgmap,mn_raw2m(msgmap, top_thread(stream, rawmsgno))); +} + +int +thread_is_kolapsed(state, stream, msgmap, rawmsgno) + struct pine *state; + MAILSTREAM *stream; + MSGNO_S *msgmap; + long rawmsgno; +{ + int collapsed; + PINETHRD_S *thrd = NULL; + unsigned long rawno, orig, orig_rawno; + + if(!stream) + return -1; + + orig = mn_get_cur(msgmap); + move_top_thread(stream, msgmap, rawmsgno); + rawno = orig_rawno = mn_m2raw(msgmap, mn_get_cur(msgmap)); + if(rawno) + thrd = fetch_thread(stream, rawno); + + if(!thrd) + return -1; + + while(collapsed = this_thread_is_kolapsed(state, stream, msgmap, rawno)) + if (F_OFF(F_ENHANCED_THREAD, state) + || (move_next_this_thread(state, stream, msgmap, 0) <= 0) + || !(rawno = mn_m2raw(msgmap, mn_get_cur(msgmap))) + || (orig_rawno != top_thread(stream, rawno))) + break; + + mn_set_cur(msgmap,orig); /* return home */ + + return collapsed; +} + +int +collapse_this_thread(state, stream, msgmap, display, special) + struct pine *state; + MAILSTREAM *stream; + MSGNO_S *msgmap; + int display; + int special; +{ + int collapsed, rv = 1, done = 0; + PINETHRD_S *thrd = NULL, *nthrd; + unsigned long rawno, orig, msgno; + + if(!stream) + return 0; + + rawno = mn_m2raw(msgmap, mn_get_cur(msgmap)); + + if(rawno) + thrd = fetch_thread(stream, rawno); + + if(!thrd) + return rv; + + collapsed = this_thread_is_kolapsed(state, stream, msgmap, rawno); + + if (special && collapsed){ + expand_this_thread(state, stream, msgmap, 0, 0); + collapsed = 0; + } + + clear_index_cache_ent(stream, mn_raw2m(msgmap,rawno), 0); + + if (!collapsed && thrd->next){ + if (thrd->rawno == top_thread(stream, thrd->rawno)) + collapse_or_expand(state, stream, msgmap, mn_get_cur(msgmap), display); + else{ + set_lflag(stream, msgmap, mn_raw2m(msgmap,thrd->rawno), MN_COLL, 1); + set_thread_subtree(stream, thrd, msgmap, 1, MN_CHID); + } + } + else{ + if (!collapsed && special + && ((F_OFF(F_ENHANCED_THREAD, state) && !thrd->next) + || F_ON(F_ENHANCED_THREAD, state))){ + if (thrd->toploose){ + if (thrd->rawno != thrd->toploose) + set_lflag(stream, msgmap, mn_raw2m(msgmap,thrd->rawno),MN_CHID, + 1); + else + set_lflag(stream, msgmap, mn_raw2m(msgmap,thrd->rawno),MN_COLL, + 1); + } + } + else{ + rv = 0; + if (display) + q_status_message(SM_ORDER, 0, 1, "Thread already collapsed"); + } + } + return rv; +} + +long +top_this_thread(stream, rawmsgno) + MAILSTREAM *stream; + long rawmsgno; +{ + PINETHRD_S *thrd = NULL; + unsigned long rawno; + + if(!stream) + return -1L; + + if(rawmsgno) + thrd = fetch_thread(stream, rawmsgno); + + if(!thrd) + return -1L; + + return thrd->top; +} +void +move_top_this_thread(stream, msgmap, rawmsgno) + MAILSTREAM *stream; + MSGNO_S *msgmap; + long rawmsgno; +{ + mn_set_cur(msgmap,mn_raw2m(msgmap, top_this_thread(stream, rawmsgno))); +} + diff -u -r alpine-0.98+dfsg/pith/thread.h alpine-0.98+dfsg+fancythread-clean/pith/thread.h --- alpine-0.98+dfsg/pith/thread.h 2006-09-22 22:06:05.000000000 +0200 +++ alpine-0.98+dfsg+fancythread-clean/pith/thread.h 2007-04-30 00:13:33.000000000 +0200 @@ -30,13 +30,13 @@ typedef struct pine_thrd { unsigned long rawno; /* raw msgno of this message */ unsigned long thrdno; /* thread number */ - unsigned long flags; unsigned long next; /* msgno of first reply to us */ unsigned long branch; /* like THREADNODE branch, next replier */ unsigned long parent; /* message that this is a reply to */ unsigned long nextthd; /* next thread, only tops have this */ unsigned long prevthd; /* previous thread, only tops have this */ unsigned long top; /* top of this thread */ + unsigned long toploose; /* top of this thread, if is loose */ unsigned long head; /* head of the whole thread list */ } PINETHRD_S; @@ -92,7 +92,7 @@ void sort_thread_callback(MAILSTREAM *, THREADNODE *); void collapse_threads(MAILSTREAM *, MSGNO_S *, PINETHRD_S *); PINETHRD_S *msgno_thread_info(MAILSTREAM *, unsigned long, PINETHRD_S *, unsigned); -void collapse_or_expand(struct pine *, MAILSTREAM *, MSGNO_S *, unsigned long); +void collapse_or_expand(struct pine *, MAILSTREAM *, MSGNO_S *, unsigned long, int); void select_thread_stmp(struct pine *, MAILSTREAM *, MSGNO_S *); unsigned long count_flags_in_thread(MAILSTREAM *, PINETHRD_S *, long); unsigned long count_lflags_in_thread(MAILSTREAM *, PINETHRD_S *, MSGNO_S *, int); @@ -107,5 +107,31 @@ PINETHRD_S *find_thread_by_number(MAILSTREAM *, MSGNO_S *, long, PINETHRD_S *); void set_search_bit_for_thread(MAILSTREAM *, PINETHRD_S *, SEARCHSET **); +unsigned long get_next (MAILSTREAM *,PINETHRD_S *); +unsigned long get_branch (MAILSTREAM *,PINETHRD_S *); +long get_length_branch (MAILSTREAM *, long); +THREADNODE *copy_tree (THREADNODE *); +void find_msgmap (MAILSTREAM *, MSGNO_S *, int, SortOrder, + unsigned); +void move_thread (struct pine *, MAILSTREAM *, MSGNO_S *, int); +void relink_threads (MAILSTREAM *, MSGNO_S *, long *); + +long top_thread (MAILSTREAM *, long); +void move_top_thread (MAILSTREAM *, MSGNO_S *, long); +long top_this_thread (MAILSTREAM *, long); +void move_top_this_thread (MAILSTREAM *, MSGNO_S *, long); +void kolapse_thread (struct pine *, MAILSTREAM *, MSGNO_S *, char, int); +int count_thread (struct pine *, MAILSTREAM *, MSGNO_S *, long); +int count_this_thread (MAILSTREAM *, unsigned long); +int this_thread_is_kolapsed (struct pine *, MAILSTREAM *, MSGNO_S *, long); +int thread_is_kolapsed (struct pine *, MAILSTREAM *, MSGNO_S *, long); +int collapse_this_thread (struct pine *, MAILSTREAM *, MSGNO_S *, int, int); +void collapse_thread (struct pine *, MAILSTREAM *, MSGNO_S *, int); +int expand_this_thread (struct pine *, MAILSTREAM *, MSGNO_S *, int, int); +void expand_thread (struct pine *, MAILSTREAM *, MSGNO_S *, int); +int move_next_this_thread (struct pine *, MAILSTREAM *, MSGNO_S *, int); +int move_next_thread (struct pine *, MAILSTREAM *, MSGNO_S *, int); +int move_prev_thread (struct pine *, MAILSTREAM *, MSGNO_S *, int); + #endif /* PITH_THREAD_INCLUDED */