Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Factory:Rebuild
alpine
chappa-fancy.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File chappa-fancy.patch of Package alpine
diff -rc alpine-2.26/alpine/arg.c alpine-2.26.fancy/alpine/arg.c *** alpine-2.26/alpine/arg.c 2022-06-02 18:14:00.463274817 -0600 --- alpine-2.26.fancy/alpine/arg.c 2022-06-02 18:14:51.007150883 -0600 *************** *** 66,71 **** --- 66,72 ---- #endif /* SMIME inside PASSFILE */ #endif 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\""); *************** *** 115,120 **** --- 116,122 ---- N_(" -z \t\tSuspend - allow use of ^Z suspension"), N_(" -r \t\tRestricted - can only send mail to oneself"), N_(" -sort <sort>\tSort - Specify sort order of folder:"), + N_(" -threadsort <sort>\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"), *************** *** 281,286 **** --- 283,289 ---- char *cmd_list = NULL; char *debug_str = NULL; char *sort = NULL; + char *threadsort = NULL; char *pinerc_file = NULL; char *lc = NULL; XOAUTH2_INFO_S x; *************** *** 504,509 **** --- 507,523 ---- 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 -rc alpine-2.26/alpine/confscroll.c alpine-2.26.fancy/alpine/confscroll.c *** alpine-2.26/alpine/confscroll.c 2022-06-02 18:14:00.463274817 -0600 --- alpine-2.26.fancy/alpine/confscroll.c 2022-06-02 18:14:51.007150883 -0600 *************** *** 136,142 **** 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 *); int longest_feature_name(void); COLOR_PAIR *sample_color(struct pine *, struct variable *); COLOR_PAIR *sampleexc_color(struct pine *, struct variable *); --- 136,142 ---- 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 *, int); int longest_feature_name(void); COLOR_PAIR *sample_color(struct pine *, struct variable *); COLOR_PAIR *sampleexc_color(struct pine *, struct variable *); *************** *** 284,290 **** CONF_S *ctmp; if(!(cl && *cl && ! ((*cl)->var == &ps->vars[V_SORT_KEY] || standard_radio_var(ps, (*cl)->var) || (*cl)->var == startup_ptr))) return; --- 284,291 ---- CONF_S *ctmp; if(!(cl && *cl && ! (((*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; *************** *** 2956,2962 **** } set_current_val((*cl)->var, TRUE, TRUE); ! if(decode_sort(ps->VAR_SORT_KEY, &def_sort, &def_sort_rev) != -1){ ps->def_sort = def_sort; ps->def_sort_rev = def_sort_rev; } --- 2957,2963 ---- } set_current_val((*cl)->var, TRUE, TRUE); ! 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; } *************** *** 2965,2970 **** --- 2966,3002 ---- 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."); *************** *** 3828,3834 **** 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)); else if(v == &ps->vars[V_SIGNATURE_FILE]) return(sigfile_pretty_value(ps, cl)); else if(v == &ps->vars[V_USE_ONLY_DOMAIN_NAME]) --- 3860,3868 ---- 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, 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]) *************** *** 4359,4372 **** char * ! sort_pretty_value(struct pine *ps, CONF_S *cl) { ! return(generalized_sort_pretty_value(ps, cl, 1)); } char * ! generalized_sort_pretty_value(struct pine *ps, CONF_S *cl, int default_ok) { char tmp[6*MAXPATH]; char *pvalnorm, *pvalexc, *pval; --- 4393,4406 ---- char * ! sort_pretty_value(struct pine *ps, CONF_S *cl, int thread) { ! return(generalized_sort_pretty_value(ps, cl, 1, thread)); } char * ! generalized_sort_pretty_value(struct pine *ps, CONF_S *cl, int default_ok, int thread) { char tmp[6*MAXPATH]; char *pvalnorm, *pvalexc, *pval; *************** *** 4416,4422 **** } else if(fixed){ pval = v->fixed_val.p; ! decode_sort(pval, &var_sort, &var_sort_rev); is_the_one = (var_sort_rev == line_sort_rev && var_sort == line_sort); utf8_snprintf(tmp, sizeof(tmp), "(%c) %s%-*w%*s%s", --- 4450,4456 ---- } else if(fixed){ pval = v->fixed_val.p; ! 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", *************** *** 4427,4435 **** is_the_one ? " (value is fixed)" : ""); } else if(is_set_for_this_level){ ! decode_sort(pval, &var_sort, &var_sort_rev); is_the_one = (var_sort_rev == line_sort_rev && var_sort == line_sort); ! decode_sort(pvalexc, &exc_sort, &exc_sort_rev); 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", --- 4461,4469 ---- is_the_one ? " (value is fixed)" : ""); } else if(is_set_for_this_level){ ! 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, 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", *************** *** 4447,4453 **** } else{ if(pvalexc){ ! decode_sort(pvalexc, &exc_sort, &exc_sort_rev); is_the_one = (exc_sort_rev == line_sort_rev && exc_sort == line_sort); utf8_snprintf(tmp, sizeof(tmp), "( ) %s%-*w%*s%s", --- 4481,4487 ---- } else{ if(pvalexc){ ! 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", *************** *** 4458,4464 **** } else{ pval = v->current_val.p; ! decode_sort(pval, &var_sort, &var_sort_rev); is_the_one = ((pval || default_ok) && var_sort_rev == line_sort_rev && var_sort == line_sort); --- 4492,4498 ---- } else{ pval = v->current_val.p; ! 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); *************** *** 5614,5622 **** else if(revert && var == &ps->vars[V_SORT_KEY]){ int def_sort_rev; ! decode_sort(VAR_SORT_KEY, &ps->def_sort, &def_sort_rev); ps->def_sort_rev = 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]){ --- 5648,5662 ---- else if(revert && var == &ps->vars[V_SORT_KEY]){ int 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 -rc alpine-2.26/alpine/confscroll.h alpine-2.26.fancy/alpine/confscroll.h *** alpine-2.26/alpine/confscroll.h 2022-06-02 18:14:00.463274817 -0600 --- alpine-2.26.fancy/alpine/confscroll.h 2022-06-02 18:14:51.007150883 -0600 *************** *** 111,117 **** int radiobutton_tool(struct pine *, int, CONF_S **, unsigned); int yesno_tool(struct pine *, int, CONF_S **, unsigned); int text_toolit(struct pine *, int, CONF_S **, unsigned, int); ! char *generalized_sort_pretty_value(struct pine *, CONF_S *, int); int exclude_config_var(struct pine *, struct variable *, int); int config_exit_cmd(unsigned); int simple_exit_cmd(unsigned); --- 111,117 ---- int radiobutton_tool(struct pine *, int, CONF_S **, unsigned); int yesno_tool(struct pine *, int, CONF_S **, unsigned); int text_toolit(struct pine *, int, CONF_S **, unsigned, int); ! char *generalized_sort_pretty_value(struct pine *, CONF_S *, int, int); int exclude_config_var(struct pine *, struct variable *, int); int config_exit_cmd(unsigned); int simple_exit_cmd(unsigned); diff -rc alpine-2.26/alpine/keymenu.c alpine-2.26.fancy/alpine/keymenu.c *** alpine-2.26/alpine/keymenu.c 2022-06-02 18:14:00.463274817 -0600 --- alpine-2.26.fancy/alpine/keymenu.c 2022-06-02 18:14:51.007150883 -0600 *************** *** 675,684 **** RCOMPOSE_MENU, HOMEKEY_MENU, ENDKEY_MENU, ! NULL_MENU, /* 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_("Quota"), {MC_QUOTA,1,{'@'}}, KS_NONE}, NULL_MENU}; INST_KEY_MENU(index_keymenu, index_keys); --- 675,699 ---- RCOMPOSE_MENU, HOMEKEY_MENU, ENDKEY_MENU, ! {"K","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}, + /* TRANSLATORS: Collapse all threads */ + {"{",N_("Collapse All"),{MC_KOLAPSE,1,{'{'}},KS_NONE}, + /* TRANSLATORS: Expand all threads */ + {"}",N_("Expand All"), {MC_EXPTHREAD,1,{'}'}},KS_NONE}, + + HELP_MENU, + OTHER_MENU, + {")","Next Threa",{MC_NEXTHREAD,1,{')'}},KS_NONE}, + {"(","Prev Threa",{MC_PRETHREAD,1,{'('}},KS_NONE}, + {"^R","Remove Thr",{MC_DELTHREAD,1,{ctrl('r')}},KS_NONE}, + {"^U","Undel Thre",{MC_UNDTHREAD,1,{ctrl('u')}},KS_NONE}, + {"^T","Select Thr",{MC_SELTHREAD,1,{ctrl('t')}},KS_NONE}, + NULL_MENU, + {"[","Close Thre",{MC_CTHREAD,1,{'['}},KS_NONE}, + {"]","Open Threa",{MC_OTHREAD,1,{']'}},KS_NONE}, {"@", N_("Quota"), {MC_QUOTA,1,{'@'}}, KS_NONE}, NULL_MENU}; INST_KEY_MENU(index_keymenu, index_keys); *************** *** 753,761 **** RCOMPOSE_MENU, HOMEKEY_MENU, ENDKEY_MENU, ! NULL_MENU, {"/",N_("Collapse/Expand"),{MC_COLLAPSE,1,{'/'}},KS_NONE}, {"@", N_("Quota"), {MC_QUOTA,1,{'@'}}, KS_NONE}, NULL_MENU}; INST_KEY_MENU(thread_keymenu, thread_keys); --- 768,789 ---- RCOMPOSE_MENU, HOMEKEY_MENU, ENDKEY_MENU, ! {"]",N_("Open Thread"),{MC_OTHREAD,1,{']'}},KS_NONE}, {"/",N_("Collapse/Expand"),{MC_COLLAPSE,1,{'/'}},KS_NONE}, + {")",N_("Next Thread"),{MC_NEXTHREAD,1,{')'}},KS_NONE}, + {"(",N_("Prev Thread"),{MC_PRETHREAD,1,{'('}},KS_NONE}, + + HELP_MENU, + OTHER_MENU, {"@", N_("Quota"), {MC_QUOTA,1,{'@'}}, KS_NONE}, + NULL_MENU, + {"^R",N_("Remove Thread"),{MC_DELTHREAD,1,{ctrl('r')}},KS_NONE}, + {"^U",N_("Undelete Thread"),{MC_UNDTHREAD,1,{ctrl('u')}},KS_NONE}, + {"^T",N_("SelecT Thread"),{MC_SELTHREAD,1,{ctrl('t')}},KS_NONE}, + NULL_MENU, + NULL_MENU, + NULL_MENU, + {"K","Sort Thread",{MC_SORTHREAD,1,{'k'}},KS_NONE}, NULL_MENU}; INST_KEY_MENU(thread_keymenu, thread_keys); *************** *** 923,929 **** NULL_MENU, NULL_MENU, NULL_MENU, ! NULL_MENU}; INST_KEY_MENU(view_keymenu, view_keys); --- 951,970 ---- NULL_MENU, NULL_MENU, NULL_MENU, ! NULL_MENU, ! ! HELP_MENU, ! OTHER_MENU, ! NULL_MENU, ! NULL_MENU, ! NULL_MENU, ! NULL_MENU, ! NULL_MENU, ! {"(",N_("Prev Thread"),{MC_PRETHREAD,1,{'('}},KS_NONE}, ! {")",N_("Next Thread"),{MC_NEXTHREAD,1,{')'}},KS_NONE}, ! {"^R",N_("Remove Thread"),{MC_DELTHREAD,1,{ctrl('r')}},KS_NONE}, ! {"^U",N_("Undelete Thread"),{MC_UNDTHREAD,1,{ctrl('u')}},KS_NONE}, ! {"^T",N_("selecT Thread"),{MC_SELTHREAD,1,{ctrl('t')}},KS_NONE}}; INST_KEY_MENU(view_keymenu, view_keys); diff -rc alpine-2.26/alpine/keymenu.h alpine-2.26.fancy/alpine/keymenu.h *** alpine-2.26/alpine/keymenu.h 2022-06-02 18:14:00.463274817 -0600 --- alpine-2.26.fancy/alpine/keymenu.h 2022-06-02 18:14:51.051150774 -0600 *************** *** 220,225 **** --- 220,238 ---- #define MC_XSADD 807 #define MC_XSDELETE 808 #define MC_XSHELP 809 + #define MC_DELTHREAD 810 + #define MC_UNDTHREAD 811 + #define MC_SELTHREAD 812 + #define MC_SSUTHREAD 813 + #define MC_DSUTHREAD 814 + #define MC_USUTHREAD 815 + #define MC_SORTHREAD 816 + #define MC_NEXTHREAD 817 + #define MC_KOLAPSE 818 + #define MC_EXPTHREAD 819 + #define MC_PRETHREAD 820 + #define MC_CTHREAD 821 + #define MC_OTHREAD 822 /* Commands for S/MIME screens */ #define MC_TRUST 900 diff -rc alpine-2.26/alpine/mailcmd.c alpine-2.26.fancy/alpine/mailcmd.c *** alpine-2.26/alpine/mailcmd.c 2022-06-02 18:14:00.463274817 -0600 --- alpine-2.26.fancy/alpine/mailcmd.c 2022-06-02 18:14:51.079150706 -0600 *************** *** 110,116 **** 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 print_index(struct pine *, MSGNO_S *, int); /* --- 110,116 ---- 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); int print_index(struct pine *, MSGNO_S *, int); /* *************** *** 1437,1443 **** if(any_messages(msgmap, NULL, NULL)){ if(any_lflagged(msgmap, MN_SLCT) > 0L){ if(apply_command(state, stream, msgmap, 0, ! AC_NONE, question_line)){ if(F_ON(F_AUTO_UNSELECT, state)){ agg_select_all(stream, msgmap, NULL, 0); unzoom_index(state, stream, msgmap); --- 1437,1443 ---- if(any_messages(msgmap, NULL, NULL)){ if(any_lflagged(msgmap, MN_SLCT) > 0L){ if(apply_command(state, stream, msgmap, 0, ! AC_NONE, question_line, 1)){ if(F_ON(F_AUTO_UNSELECT, state)){ agg_select_all(stream, msgmap, NULL, 0); unzoom_index(state, stream, msgmap); *************** *** 1455,1477 **** /*-------- Sort command -------*/ case MC_SORT : { int were_threading = THREADING(); SortOrder sort = mn_get_sort(msgmap); int rev = mn_get_revsort(msgmap); dprint((1,"MAIL_CMD: sort\n")); ! if(select_sort(state, question_line, &sort, &rev)){ /* $ command reinitializes threading collapsed/expanded info */ if(SORT_IS_THREADED(msgmap) && !SEP_THRDINDX()) erase_threading_info(stream, msgmap); if(ps_global && ps_global->ttyo){ blank_keymenu(ps_global->ttyo->screen_rows - 2, 0); ps_global->mangled_footer = 1; } ! sort_folder(stream, msgmap, sort, rev, SRT_VRB|SRT_MAN); } state->mangled_footer = 1; --- 1455,1489 ---- /*-------- 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(sort == SortThread) ! sort = ps_global->thread_cur_sort; ! 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); + if(command == MC_SORTHREAD){ + ps_global->thread_cur_sort = sort; + sort = SortThread; + } + else if(sort == SortThread) /* command = MC_SORT */ + ps_global->thread_cur_sort = F_ON(F_THREAD_SORTS_BY_ARRIVAL, ps_global) + ? SortArrival : ps_global->thread_def_sort; + if(ps_global && ps_global->ttyo){ blank_keymenu(ps_global->ttyo->screen_rows - 2, 0); ps_global->mangled_footer = 1; } ! sort_folder(stream, msgmap, sort, rev, SRT_VRB|SRT_MAN, 1); } state->mangled_footer = 1; *************** *** 3314,3319 **** --- 3326,3335 ---- 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, *************** *** 3415,3420 **** --- 3431,3439 ---- */ 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){ *************** *** 7333,7339 **** * Maybe it makes sense to zoom after a select but not after a colon * command even though they are very similar. */ ! thread_command(state, state->mail_stream, msgmap, ':', -FOOTER_ROWS(state)); } else{ if((all_selected = --- 7352,7358 ---- * Maybe it makes sense to zoom after a select but not after a colon * command even though they are very similar. */ ! thread_command(state, state->mail_stream, msgmap, ':', -FOOTER_ROWS(state), 1); } else{ if((all_selected = *************** *** 7389,7395 **** ----*/ int apply_command(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap, ! UCS preloadkeystroke, int flags, int q_line) { int i = 8, /* number of static entries in sel_opts3 */ rv = 0, --- 7408,7414 ---- ----*/ int apply_command(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap, ! UCS preloadkeystroke, int flags, int q_line, int display) { int i = 8, /* number of static entries in sel_opts3 */ rv = 0, *************** *** 7556,7564 **** collapse_or_expand(state, stream, msgmap, F_ON(F_SLASH_COLL_ENTIRE, ps_global) ? 0L ! : mn_get_cur(msgmap)); break; case ':' : select_thread_stmp(state, stream, msgmap); break; --- 7575,7593 ---- collapse_or_expand(state, stream, msgmap, F_ON(F_SLASH_COLL_ENTIRE, ps_global) ? 0L ! : 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; *************** *** 9604,9613 **** Returns 0 if it was cancelled, 1 otherwise. ----*/ int ! select_sort(struct pine *state, int ql, SortOrder *sort, int *rev) { char prompt[200], tmp[3], *p; ! int s, i; int deefault = 'a', retval = 1; HelpType help; ESCKEY_S sorts[14]; --- 9633,9642 ---- Returns 0 if it was cancelled, 1 otherwise. ----*/ int ! select_sort(struct pine *state, int ql, SortOrder *sort, int *rev, int thread) { char prompt[200], tmp[3], *p; ! int s, i, j; int deefault = 'a', retval = 1; HelpType help; ESCKEY_S sorts[14]; *************** *** 9640,9656 **** 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; } sorts[i].ch = 'r'; --- 9669,9694 ---- strncpy(prompt, _("Choose type of sort, or 'R' to reverse current sort : "), sizeof(prompt)); ! 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 || allowed_thread_key(state->sort_types[i])){ ! 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'; *************** *** 9674,9681 **** state->mangled_body = 1; /* signal screen's changed */ if(s == 'r') *rev = !mn_get_revsort(state->msgmap); ! else *sort = state->sort_types[s]; if(F_ON(F_SHOW_SORT, ps_global)) ps_global->mangled_header = 1; --- 9712,9728 ---- state->mangled_body = 1; /* signal screen's changed */ if(s == 'r') *rev = !mn_get_revsort(state->msgmap); ! else{ ! if(thread){ ! for(i = 0; state->sort_types[i] != EndofList; i++){ ! if(struncmp(sort_name(state->sort_types[i]), ! sorts[s].label, strlen(sorts[s].label)) == 0) ! break; ! } ! s = i; ! } *sort = state->sort_types[s]; + } if(F_ON(F_SHOW_SORT, ps_global)) ps_global->mangled_header = 1; *************** *** 10059,10061 **** --- 10106,10484 ---- } #endif /* _WINDOWS */ + + void + cmd_delete_this_thread(state, stream, msgmap) + 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(state, stream, msgmap) + 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, MCMD_NONE, cmd_delete_index); + count = count_thread(state, stream, msgmap, rawno); + q_status_message2(SM_ORDER, 0, 1, "%s message%s marked deleted", + int2string(count), plural(count)); + } + + 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, 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; + } + + void + collapse_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; + + 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(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; + + 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, 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 + 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)); + } + + + void + cmd_undelete_this_thread(state, stream, msgmap) + 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(state, stream, msgmap) + 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 + kolapse_thread(state, stream, msgmap, ch, display) + 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))); + } + + void + cmd_select_thread(state, stream, msgmap) + 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 -rc alpine-2.26/alpine/mailcmd.h alpine-2.26.fancy/alpine/mailcmd.h *** alpine-2.26/alpine/mailcmd.h 2022-06-02 18:14:00.463274817 -0600 --- alpine-2.26.fancy/alpine/mailcmd.h 2022-06-02 18:14:51.087150687 -0600 *************** *** 90,96 **** 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); char **choose_list_of_keywords(void); char *choose_a_charset(int); char **choose_list_of_charsets(void); --- 90,96 ---- 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); char **choose_list_of_keywords(void); char *choose_a_charset(int); char **choose_list_of_charsets(void); *************** *** 108,113 **** int flag_callback(int, long); MPopup *flag_submenu(MESSAGECACHE *); #endif ! #endif /* PINE_MAILCMD_INCLUDED */ --- 108,122 ---- int flag_callback(int, long); MPopup *flag_submenu(MESSAGECACHE *); #endif ! void cmd_delete_thread(struct pine *, MAILSTREAM *, MSGNO_S *); ! void cmd_delete_this_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 *); ! void kolapse_thread(struct pine *, MAILSTREAM *, MSGNO_S *, char, int); ! void collapse_thread(struct pine *, MAILSTREAM *, MSGNO_S *, int); ! void expand_thread(struct pine *, MAILSTREAM *, MSGNO_S *, int); ! int collapse_this_thread(struct pine *, MAILSTREAM *, MSGNO_S *, int, int); ! int expand_this_thread(struct pine *, MAILSTREAM *, MSGNO_S *, int, int); #endif /* PINE_MAILCMD_INCLUDED */ diff -rc alpine-2.26/alpine/mailindx.c alpine-2.26.fancy/alpine/mailindx.c *** alpine-2.26/alpine/mailindx.c 2022-06-02 18:14:00.463274817 -0600 --- alpine-2.26.fancy/alpine/mailindx.c 2022-06-02 18:14:51.131150578 -0600 *************** *** 560,565 **** --- 560,566 ---- /*---------- Scroll line up ----------*/ case MC_CHARUP : + previtem: (void) process_cmd(state, stream, msgmap, MC_PREVITEM, (style == MsgIndex || style == MultiMsgIndex *************** *** 577,582 **** --- 578,584 ---- /*---------- Scroll line down ----------*/ case MC_CHARDOWN : + nextitem: /* * Special Page framing handling here. If we * did something that should scroll-by-a-line, frame *************** *** 794,799 **** --- 796,802 ---- case MC_THRDINDX : + mc_thrdindx: if(any_lflagged(msgmap, MN_SLCT)){ PINETHRD_S *thrd, *topthrd; for(i = 1L; i > 0L && i <= mn_get_total(msgmap);){ *************** *** 861,867 **** && mp.col == id.plus_col && style != ThreadIndex){ collapse_or_expand(state, stream, msgmap, ! mn_get_cur(msgmap)); } else if (mp.doubleclick){ if(mp.button == M_BUTTON_LEFT){ --- 864,870 ---- && mp.col == id.plus_col && style != ThreadIndex){ collapse_or_expand(state, stream, msgmap, ! mn_get_cur(msgmap), 1); } else if (mp.doubleclick){ if(mp.button == M_BUTTON_LEFT){ *************** *** 970,978 **** case MC_COLLAPSE : ! thread_command(state, stream, msgmap, ch, -FOOTER_ROWS(state)); break; case MC_DELETE : case MC_UNDELETE : case MC_REPLY : --- 973,1076 ---- case MC_COLLAPSE : ! thread_command(state, stream, msgmap, ch, -FOOTER_ROWS(state), 1); 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_DELETE : case MC_UNDELETE : case MC_REPLY : *************** *** 993,1005 **** if(rawno) thrd = fetch_thread(stream, rawno); ! collapsed = thrd && thrd->next ! && get_lflag(stream, NULL, rawno, MN_COLL); } if(collapsed){ thread_command(state, stream, msgmap, ! ch, -FOOTER_ROWS(state)); /* increment current */ if(cmd == MC_DELETE){ advance_cur_after_delete(state, stream, msgmap, --- 1091,1102 ---- if(rawno) thrd = fetch_thread(stream, rawno); ! collapsed = thread_is_kolapsed(ps_global, stream, msgmap, rawno); } if(collapsed){ thread_command(state, stream, msgmap, ! ch, -FOOTER_ROWS(state),1); /* increment current */ if(cmd == MC_DELETE){ advance_cur_after_delete(state, stream, msgmap, *************** *** 2692,2697 **** --- 2789,2795 ---- 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; *************** *** 2760,2770 **** /* n is the end of this thread */ while(thrd){ 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); else thrd = NULL; } --- 2858,2869 ---- /* n is the end of this thread */ while(thrd){ + unsigned long next = 0L, branch = 0L; n = mn_raw2m(msgs, thrd->rawno); ! 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; } *************** *** 2872,2878 **** void thread_command(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap, ! UCS preloadkeystroke, int q_line) { PINETHRD_S *thrd = NULL; unsigned long rawno, save_branch; --- 2971,2977 ---- void thread_command(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap, ! UCS preloadkeystroke, int q_line, int display) { PINETHRD_S *thrd = NULL; unsigned long rawno, save_branch; *************** *** 2921,2927 **** cancel_busy_cue(0); (void ) apply_command(state, stream, msgmap, preloadkeystroke, flags, ! q_line); /* restore the original flags */ copy_lflags(stream, msgmap, MN_STMP, MN_SLCT); --- 3020,3026 ---- cancel_busy_cue(0); (void ) apply_command(state, stream, msgmap, preloadkeystroke, flags, ! q_line, display); /* restore the original flags */ copy_lflags(stream, msgmap, MN_STMP, MN_SLCT); *************** *** 3438,3444 **** if(set){ sort_folder(ps_global->mail_stream, ps_global->msgmap, order & 0x000000ff, ! (order & 0x00000100) != 0, SRT_VRB); mswin_beginupdate(); update_titlebar_message(); update_titlebar_status(); --- 3537,3543 ---- if(set){ sort_folder(ps_global->mail_stream, ps_global->msgmap, order & 0x000000ff, ! (order & 0x00000100) != 0, SRT_VRB, 1); mswin_beginupdate(); update_titlebar_message(); update_titlebar_status(); diff -rc alpine-2.26/alpine/mailindx.h alpine-2.26.fancy/alpine/mailindx.h *** alpine-2.26/alpine/mailindx.h 2022-06-02 18:14:00.463274817 -0600 --- alpine-2.26.fancy/alpine/mailindx.h 2022-06-02 18:14:51.143150549 -0600 *************** *** 103,109 **** 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); COLOR_PAIR *apply_rev_color(COLOR_PAIR *, int); #ifdef _WINDOWS int index_sort_callback(int, long); --- 103,109 ---- 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, int); COLOR_PAIR *apply_rev_color(COLOR_PAIR *, int); #ifdef _WINDOWS int index_sort_callback(int, long); diff -rc alpine-2.26/alpine/mailview.c alpine-2.26.fancy/alpine/mailview.c *** alpine-2.26/alpine/mailview.c 2022-06-02 18:14:00.463274817 -0600 --- alpine-2.26.fancy/alpine/mailview.c 2022-06-02 18:14:51.167150490 -0600 *************** *** 3670,3675 **** --- 3670,3721 ---- 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 -rc alpine-2.26/alpine/roleconf.c alpine-2.26.fancy/alpine/roleconf.c *** alpine-2.26/alpine/roleconf.c 2022-06-02 18:14:00.463274817 -0600 --- alpine-2.26.fancy/alpine/roleconf.c 2022-06-02 18:14:51.175150471 -0600 *************** *** 4473,4483 **** ctmp->tool = role_sort_tool; ctmp->valoffset = rindent; ctmp->flags |= CF_NOSELECT; ! ctmp->value = cpystr(set_choose); \ pval = PVAL(&sort_act_var, ew); if(pval) ! decode_sort(pval, &def_sort, &def_sort_rev); /* allow user to set their default sort order */ new_confline(&ctmp)->var = &sort_act_var; --- 4473,4483 ---- ctmp->tool = role_sort_tool; ctmp->valoffset = rindent; ctmp->flags |= CF_NOSELECT; ! ctmp->value = cpystr(set_choose); pval = PVAL(&sort_act_var, ew); if(pval) ! decode_sort(pval, &def_sort, &def_sort_rev, 0); /* allow user to set their default sort order */ new_confline(&ctmp)->var = &sort_act_var; *************** *** 4487,4493 **** ctmp->tool = role_sort_tool; ctmp->valoffset = rindent; ctmp->varmem = -1; ! ctmp->value = generalized_sort_pretty_value(ps, ctmp, 0); for(j = 0; j < 2; j++){ for(i = 0; ps->sort_types[i] != EndofList; i++){ --- 4487,4493 ---- ctmp->tool = role_sort_tool; ctmp->valoffset = rindent; ctmp->varmem = -1; ! 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++){ *************** *** 4499,4505 **** ctmp->valoffset = rindent; ctmp->varmem = i + (j * EndofList); ctmp->value = generalized_sort_pretty_value(ps, ctmp, ! 0); } } --- 4499,4505 ---- ctmp->valoffset = rindent; ctmp->varmem = i + (j * EndofList); ctmp->value = generalized_sort_pretty_value(ps, ctmp, ! 0, 0); } } *************** *** 5432,5438 **** (*result)->patgrp->stat_boy = PAT_STAT_EITHER; if(sort_act){ ! decode_sort(sort_act, &def_sort, &def_sort_rev); (*result)->action->sort_is_set = 1; (*result)->action->sortorder = def_sort; (*result)->action->revsort = (def_sort_rev ? 1 : 0); --- 5432,5438 ---- (*result)->patgrp->stat_boy = PAT_STAT_EITHER; if(sort_act){ ! 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 -rc alpine-2.26/alpine/setup.c alpine-2.26.fancy/alpine/setup.c *** alpine-2.26/alpine/setup.c 2022-06-02 18:14:00.463274817 -0600 --- alpine-2.26.fancy/alpine/setup.c 2022-06-02 18:14:51.207150392 -0600 *************** *** 258,264 **** ctmpa->flags |= CF_NOSELECT; ctmpa->value = cpystr("--- ----------------------"); ! decode_sort(pval, &def_sort, &def_sort_rev); for(j = 0; j < 2; j++){ for(i = 0; ps->sort_types[i] != EndofList; i++){ --- 258,264 ---- ctmpa->flags |= CF_NOSELECT; ctmpa->value = cpystr("--- ----------------------"); ! decode_sort(pval, &def_sort, &def_sort_rev, 0); for(j = 0; j < 2; j++){ for(i = 0; ps->sort_types[i] != EndofList; i++){ *************** *** 273,278 **** --- 273,327 ---- } } } + else if(vtmp == &ps->vars[V_THREAD_SORT_KEY]){ /* radio case */ + SortOrder thread_def_sort; + int thread_def_sort_rev, lv; + + 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 (allowed_thread_key(ps->sort_types[i])){ + 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; *************** *** 465,470 **** --- 514,528 ---- } } + 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(ps_global->mail_stream, 0); + reset_sort_order(SRT_VRB); + } + } + treat_color_vars_as_text = 0; free_saved_config(ps, &vsave, expose_hidden_config); #ifdef _WINDOWS diff -rc alpine-2.26/pith/conf.c alpine-2.26.fancy/pith/conf.c *** alpine-2.26/pith/conf.c 2022-06-02 18:14:00.491274749 -0600 --- alpine-2.26.fancy/pith/conf.c 2022-06-02 18:14:51.247150294 -0600 *************** *** 203,208 **** --- 203,210 ---- 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\"."; *************** *** 541,546 **** --- 543,550 ---- NULL, cf_text_fcc_name_rule}, {"sort-key", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, NULL, cf_text_sort_key}, + {"thread-sort-key", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, + NULL, cf_text_thread_sort_key}, {"addrbook-sort-rule", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, "Address Book Sort Rule", cf_text_addrbook_sort_rule}, {"folder-sort-rule", 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, *************** *** 1615,1621 **** 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; long rvl; PINERC_S *fixedprc = NULL; FeatureLevel obs_feature_level; --- 1619,1625 ---- 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, thread_def_sort_rev; long rvl; PINERC_S *fixedprc = NULL; FeatureLevel obs_feature_level; *************** *** 1643,1648 **** --- 1647,1653 ---- 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); *************** *** 2647,2653 **** 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){ 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; --- 2652,2658 ---- 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,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; *************** *** 2656,2661 **** --- 2661,2677 ---- 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++) *************** *** 3081,3086 **** --- 3097,3104 ---- F_COLOR_LINE_IMPORTANT, h_config_color_thrd_import, PREF_INDX, 0}, {"thread-sorts-by-arrival", "Thread Sorts by Arrival", F_THREAD_SORTS_BY_ARRIVAL, h_config_thread_sorts_by_arrival, PREF_INDX, 0}, + {"enhanced-fancy-thread-support", "Enhanced Fancy Thread Support", + F_ENHANCED_THREAD, h_config_enhanced_thread, PREF_INDX, 0}, /* Viewer prefs */ {"enable-msg-view-addresses", "Enable Message View Address Links", *************** *** 7876,7881 **** --- 7894,7901 ---- 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 -rc alpine-2.26/pith/conf.h alpine-2.26.fancy/pith/conf.h *** alpine-2.26/pith/conf.h 2022-06-02 18:14:00.491274749 -0600 --- alpine-2.26.fancy/pith/conf.h 2022-06-02 18:14:51.259150264 -0600 *************** *** 155,160 **** --- 155,163 ---- #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 -rc alpine-2.26/pith/conftype.h alpine-2.26.fancy/pith/conftype.h *** alpine-2.26/pith/conftype.h 2022-06-02 18:14:00.491274749 -0600 --- alpine-2.26.fancy/pith/conftype.h 2022-06-02 18:14:51.303150157 -0600 *************** *** 59,64 **** --- 59,65 ---- , 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 *************** *** 530,535 **** --- 531,537 ---- F_QUELL_TIMEZONE, F_QUELL_USERAGENT, F_COLOR_LINE_IMPORTANT, + F_ENHANCED_THREAD, F_SLASH_COLL_ENTIRE, F_ENABLE_FULL_HDR_AND_TEXT, F_QUELL_FULL_HDR_RESET, *************** *** 795,799 **** --- 797,802 ---- /* exported prototypes */ + #define DF_THREAD_SORT_KEY "thread" #endif /* PITH_CONFTYPE_INCLUDED */ diff -rc alpine-2.26/pith/flag.c alpine-2.26.fancy/pith/flag.c *** alpine-2.26/pith/flag.c 2022-06-02 18:14:00.491274749 -0600 --- alpine-2.26.fancy/pith/flag.c 2022-06-02 18:14:51.319150118 -0600 *************** *** 588,601 **** was_invisible = (pelt->hidden || pelt->colhid) ? 1 : 0; if((chk_thrd_cnt = ((msgs->visible_threads >= 0L) && THRD_INDX_ENABLED() && (f & MN_HIDE) && (pelt->hidden != v))) != 0){ thrd = fetch_thread(stream, rawno); if(thrd && thrd->top){ ! if(thrd->top == thrd->rawno) topthrd = thrd; else ! topthrd = fetch_thread(stream, thrd->top); } if(topthrd){ --- 588,603 ---- was_invisible = (pelt->hidden || pelt->colhid) ? 1 : 0; + thrd = fetch_thread(stream, rawno); + if((chk_thrd_cnt = ((msgs->visible_threads >= 0L) && THRD_INDX_ENABLED() && (f & MN_HIDE) && (pelt->hidden != v))) != 0){ thrd = fetch_thread(stream, rawno); if(thrd && thrd->top){ ! if(top_thread(stream, thrd->top) == thrd->rawno) topthrd = thrd; else ! topthrd = fetch_thread(stream, top_thread(stream, thrd->top)); } if(topthrd){ diff -rc alpine-2.26/pith/indxtype.h alpine-2.26.fancy/pith/indxtype.h *** alpine-2.26/pith/indxtype.h 2022-06-02 18:14:00.491274749 -0600 --- alpine-2.26.fancy/pith/indxtype.h 2022-06-02 18:14:51.331150088 -0600 *************** *** 78,84 **** iKey, iKeyInit, iPrefDate, iPrefTime, iPrefDateTime, iCurPrefDate, iCurPrefTime, iCurPrefDateTime, ! iSize, iSizeComma, iSizeNarrow, iDescripSize, iNewsAndTo, iToAndNews, iNewsAndRecips, iRecipsAndNews, iFromTo, iFromToNotNews, iFrom, iTo, iSender, iCc, iNews, iRecips, iCurNews, iArrow, --- 78,84 ---- iKey, iKeyInit, iPrefDate, iPrefTime, iPrefDateTime, iCurPrefDate, iCurPrefTime, iCurPrefDateTime, ! iSize, iSizeComma, iSizeNarrow, iDescripSize, iSizeThread, iNewsAndTo, iToAndNews, iNewsAndRecips, iRecipsAndNews, iFromTo, iFromToNotNews, iFrom, iTo, iSender, iCc, iNews, iRecips, iCurNews, iArrow, diff -rc alpine-2.26/pith/mailindx.c alpine-2.26.fancy/pith/mailindx.c *** alpine-2.26/pith/mailindx.c 2022-06-02 18:14:00.491274749 -0600 --- alpine-2.26.fancy/pith/mailindx.c 2022-06-02 18:14:51.347150049 -0600 *************** *** 225,230 **** --- 225,231 ---- case iSTime: case iKSize: case iSize: + case iSizeThread: case iPrioAlpha: (*answer)[column].req_width = 7; break; *************** *** 452,457 **** --- 453,459 ---- {"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}, *************** *** 950,956 **** iSDateTimeS1, iSDateTimeS2, iSDateTimeS3, iSDateTimeS4, iSDateTimeIso24, iSDateTimeIsoS24, iSDateTimeS124, iSDateTimeS224, iSDateTimeS324, iSDateTimeS424, ! iSize, iSizeComma, iSizeNarrow, iKSize, iDescripSize, iPrio, iPrioBang, iPrioAlpha, iInit, iAtt, iTime24, iTime12, iTimezone, iMonAbb, iYear, iYear2Digit, iDay2Digit, iMon2Digit, iDayOfWeekAbb, iScore, iMonLong, iDayOfWeek --- 952,958 ---- iSDateTimeS1, iSDateTimeS2, iSDateTimeS3, iSDateTimeS4, iSDateTimeIso24, iSDateTimeIsoS24, iSDateTimeS124, iSDateTimeS224, iSDateTimeS324, iSDateTimeS424, ! iSize, iSizeComma, iSizeNarrow, iKSize, iDescripSize, iSizeThread, iPrio, iPrioBang, iPrioAlpha, iInit, iAtt, iTime24, iTime12, iTimezone, iMonAbb, iYear, iYear2Digit, iDay2Digit, iMon2Digit, iDayOfWeekAbb, iScore, iMonLong, iDayOfWeek *************** *** 1143,1148 **** --- 1145,1151 ---- case iTime12: case iSize: case iKSize: + case iSizeThread: cdesc->actual_length = 7; cdesc->adjustment = Right; break; *************** *** 1237,1243 **** cdesc->ctype != iNothing; cdesc++) if(cdesc->ctype == iSize || cdesc->ctype == iKSize || ! cdesc->ctype == iSizeNarrow || cdesc->ctype == iSizeComma || cdesc->ctype == iDescripSize){ if(cdesc->actual_length == 0){ if((fix=cdesc->width) > 0){ /* had this reserved */ --- 1240,1246 ---- cdesc->ctype != iNothing; cdesc++) if(cdesc->ctype == iSize || cdesc->ctype == iKSize || ! 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 */ *************** *** 1623,1632 **** /* find next thread which is visible */ do{ 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 thrd = NULL; } while(thrd --- 1626,1637 ---- /* find next thread which is visible */ do{ + unsigned long branch; if(mn_get_revsort(msgmap) && thrd->prevthd) thrd = fetch_thread(stream, thrd->prevthd); ! /*branch = get_branch(stream,thrd)*/ ! else if(!mn_get_revsort(msgmap) && thrd->branch) ! thrd = fetch_thread(stream, thrd->branch); else thrd = NULL; } while(thrd *************** *** 2038,2050 **** */ ice = copy_ice(ice); /* is this a collapsed thread index line? */ ! if(!idata->bogus && THREADING()){ ! thrd = fetch_thread(idata->stream, idata->rawno); ! collapsed = thrd && thrd->next ! && get_lflag(idata->stream, NULL, ! idata->rawno, MN_COLL); ! } /* calculate contents of the required fields */ for(cdesc = ps_global->index_disp_format; cdesc->ctype != iNothing; cdesc++) --- 2043,2052 ---- */ ice = copy_ice(ice); + thrd = fetch_thread(idata->stream, idata->rawno); /* is this a collapsed thread index line? */ ! if(!idata->bogus && THREADING()) ! collapsed = thrd && thread_is_kolapsed(ps_global, idata->stream, ps_global->msgmap, idata->rawno); /* calculate contents of the required fields */ for(cdesc = ps_global->index_disp_format; cdesc->ctype != iNothing; cdesc++) *************** *** 2546,2552 **** --- 2548,2577 ---- break; + case iSizeThread: + if (!THREADING()){ + goto getsize; + } else if (collapsed){ + l = count_flags_in_thread(idata->stream, thrd, F_NONE); + snprintf(str, sizeof(str), "(%lu)", l); + } + else{ + thrd = fetch_thread(idata->stream, idata->rawno); + if(!thrd) + snprintf(str, sizeof(str), "%s", "Error"); + else{ + long lengthb; + lengthb = get_length_branch(idata->stream, idata->rawno); + if (lengthb > 0L) + snprintf(str, sizeof(str), "(%lu)", lengthb); + else + snprintf(str,sizeof(str), "%s", " "); + } + } + break; + case iSize: + getsize: /* 0 ... 9999 */ if((l = fetch_size(idata)) < 10*1000L) snprintf(str, sizeof(str), "(%lu)", l); *************** *** 5578,5587 **** if(pith_opt_condense_thread_cue) width = (*pith_opt_condense_thread_cue)(thd, ice, &str, &strsize, width, ! thd && thd->next ! && get_lflag(idata->stream, ! NULL,idata->rawno, ! MN_COLL)); /* * width is < available strsize and --- 5603,5610 ---- if(pith_opt_condense_thread_cue) width = (*pith_opt_condense_thread_cue)(thd, ice, &str, &strsize, width, ! this_thread_is_kolapsed(ps_global, idata->stream, ps_global->msgmap, idata->rawno) && ! (count_thread(ps_global,idata->stream, ps_global->msgmap, idata->rawno) != 1)); /* * width is < available strsize and *************** *** 6207,6217 **** border = str + width; if(pith_opt_condense_thread_cue) width = (*pith_opt_condense_thread_cue)(thd, ice, &str, &strsize, width, ! thd && thd->next ! && get_lflag(idata->stream, ! NULL,idata->rawno, ! MN_COLL)); ! fptr = str; if(thd) --- 6230,6237 ---- border = str + width; if(pith_opt_condense_thread_cue) width = (*pith_opt_condense_thread_cue)(thd, ice, &str, &strsize, width, ! this_thread_is_kolapsed(ps_global, idata->stream, ps_global->msgmap, idata->rawno) && ! (count_thread(ps_global,idata->stream, ps_global->msgmap, idata->rawno) != 1)); fptr = str; if(thd) diff -rc alpine-2.26/pith/pattern.c alpine-2.26.fancy/pith/pattern.c *** alpine-2.26/pith/pattern.c 2022-06-02 18:14:00.491274749 -0600 --- alpine-2.26.fancy/pith/pattern.c 2022-06-02 18:14:51.359150020 -0600 *************** *** 1753,1759 **** SortOrder def_sort; int def_sort_rev; ! if(decode_sort(p, &def_sort, &def_sort_rev) != -1){ action->sort_is_set = 1; action->sortorder = def_sort; action->revsort = (def_sort_rev ? 1 : 0); --- 1753,1759 ---- SortOrder def_sort; int def_sort_rev; ! 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 -rc alpine-2.26/pith/pine.hlp alpine-2.26.fancy/pith/pine.hlp *** alpine-2.26/pith/pine.hlp 2022-06-02 18:14:00.491274749 -0600 --- alpine-2.26.fancy/pith/pine.hlp 2022-06-02 18:14:51.399149922 -0600 *************** *** 5321,5326 **** --- 5321,5327 ---- <li><a href="h_config_signature_file">OPTION: <!--#echo var="VAR_signature-file"--></a> <li><a href="h_config_smtp_server">OPTION: <!--#echo var="VAR_smtp-server"--></a> <li><a href="h_config_sort_key">OPTION: <!--#echo var="VAR_sort-key"--></a> + <li><a href="h_config_thread_sort_key">OPTION: <!--#echo var="VAR_thread-sort-key"--></a> <li><a href="h_config_speller">OPTION: <!--#echo var="VAR_speller"--></a> <li><a href="h_config_aspell_dictionary">OPTION: <!--#echo var="VAR_aspell-dictionary-list"--></a> <li><a href="h_config_sshcmd">OPTION: <!--#echo var="VAR_ssh-command"--></a> *************** *** 7262,7267 **** --- 7263,7425 ---- <End of help on this topic> </BODY> </HTML> + ======= h_thread_index_sort_arrival ======= + <HTML> + <HEAD> + <TITLE>SORT OPTION: Arrival</TITLE> + </HEAD> + <BODY> + <H1>SORT OPTION: Arrival</H1> + + The <EM>Arrival</EM> 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. + + <P> + <End of help on this topic> + </BODY> + </HTML> + ======= h_thread_index_sort_date ======= + <HTML> + <HEAD> + <TITLE>SORT OPTION: Date</TITLE> + </HEAD> + <BODY> + <H1>SORT OPTION: Date</H1> + + The <EM>Date</EM> sort option in the THREAD INDEX screen sorts + threads by the date in which messages were sent. The thread containing the + last message in this order is displayed last. + <P> + <End of help on this topic> + </BODY> + </HTML> + ======= h_thread_index_sort_subj ======= + <HTML> + <HEAD> + <TITLE>SORT OPTION: Subject</TITLE> + </HEAD> + <BODY> + <H1>SORT OPTION: Subject</H1> + + The <EM>Subject</EM> sort option has not been defined yet. + + <P> + <End of help on this topic> + </BODY> + </HTML> + ======= h_thread_index_sort_ordsubj ======= + <HTML> + <HEAD> + <TITLE>SORT OPTION: OrderedSubject</TITLE> + </HEAD> + <BODY> + <H1>SORT OPTION: OrderedSubject</H1> + + The <EM>OrderedSubject</EM> sort option in the THREAD INDEX screen is + the same as sorting by <A HREF="h_thread_index_sort_subj">Subject</A>. + + <P> + <End of help on this topic> + </BODY> + </HTML> + ======= h_thread_index_sort_thread ======= + <HTML> + <HEAD> + <TITLE>SORT OPTION: Thread</TITLE> + </HEAD> + <BODY> + <H1>SORT OPTION: Thread</H1> + + The <EM>Thread</EM> 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. + + <P> + <End of help on this topic> + </BODY> + </HTML> + ======= h_thread_index_sort_from ======= + <HTML> + <HEAD> + <TITLE>SORT OPTION: From</TITLE> + </HEAD> + <BODY> + <H1>SORT OPTION: From</H1> + + The <EM>From</EM> sort option has not been defined yet. + + <P> + <End of help on this topic> + </BODY> + </HTML> + ======= h_thread_index_sort_size ======= + <HTML> + <HEAD> + <TITLE>SORT OPTION: Size</TITLE> + </HEAD> + <BODY> + <H1>SORT OPTION: Size</H1> + + The <EM>Size</EM> sort option sorts threads by their size (the number + of messages in the thread). This could be used to find conversations + where no reply has been sent by any of the participants in the thread + (e.g. those whose length is equal to one). Longer threads appear + below shorter ones. + + <P> + <End of help on this topic> + </BODY> + </HTML> + ======= h_thread_index_sort_score ======= + <HTML> + <HEAD> + <TITLE>SORT OPTION: Score</TITLE> + </HEAD> + <BODY> + <H1>SORT OPTION: Score</H1> + + The <EM>Score</EM> 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. + + <P> + <End of help on this topic> + </BODY> + </HTML> + ======= h_thread_index_sort_to ======= + <HTML> + <HEAD> + <TITLE>SORT OPTION: To</TITLE> + </HEAD> + <BODY> + <H1>SORT OPTION: To</H1> + + The <EM>To</EM> sort option has not been defined yet. + + <P> + <End of help on this topic> + </BODY> + </HTML> + ======= h_thread_index_sort_cc ======= + <HTML> + <HEAD> + <TITLE>SORT OPTION: Cc</TITLE> + </HEAD> + <BODY> + <H1>SORT OPTION: Cc</H1> + + The <EM>Cc</EM> sort option has not been defined yet. + + <P> + <End of help on this topic> + </BODY> + </HTML> ======= h_index_cmd_whereis ======= <HTML> <HEAD> *************** *** 20839,20844 **** --- 20997,21010 ---- <P> </DD> + <DT>SIZETHREAD</DT> + <DD> + 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. + </DD> + <DT>SIZENARROW</DT> <DD> This token represents the total size, in bytes, of the message. *************** *** 24555,24560 **** --- 24721,24765 ---- <End of help on this topic> </BODY> </HTML> + ====== h_config_thread_sort_key ===== + <HTML> + <HEAD> + <TITLE>OPTION: <!--#echo var="VAR_thread-sort-key--></TITLE> + </HEAD> + <BODY> + <H1>OPTION: <!--#echo var="VAR_thread-sort-key--></TITLE></H1> + + 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. + + <P> + <UL> + <LI> <A HREF="h_thread_index_sort_arrival">Arrival</A> + <LI> <A HREF="h_thread_index_sort_date">Date</A> + <!-- <LI> <A HREF="h_thread_index_sort_subj">Subject</A> + <LI> <A HREF="h_thread_index_sort_ordsubj">OrderedSubj</A>--> + <LI> <A HREF="h_thread_index_sort_thread">Thread</A> + <!-- <LI> <A HREF="h_thread_index_sort_from">From</A> --> + <LI> <A HREF="h_thread_index_sort_size">Size</A> + <LI> <A HREF="h_thread_index_sort_score">Score</A> + <!-- <LI> <A HREF="h_thread_index_sort_to">To</A> + <LI> <A HREF="h_thread_index_sort_cc">Cc</A>--> + </UL> + + <P> Each type of sort may also be reversed. Normal default is by + "Thread". + + <P> + <UL> + <LI><A HREF="h_finding_help">Finding more information and requesting help</A> + </UL><P> + <End of help on this topic> + </BODY> + </HTML> ====== h_config_other_startup ===== <HTML> <HEAD> *************** *** 32604,32609 **** --- 32809,32831 ---- <End of help on this topic> </BODY> </HTML> + ====== h_config_enhanced_thread ===== + <HTML> + <HEAD> + <TITLE>FEATURE: <!--#echo var="FEAT_enhanced-fancy-thread-support"--></TITLE> + </HEAD> + <BODY> + <H1>FEATURE: <!--#echo var="FEAT_enhanced-fancy-thread-support"--></H1> + + If this option is set certain commands in Pine will operate in loose + threads too. For example, the command ^R marks a thread deleted, but if + this feature is set, it will remove all threads that share the same missing + parent with this thread. + + <P> + <End of help on this topic> + </BODY> + </HTML> ====== h_config_news_cross_deletes ===== <HTML> <HEAD> diff -rc alpine-2.26/pith/sort.c alpine-2.26.fancy/pith/sort.c *** alpine-2.26/pith/sort.c 2022-06-02 18:14:00.491274749 -0600 --- alpine-2.26.fancy/pith/sort.c 2022-06-02 18:14:51.399149922 -0600 *************** *** 87,93 **** ----*/ void sort_folder(MAILSTREAM *stream, MSGNO_S *msgmap, SortOrder new_sort, ! int new_rev, unsigned int flags) { long raw_current, i, j; unsigned long *sort = NULL; --- 87,93 ---- ----*/ void sort_folder(MAILSTREAM *stream, MSGNO_S *msgmap, SortOrder new_sort, ! int new_rev, unsigned int flags, int first) { long raw_current, i, j; unsigned long *sort = NULL; *************** *** 97,102 **** --- 97,111 ---- 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" : "")); *************** *** 526,545 **** * argument also means arrival/reverse. */ int ! decode_sort(char *sort_spec, SortOrder *def_sort, int *def_sort_rev) { char *sep; char *fix_this = NULL; ! int x, reverse; if(!sort_spec || !*sort_spec){ ! *def_sort = SortArrival; *def_sort_rev = 0; return(0); } if(struncmp(sort_spec, "reverse", strlen(sort_spec)) == 0){ ! *def_sort = SortArrival; *def_sort_rev = 1; return(0); } --- 535,554 ---- * argument also means arrival/reverse. */ int ! decode_sort(char *sort_spec, SortOrder *def_sort, int *def_sort_rev, int thread) { char *sep; char *fix_this = NULL; ! int x = 0, reverse; if(!sort_spec || !*sort_spec){ ! *def_sort = thread ? SortThread : SortArrival; *def_sort_rev = 0; return(0); } if(struncmp(sort_spec, "reverse", strlen(sort_spec)) == 0){ ! *def_sort = thread ? SortThread : SortArrival; *def_sort_rev = 1; return(0); } *************** *** 568,574 **** if(ps_global->sort_types[x] == EndofList) return(-1); ! *def_sort = ps_global->sort_types[x]; *def_sort_rev = reverse; return(0); } --- 577,583 ---- if(ps_global->sort_types[x] == EndofList) return(-1); ! *def_sort = ps_global->sort_types[x]; *def_sort_rev = reverse; return(0); } *************** *** 685,691 **** /* set default order */ the_sort_order = ps_global->def_sort; ! sort_is_rev = ps_global->def_sort_rev; if(ps_global->mail_stream && nonempty_patterns(rflags, &pstate)){ for(pat = first_pattern(&pstate); pat; pat = next_pattern(&pstate)){ --- 694,702 ---- /* set default order */ the_sort_order = ps_global->def_sort; ! 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)){ *************** *** 698,706 **** && pat->action->sort_is_set){ the_sort_order = pat->action->sortorder; sort_is_rev = pat->action->revsort; } } sort_folder(ps_global->mail_stream, ps_global->msgmap, ! the_sort_order, sort_is_rev, flags); } --- 709,723 ---- && 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(the_sort_order == SortThread && !(flags & SRT_MAN)) + 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, 1); } diff -rc alpine-2.26/pith/sort.h alpine-2.26.fancy/pith/sort.h *** alpine-2.26/pith/sort.h 2022-06-02 18:14:00.491274749 -0600 --- alpine-2.26.fancy/pith/sort.h 2022-06-02 18:14:51.407149902 -0600 *************** *** 23,29 **** #define refresh_sort(S,M,F) sort_folder((S), (M), mn_get_sort(M), \ ! mn_get_revsort(M), (F)) struct global_sort_data { MSGNO_S *msgmap; --- 23,29 ---- #define refresh_sort(S,M,F) sort_folder((S), (M), mn_get_sort(M), \ ! mn_get_revsort(M), (F), 1) struct global_sort_data { MSGNO_S *msgmap; *************** *** 42,49 **** /* exported prototypes */ char *sort_name(SortOrder); ! void sort_folder(MAILSTREAM *, MSGNO_S *, SortOrder, int, unsigned); ! int decode_sort(char *, SortOrder *, int *); void reset_sort_order(unsigned); --- 42,49 ---- /* exported prototypes */ char *sort_name(SortOrder); ! void sort_folder(MAILSTREAM *, MSGNO_S *, SortOrder, int, unsigned, int); ! int decode_sort(char *, SortOrder *, int *, int); void reset_sort_order(unsigned); diff -rc alpine-2.26/pith/state.c alpine-2.26.fancy/pith/state.c *** alpine-2.26/pith/state.c 2022-06-02 18:14:00.491274749 -0600 --- alpine-2.26.fancy/pith/state.c 2022-06-02 18:14:51.411149892 -0600 *************** *** 71,76 **** --- 71,77 ---- p = (struct pine *)fs_get(sizeof (struct pine)); memset((void *) p, 0, sizeof(struct pine)); + p->thread_def_sort = SortDate; p->def_sort = SortArrival; p->sort_types[0] = SortSubject; p->sort_types[1] = SortArrival; diff -rc alpine-2.26/pith/state.h alpine-2.26.fancy/pith/state.h *** alpine-2.26/pith/state.h 2022-06-02 18:14:00.491274749 -0600 --- alpine-2.26.fancy/pith/state.h 2022-06-02 18:14:51.415149883 -0600 *************** *** 151,156 **** --- 151,158 ---- 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 tcptimeout:1; /* a tcp timeout is in progress */ *************** *** 315,320 **** --- 317,325 ---- EditWhich ew_for_srch_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 -rc alpine-2.26/pith/thread.c alpine-2.26.fancy/pith/thread.c *** alpine-2.26/pith/thread.c 2022-06-02 18:14:00.491274749 -0600 --- alpine-2.26.fancy/pith/thread.c 2022-06-02 18:14:51.415149883 -0600 *************** *** 26,37 **** #include "../pith/mailcmd.h" #include "../pith/ablookup.h" /* * Internal prototypes */ long *sort_thread_flatten(THREADNODE *, MAILSTREAM *, long *, ! char *, long, PINETHRD_S *, unsigned); void make_thrdflags_consistent(MAILSTREAM *, MSGNO_S *, PINETHRD_S *, int); THREADNODE *collapse_threadnode_tree(THREADNODE *); THREADNODE *collapse_threadnode_tree_sorted(THREADNODE *); --- 26,43 ---- #include "../pith/mailcmd.h" #include "../pith/ablookup.h" + static int erase_thread_info = 1; + + typedef struct sizethread_t { + int count; + long pos; + } SIZETHREAD_T; /* * Internal prototypes */ long *sort_thread_flatten(THREADNODE *, MAILSTREAM *, long *, ! char *, long, PINETHRD_S *, unsigned, int, long, long); void make_thrdflags_consistent(MAILSTREAM *, MSGNO_S *, PINETHRD_S *, int); THREADNODE *collapse_threadnode_tree(THREADNODE *); THREADNODE *collapse_threadnode_tree_sorted(THREADNODE *); *************** *** 39,44 **** --- 45,51 ---- THREADNODE *insert_tree_in_place(THREADNODE *, THREADNODE *); unsigned long branch_greatest_num(THREADNODE *, int); long calculate_visible_threads(MAILSTREAM *); + int pine_compare_size_thread(const qsort_t *, const qsort_t *); PINETHRD_S * *************** *** 91,110 **** set_flags_for_thread(MAILSTREAM *stream, MSGNO_S *msgmap, int f, PINETHRD_S *thrd, int v) { PINETHRD_S *nthrd, *bthrd; if(!(stream && thrd && msgmap)) return; set_lflag(stream, msgmap, mn_raw2m(msgmap, thrd->rawno), f, v); ! if(thrd->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(bthrd) set_flags_for_thread(stream, msgmap, f, bthrd, v); } --- 98,119 ---- 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((next = get_next(stream,thrd))){ ! nthrd = fetch_thread(stream, next); if(nthrd) set_flags_for_thread(stream, msgmap, f, nthrd, v); } ! ! if((branch = get_branch(stream, thrd))){ ! bthrd = fetch_thread(stream, branch); if(bthrd) set_flags_for_thread(stream, msgmap, f, bthrd, v); } *************** *** 118,124 **** MESSAGECACHE *mc; PINELT_S *peltp; ! if(!(stream && stream->spare)) return; ps_global->view_skipped_index = 0; --- 127,133 ---- MESSAGECACHE *mc; PINELT_S *peltp; ! if(!(stream && stream->spare) || !erase_thread_info) return; ps_global->view_skipped_index = 0; *************** *** 151,157 **** PINETHRD_S *thrd = NULL; unsigned long msgno, rawno; int un_view_thread = 0; ! long raw_current; char *dup_chk = NULL; --- 160,166 ---- PINETHRD_S *thrd = NULL; unsigned long msgno, rawno; int un_view_thread = 0; ! long raw_current, branch; char *dup_chk = NULL; *************** *** 164,173 **** * way. If the dummy node is at the top-level, then its children are * promoted to the top-level as separate threads. */ ! if(F_ON(F_THREAD_SORTS_BY_ARRIVAL, ps_global)) ! collapsed_tree = collapse_threadnode_tree_sorted(tree); ! else ! collapsed_tree = collapse_threadnode_tree(tree); /* dup_chk is like sort with an origin of 1 */ dup_chk = (char *) fs_get((mn_get_nmsgs(g_sort.msgmap)+1) * sizeof(char)); --- 173,183 ---- * way. If the dummy node is at the top-level, then its children are * promoted to the top-level as separate threads. */ ! collapsed_tree = F_ON(F_ENHANCED_THREAD, ps_global) ! ? copy_tree(tree) ! : (F_ON(F_THREAD_SORTS_BY_ARRIVAL, ps_global) ! ? collapse_threadnode_tree_sorted(tree) ! : collapse_threadnode_tree(tree)); /* dup_chk is like sort with an origin of 1 */ dup_chk = (char *) fs_get((mn_get_nmsgs(g_sort.msgmap)+1) * sizeof(char)); *************** *** 178,184 **** (void) sort_thread_flatten(collapsed_tree, stream, &g_sort.msgmap->sort[1], dup_chk, mn_get_nmsgs(g_sort.msgmap), ! NULL, THD_TOP); /* reset the inverse array */ msgno_reset_isort(g_sort.msgmap); --- 188,194 ---- (void) sort_thread_flatten(collapsed_tree, stream, &g_sort.msgmap->sort[1], dup_chk, mn_get_nmsgs(g_sort.msgmap), ! NULL, THD_TOP, 0, 1L, 0L); /* reset the inverse array */ msgno_reset_isort(g_sort.msgmap); *************** *** 336,347 **** else{ thrd = fetch_head_thread(stream); while(thrd){ /* * 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(thrd->next){ PINETHRD_S *nthrd; --- 346,359 ---- 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 && !get_lflag(stream, NULL,thrd->rawno, MN_COLL)) ! set_lflag(stream, g_sort.msgmap, msgno, MN_CHID, 0); if(thrd->next){ PINETHRD_S *nthrd; *************** *** 355,363 **** MN_COLL)); } ! if(thrd->nextthd) ! thrd = fetch_thread(stream, thrd->nextthd); ! else thrd = NULL; } } --- 367,376 ---- MN_COLL)); } ! while (thrd && top_thread(stream, thrd->rawno) == top ! && thrd->nextthd) ! thrd = fetch_thread(stream, thrd->nextthd); ! if (!(thrd && thrd->nextthd)) thrd = NULL; } } *************** *** 408,414 **** int a_parent_is_collapsed) { PINETHRD_S *nthrd, *bthrd; ! unsigned long msgno; if(!thrd) return; --- 421,427 ---- int a_parent_is_collapsed) { PINETHRD_S *nthrd, *bthrd; ! unsigned long msgno, next, branch; if(!thrd) return; *************** *** 426,433 **** set_lflag(stream, msgmap, msgno, MN_CHID, 0); } ! if(thrd->next){ ! nthrd = fetch_thread(stream, thrd->next); if(nthrd) make_thrdflags_consistent(stream, msgmap, nthrd, a_parent_is_collapsed --- 439,446 ---- set_lflag(stream, msgmap, msgno, MN_CHID, 0); } ! if((next = get_next(stream, thrd))){ ! nthrd = fetch_thread(stream, next); if(nthrd) make_thrdflags_consistent(stream, msgmap, nthrd, a_parent_is_collapsed *************** *** 436,443 **** MN_COLL)); } ! if(thrd->branch){ ! bthrd = fetch_thread(stream, thrd->branch); if(bthrd) make_thrdflags_consistent(stream, msgmap, bthrd, a_parent_is_collapsed); --- 449,456 ---- MN_COLL)); } ! if((branch = get_branch(stream, thrd))){ ! bthrd = fetch_thread(stream, branch); if(bthrd) make_thrdflags_consistent(stream, msgmap, bthrd, a_parent_is_collapsed); *************** *** 484,492 **** long * sort_thread_flatten(THREADNODE *node, MAILSTREAM *stream, long *entry, char *dup_chk, long maxno, ! PINETHRD_S *thrd, unsigned int flags) { ! PINETHRD_S *newthrd = NULL; if(node){ if(node->num > 0L && node->num <= maxno){ /* holes happen */ --- 497,506 ---- long * sort_thread_flatten(THREADNODE *node, MAILSTREAM *stream, long *entry, char *dup_chk, long maxno, ! PINETHRD_S *thrd, unsigned int flags, ! int adopted, long top, long threadno) { ! PINETHRD_S *newthrd = NULL, *save_thread = NULL; if(node){ if(node->num > 0L && node->num <= maxno){ /* holes happen */ *************** *** 494,499 **** --- 508,516 ---- *entry = node->num; dup_chk[node->num] = 1; + if(adopted == 2) + top = node->num; + /* * Build a richer threading structure that will help us paint * and operate on threads and subthreads. *************** *** 502,521 **** if(newthrd){ entry++; if(node->next) entry = sort_thread_flatten(node->next, stream, entry, dup_chk, maxno, ! newthrd, THD_NEXT); if(node->branch) entry = sort_thread_flatten(node->branch, stream, entry, dup_chk, maxno, newthrd, ! (flags == THD_TOP) ? THD_TOP ! : THD_BRANCH); } } } } return(entry); --- 519,569 ---- if(newthrd){ entry++; + if(adopted == 2) + threadno = newthrd->thrdno; + if(adopted){ + newthrd->toploose = top; + newthrd->thrdno = threadno; + } + adopted = adopted ? 1 : 0; if(node->next) entry = sort_thread_flatten(node->next, stream, entry, dup_chk, maxno, ! newthrd, THD_NEXT, adopted, top, threadno); if(node->branch) entry = sort_thread_flatten(node->branch, stream, entry, dup_chk, maxno, 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, dup_chk, + maxno, thrd, THD_TOP, adopted, top, threadno); + adopted = 0; + if(node->branch){ + if(entry){ + long *last_entry = entry; + + do{ + last_entry--; + save_thread = ((PINELT_S *)mail_elt(stream, *last_entry)->sparep)->pthrd; + } while (save_thread->parent != 0L); + entry = sort_thread_flatten(node->branch, stream, entry, dup_chk, + maxno, save_thread, (flags == THD_TOP ? THD_TOP : THD_BRANCH), + adopted, top, threadno); + } + else + entry = sort_thread_flatten(node->branch, stream, entry, dup_chk, + maxno, NULL, THD_TOP, adopted, top, threadno); + } + } } return(entry); *************** *** 784,790 **** */ void collapse_or_expand(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap, ! long unsigned int msgno) { int collapsed, adjust_current = 0; PINETHRD_S *thrd = NULL, *nthrd; --- 832,838 ---- */ void collapse_or_expand(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap, ! long unsigned int msgno, int display) { int collapsed, adjust_current = 0; PINETHRD_S *thrd = NULL, *nthrd; *************** *** 837,843 **** if(!thrd) return; ! collapsed = get_lflag(stream, NULL, thrd->rawno, MN_COLL) && thrd->next; if(collapsed){ msgno = mn_raw2m(msgmap, thrd->rawno); --- 885,891 ---- if(!thrd) return; ! collapsed = this_thread_is_kolapsed(ps_global, stream, msgmap, thrd->rawno); if(collapsed){ msgno = mn_raw2m(msgmap, thrd->rawno); *************** *** 855,867 **** 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)) != NULL) set_thread_subtree(stream, nthrd, msgmap, 1, MN_CHID); clear_index_cache_ent(stream, msgno, 0); } } ! else q_status_message(SM_ORDER, 0, 1, _("No thread to collapse or expand on this line")); --- 903,915 ---- msgno = mn_raw2m(msgmap, thrd->rawno); if(msgno > 0L && msgno <= mn_get_total(msgmap)){ set_lflag(stream, msgmap, msgno, MN_COLL, 1); ! if((thrd->next) && ((nthrd = fetch_thread(stream, thrd->next)) != NULL)) set_thread_subtree(stream, nthrd, msgmap, 1, MN_CHID); clear_index_cache_ent(stream, msgno, 0); } } ! else if(display) q_status_message(SM_ORDER, 0, 1, _("No thread to collapse or expand on this line")); *************** *** 948,965 **** unsigned long count = 0; 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(nthrd) count += count_flags_in_thread(stream, nthrd, flags); } ! if(thrd->branch){ ! bthrd = fetch_thread(stream, thrd->branch); if(bthrd) count += count_flags_in_thread(stream, bthrd, flags); } --- 996,1014 ---- unsigned long 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((next = get_next(stream, thrd))){ ! nthrd = fetch_thread(stream, next); if(nthrd) count += count_flags_in_thread(stream, nthrd, flags); } ! if((branch = get_branch(stream, thrd))){ ! bthrd = fetch_thread(stream, branch); if(bthrd) count += count_flags_in_thread(stream, bthrd, flags); } *************** *** 1047,1066 **** mark_msgs_in_thread(MAILSTREAM *stream, PINETHRD_S *thrd, MSGNO_S *msgmap) { int count = 0; 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(nthrd) count += mark_msgs_in_thread(stream, nthrd, msgmap); } ! if(thrd->branch){ ! bthrd = fetch_thread(stream, thrd->branch); if(bthrd) count += mark_msgs_in_thread(stream, bthrd, msgmap); } --- 1096,1116 ---- 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((next = get_next(stream, thrd))){ ! nthrd = fetch_thread(stream, next); if(nthrd) count += mark_msgs_in_thread(stream, nthrd, msgmap); } ! if((branch = get_branch(stream, thrd))){ ! bthrd = fetch_thread(stream, branch); if(bthrd) count += mark_msgs_in_thread(stream, bthrd, msgmap); } *************** *** 1094,1100 **** /* flags to set or clear */ /* set or clear? */ { ! unsigned long msgno; PINETHRD_S *nthrd, *bthrd; if(!thrd || !stream || thrd->rawno < 1L || thrd->rawno > stream->nmsgs) --- 1144,1150 ---- /* flags to set or clear */ /* set or clear? */ { ! unsigned long msgno, next, branch; PINETHRD_S *nthrd, *bthrd; if(!thrd || !stream || thrd->rawno < 1L || thrd->rawno > stream->nmsgs) *************** *** 1118,1131 **** 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(nthrd) set_thread_lflags(stream, nthrd, msgmap, flags, v); } ! if(thrd->branch){ ! bthrd = fetch_thread(stream, thrd->branch); if(bthrd) set_thread_lflags(stream, bthrd, msgmap, flags, v); } --- 1168,1181 ---- if(msgno > 0L && flags == MN_CHID2 && v == 1) clear_index_cache_ent(stream, msgno, 0); ! if((next = get_next(stream, thrd))){ ! nthrd = fetch_thread(stream, next); if(nthrd) set_thread_lflags(stream, nthrd, msgmap, flags, v); } ! if((branch = get_branch(stream,thrd))){ ! bthrd = fetch_thread(stream, branch); if(bthrd) set_thread_lflags(stream, bthrd, msgmap, flags, v); } *************** *** 1214,1232 **** char to_us = ' '; char branch_to_us = ' '; PINETHRD_S *nthrd, *bthrd; 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(nthrd) to_us = to_us_symbol_for_thread(stream, nthrd, consider_flagged); } if(((consider_flagged && to_us != '*') || (!consider_flagged && to_us != '+')) ! && thrd->branch){ bthrd = fetch_thread(stream, thrd->branch); if(bthrd) branch_to_us = to_us_symbol_for_thread(stream, bthrd, consider_flagged); --- 1264,1283 ---- char to_us = ' '; char branch_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((next = get_next(stream,thrd))){ ! nthrd = fetch_thread(stream, next); if(nthrd) to_us = to_us_symbol_for_thread(stream, nthrd, consider_flagged); } if(((consider_flagged && to_us != '*') || (!consider_flagged && to_us != '+')) ! && (branch = get_branch(stream, thrd))){ bthrd = fetch_thread(stream, thrd->branch); if(bthrd) branch_to_us = to_us_symbol_for_thread(stream, bthrd, consider_flagged); *************** *** 1276,1282 **** break; } ! if(to_us != '+' && resent_to_us(&idata)) to_us = '+'; if(to_us == ' ' && F_ON(F_MARK_FOR_CC,ps_global)) --- 1327,1333 ---- break; } ! if(to_us != '+' && !idata.bogus && resent_to_us(&idata)) to_us = '+'; if(to_us == ' ' && F_ON(F_MARK_FOR_CC,ps_global)) *************** *** 1324,1330 **** set_lflag(stream, msgmap, msgno, flags, v); ! 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); --- 1375,1382 ---- set_lflag(stream, msgmap, msgno, flags, v); ! 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); *************** *** 1364,1371 **** if(rawno) thrd = fetch_thread(stream, rawno); ! if(thrd && thrd->top && thrd->top != thrd->rawno) ! thrd = fetch_thread(stream, thrd->top); if(!thrd) return 0; --- 1416,1423 ---- if(rawno) thrd = fetch_thread(stream, rawno); ! if(thrd && thrd->top && top_thread(stream,thrd->top) != thrd->rawno) ! thrd = fetch_thread(stream, top_thread(stream,thrd->top)); if(!thrd) return 0; *************** *** 1429,1435 **** thrd = fetch_thread(stream, rawno); if(thrd && thrd->top) ! topthrd = fetch_thread(stream, thrd->top); if(!topthrd) return 0; --- 1481,1487 ---- thrd = fetch_thread(stream, rawno); if(thrd && thrd->top) ! topthrd = fetch_thread(stream, top_thread(stream,thrd->top)); if(!topthrd) return 0; *************** *** 1535,1540 **** --- 1587,1593 ---- set_search_bit_for_thread(MAILSTREAM *stream, PINETHRD_S *thrd, SEARCHSET **msgset) { PINETHRD_S *nthrd, *bthrd; + unsigned long next, branch; if(!(stream && thrd)) return; *************** *** 1543,1557 **** && (!(msgset && *msgset) || in_searchset(*msgset, thrd->rawno))) mm_searched(stream, thrd->rawno); ! if(thrd->next){ ! nthrd = fetch_thread(stream, thrd->next); if(nthrd) set_search_bit_for_thread(stream, nthrd, msgset); } ! if(thrd->branch){ ! bthrd = fetch_thread(stream, thrd->branch); if(bthrd) set_search_bit_for_thread(stream, bthrd, msgset); } } --- 1596,2217 ---- && (!(msgset && *msgset) || in_searchset(*msgset, thrd->rawno))) mm_searched(stream, thrd->rawno); ! if((next= get_next(stream, thrd))){ ! nthrd = fetch_thread(stream, next); if(nthrd) set_search_bit_for_thread(stream, nthrd, msgset); } ! if((branch = get_branch(stream, thrd))){ ! bthrd = fetch_thread(stream, branch); if(bthrd) set_search_bit_for_thread(stream, bthrd, msgset); } } + + /* + * 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); + } + + 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 + move_top_thread(MAILSTREAM *stream, MSGNO_S *msgmap, long rawmsgno) + { + mn_set_cur(msgmap,mn_raw2m(msgmap, top_thread(stream, rawmsgno))); + } + + long + top_this_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 thrd->top; + } + + void + move_top_this_thread(MAILSTREAM *stream, MSGNO_S *msgmap, long rawmsgno) + { + mn_set_cur(msgmap,mn_raw2m(msgmap, top_this_thread(stream, rawmsgno))); + } + + int + thread_is_kolapsed(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; + } + + /* this function tells us if the thread (or branch in the case of loose threads) + * is collapsed + */ + + int + this_thread_is_kolapsed(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; + } + + /* + * This function assumes that it is called at a top of a thread in its + * first call + */ + + int + count_this_thread(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(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; + } + + unsigned long + get_branch(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(MAILSTREAM *stream, PINETHRD_S *thrd) + { + return thrd->next; + } + + long + get_length_branch(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; + } + + int pine_compare_size_thread(const qsort_t *a, const qsort_t *b) + { + SIZETHREAD_T *s = (SIZETHREAD_T *) a, *t = (SIZETHREAD_T *) b; + + return s->count == t->count ? s->pos - t->pos : s->count - t->count; + } + + + + void + find_msgmap(MAILSTREAM *stream, MSGNO_S *msgmap, int flags, SortOrder ordersort, unsigned is_rev) + { + long *old_arrival,*new_arrival; + long init_thread, end_thread, current; + long i, j, k; + long tmsg, ntmsg, nthreads; + SIZETHREAD_T *l; + PINETHRD_S *thrd; + + erase_thread_info = 0; + current = mn_m2raw(msgmap, mn_get_cur(msgmap)); + + switch(ordersort){ + case SortSize: + sort_folder(stream, msgmap, SortThread, 0, SRT_VRB, 0); + tmsg = mn_get_total(msgmap) + 1; + + if(tmsg <= 1) + return; + + for (i= 1L, k = 0L; i <= mn_get_total(msgmap); i += count_thread(ps_global, stream, msgmap, msgmap->sort[i]), k++); + l = (SIZETHREAD_T *) fs_get(k*sizeof(SIZETHREAD_T)); + for (j = 0L, i=1L; j < k && i<= mn_get_total(msgmap); ){ + l[j].count = count_thread(ps_global, stream, msgmap, msgmap->sort[i]); + l[j].pos = i; + i += l[j].count; + j++; + } + qsort((void *)l, (size_t) k, sizeof(SIZETHREAD_T), pine_compare_size_thread); + old_arrival = (long *) fs_get(tmsg * sizeof(long)); + for(i = 1L, j = 0; j < k; j++){ /* copy thread of length .count */ + int p; + for(p = 0; p < l[j].count; p++) + old_arrival[i++] = msgmap->sort[l[j].pos + p]; + } + fs_give((void **)&l); + break; + default: + sort_folder(stream, msgmap, ordersort, 0, SRT_VRB, 0); + tmsg = mn_get_total(msgmap) + 1; + + if (tmsg <= 1) + return; + + old_arrival = (long *) fs_get(tmsg * sizeof(long)); + for (i= 1L;(i <= mn_get_total(msgmap)) && (old_arrival[i] = msgmap->sort[i]); i++); + /* sort by thread */ + sort_folder(stream, msgmap, SortThread, 0, SRT_VRB, 0); + break; + + } + + 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); + /* we copy from the bottom, the last one to be filled is new_arrival[1] */ + while (new_arrival[1] == 0){ + int done = 0; + long n; + + init_thread = top_thread(stream, old_arrival[i]); + thrd = fetch_thread(stream, init_thread); + for (n = mn_get_total(msgmap); new_arrival[n] != 0 && !done; n--) + done = (new_arrival[n] == init_thread); + if (!done){ + 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; + for(k = 1L; k <= j; k++) + new_arrival[tmsg - k] = msgmap->sort[end_thread - 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(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(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; + } + } + } + + 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; + } + + /* add more keys to this list */ + int + allowed_thread_key(SortOrder sort) + { + return sort == SortArrival || sort == SortDate + || sort == SortScore || sort == SortThread + || sort == SortSize; + } + diff -rc alpine-2.26/pith/thread.h alpine-2.26.fancy/pith/thread.h *** alpine-2.26/pith/thread.h 2022-06-02 18:14:00.491274749 -0600 --- alpine-2.26.fancy/pith/thread.h 2022-06-02 18:14:51.415149883 -0600 *************** *** 38,43 **** --- 38,44 ---- 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; *************** *** 93,99 **** 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 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); --- 94,100 ---- 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, 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,112 **** int unview_thread(struct pine *, MAILSTREAM *, MSGNO_S *); PINETHRD_S *find_thread_by_number(MAILSTREAM *, MSGNO_S *, long, PINETHRD_S *); void set_search_bit_for_thread(MAILSTREAM *, PINETHRD_S *, SEARCHSET **); ! #endif /* PITH_THREAD_INCLUDED */ --- 108,131 ---- int unview_thread(struct pine *, MAILSTREAM *, MSGNO_S *); PINETHRD_S *find_thread_by_number(MAILSTREAM *, MSGNO_S *, long, PINETHRD_S *); void set_search_bit_for_thread(MAILSTREAM *, PINETHRD_S *, SEARCHSET **); ! 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); ! long top_this_thread(MAILSTREAM *, long); ! long get_length_branch(MAILSTREAM *, long); ! unsigned long get_next(MAILSTREAM *,PINETHRD_S *); ! unsigned long get_branch(MAILSTREAM *,PINETHRD_S *); ! 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 move_prev_thread(struct pine *, MAILSTREAM *, MSGNO_S *, int); ! int move_next_thread(struct pine *, MAILSTREAM *, MSGNO_S *, int); ! int move_next_this_thread(struct pine *, MAILSTREAM *, MSGNO_S *, int); ! void move_top_thread(MAILSTREAM *, MSGNO_S *, long); ! void move_top_this_thread(MAILSTREAM *, MSGNO_S *, long); ! THREADNODE *copy_tree(THREADNODE *); ! int allowed_thread_key(SortOrder sort); #endif /* PITH_THREAD_INCLUDED */ diff -rc alpine-2.26/web/src/alpined.d/alpined.c alpine-2.26.fancy/web/src/alpined.d/alpined.c *** alpine-2.26/web/src/alpined.d/alpined.c 2022-06-02 18:14:00.503274719 -0600 --- alpine-2.26.fancy/web/src/alpined.d/alpined.c 2022-06-02 18:14:51.423149863 -0600 *************** *** 2751,2757 **** init_save_defaults(); break; case V_SORT_KEY: ! decode_sort(wps_global->VAR_SORT_KEY, &wps_global->def_sort, &def_sort_rev); break; case V_VIEW_HDR_COLORS : set_custom_spec_colors(wps_global); --- 2751,2757 ---- init_save_defaults(); break; case V_SORT_KEY: ! decode_sort(wps_global->VAR_SORT_KEY, &wps_global->def_sort, &def_sort_rev, 0); break; case V_VIEW_HDR_COLORS : set_custom_spec_colors(wps_global); *************** *** 6327,6333 **** && mn_get_revsort(sp_msgmap(wps_global->mail_stream)) == reversed)) sort_folder(wps_global->mail_stream, sp_msgmap(wps_global->mail_stream), wps_global->sort_types[i], ! reversed, 0); break; } --- 6327,6333 ---- && mn_get_revsort(sp_msgmap(wps_global->mail_stream)) == reversed)) sort_folder(wps_global->mail_stream, sp_msgmap(wps_global->mail_stream), wps_global->sort_types[i], ! reversed, 0, 1); break; }
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor