home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Unix System Administration Handbook 1997 October
/
usah_oct97.iso
/
news
/
nn.tar
/
nn-6.5.1
/
menu.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-08-17
|
53KB
|
2,355 lines
/*
* (c) Copyright 1990, Kim Fabricius Storm. All rights reserved.
*
* selection mode menu
*/
#include "config.h"
#include "articles.h"
#include "keymap.h"
#include "nn_term.h"
#include "menu.h"
#include "regexp.h"
/* menu.c */
#ifdef __STDC__
struct menu_info;
#endif
static article_number root_article __APROTO((register article_number root));
static article_number next_root_article __APROTO((register article_number root));
static void set_root_if_closed __APROTO((void));
static article_number thread_counters __APROTO((article_number art));
static void cursor_at_id __APROTO((void));
static attr_type closed_attr __APROTO((register struct menu_info *mi, char *cbuf));
static void mark __APROTO((void));
static void toggle __APROTO((void));
static do_auto_kill __APROTO((void));
static int do_auto_select __APROTO((regexp *re, int mode));
static quit_preview __APROTO((int cmd));
static void count_selected_articles __APROTO((void));
static show_articles __APROTO((void));
static int get_k_cmd_1 __APROTO((void));
static int get_k_cmd __APROTO((void));
static repl_attr __APROTO((register article_number first, register article_number last, int old, int new, int update));
static repl_attr_subject __APROTO((int old, int new, int update));
static repl_attr_all __APROTO((int old, int new, int update));
static void get_purpose __APROTO((char *purpose));
static do_consolidation __APROTO((void));
import char *news_lib_directory;
export int echo_prefix_key = 1; /* echo prefix keys */
export int preview_window = 0; /* size of preview window */
export int fmt_linenum = 1; /* menu line format */
export int fmt_rptsubj = 0; /* repeat identical subjects if !0 */
export int novice = 1; /* novice mode -- use extended prompts */
export int long_menu = 0; /* don't put empty lines around menu lines */
export int delay_redraw = 0; /* prompt again if :-command clears screen */
export int slow_mode = 0; /* mark selected articles with *s */
export int re_layout = 0; /* Re: format presentation on menus */
export int collapse_subject = 25; /* collapse long subjects at position */
export int conf_group_entry = 0; /* ask whether group should be entered */
export int conf_entry_limit = 0; /* ask only if more than .. unread */
export int mark_read_skip = 4; /* effect of X command */
export int mark_read_return = 0; /* effect of Z command */
export int mark_next_group = 0; /* effect of N command */
export int show_purpose_mode = 1; /* 0: never, 1: new, 2: always */
export int read_ret_next_page = 0; /* Z returns to next page */
export int consolidated_menu = 0; /* show only root articles */
export int save_closed_mode = 13; /* ask how to save closed subj, dflt all */
export int auto_select_rw = 0; /* select subject read or written */
export int auto_select_closed = 1; /* select all in closed subject */
export int menu_spacing = 0; /* number of screen lines per menu line */
export char *counter_delim_left = "[";
export char *counter_delim_right = "] ";
export int counter_padding = 5; /* counters are padded to align subjects */
export int auto_preview_mode = 0; /* preview rather than select */
export int preview_continuation = 12; /* what to do after preview */
export int preview_mark_read = 1; /* previewed articles are A_READ */
export int select_on_sender = 0; /* find command selects on sender */
export int auto_select_subject = 0; /* auto select articles with same subj. */
export int auto_read_limit = 0; /* ignore auto_read_mode if less articles */
export char delayed_msg[100] = ""; /* give to msg() after redraw */
export int flush_typeahead = 0;
import int also_read_articles;
import int merged_menu;
import int case_fold_search;
import int ignore_fancy_select;
import int kill_file_loaded;
import int new_read_prompt;
import int any_message;
import int enable_stop;
import int alt_cmd_key, in_menu_mode;
import int mouse_y,mouse_x; /*mouse event position */
import int mouse_state;
extern key_type erase_key;
extern int get_from_macro;
extern group_completion();
static regexp *regular_expr = NULL;
static int firstl; /* first menu line */
static article_number firsta; /* first article on menu (0 based) */
static article_number nexta; /* first article on next menu */
static int cura; /* current article */
static int next_cura; /* article to become cura if >= 0 */
static int numa; /* no of articles on menu - 1 */
static attr_type last_attr;
#define INTERVAL1 ('z' - 'a' + 1)
#define INTERVAL2 ('9' - '0' + 1)
char ident[] = "abcdefghijklmnopqrstuvwxyz0123456789";
char attributes[30] = " .,+=#! **"; /* Corresponds to A_XXXX in data.h */
static int menu_length; /* current no of line on menu */
static int menu_articles; /* current no of articles on menu */
static struct menu_info { /* info for each menu line */
int mi_cura; /* cura corresponding to this menu line */
int mi_total; /* total number of articles with this subject */
int mi_unread; /* no of unread articles with this subject */
int mi_selected; /* no of selected articles with this subject */
int mi_left; /* no of articles marked for later viewing */
int mi_art_id; /* article id (for mark()) */
} menu_info[INTERVAL1+INTERVAL2];
static struct menu_info *art_id_to_mi[INTERVAL1+INTERVAL2];
#define IS_VISIBLE(ah) (((ah)->flag & (A_CLOSED | A_ROOT_ART)) != A_CLOSED)
int
prt_replies(level)
int level;
{
int re;
if (level == 0) return 0;
re = level & 0x80;
level &= 0x7f;
switch (re_layout) {
case 1:
if (!re) return 0;
so_printf(">");
return 1;
case 2:
switch (level) {
case 0:
return 0;
case 1:
so_printf(">");
return 1;
default:
so_printf("%d>", level);
return level < 10 ? 2 : 3;
}
case 3:
so_printf("Re: ");
return 4;
case 4:
if (level == 0 && re) level++;
break;
}
if (level < 10) {
so_printf("%-.*s", level, ">>>>>>>>>");
return level;
}
so_printf(">>>%3d >>>>", level);
return 11;
}
static article_number root_article(root)
register article_number root;
{
register article_header *ah = articles[root];
if (ah->flag & A_ROOT_ART)
return root;
while (root > 0) {
if (articles[root]->flag & A_ROOT_ART) break;
root--;
}
return root;
}
static article_number next_root_article(root)
register article_number root;
{
while (++root < n_articles)
if (articles[root]->flag & A_ROOT_ART) break;
return root;
}
static void
set_root_if_closed()
{
if (articles[firsta + cura]->flag & A_CLOSED)
cura = root_article(firsta + cura) - firsta;
}
/*
* count info for thread containing article #art (must be on menu!)
* returns article number for next root article
*/
static article_number thread_counters(art)
article_number art;
{
register struct menu_info *mi;
register article_number n;
int total, unread, selected, left;
if (!(articles[art]->flag & A_CLOSED)) return art + 1;
total = unread = selected = left = 0;
n = art = root_article(art);
while (n < n_articles) {
if (articles[n]->attr == 0) unread++;
else if (articles[n]->attr & A_SELECT) selected++;
else if (articles[n]->attr == A_LEAVE_NEXT) left++;
total++;
if (++n == n_articles) break;
if (articles[n]->flag & A_ROOT_ART) break;
}
unread += selected;
mi = menu_info + articles[art]->menu_line;
mi->mi_total = total;
mi->mi_unread = unread;
mi->mi_selected = selected;
mi->mi_left = left;
return n;
}
static void
cursor_at_id()
{
gotoxy(0, firstl + articles[firsta + cura]->menu_line);
fl; /* place cursor at current article id */
save_xy();
}
static attr_type closed_attr(mi, cbuf)
register struct menu_info *mi;
char *cbuf;
{
char lft[10], sel[10], unr[10];
attr_type cattr;
if (mi->mi_total == mi->mi_left)
cattr = A_LEAVE_NEXT;
else if (mi->mi_unread == 0)
cattr = A_READ;
else if (mi->mi_total == mi->mi_selected)
cattr = A_SELECT;
else if (auto_select_closed == 1 && mi->mi_unread == mi->mi_selected)
cattr = A_SELECT;
else if (mi->mi_selected)
cattr = A_KILL; /* pseudo flag -> highlight cbuf */
else
cattr = 0;
lft[0] = sel[0] = unr[0] = NUL;
if (mi->mi_left && mi->mi_left < mi->mi_unread)
sprintf(lft, "%d,", mi->mi_left);
if (mi->mi_selected && mi->mi_selected < mi->mi_unread)
sprintf(sel, "%d/", mi->mi_selected);
if (mi->mi_unread && mi->mi_unread < mi->mi_total)
sprintf(unr, "%d:", mi->mi_unread);
sprintf(cbuf, "%s%s%s%d", lft, sel, unr, mi->mi_total);
return cattr;
}
static int subj_indent;
static void
mark()
{
register article_header *ah;
register struct menu_info *mi;
int lno, lnum, lsubj, lname;
int pad;
char cbuf[80];
attr_type cattr = 0;
ah = articles[firsta + cura];
if (!IS_VISIBLE(ah)) return;
last_attr = ah->attr;
if (ah->disp_attr == A_NOT_DISPLAYED) {
mi = &menu_info[ah->menu_line];
lno = firstl + ah->menu_line;
gotoxy(0, lno);
tputc(ident[mi->mi_art_id]);
cattr = closed_attr(mi, cbuf);
goto print_line;
}
if (cura < 0 || cura > numa) return;
lno = firstl + ah->menu_line;
if (ah->flag & A_CLOSED) {
struct menu_info old;
char oldctr[80];
mi = &menu_info[ah->menu_line];
old = *mi;
thread_counters(firsta + cura);
if (old.mi_total == mi->mi_total &&
old.mi_selected == mi->mi_selected &&
old.mi_left == mi->mi_left &&
old.mi_unread == mi->mi_unread) return;
cattr = closed_attr(mi, cbuf);
if (!slow_mode) goto print_line;
closed_attr(&old, oldctr);
if (strcmp(cbuf, oldctr)) goto print_line;
last_attr = cattr;
}
if (last_attr == ah->disp_attr) return;
/* A_AUTO_SELECT will not occur here! */
if (!slow_mode)
if (last_attr == A_SELECT) {
if ((ah->disp_attr & A_SELECT) == 0) goto print_line;
} else {
if (ah->disp_attr & A_SELECT) goto print_line;
}
gotoxy(1, lno);
tputc(attributes[ah->attr]);
goto out;
print_line:
/* menu line formats:
1 3 8 10 20 22 xx
: : : : : : :
-1 id name:8 subject
0 id name subject +lines
1 id name lines subject
2 id lines subject
3 id subject
4 id subject (or as 1 if short subject)
*/
if ((ah->flag & A_CLOSED) == 0) {
cattr = ah->attr;
cbuf[0] = NUL;
}
if (fmt_linenum > 4) fmt_linenum = 1;
if (!slow_mode && (cattr & A_SELECT)) {
if (so_gotoxy(1, lno, 1) == 0)
tputc(attributes[A_SELECT]);
} else {
gotoxy(1, lno);
tputc(cattr == A_KILL ? ' ' : attributes[cattr]);
}
if (ah->lines < 10) lnum = 1; else
if (ah->lines < 100) lnum = 2; else
if (ah->lines < 1000) lnum = 3; else
if (ah->lines < 10000) lnum = 4; else lnum = 5;
lsubj = Columns - cookie_size - 2; /* ident char + space */
switch (fmt_linenum) {
case -1:
lsubj -= 9;
so_printf("%-8.8s ", ah->sender);
goto no_counters;
case 0:
lsubj -= NAME_LENGTH + 1 + 2 + lnum; /* name. .subj. +.lines */
so_printf("%-*s ", NAME_LENGTH, ah->sender);
break;
case 4:
if ((int)ah->subj_length > (lsubj - NAME_LENGTH - 5))
if (fmt_rptsubj || lno == firstl || (ah->flag & A_SAME) == 0) {
so_printf(" ");
lsubj -= 2;
break;
}
/* else use layout 1, so fall thru */
/* FALL THRU */
case 1:
lsubj -= NAME_LENGTH + 5;
/* name.lines. .subj (name may be shortened) */
lname = NAME_LENGTH + 2 - lnum;
so_printf("%-*.*s ", lname, lname, ah->sender);
so_printf(ah->lines >= 0 ? "%d " : "? ", ah->lines);
break;
case 2:
lsubj -= 6;
so_printf(ah->lines >=0 ? "%5d " : " ? ", ah->lines);
break;
case 3:
break;
}
if (cbuf[0]) {
so_printf("%s", counter_delim_left);
if (cattr == A_KILL) so_gotoxy(-1, -1, 0);
so_printf("%s", cbuf);
if (cattr == A_KILL) so_end();
so_printf("%s", counter_delim_right);
pad = strlen(cbuf) + strlen(counter_delim_left) + strlen(counter_delim_right);
if (cattr == A_KILL) pad += cookie_size * 2;
lsubj -= pad > subj_indent ? pad : subj_indent;
pad = subj_indent - pad;
} else {
lsubj -= subj_indent;
pad = subj_indent;
}
if (pad > 0) {
if (pad > 20) pad = 20;
so_printf(" "+20-pad);
}
no_counters:
if (!fmt_rptsubj && lno > firstl && ah->flag & A_SAME) {
if (ah->replies == 0 || prt_replies(ah->replies) == 0)
so_printf("-");
} else {
lsubj -= prt_replies(ah->replies);
if (lsubj >= (int)ah->subj_length)
so_printf("%s", ah->subject);
else
if (collapse_subject < 0)
so_printf("%-.*s", lsubj, ah->subject);
else {
if (collapse_subject > 0)
so_printf("%-.*s", collapse_subject, ah->subject);
so_printf("<>%s", ah->subject + ah->subj_length - lsubj + collapse_subject + 2);
}
}
if (fmt_linenum == 0)
so_printf(ah->lines >= 0 ? " +%d" : " +?", ah->lines);
so_end();
if ((ah->flag & A_CLOSED) && lsubj > (int)ah->subj_length)
clrline_noflush();
out:
ah->disp_attr = last_attr;
return;
}
static void
toggle()
{
last_attr = articles[firsta + cura]->attr =
articles[firsta + cura]->attr & A_SELECT ? 0 : A_SELECT;
}
static int
do_auto_kill()
{
register article_number i;
register article_header *ah, **ahp;
int any = 0;
for (i = 0, ahp = articles; i < n_articles; i++, ahp++) {
ah = *ahp;
if (auto_select_article(ah, 0)) {
ah->attr = A_KILL;
any = 1;
}
}
return any;
}
/*
* perform auto selections that are not already selected
* if article is in range firsta..firsta+numa (incl) mark article
*/
static int
do_auto_select(re, mode)
regexp *re;
int mode;
{
register article_number i;
register article_header *ah, **ahp;
int count = 0, o_cura, should_mark;
if (mode == 1 && re == NULL)
if (!kill_file_loaded && !init_kill()) return 0;
o_cura = cura;
should_mark = 0;
/*
* note: this code assumes that a visible article will be found
* before anything is marked
*/
for (i = 0, ahp = articles; i < n_articles; i++, ahp++) {
ah = *ahp;
if (IS_VISIBLE(ah)) {
if (should_mark) {
mark();
should_mark = 0;
}
cura = i - firsta;
}
if (re != NULL) {
if (!regexec_cf(re, select_on_sender ? ah->sender : ah->subject)) continue;
} else
if (!auto_select_article(ah, mode)) continue;
count++;
if (ah->attr & A_SELECT) continue;
ah->attr = A_SELECT;
if (firsta <= i && i <= (firsta+numa))
should_mark = 1;
}
if (should_mark) mark();
if (count)
msg("Selected %d article%s", count, plural((long)count));
else
msg("No selections");
cura = o_cura;
return 0;
}
static int
quit_preview(cmd)
int cmd;
{
int op;
if ((firsta + cura) >= n_articles) return 1;
op = preview_continuation;
if (cmd == MC_PREVIEW_NEXT) op /= 10;
op %= 10;
switch (op) {
case 0:
return 1;
case 1:
return 0;
case 2:
return articles[firsta+cura]->flag & A_ROOT_ART;
}
return 0;
}
export long n_selected;
export int show_art_next_invalid;
static void
count_selected_articles()
{
register article_number cur;
n_selected = 0;
for (cur = 0; cur < n_articles; cur++) {
if (articles[cur]->attr & A_SELECT) n_selected++;
}
}
static int
show_articles()
{
register article_number cur, next;
register article_header *ah;
article_number elim_list[1];
register int mode;
int cmd, prev = -1, again;
attr_type o_attr;
do {
for (cur = 0; cur < n_articles; cur++) {
if (articles[cur]->attr & A_SELECT) break;
}
while (cur < n_articles) {
for (next = cur+1; next < n_articles; next++) {
if (articles[next]->attr & A_SELECT) break;
}
show_art_next_invalid = 0;
show:
ah = articles[cur];
o_attr = ah->attr;
ah->attr = 0;
if (auto_select_rw && !ignore_fancy_select &&
!auto_select_article(ah,1))
enter_kill_file(current_group,ah->subject,6,30);
if (new_read_prompt)
count_selected_articles();
mode = 0;
if (prev >= 0) mode |= MM_PREVIOUS;
if (next == n_articles) mode |= MM_LAST_SELECTED;
if ((cur + 1) >= n_articles) mode |= MM_LAST_ARTICLE;
if (cur == 0) mode |= MM_FIRST_ARTICLE;
cmd = more(ah, mode, 0);
switch (cmd) {
case MC_DO_KILL:
if (do_auto_kill()) {
elim_list[0] = next;
elim_articles(elim_list, 1);
cur = elim_list[0];
/* if next was n_articles, cur will be 0 */
if (cur >= n_articles || cur < 0
|| (articles[cur]->attr & A_SELECT) == 0)
cur = n_articles;
continue;
}
break;
case MC_DO_SELECT:
break;
case MC_PREV:
ah->attr = o_attr;
if (prev == next) break;
next = cur; cur = prev; prev = next;
goto show;
case MC_NEXTSUBJ:
ah->attr = A_READ;
for (next = cur+1; next < n_articles; next++) {
if ((ah = articles[next])->flag & A_ROOT_ART) break;
ah->attr = A_READ;
}
for (; next < n_articles; next++) {
if (articles[next]->attr & A_SELECT) break;
}
break;
case MC_ALLSUBJ:
ah->attr = A_READ;
for (next = cur+1; next < n_articles; next++) {
ah = articles[next];
if (ah->flag & A_ROOT_ART) break;
ah->attr = A_SELECT;
}
for (next = cur+1; next < n_articles; next++)
if (articles[next]->attr & A_SELECT) break;
break;
case MC_MENU:
ah->attr = o_attr;
if (nexta - firsta < n_articles) {
/* Keep a little article context by making the */
/* current article go on menu line 6 if possible */
if (IS_VISIBLE(articles[cur]))
firsta = cur;
else
firsta = root_article(cur);
for (next = 0; firsta > 0 && next < 5; next++) {
firsta--;
if (!IS_VISIBLE(articles[firsta]))
firsta = root_article(firsta);
}
}
next_cura = cur - firsta;
return MC_MENU;
case MC_NEXT:
if (ah->attr == 0) /* Not set by more (sufficient ?!?!) */
ah->attr = A_READ;
break;
case MC_BACK_ART:
ah->attr = o_attr ? o_attr : A_SEEN;
next = cur - 1;
break;
case MC_FORW_ART:
ah->attr = o_attr ? o_attr : A_SEEN;
next = cur + 1;
break;
case MC_NEXTGROUP:
case MC_REENTER_GROUP:
case MC_QUIT:
ah->attr = o_attr;
return cmd;
case MC_READGROUP:
for (cur = 0; cur < n_articles; cur++) {
ah = articles[cur];
if (ah->attr == 0 || (ah->attr & A_SELECT))
ah->attr = A_READ;
}
return MC_NEXTGROUP;
}
if (show_art_next_invalid)
for (next = cur+1; next < n_articles; next++) {
if (articles[next]->attr & A_SELECT) break;
}
prev = cur; cur = next;
}
for (cur = 0; cur < n_articles; cur++)
if (articles[cur]->attr & A_SELECT) break;
again = 0;
if (cur < n_articles) continue;
for (cur = 0; cur < n_articles; cur++) {
ah = articles[cur];
if (ah->attr == A_LEAVE) {
if (again == 0) {
prompt("Show left over articles again now? ");
if (yes(0) <= 0) break;
}
ah->attr = A_SELECT;
again++;
}
}
if (again > 1)
sprintf(delayed_msg, "Showing %ld articles again", again);
} while (again);
return MC_READGROUP;
}
static int article_id;
static int cur_key;
static int is_k_select; /* set when K_ARTICLE_ID was really K_SELECT */
#define MOUSE (mouse_y >= 0)
static int mouse_map(map)
int map;
{
/* remap mouse functions back into normal functions */
if (map == K_M_SELECT) {
map = K_ARTICLE_ID;
} else
if (map == K_M_PREVIEW) {
map = K_PREVIEW;
} else
if (map == K_M_SELECT_SUBJECT) {
map = K_SELECT_SUBJECT;
} else
if (map == K_M_SELECT_RANGE) {
map = K_SELECT_RANGE;
} else
return map;
/* deal with mouse article selection */
if (MOUSE) {
if ((mouse_y >= firstl) && (mouse_y <= firstl + menu_length - 1)){
article_id = mouse_y - firstl;
article_id = art_id_to_mi[article_id]->mi_cura;
}
}
return map;
}
static int get_k_cmd_1()
{
register int c, map;
int *key_map = menu_key_map;
if (flush_typeahead) flush_input();
loop:
article_id = -1;
if ((c = get_c()) & GETC_COMMAND) {
cur_key = K_interrupt;
map = c & ~GETC_COMMAND;
} else {
cur_key = c;
map = key_map[c];
}
if (s_hangup) map = K_QUIT;
if (map & K_PREFIX_KEY) {
key_map = keymaps[map & ~K_PREFIX_KEY].km_map;
if (echo_prefix_key) msg("%s", key_name(cur_key));
goto loop;
}
is_k_select = 0;
if (map == K_SELECT) {
map = K_ARTICLE_ID;
article_id = cura;
is_k_select = 1;
} else
if (map & K_ARTICLE_ID) {
article_id = map & ~K_ARTICLE_ID;
map = K_ARTICLE_ID;
if (article_id < 0 || article_id >= menu_articles) {
ding();
goto loop;
}
article_id = art_id_to_mi[article_id]->mi_cura;
} else
map = mouse_map(map);
if (any_message && map != K_LAST_MESSAGE) clrmsg(-1);
return map;
}
static int get_k_cmd()
{
register int map;
map = get_k_cmd_1();
if (map & K_MACRO)
map = orig_menu_map[cur_key];
return map;
}
char *pct(start, end, first, last)
long start, end, first, last;
{
long n = end - start;
static char buf[16];
char *fmt;
if (first <= start || n <= 0)
if (last >= end || n <= 0)
return "All";
else
fmt = "Top %d%%";
else
if (last >= end)
return "Bot";
else
fmt = "%d%%";
sprintf(buf, fmt, ((last - start) * 100)/n);
return buf;
}
static int
repl_attr(first, last, old, new, update)
register article_number first, last;
register attr_type old, new;
int update;
{
int any;
register article_header *ah;
article_number ocura = cura;
if (new == old) return 0;
if (new == A_KILL) update = 0;
any = 0;
cura = -1;
while (first < last) {
ah = articles[first];
if (cura >= 0 && ah->flag & A_ROOT_ART) {
set_root_if_closed();
mark();
cura = -1;
}
if (old == A_KILL || ah->attr == old) {
ah->attr = new;
if (update && first >= firsta && first < nexta) {
cura = first - firsta;
if ((ah->flag & A_CLOSED) == 0) {
mark();
cura = -1;
}
}
any = 1;
}
first++;
}
if (cura >= 0) {
set_root_if_closed();
mark();
}
cura = update ? last - firsta : ocura;
return any;
}
static int
repl_attr_subject(old, new, update)
attr_type old, new;
int update;
{
int f, l;
f = root_article(firsta+cura);
l = next_root_article(firsta+cura);
if (old == A_SELECT)
(void) repl_attr(f, l, A_AUTO_SELECT, A_SELECT, update);
return repl_attr(f, l, old, new, update);
}
static int
repl_attr_all(old, new, update)
attr_type old, new;
int update;
{
return repl_attr((article_number)0, n_articles, old, new, update);
}
static void
get_purpose(purpose)
char *purpose;
{
#ifdef CACHE_PURPOSE
register char *cp;
extern char *purp_lookup();
cp = purp_lookup(current_group->group_name);
strncpy(purpose, cp, 76);
return;
#else
FILE *f;
char line[256], *group;
register char *cp, *pp;
register int len;
if (current_group == NULL) return;
if ((current_group->master_flag & M_VALID) == 0) return;
if (current_group->group_flag & G_FAKED) return;
if ((f = open_purpose_file()) == NULL) return;
group = current_group->group_name;
len = current_group->group_name_length;
while (fgets(line, 256, f) != NULL) {
if (!isascii(line[len]) || !isspace(line[len])) continue;
if (strncmp(line, group, len)) continue;
cp = line + len;
while (*cp && isspace(*cp)) cp++;
for (pp = purpose, len = 76; --len >= 0 && *cp && *cp != NL; )
*pp++ = *cp++;
*pp = NUL;
}
#endif /* CACHE_PURPOSE */
}
/*
* bypass_consolidation may be set to temporarily overrule the global
* consolidated_menu variable:
* 1: don't consolidate (e.g. for G=... )
* 2: do consolidate
* 3: use consolidated_mode
*/
export int bypass_consolidation = 0;
static int cur_bypass = 0; /* current bypass status (see below) */
static int
do_consolidation()
{
int consolidate;
switch (bypass_consolidation) {
case 0:
break;
case 1:
cur_bypass = -1; /* no consolidation */
break;
case 2:
cur_bypass = 1; /* force consolidation */
break;
case 3:
cur_bypass = 0; /* reset bypass to use consolidated_menu */
break;
}
bypass_consolidation = 0;
if (cur_bypass)
consolidate = cur_bypass > 0;
else
consolidate = consolidated_menu;
if (consolidate)
for (nexta = 0; nexta < n_articles; nexta++)
articles[nexta]->flag |= A_CLOSED;
else
for (nexta = 0; nexta < n_articles; nexta++)
articles[nexta]->flag &= ~A_CLOSED;
return consolidate;
}
int
menu(print_header)
fct_type print_header;
{
register k_cmd, cur_k_cmd;
register article_header *ah;
register struct menu_info *mi;
int consolidate, o_bypass;
int last_k_cmd;
int menu_cmd = 0, temp;
int save_selected;
article_number last_save;
attr_type orig_attr, junk_attr;
int doing_unshar, did_unshar, junk_prompt;
char *fname, *savemode;
int maxa; /* max no of articles per menu page */
article_number o_firsta, temp1 = 0, temp2;
int o_mode; /* for recursive calls */
static menu_level = 0;
char purpose[80], pr_fmt[60];
article_number elim_list[3];
int entry_check;
int auto_read;
long o_selected;
#define menu_return(cmd) \
{ menu_cmd = (cmd); goto menu_exit; }
flush_input();
o_firsta = firsta;
o_mode = in_menu_mode;
o_selected = n_selected;
in_menu_mode = 1;
menu_level++;
if (menu_level == 1) {
if ((current_group->group_flag & G_COUNTED)
&& n_articles != current_group->unread_count) {
add_unread(current_group, -1);
current_group->unread_count = n_articles;
add_unread(current_group, 0);
}
entry_check = conf_group_entry && n_articles > conf_entry_limit;
auto_read = auto_read_limit < 0 || n_articles <= auto_read_limit;
} else {
entry_check = 0;
auto_read = 0;
}
sprintf(pr_fmt,
menu_level == 1 ?
"\1\2-- SELECT %s-----%%s-----\1" :
"\1\2-- SELECT %s-----%%s-----<%s%d>--\1",
novice ? "-- help:? " : "",
novice ? "level " : "",
menu_level);
purpose[0] = NUL;
if (!merged_menu)
switch (show_purpose_mode) {
case 0: break;
case 1: if ((current_group->group_flag & G_NEW) == 0) break;
case 2: get_purpose(purpose);
if (purpose[0]) strcpy(delayed_msg, purpose);
}
o_bypass = cur_bypass;
cur_bypass = 0;
consolidate = do_consolidation();
firsta = 0;
while (firsta < n_articles && articles[firsta]->attr == A_SEEN)
firsta++;
if (firsta == n_articles) firsta = 0;
next_cura = -1;
cur_k_cmd = K_UNBOUND;
#ifdef HAVE_JOBCONTROL
#define REDRAW_CHECK if (s_redraw) goto do_redraw
do_redraw:
/* safe to clear here, because we are going to redraw anyway */
s_redraw = 0;
#else
#define REDRAW_CHECK
#endif
redraw:
s_keyboard = 0;
empty_menu_hack: /* do: "s_keyboard=1; goto empty_menu_hack;" */
if (!slow_mode) s_keyboard = 0;
nexta = firsta;
clrdisp();
if (entry_check) {
prompt_line = firstl = CALL(print_header)();
prompt("\1Enter?\1 ");
if ((temp = yes(0)) <= 0) {
if (temp < 0) {
prompt("\1Mark as read?\1 ");
if ((temp = yes(0)) < 0) menu_return(ME_QUIT);
if (temp > 0) repl_attr_all(A_KILL, A_READ, 0);
}
menu_return(ME_NEXT);
}
gotoxy(0, firstl);
clrline();
}
if (auto_read) {
auto_read = entry_check = 0;
if (repl_attr_all(0, A_AUTO_SELECT, 0)) {
k_cmd = K_READ_GROUP_UPDATE;
if (purpose[0])
strcpy(delayed_msg, purpose);
else
sprintf(delayed_msg, "Entering %s, %ld articles",
current_group->group_name, (long)n_articles);
goto do_auto_read;
}
}
if (!entry_check)
firstl = CALL(print_header)();
entry_check = 0;
maxa = Lines - preview_window - firstl - 2;
if (!long_menu) firstl++, maxa -= 2;
if (maxa > (INTERVAL1 + INTERVAL2))
maxa = INTERVAL1 + INTERVAL2;
nextmenu:
no_raw();
gotoxy(0, firstl);
clrpage();
if (articles[nexta]->flag & A_CLOSED)
nexta = root_article(nexta);
firsta = nexta;
cura = 0;
REDRAW_CHECK;
menu_length = 0;
menu_articles = 0;
goto draw_menu;
partial_redraw:
next_cura = cura;
partial_redraw_nc:
nexta = firsta + cura;
menu_length = articles[nexta]->menu_line;
menu_articles = menu_info[menu_length].mi_art_id;
gotoxy(0, firstl + menu_length);
clrpage();
draw_menu:
subj_indent = consolidate ? counter_padding : 0;
if (!s_keyboard) {
int first_menu_line = menu_length;
mi = menu_info + menu_length;
while (nexta < n_articles) {
REDRAW_CHECK;
ah = articles[nexta];
if (ah->flag & A_HIDE) {
ah->menu_line = menu_length; /* just in case.... */
continue;
}
if (menu_length > first_menu_line) {
switch (menu_spacing) {
case 0:
break;
case 1:
if ((ah->flag & A_ROOT_ART) == 0) break;
/* XXX: bug? Another fall? */
case 2:
menu_length++;
mi++;
break;
}
if (menu_length >= maxa) break;
}
ah->menu_line = menu_length;
art_id_to_mi[menu_articles] = mi;
mi->mi_art_id = menu_articles++;
mi->mi_cura = cura = nexta - firsta;
if (ah->flag & A_CLOSED) { /* skip rest of thread */
nexta = thread_counters(nexta);
if (nexta == firsta + cura + 1)
ah->flag &= ~A_CLOSED;
else {
article_number tmpa = firsta + cura;
while (++tmpa < nexta)
articles[tmpa]->menu_line = menu_length;
}
} else
nexta++;
ah->disp_attr = A_NOT_DISPLAYED;
mark();
if (++menu_length >= maxa) break;
mi++;
}
}
if (menu_length > maxa) menu_length = maxa;
fl;
s_keyboard = 0;
prompt_line = firstl + menu_length;
if (!long_menu || menu_length < maxa) prompt_line++;
numa = nexta - firsta - 1;
if (numa < 0) prompt_line++;
/* Changed by Stefan Schwarz (stefans@bauv.unibw-muenchen.de Nov. 17, 1992 */
if (firsta + next_cura >= nexta) next_cura = -1;
/* End of changes*/
if (next_cura >= 0) {
cura = next_cura;
set_root_if_closed();
next_cura = -1;
} else {
cura = 0;
for (article_id = firsta; cura < numa; article_id++, cura++)
{
if ((articles[article_id]->attr & A_SELECT) == 0) break; /*???*/
if (!IS_VISIBLE(articles[article_id])) continue;
}
if (!IS_VISIBLE(articles[article_id]))
cura = root_article(article_id) - firsta;
}
build_prompt:
nn_raw();
Prompt:
prompt(pr_fmt,
pct(0L, (long)(n_articles-1), (long)firsta, (long)(firsta+numa)));
if (delayed_msg[0] != NUL) {
msg(delayed_msg);
delayed_msg[0] = NUL;
}
same_prompt:
if (cura < 0 || cura > numa) cura = 0;
if (!IS_VISIBLE(articles[firsta+cura])) {
cura = next_root_article(firsta + cura) - firsta;
if (cura > numa) cura = 0;
}
if (numa >= 0) {
cursor_at_id();
}
last_k_cmd = cur_k_cmd;
get_next_k_cmd:
k_cmd = get_k_cmd_1();
alt_key:
if (k_cmd & K_MACRO) {
m_invoke(k_cmd & ~K_MACRO);
goto get_next_k_cmd;
}
#define STATE(state) {k_cmd = state; goto new_state;}
/* mouse clicks on top or bottom prompt bars */
#define MOUSE_MENU \
if (MOUSE) { \
if (mouse_y > firstl + menu_length ) { \
STATE(K_CONTINUE); \
} else if (mouse_y == firstl + menu_length ) { \
STATE(K_UNBOUND); \
} else if (mouse_y < firstl - 1) { \
if (firsta > 0) { \
STATE(K_PREV_PAGE); \
} else { \
STATE(K_PREVIOUS); \
} \
} else if (mouse_y == firstl - 1) { \
STATE(K_UNBOUND); \
} \
}
new_state:
switch (cur_k_cmd = k_cmd) {
case K_UNBOUND:
ding();
flush_input();
/* FALL THRU */
case K_INVALID:
goto same_prompt;
case K_REDRAW:
next_cura = cura;
goto redraw;
case K_LAST_MESSAGE:
msg((char *)NULL);
goto same_prompt;
case K_HELP:
if (numa < 0) goto nextmenu; /* give specific help here */
display_help("menu");
goto redraw;
case K_SHELL:
if (group_file_name) *group_file_name = NUL;
if (shell_escape()) goto redraw;
goto Prompt;
case K_VERSION:
prompt(P_VERSION);
goto same_prompt;
case K_EXTENDED_CMD:
temp = consolidated_menu;
switch (alt_command()) {
case AC_UNCHANGED:
goto same_prompt;
case AC_QUIT:
menu_return( ME_QUIT );
case AC_PROMPT:
goto Prompt;
case AC_REORDER:
firsta = 0;
consolidate = do_consolidation();
goto redraw;
case AC_REDRAW:
if (temp != consolidated_menu)
consolidate = do_consolidation();
goto redraw;
case AC_KEYCMD:
k_cmd = alt_cmd_key;
goto alt_key;
case AC_REENTER_GROUP:
menu_return(ME_REENTER_GROUP);
}
/* XXX: bug? fall */
case K_QUIT:
menu_return(ME_QUIT);
case K_M_TOGGLE:
if (mouse_state) {
xterm_mouse_off();
mouse_state = 0;
} else {
xterm_mouse_on();
mouse_state = 1;
}
goto Prompt;
case K_CANCEL:
savemode = "Cancel";
fname = "";
goto cancel1;
case K_SAVE_NO_HEADER:
case K_SAVE_SHORT_HEADER:
case K_SAVE_FULL_HEADER:
case K_PRINT:
case K_UNSHAR:
case K_PATCH:
case K_UUDECODE:
if (numa < 0) goto nextmenu;
fname = init_save(k_cmd, &savemode);
if (fname == NULL) goto Prompt;
cancel1:
enable_stop = 0;
save_selected = 0;
doing_unshar = k_cmd == K_UNSHAR || k_cmd == K_PATCH;
did_unshar = 0;
m_startinput();
if (novice)
msg(" * selected articles on this page, + all selected articles");
while (!save_selected && !did_unshar) {
prompt("\1%s\1 %.*s Article (* +): ",
savemode, Columns - 25, fname);
k_cmd = get_k_cmd();
if (k_cmd == K_SELECT_SUBJECT) {
save_selected = 1;
cura = 0;
article_id = firsta;
last_save = firsta + numa;
} else
if (k_cmd == K_AUTO_SELECT) {
save_selected = 1;
cura = -firsta;
article_id = 0;
last_save = n_articles - 1;
} else
if (k_cmd == K_ARTICLE_ID) {
cura = article_id;
article_id += firsta;
last_save = article_id;
if (articles[article_id]->flag & A_CLOSED) {
int n = save_closed_mode % 10;
if (article_id == n_articles - 1)
goto save_it;
if (articles[article_id + 1]->flag & A_ROOT_ART)
goto save_it;
if (save_closed_mode >= 10) {
prompt("\1%s thread\1 (r)oot (s)elected (u)nread (b)oth (a)ll (%c)",
savemode, "rsuba"[n]);
switch (get_c()) {
case 'r': n = 0; break;
case 's': n = 1; break;
case 'u': n = 2; break;
case 'b': n = 3; break;
case 'a': n = 4; break;
case SP:
case CR:
case NL: break;
default: ding(); goto Prompt;
}
}
switch (n) {
case 0: /* save root only */
break;
case 1: /* save all selected */
save_selected = 1;
break;
case 2: /* save all unread */
save_selected = 2;
break;
case 3: /* save all selected + unread */
save_selected = 3;
break;
case 4: /* save all articles */
break;
}
if (n) last_save = next_root_article(article_id) - 1;
save_selected |= 8; /* closed subject */
temp1 = cura;
}
} else
break;
save_it:
for ( ; article_id <= last_save ; article_id++, cura++) {
ah = articles[article_id];
switch (save_selected & 0x3) {
case 0:
break;
case 3:
if (ah->attr == 0) break;
/* XXX: check fall */
case 1:
if ((ah->attr & A_SELECT) == 0) continue;
break;
case 2:
if (ah->attr == 0) break;
continue;
}
if (cur_k_cmd == K_CANCEL) {
if (current_group->group_flag & G_FOLDER) {
fcancel(ah);
} else
switch (cancel(ah)) {
case -1:
did_unshar = 1;
continue;
case 0:
ah->attr = A_CANCEL;
break;
default:
continue;
}
if (!did_unshar)
mark();
continue;
}
if (doing_unshar) {
did_unshar++;
} else
if (ah->subject != NULL)
prompt("Processing '%.50s'...", ah->subject);
else if (cura >= 0 && cura <= numa)
prompt("Processing %c...", ident[cura]);
else
prompt("Processing entry %d...", article_id);
if (save(ah)) {
ah->attr = A_READ;
if (doing_unshar) continue;
if (cura >= 0 && cura <= numa)
mark();
}
}
if (save_selected & 8) {
save_selected = 0; /* select closed */
cura = temp1;
/* mark(); */
}
}
if (save_selected) cura = 0;
m_endinput();
enable_stop = 1;
if (cur_k_cmd != K_CANCEL)
end_save();
if (did_unshar) {
tprintf("\r\n");
any_key(0);
goto redraw;
}
goto Prompt;
case K_FOLLOW_UP:
#ifdef NNTP_POST
if (use_nntp && nntp_no_post()) goto same_prompt;
#endif
case K_REPLY:
if (numa < 0) goto nextmenu;
prompt(k_cmd == K_REPLY ?
"\1Reply to author\1 of article: " :
"\1Follow Up\1 to article: ");
if (get_k_cmd() == K_ARTICLE_ID)
if (answer(articles[firsta+article_id], k_cmd, -1))
goto redraw;
goto Prompt;
case K_POST:
#ifdef NNTP_POST
if (use_nntp && nntp_no_post())
goto same_prompt;
#endif
if (post_menu()) goto redraw;
goto Prompt;
case K_MAIL_OR_FORWARD:
if (numa < 0) goto nextmenu;
prompt("\1Article to be forwarded\1 (SP if none): ");
if ((k_cmd = get_k_cmd()) == K_ARTICLE_ID) {
if (answer(articles[firsta+article_id], K_MAIL_OR_FORWARD, 1))
goto redraw;
} else
if (k_cmd == K_CONTINUE)
if (answer((article_header *)NULL, K_MAIL_OR_FORWARD, 0))
goto redraw;
goto Prompt;
/*
case K_CANCEL:
if (numa < 0) goto nextmenu;
if (current_group->group_flag & G_FOLDER) {
prompt("\1Cancel Folder\1 Article: ");
if (get_k_cmd() == K_ARTICLE_ID) {
cura = article_id;
fcancel(articles[firsta+article_id]);
mark();
}
goto Prompt;
}
prompt("\1Cancel\1 Article: ");
if (get_k_cmd() == K_ARTICLE_ID)
if (cancel(articles[firsta+article_id]) & 1) goto redraw;
goto Prompt;
*/
case K_UNSUBSCRIBE:
if (unsubscribe(current_group)) {
if (current_group->group_flag & G_UNSUBSCRIBED)
menu_return(ME_NEXT);
home();
CALL(print_header)();
}
goto Prompt;
case K_GROUP_OVERVIEW:
group_overview(-1);
goto redraw;
case K_KILL_HANDLING:
switch (kill_menu((article_header *)NULL)) {
case 0: /* select */
do_auto_select((regexp *)NULL, 2);
break;
case 1: /* kill */
if (!do_auto_kill()) break;
goto junk_killed_articles;
default:
break;
}
goto Prompt;
case K_CONTINUE: /* goto next menu page or show the articles */
repl_attr(firsta, nexta, 0, A_SEEN, 0);
/* FALL THRU */
case K_CONTINUE_NO_MARK: /* but don't mark unselected articles */
if (nexta < n_articles) goto nextmenu;
break;
case K_READ_GROUP_THEN_SAME:
if ((temp = mark_read_return)) goto do_marked_by;
break;
case K_NEXT_GROUP_NO_UPDATE:
if ((temp = mark_next_group)) goto do_marked_by;
menu_return(ME_NEXT);
case K_READ_GROUP_UPDATE:
if ((temp = mark_read_skip) == 0) break;
do_marked_by:
temp1 = 0; temp2 = n_articles;
switch (temp) {
case 1:
temp1 = firsta;
/* FALL THRU */
case 3:
temp2 = nexta;
break;
case 2:
temp2 = firsta - 1;
break;
case 4:
break;
}
repl_attr(temp1, temp2, 0, A_SEEN, 0);
if (k_cmd != K_NEXT_GROUP_NO_UPDATE) break;
menu_return(ME_NEXT);
case K_PREVIOUS:
menu_return(ME_PREV);
case K_ADVANCE_GROUP:
case K_BACK_GROUP:
if (merged_menu) {
msg("No possible on merged menu");
goto same_prompt;
}
/* FALL THRU */
case K_GOTO_GROUP:
temp1 = n_articles;
switch (goto_group(k_cmd, (article_header *)NULL, (flag_type)0)) {
case ME_REDRAW:
firsta = 0;
if (temp1 != n_articles && consolidate)
consolidate = do_consolidation();
goto redraw;
case ME_NO_ARTICLES:
msg("No selections made.");
/* FALL THRU */
case ME_NO_REDRAW:
goto Prompt;
case ME_QUIT:
menu_return( ME_QUIT );
case ME_PREV:
goto redraw;
case ME_NEXT:
s_keyboard = 1;
goto empty_menu_hack;
}
/* XXX: Fall ? */
case K_OPEN_SUBJECT:
if (numa < 0) goto nextmenu;
prompt("\1Open subject\1");
k_cmd = get_k_cmd();
if (k_cmd != K_ARTICLE_ID) {
if (k_cmd != cur_k_cmd) goto Prompt;
article_id = cura;
}
open_subject:
ah = articles[firsta+article_id];
if (!(ah->flag & A_CLOSED) ||
(ah->flag & (A_ROOT_ART | A_NEXT_SAME)) == A_ROOT_ART)
goto Prompt;
cura = article_id = root_article(firsta + article_id) - firsta;
while (cura + firsta < n_articles) {
ah = articles[firsta+cura];
if (cura > article_id && ah->flag & A_ROOT_ART)
break;
ah->flag &= ~A_CLOSED;
cura++;
}
cura = article_id;
goto partial_redraw;
case K_CLOSE_SUBJECT:
if (numa < 0) goto nextmenu;
prompt("\1Close subject\1");
k_cmd = get_k_cmd();
if (k_cmd != K_ARTICLE_ID) {
if (k_cmd != cur_k_cmd) goto Prompt;
article_id = cura;
}
ah = articles[firsta+article_id];
if ((ah->flag & A_CLOSED) ||
(ah->flag & (A_ROOT_ART | A_NEXT_SAME)) == A_ROOT_ART) {
cura = next_root_article(firsta + cura) - firsta;
goto Prompt;
}
cura = article_id = root_article(firsta + article_id) - firsta;
while (cura + firsta < n_articles) {
ah = articles[firsta+cura];
if (cura > article_id && ah->flag & A_ROOT_ART)
break;
ah->flag |= A_CLOSED;
cura++;
}
cura = article_id;
next_cura = next_root_article(firsta + cura) - firsta;
if (next_cura < 0 || next_cura > numa) next_cura = 0;
if (cura >= 0) goto partial_redraw_nc;
articles[cura + firsta]->menu_line = articles[firsta]->menu_line;
firsta += cura;
goto redraw;
case K_LEAVE_NEXT:
case K_JUNK_ARTICLES:
junk_prompt = cur_k_cmd == K_JUNK_ARTICLES ? 1 : 5;
for (;;) {
switch (junk_prompt) {
case 1:
if (novice) msg("Use J repeatedly to select other functions");
prompt("\1Mark read\1 S)een U)nmarked A)ll *+)selected a-z . [LN]");
junk_attr = A_READ;
break;
case 2:
prompt("\1Unmark\1 S)een R)ead a-z [*+LAN.J] ");
junk_attr = 0;
break;
case 3:
prompt("\1Select\1 L)eft-over, N(leave-next) [USRa-z.J]");
junk_attr = A_SELECT;
break;
case 4:
prompt("\1Kill\1 R)ead S)een [LANU*+a-z.J]");
junk_attr = A_KILL;
break;
case 5:
prompt("\1Leave\1 a-z .,/ * + U)nmarked [LANRSJ]");
junk_attr = A_LEAVE_NEXT;
break;
default:
junk_prompt = 1;
continue;
}
junk_another:
if (cura < 0 || cura > numa) cura = 0;
cursor_at_id();
switch (get_k_cmd()) {
case K_JUNK_ARTICLES:
junk_prompt++; /* can be 0 */
continue;
case K_ARTICLE_ID:
cura = article_id;
if (junk_attr == A_KILL) junk_attr = A_READ;
if (auto_select_closed > 0 && articles[firsta + cura]->flag & A_CLOSED)
repl_attr_subject(A_KILL, junk_attr, 1);
else {
articles[firsta + cura]->attr = junk_attr;
mark();
cura++;
}
goto junk_another;
case K_NEXT_LINE:
cura++;
goto junk_another;
case K_PREV_LINE:
--cura;
goto junk_another;
case K_SELECT_SUBJECT:
if (junk_attr == A_KILL) junk_attr = A_READ;
repl_attr(firsta, nexta, A_AUTO_SELECT, A_SELECT, 0);
repl_attr(firsta, nexta, A_SELECT, junk_attr, 1);
goto Prompt;
case K_AUTO_SELECT:
repl_attr_all(A_AUTO_SELECT, A_SELECT, 0);
orig_attr = A_SELECT;
break;
default:
switch (cur_key) {
case 'S':
orig_attr = A_SEEN;
break;
case 'U':
orig_attr = 0;
break;
case 'L':
if (junk_attr == A_KILL) junk_attr = A_READ;
orig_attr = A_LEAVE;
break;
case 'A':
orig_attr = A_KILL;
break;
case 'N':
orig_attr = A_LEAVE_NEXT;
break;
case 'R': /* kill read articles */
orig_attr = A_READ;
break;
default:
goto Prompt;
}
break;
}
break;
}
if (nexta - firsta < n_articles) {
prompt("On all menu pages? ");
switch (yes(1)) {
case -1:
goto Prompt;
case 0:
if (!repl_attr(firsta, nexta, orig_attr, junk_attr, 1))
goto Prompt;
break;
case 1:
if (!repl_attr_all(orig_attr, junk_attr, 1))
goto Prompt;
break;
}
} else
if (!repl_attr(firsta, nexta, orig_attr, junk_attr, 1))
goto Prompt;
if (junk_attr != A_KILL) goto Prompt;
junk_killed_articles:
elim_list[0] = firsta;
elim_list[1] = firsta + cura;
elim_list[2] = nexta;
if (elim_articles(elim_list, 3)) {
firsta = elim_list[0];
goto redraw;
}
firsta = elim_list[0];
cura = elim_list[1] - firsta;
nexta = elim_list[2];
goto Prompt;
case K_ARTICLE_ID:
if (numa < 0) goto nextmenu;
MOUSE_MENU;
if (!is_k_select && auto_preview_mode) goto auto_preview;
cura = article_id;
if (!auto_select_closed || !(articles[firsta+cura]->flag & A_CLOSED)) {
toggle();
if (!is_k_select && auto_select_subject) goto select_subject;
mark();
cura++;
goto same_prompt;
}
if (auto_select_closed < 0) {
article_id = cura;
goto open_subject;
}
mi = menu_info + articles[firsta+cura]->menu_line;
if (mi->mi_unread == 0)
repl_attr_subject(A_KILL, A_SELECT, 1);
else if (mi->mi_selected == mi->mi_unread)
repl_attr_subject(auto_select_closed == 2 ? A_KILL : A_SELECT, 0, 1);
else
repl_attr_subject(auto_select_closed == 2 ? A_KILL : 0, A_SELECT, 1);
goto same_prompt;
case K_SELECT_INVERT:
if (numa < 0) goto nextmenu;
temp = cura;
no_raw(); /* for x-on/x-off */
for (cura = 0; cura <= numa; cura++) {
toggle();
}
for (cura = 0; cura <= numa; cura++) {
if (IS_VISIBLE(articles[firsta+cura])) mark();
}
fl;
REDRAW_CHECK;
nn_raw();
cura = temp;
goto same_prompt;
case K_UNSELECT_ALL:
if (last_k_cmd == K_UNSELECT_ALL)
repl_attr_all(A_SELECT, 0, 1);
else
repl_attr_all(A_AUTO_SELECT, 0, 1);
fl;
cura = 0;
goto same_prompt;
case K_NEXT_LINE:
if (numa < 0) goto nextmenu;
cura++;
goto same_prompt;
case K_PREV_LINE:
if (numa < 0) goto nextmenu;
if (--cura < 0) cura = numa;
set_root_if_closed();
goto same_prompt;
case K_SELECT_SUBJECT:
if (numa < 0) goto nextmenu;
MOUSE_MENU;
if (MOUSE)
cura = article_id;
if (last_k_cmd != K_ARTICLE_ID)
toggle();
select_subject:
repl_attr_subject(A_KILL, last_attr, 1);
goto same_prompt;
case K_SELECT_RANGE:
if (numa < 0) goto nextmenu;
if (last_k_cmd == K_ARTICLE_ID) {
cura--;
if (cura < 0) cura = numa;
} else
last_attr = (articles[firsta+cura]->attr & A_SELECT) ? 0 : A_SELECT;
range_again:
if (MOUSE) {
if ((mouse_y < firstl) || (mouse_y > firstl + menu_length - 1))
goto same_prompt;
/* stop selection when down click changes groups */
if (last_k_cmd == K_INVALID)
goto same_prompt;
} else {
prompt("\1%select range\1 %c-", last_attr ? "S" : "Des", ident[cura]);
k_cmd = get_k_cmd();
if (k_cmd == K_SELECT_RANGE) {
last_attr = last_attr ? 0 : A_SELECT;
goto range_again;
}
if (k_cmd != K_ARTICLE_ID) goto Prompt;
}
if (article_id > cura) {
article_number tmp = cura;
cura = article_id;
article_id = tmp;
}
repl_attr(firsta+article_id, firsta+cura+1, A_KILL, last_attr, 1);
goto Prompt;
case K_AUTO_SELECT:
do_auto_select((regexp *)NULL, 1);
goto same_prompt;
case K_GOTO_MATCH:
prompt("\1Select regexp\1 ");
if ((fname = get_s(NONE, NONE, NONE, NULL_FCT)) == NULL)
goto Prompt;
if (*fname != NUL) {
if (regular_expr) freeobj(regular_expr);
if (case_fold_search) fold_string(fname);
regular_expr = regcomp(fname);
}
if (regular_expr == NULL)
msg("No previous expression");
else
do_auto_select(regular_expr, 2);
goto Prompt;
case K_NEXT_PAGE:
if (nexta < n_articles) goto nextmenu;
if (firsta == 0) goto same_prompt;
nexta = 0;
goto nextmenu;
case K_PREV_PAGE:
if (firsta == 0 && nexta == n_articles) goto same_prompt;
prevmenu:
nexta = (firsta > 0 ? firsta : n_articles);
for (menu_length = maxa; menu_length > 0 && --nexta >= 0; ) {
if (!IS_VISIBLE(articles[nexta])) continue;
if (--menu_length > 0) {
switch (menu_spacing) {
case 0:
break;
case 1:
if ((articles[nexta]->flag & A_ROOT_ART) == 0) break;
/* XXX: fall? */
case 2:
--menu_length;
break;
}
}
}
if (nexta < 0) nexta = 0;
goto nextmenu;
case K_FIRST_PAGE:
if (firsta == 0) goto same_prompt;
nexta = 0;
goto nextmenu;
case K_LAST_PAGE:
if (nexta == n_articles) goto same_prompt;
firsta = 0;
goto prevmenu;
case K_PREVIEW:
if (numa < 0) goto nextmenu;
preview_other:
MOUSE_MENU;
if (! MOUSE) {
prompt("\1Preview article\1");
k_cmd = get_k_cmd();
if (k_cmd != K_ARTICLE_ID) {
if (k_cmd != K_PREVIEW)
goto Prompt;
article_id = cura;
}
}
auto_preview:
temp = prompt_line;
preview_next:
cura = article_id;
ah = articles[firsta+cura];
no_raw();
orig_attr = ah->attr;
ah->attr = 0;
menu_cmd = more(ah, MM_PREVIEW, prompt_line);
if (menu_cmd == MC_MENU) {
if (ah->attr == 0) ah->attr = orig_attr;
if (prompt_line < 0) {
next_cura = cura;
goto redraw;
}
mark();
prompt_line = temp;
next_cura = -1;
goto build_prompt;
}
if (ah->attr == 0)
ah->attr = preview_mark_read ? A_READ : orig_attr;
if (prompt_line >= 0)
mark();
next_cura = ++cura;
switch (menu_cmd) {
case MC_DO_KILL:
if (!do_auto_kill()) break;
elim_list[0] = firsta;
elim_list[1] = firsta + cura;
elim_articles(elim_list, 2);
firsta = elim_list[0];
next_cura = elim_list[1] - firsta;
goto redraw;
case MC_DO_SELECT:
if (prompt_line >= 0) { /* not redrawn */
do_auto_select((regexp *)NULL, 2);
break;
}
numa = -1;
do_auto_select((regexp *)NULL, 2);
/* FALL THRU */
case MC_QUIT:
menu_return( ME_QUIT );
case MC_REENTER_GROUP:
menu_return( ME_REENTER_GROUP );
case MC_NEXT:
case MC_PREVIEW_NEXT:
if (prompt_line < 0) { /* redrawn screen ! */
if (quit_preview(menu_cmd)) goto redraw;
prompt_line = Lines;
} else {
/* if (ah->attr == A_LEAVE || ah->attr == A_LEAVE_NEXT) {
cura--;
mark();
cura++;
}
*/ if (quit_preview(menu_cmd)) {
next_cura = -1;
break;
}
prompt_line = temp;
}
article_id = cura;
goto preview_next;
case MC_PREVIEW_OTHER:
prompt_line = temp;
nn_raw();
goto preview_other;
default:
if (prompt_line < 0) goto redraw;
break;
}
prompt_line = temp;
goto build_prompt;
case K_LAYOUT:
if (++fmt_linenum > 4) fmt_linenum = 0;
goto redraw;
default:
msg("Command %d not supported", k_cmd);
goto same_prompt;
}
no_raw();
do_auto_read:
switch (show_articles()) {
case MC_MENU:
goto redraw;
case MC_READGROUP:
if (k_cmd == K_READ_GROUP_THEN_SAME) {
if (read_ret_next_page && nexta < n_articles)
firsta = nexta;
goto redraw;
}
/* XXX: fall? */
case MC_NEXTGROUP:
menu_cmd = ME_NEXT;
break;
case MC_REENTER_GROUP:
menu_cmd = ME_REENTER_GROUP;
break;
case MC_QUIT:
menu_cmd = ME_QUIT;
break;
default:
sys_error("show_articles returned improper value");
}
menu_exit:
cur_bypass = o_bypass;
n_selected = o_selected;
firsta = o_firsta;
in_menu_mode = o_mode;
menu_level--;
no_raw();
return menu_cmd;
}
/*
* return article header for article on menu
*/
article_header *get_menu_article()
{
register article_header *ah;
tprintf(" from article: "); fl;
if (get_k_cmd() == K_ARTICLE_ID) {
ah = articles[firsta + article_id];
if (ah->a_group) init_group(ah->a_group);
return ah;
}
return NULL;
}
/*
* read command from command line
*/
int
alt_command()
{
int ok_val, macro_cmd;
char *cmd, brkchars[10];
if (get_from_macro)
ok_val = AC_UNCHANGED;
else {
prompt(":");
ok_val = AC_PROMPT;
}
again:
sprintf(brkchars, "?%c ", erase_key);
cmd = get_s(NONE, NONE, brkchars, alt_completion);
if (cmd == NULL ||
*cmd == NUL || *cmd == SP || (key_type)*cmd == erase_key)
return ok_val;
macro_cmd = get_from_macro;
if (*cmd == '?') {
display_file("help.extended", CLEAR_DISPLAY);
ok_val = AC_REDRAW;
goto new_prompt;
}
ok_val = parse_command(cmd, ok_val, (FILE *)NULL);
if (ok_val != AC_REDRAW || !delay_redraw) return ok_val;
new_prompt:
if (macro_cmd) return ok_val;
prompt_line = -1;
tprintf("\n\r:");
fl;
goto again;
}