[comp.sources.unix] v19i068: NN, a Usenet news reader, Part07/15

rsalz@uunet.uu.net (Rich Salz) (06/23/89)

Submitted-by: storm@texas.dk (Kim F. Storm)
Posting-number: Volume 19, Issue 68
Archive-name: nn/part07

#!/bin/sh
# this is part 7 of a multipart archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file master.c continued
#
CurArch=7
if test ! -r s2_seq_.tmp
then echo "Please unpack part 1 first!"
     exit 1; fi
( read Scheck
  if test "$Scheck" != $CurArch
  then echo "Please unpack part $Scheck next!"
       exit 1;
  else exit 0; fi
) < s2_seq_.tmp || exit 1
echo "x - Continuing file master.c"
sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' >> master.c
X	write_error();
X    fflush(master_file);
X}
X
X
Xclean_group(gh)
Xregister group_header *gh;
X{
X    if (trace)
X	log_entry('T', "CLEAN %s", gh->group_name);
X    
X    gh->first_l_article = 0;
X    gh->last_l_article = 0;
X
X    gh->index_write_offset = (off_t)0;
X    gh->data_write_offset = (off_t)0;
X
X    gh->group_flag &= ~G_EXPIRE;
X    gh->group_flag |= G_BLOCKED;
X    
X    save_group(gh);
X}
X
X/*
X *	Build initial master file ; calls Initialize script and
X *	reads info from its standard output
X */
X
Xbuild_master()
X{
X    char command[512];
X    char groupname[512];
X    group_header group;
X    FILE *group_file, *src;
X    int lcount, use_group_file;
X
X
X    printf("Confirm initialization by typing 'OK': ");
X    fl;
X    gets(command);
X    if (strcmp(command, "OK")) {
X	printf("No initialization\n");
X	nn_exit(0);
X    }
X
X    printf("Initializing master data base...");
X    fl;
X	
X    if (chdir(lib_directory) < 0)	/* so we can use open_file */
X	sys_error("lib");
X
X#ifdef NNTP
X    if (use_nntp && nntp_get_active() < 0)
X	    sys_error("Can't get active file");
X#endif
X    /* check active file for duplicates */
X
X    sprintf(command, "awk 'NF>0{print $1}' %s | sort | uniq -d", news_active);
X    
X    src = popen(command, "r");
X
X    for (lcount = 0; fgets(groupname, 512, src); lcount++) {
X	if (lcount == 0)
X	    printf("\n%s contains duplicate entries for the following groups:",
X		   news_active);
X	    
X	fputs(groupname, stdout);
X    }
X
X    pclose(src);
X
X    if (lcount > 0) {
X	printf("Do you want to repair this file before continuing ? (y)");
X	gets(command);
X	if (command[0] == NUL || command[0] == 'y' || command[0] == 'Y')
X	    nn_exit(0);
X    }
X
X    /* if a "GROUPS" file exist offer to use that, else */
X    /* read group names from active file */
X
X    use_group_file = 0;
X    
X    if (src = open_groups(OPEN_READ)) {
X	printf("\nA GROUPS file already exist -- reuse it? (y)");
X	fl;
X	gets(command);
X	if (command[0] == NUL || command[0] == 'y' || command[0] == 'Y') {
X	    use_group_file = 1;
X	} else
X	    fclose(src);
X    }
X    
X    if (!use_group_file) {
X	strcpy(command, "awk 'NF>0{print $1}' ");
X	strcat(command, news_active);
X	strcat(command, " | sort -u");
X        
X	src = popen(command, "r");
X
X	group_file = open_groups(OPEN_CREATE|MUST_EXIST);
X    }
X    
X    open_master(OPEN_CREATE);
X
X    fseek(master_file, sizeof(master), 0);
X    
X    master.number_of_groups = 0;
X    
X    while (fgets(groupname, 512, src)) {
X
X	group.group_num = master.number_of_groups++;
X	
X	group.group_name_length = strlen(groupname) - 1;	/* strip NL */
X	groupname[group.group_name_length] = NUL;
X	group.group_name = groupname;
X
X	init_group(&group);
X
X	clean_group(&group);
X	
X	group.group_flag = 0;
X
X	/* moderation flag will be set by first visit_active_file call */
X
X	if (strcmp(groupname, "control") == 0)
X	    group.group_flag |= G_CONTROL;
X	
X	save_group(&group);
X
X	if (!use_group_file) {
X	    groupname[group.group_name_length] = NL;
X	    Fwrite(groupname, sizeof(char), 
X		   group.group_name_length + 1, group_file);
X	}
X    }
X
X    if (use_group_file) {
X	master.next_group_write_offset = ftell(src);
X	fclose(src);
X    } else {
X	master.next_group_write_offset = ftell(group_file);
X	fclose(group_file);
X	pclose(src);
X    }
X    
X    master.last_scan = 0;
X
X    save_master();
X    
X    close_master();
X
X    printf("done\n");
X
X    log_entry('M', "Master data base initialized");
X    
X    fl;
X}
X
X
X/*
X * receive commands from administrator
X */
X
Xreceive_admin()
X{
X    FILE *gate;
X    char buffer[128], *bp;
X    char command, *user_date;
X    long arg1, arg2;
X    int must_collect;
X    register group_header *gh;
X    
X    gate = open_file(relative(lib_directory, "GATE"), OPEN_READ | OPEN_UNLINK);
X    if (gate == NULL) return 0;
X    
X    sleep(2);	/* give administrator time to flush buffers */
X
X    must_collect = 0;
X    
X    while (fgets(buffer, 128, gate)) {
X	bp = buffer;
X	command = *bp;
X	if ((bp = strchr(bp, ';')) == NULL) continue;
X	arg1 = atol(++bp);
X	if ((bp = strchr(bp, ';')) == NULL) continue;
X	arg2 = atol(++bp);
X	if ((bp = strchr(bp, ';')) == NULL) continue;
X	user_date = ++bp;
X	if ((bp = strchr(bp, ';')) == NULL) continue;
X	*bp++ = NUL;
X	if (*bp != NL) continue;
X	
X	log_entry('A', "RECV %c %ld %ld (%s)",
X		  command, arg1, arg2, user_date);
X
X	if (arg1 >= 0 && arg1 < master.number_of_groups)
X	    gh = &active_groups[arg1];
X	else
X	    gh = NULL;
X	
X	switch (command) {
X
X	 case 'r':
X	    repeat_delay = arg1;
X	    continue;
X	    
X	 case 'e':
X	    expire_level = arg1;
X	    continue;
X	    
X	 case 'X':	/* expire */
X	    if (gh) {
X		gh->group_flag |= G_EXPIRE | G_BLOCKED;
X		save_group(gh);
X		break;
X	    } 
X	    visit_active_file();	/* just in case */
X	    Loop_Groups_Header(gh) {
X		if (gh->first_l_article + arg2 < gh->first_article) {
X		    gh->group_flag |= G_EXPIRE;
X		    save_group(gh);	/* could block here */
X		}
X	    }
X	    break;
X
X	 case 'S':	/* set flag */
X	    gh->group_flag |= arg2;
X	    save_group(gh);
X	    continue;
X
X	 case 'C':	/* clear flag */
X	    gh->group_flag |= arg2;
X	    save_group(gh);
X	    continue;
X
X	 case 'R':	/* recollect */
X	    if (gh) {
X		clean_group(gh);
X	    } else
X		Loop_Groups_Header(gh)
X		    clean_group(gh);
X	    break;
X
X	 case 'U':	/* unconditional pass */
X	    unconditional++;
X	    break;
X
X	 case 'T':	/* toggle trace flag */
X	    trace = !trace;
X	    continue;
X	    
X	 default:
X	    continue;
X	}	 
X	must_collect++;   
X    }
X    
X    fclose(gate);
X
X    return must_collect;
X}    
X
X
X/*
X * disk write with check -- halt if no space on disk
X */
X
X
XFwrite(buf, size, nitems, stream)
Xchar *buf;
Xint size;
Xint nitems;
XFILE *stream;
X{
X    if (fwrite(buf, size, nitems, stream) != nitems)
X	write_error();
X}
X
Xwrite_error()
X{
X    /*
X     * should wait for problems to clear out rather than die...
X     */
X    sys_error("DISK WRITE ERROR");
X}
X
X/*
X * dummy routines - should never be called by master
X */
X
X/*VARARGS*/
Xuser_error()
X{
X    dummy_error("user_error");
X}
X
Xdummy_error(name)
Xchar *name;
X{
X    sys_error("Dummy routine called by master: %s", name);
X}
X
X
X#ifdef NNTP /* XXX */
Xmsg() {}
X#endif /* NNTP Bogus */
NO_NEWS_IS_GOOD_NEWS
echo "File master.c is complete"
chmod 0644 master.c || echo "restore of master.c fails"
set `wc -c master.c`;Sum=$1
if test "$Sum" != "15145"
then echo original size 15145, current size $Sum;fi
echo "x - extracting match.c (Text)"
sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > match.c &&
X#define	NUL	'\0'
X#define	NULL	((char *)0)
X
X
X#ifdef notdef
X
X/* use this table for creating input to the match.h routines */
X
Xchar match_xxx[128] = {
X    
X/*  NUL SOH STX ETX EOT ENQ ACK BEL BS  TAB NL  VT  FF  CR  SO  SI  */
X    00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 
X
X/*  DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN EM  SUB ESC FS  GS  RS  US  */
X    00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 
X
X/*  SP  !   "   #   $   %   &   '   (   )   *   +   ,   -   .   /   */
X    00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 
X
X/*  0   1   2   3   4   5   6   7   8   9   :   ;   <   =   >   ?   */
X    00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 
X
X/*  @   A   B   C   D   E   F   G   H   I   J   K   L   M   N   O   */
X    00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 
X
X/*  P   Q   R   S   T   U   V   W   X   Y   Z   [   \   ]   ^   _   */
X    00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 
X
X/*  `   a   b   c   d   e   f   g   h   i   j   k   l   m   n   o   */
X    00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 
X
X/*  p   q   r   s   t   u   v   w   x   y   z   {   |   }   ~   DEL */
X    00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
X
X};
X#endif
X
X
X/*
X * the following routines only works for ASCII !!!!
X *
X * they are a quick hack to check for the occurrence of a word
X * (regardless of case) in a string
X */
X
X#define UNIFY 040
X
Xinit_quick_match(mask)
Xchar *mask;
X{
X	register char *m;
X
X	for (m = mask; *m; m++) *m |= UNIFY;
X}
X
Xchar *quick_match(subject, mask)
Xregister char *subject;
Xchar *mask;
X{
X	register char *q, *m;
X	register char m1 = *mask;
X
X	for (; *subject; subject++) {
X		if ((*subject | UNIFY) != m1) continue;
X
X		q = subject; m = mask;
X		do
X			if (*++m == NUL) return subject;
X		while ((*++q | UNIFY) == *m); 
X	}
X	return NULL;
X}
NO_NEWS_IS_GOOD_NEWS
chmod 0644 match.c || echo "restore of match.c fails"
set `wc -c match.c`;Sum=$1
if test "$Sum" != "1884"
then echo original size 1884, current size $Sum;fi
echo "x - extracting match.h (Text)"
sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > match.h &&
X/* usage:
X *    MATCH_DROP(t, a) and MATCH_DROP(t, b) must both be proven false
X *    before MATCH_EQ(t, a, b) is used.
X */
X
X#define	MATCH_DROP(table, c) ( c & 0200 || table[c] == 0 )
X		
X#define MATCH_EQ(table, a, b) ( a == b || table[a] == table[b] )
X
X#define MATCH_LS_EQ(table, a, b) ( a <= b || table[a] <= table[b] )
X
X#define MATCH_LS(table, a, b) ( a < b || table[a] < table[b] )
X
X#define	MATCH_CMP(table, a, b) (table[a] - table[b])
NO_NEWS_IS_GOOD_NEWS
chmod 0644 match.h || echo "restore of match.h fails"
set `wc -c match.h`;Sum=$1
if test "$Sum" != "439"
then echo original size 439, current size $Sum;fi
echo "x - extracting menu.c (Text)"
sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > menu.c &&
X/*
X * 	selection mode menu
X */
X
X#include "config.h"
X#include "articles.h"
X#include "term.h"
X#include "keymap.h"
X#include "menu.h"
X
X
Xexport int  preview_window = 0;	/* size of preview window */
Xexport int  fmt_linenum    = 1; /* menu line format */
Xexport int  fmt_rptsubj    = 0; /* repeat identical subjects if !0 */
Xexport int  novice	   = 1; /* novice mode -- use extended prompts */
Xexport int  long_menu	   = 0; /* don't put empty lines around menu lines */
Xexport int  delay_redraw   = 0; /* prompt again if :-command clears screen */
X
Xexport char *delayed_msg = NULL;	/* give to msg() after redraw */
X
Ximport also_read_articles;
Ximport merged_menu;
X
Xextern group_completion();
X
Xstatic int firstl;	/* first menu line */
X
Xstatic int firsta;	/* first article on menu (0 based) */
Xstatic int cura;	/* current article */
Xstatic int next_cura;	/* article to become cura if >= 0 */
Xstatic int numa;	/* no of articles on menu - 1 */
X
X#define INTERVAL1	('z' - 'a' + 1)
X#define INTERVAL2	('9' - '0' + 1)
X
Xchar ident[] = "abcdefghijklmnopqrstuvwxyz0123456789";
Xchar Ident[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ&&&&&&&&&&";
X
X/* mark commands */
X
X#define	OFF	0
X#define	ON	1
X#define	TOGGLE	2
X#define	INIT	3
X#define	SAVED	4
X#define	REMOVE	5
X#define CANCEL	6
X
Xstatic int how;
X
Xstatic mark()
X{
X    register article_header *ah;
X    int lno, curhow, must_print, lnum, lsubj, lname;
X
X    ah = articles[firsta + cura];
X    curhow = (ah->flag & A_SELECT) ? ON : OFF;
X    if (how == curhow) return;
X
X    lno = firstl + cura;
X    must_print = STANDOUT;
X
X toggle:
X
X    switch (how) {
X  
X     case TOGGLE:
X	how = (curhow == ON) ? OFF : ON;
X	goto toggle;
X	
X     case ON:
X	if (ah->flag & A_CANCEL) {
X	    if (curhow == OFF) return;
X	    how = OFF;
X	    goto toggle;
X	}
X	ah->flag |= A_SELECT;
X	break;
X	
X     case OFF:
X	ah->flag &= ~A_SELECT;
X	break;
X
X     case INIT:
X	gotoxy(0, lno);
X	putchar(ident[cura]);
X	how = curhow;
X	must_print = 1;
X	break;
X
X     case SAVED:
X	gotoxy(0, lno);
X	putchar(Ident[cura]);
X	return;
X
X     case REMOVE:
X	gotoxy(0, lno);
X	clrline();
X	return;
X
X     case CANCEL:
X	gotoxy(1, lno);
X	if (ah->flag & A_SELECT) {
X	    ah->flag &= ~A_SELECT;
X	    break;
X	}
X	putchar((ah->flag & A_CANCEL) ? '#' : ' ');
X	return;
X    }
X
X    if (cura < 0 || cura > numa) return;
X
X    /* menu line formats:
X                1  3    8 10     20 22        xx
X		:  :    :  :      :  :        :
X       0	id name           subject     +lines
X       1	id name       lines  subject
X       2	id  lines  subject
X       3	id subject
X       4	id name:8 subject
X     */
X
X    if (must_print) {
X
X	if (fmt_linenum > 4) fmt_linenum = 1;
X	
X	if (ah->flag & A_CANCEL) {
X	    gotoxy(1, lno);
X	    putchar('#');
X	} else
X	if (how == ON) {
X	    if (so_gotoxy(1, lno, 1) == 0) putchar('*');
X	} else {
X	    gotoxy(1, lno);
X	    putchar(' ');
X	}
X
X	if (fmt_linenum >   1) lnum = 0; else
X	if (ah->lines <    10) lnum = 1; else
X	if (ah->lines <   100) lnum = 2; else
X	if (ah->lines <  1000) lnum = 3; else
X	if (ah->lines < 10000) lnum = 4; else lnum = 5;
X	
X	lsubj = Columns - cookie_size - 2; /* ident char + space */
X
X	switch (fmt_linenum) {
X	    
X	 case 0:
X	    lsubj -= NAME_LENGTH + 1 + 2 + lnum;  /* name. .subj. +.lines */
X	    so_printf("%-*s ", NAME_LENGTH, ah->sender);
X	    break;
X	    
X	 case 1:
X	    lsubj -= NAME_LENGTH + 4; 
X	    /* name.lines.  .subj (name may be shortened) */
X	    lname = NAME_LENGTH + 2 - lnum;
X	    lsubj -= 4;	/* 2 columns for the number + 2 spaces */
X	    so_printf("%-*.*s ", lname, lname, ah->sender);
X	    so_printf(ah->lines >= 0 ? "%d  " : "?  ", ah->lines);
X	    break;
X	   
X	 case 2:
X	    lsubj -= 6;
X	    so_printf("%5d ", ah->lines);
X	    break;
X	    
X	 case 3:
X	    break;
X
X	 case 4:
X	    lsubj -= 9;
X	    so_printf("%-8.8s ", ah->sender);
X	    break;
X	}
X
X	if (!fmt_rptsubj && lno > firstl && ah->flag & A_SAME) {
X	    if (ah->replies == 0)
X		so_printf("-");
X	    else
X		prt_replies(ah->replies);
X	} else {
X	    lsubj -= prt_replies(ah->replies);
X	    so_printf("%-.*s", lsubj, ah->subject);
X	}	
X
X	if (fmt_linenum == 0)
X	    so_printf(ah->lines >= 0 ? " +%d" : " +?", ah->lines);
X
X	so_end();
X    } else
X	putchar((how == OFF) ? ' ' : '*');
X    
X    fl;
X    
X    return;
X}
X
X
Xstatic prt_replies(level)
X{
X    if (level == 0) return 0;
X    
X    if (level < 10) {
X	so_printf("%-.*s", level, ">>>>>>>>>");
X	return level;
X    }
X    
X    so_printf(">>>%3d >>>>", level);
X    return 11;
X}
X
X
Xstatic int article_id;
X
Xstatic int get_k_cmd()
X{
X    register int c, map;
X
X loop:
X    
X    article_id = -1;
X    
X    if ((c = get_c()) & GETC_COMMAND)
X	map = c & ~GETC_COMMAND;
X    else
X	map = menu_key_map[c];
X    
X    if (s_hangup) map = K_QUIT;
X    
X    if (map & K_MACRO) {
X	m_invoke(map & ~K_MACRO);
X	goto loop;
X    }
X    
X    if (map & K_ARTICLE_ID) {
X	article_id = map & ~K_ARTICLE_ID;
X	map = K_ARTICLE_ID;
X	
X	if (article_id < 0 || article_id > numa) {
X	    ding();
X	    goto loop;
X	}
X    }    
X    
X    return map;
X}
X
X
Xchar *pct(start, end, first, last)
Xlong start, end, first, last;
X{
X    long n = end - start;
X    static char buf[16];
X    char *fmt;
X    
X    if (first <= start || n <= 0)
X	if (last >= end) 
X	    return "All";
X	else
X	    fmt = "Top %d%%";
X    else
X	if (last >= end)
X	    return "Bot";
X	else
X	    fmt = "%d%%";
X    
X    sprintf(buf, fmt, ((last - start) * 100)/n);
X    return buf;
X}
X
Xmenu(print_header)
Xint (* print_header)();
X{
X    register 		k_cmd, cur_k_cmd;
X    register		article_header *ah;
X    int			last_k_cmd, last_how, was_selected;
X    int 		seen_all, menu_cmd, temp;
X    int 		save_selected, last_save;
X    int			doing_unshar, did_unshar;
X    char 		*fname, *savemode, *init_save();
X    int 		nexta;	/* first article on next menu */
X    int 		maxa;	/* max no of articles per menu page */
X    int 		o_firsta, o_mode;	/* for recursive calls */
X    static		menu_level = 0;
X    char		purpose[80], pr_fmt[60];
X    extern int 		enable_stop, file_completion();
X    extern int		alt_cmd_key, in_menu_mode, slow_mode, any_message;
X    
X#define	menu_return(cmd) \
X    { menu_cmd = (cmd); goto menu_exit; }
X
X    o_firsta = firsta;
X    o_mode = in_menu_mode;
X    in_menu_mode = 1;
X    
X    menu_level++;
X
X    sprintf(pr_fmt, 
X	    menu_level == 1 ? 
X	      "\1\2-- SELECT %s-----%%s-----\1" :
X	      "\1\2-- SELECT %s-----%%s-----<%s%d>--\1",
X	      novice ? "-- help:? " : "",
X	      novice ? "level " : "",
X	      menu_level);
X
X    purpose[0] = NUL;
X    if (!merged_menu && current_group->group_flag & G_NEW)
X	get_purpose(purpose);
X    
X    seen_all = 0;
X    firsta = 0;
X    while (firsta < n_articles && articles[firsta]->flag & A_SEEN)
X	firsta++;
X
X    if (firsta == n_articles) {
X	seen_all++;
X	firsta = 0;
X    }
X    
X    next_cura = -1;
X    cur_k_cmd = K_UNBOUND;
X    
X#ifdef HAVE_JOBCONTROL
X#define	REDRAW_CHECK	if (s_redraw) goto do_redraw
X    
X do_redraw:
X    /* safe to clear here, because we are going to redraw anyway */
X    s_redraw = 0; 
X#else
X#define REDRAW_CHECK
X#endif
X
X redraw:
X    s_keyboard = 0;
X
X empty_menu_hack:	/* do: "s_keyboard=1; goto empty_menu_hack;" */
X    if (!slow_mode) s_keyboard = 0;
X    
X    nexta = firsta;
X    
X    clrdisp();
X    
X    firstl = (*print_header)();
X    maxa = Lines - preview_window - firstl - 2;
X    if (!long_menu) firstl++, maxa -= 2;
X
X    if (maxa > (INTERVAL1 + INTERVAL2))
X	maxa = INTERVAL1 + INTERVAL2;
X
X nextmenu:
X
X    no_raw();
X    gotoxy(0, firstl);
X    clrpage(firstl);
X    
X    if (nexta > 0) {
X	while (firsta < nexta)
X	    articles[firsta++]->flag |= A_SEEN;
X    } else
X	if (purpose[0]) {
X	    msg(purpose);
X	}
X
X    firsta = nexta;
X    numa = Lines; /* for mark; is set correctly below */
X    cura = 0;
X    
X    REDRAW_CHECK;
X    
X    if (!s_keyboard)
X	while (nexta < n_articles && cura < maxa) {
X	    
X	    REDRAW_CHECK;
X    
X	    how = INIT;
X	    mark(); fl;
X	    
X	    if (s_keyboard) {	  /* Signal may have corrupted output.  */
X		if (cura == 0)
X		    mark();	  /* redraw first entry */
X		else {
X		    how = REMOVE; /* We delete the last entry (the user */
X		    mark();	  /* wanted to stop the output anyway)  */
X		    cura--;
X		    nexta--;
X		}		    
X		break;
X	    }
X	    
X	    nexta++; cura++;
X	}
X    
X    s_keyboard = 0;
X
X    prompt_line = firstl + cura;
X    if (!long_menu || cura < maxa) prompt_line++;
X
X    numa = nexta - firsta - 1;
X     if (numa < 0) prompt_line++;
X
X     if (next_cura >= 0) {
X	 cura = next_cura;
X	 next_cura = -1;
X     } else {
X	 cura = 0;
X	 for (article_id = firsta; cura < numa; article_id++, cura++)
X	     if ((articles[article_id]->flag & A_SELECT) == 0) break;
X     }
X
X     how = TOGGLE;
X
X  build_prompt:
X
X     raw();
X
X  Prompt:
X
X     prompt(pr_fmt,
X	    pct(0L, (long)(n_articles-1), (long)firsta, (long)(firsta+numa)));
X
X     if (delayed_msg != NULL) {
X	 msg(delayed_msg);
X	 delayed_msg = NULL;
X     }
X
X  same_prompt:
X
X     if (cura < 0 || cura > numa) cura = 0;
X
X     if (numa >= 0) {
X	 gotoxy(0, firstl + cura); 
X	 fl; /* place cursor at current article id */
X     }
X
X     last_k_cmd = cur_k_cmd;
X     cur_k_cmd = k_cmd = get_k_cmd();
X     if (any_message) clrmsg(-1);
X
X  alt_key:
X
X     switch (k_cmd) {
X
X      case K_UNBOUND:
X	 ding();
X	 flush_input();
X	 goto same_prompt;
X
X      case K_REDRAW:
X	 goto redraw;
X
X      case K_LAST_MESSAGE:
X	 msg((char *)NULL);
X	 goto same_prompt;
X
X      case K_HELP:
X	 if (numa < 0)  goto nextmenu;	/* give specific help here */
X	 display_help("menu");
X	 goto redraw;
X
X      case K_SHELL:
X	 if (group_file_name) *group_file_name = NUL;
X	 if (shell_escape()) goto redraw;
X	 goto Prompt;
X
X      case K_VERSION:
X	 prompt(P_VERSION);
X	 goto same_prompt;
X
X      case K_EXTENDED_CMD:
X	 switch (alt_command()) {
X
X	  case AC_QUIT:
X	     menu_return( ME_QUIT );
X
X	  case AC_PROMPT:
X	     goto Prompt;
X
X	  case AC_REORDER:
X	     firsta = 0;
X	     /* fall thru */
X	  case AC_REDRAW:
X	     goto redraw;
X
X	  case AC_KEYCMD:
X	     k_cmd = alt_cmd_key;
X	     goto alt_key;
X
X	  case AC_HEADER:
X	     home();
X	     (*print_header)();
X	     goto Prompt;
X	 }
X
X      case K_QUIT:
X	 menu_return(ME_QUIT);
X
X      case K_SAVE_NO_HEADER:
X      case K_SAVE_SHORT_HEADER:
X      case K_SAVE_FULL_HEADER:
X      case K_PRINT:
X      case K_UNSHAR:
X      case K_PATCH:
X
X	 if (numa < 0) goto nextmenu;
X
X	 fname = init_save(k_cmd, &savemode);
X	 if (fname == NULL) goto Prompt;
X
X	 enable_stop = 0;
X	 save_selected = 0;
X	 doing_unshar = k_cmd == K_UNSHAR || k_cmd == K_PATCH;
X	 did_unshar = 0;
X
X	 m_startinput();
X
X	 while (!save_selected && !did_unshar) {
X	     prompt("\1%s\1 %.*s Article (* +): ",
X		    savemode, Columns - 25, fname);
X
X	     k_cmd = get_k_cmd();
X
X	     if (k_cmd == K_SELECT_SUBJECT) {
X		 save_selected = 1;
X		 cura = 0;
X		 article_id = firsta;
X		 last_save = firsta + numa;
X	     } else
X	     if (k_cmd == K_AUTO_SELECT) {
X		 save_selected = 2;
X		 cura = -firsta;
X		 article_id = 0;
X		 last_save = n_articles - 1;
X	     } else
X	     if (k_cmd == K_ARTICLE_ID) {
X		 cura = article_id;
X		 article_id += firsta;
X		 last_save = article_id;
X	     } else
X		 break;
X
X	     for ( ; article_id <= last_save ; article_id++, cura++) {
X		 ah = articles[article_id];
X		 if (save_selected && (ah->flag & A_SELECT) == 0) continue;
X
X		 if (doing_unshar) {
X		     did_unshar++;
X		 } else
X		 if (cura >= 0 && cura <= numa)
X		     prompt("Processing %c...", ident[cura]);
X		 else
X		     prompt("Processing entry %d...", article_id);
X
X		 if (save(ah)) {
X		     if (doing_unshar) {
X			 if (save_selected)
X			     ah->flag &= ~A_SELECT;
X		     } else
X		     if (cura >= 0 && cura <= numa) {
X			 how = save_selected ? OFF : SAVED;
X			 mark();
X			 how = TOGGLE;
X		     } else
X		     if (save_selected)
X			 ah->flag &= ~A_SELECT;
X		 }
X	     }
X	 }
X
X	 if (save_selected) cura = 0;
X	 how = TOGGLE;
X
X	 m_endinput();
X
X	 enable_stop = 1;
X	 end_save();
X
X	 if (did_unshar) {
X	     any_key(0);
X	     goto redraw;
X	 }	
X	 goto Prompt;
X
X      case K_REPLY:
X      case K_FOLLOW_UP:
X	 if (numa < 0) goto nextmenu;
X
X	 prompt(k_cmd == K_REPLY ? 
X		"\1Reply to author\1 of article: " : 
X		"\1Follow Up\1 to article: ");
X
X	 if (get_k_cmd() == K_ARTICLE_ID)
X	     if (answer(articles[firsta+article_id], k_cmd, -1))
X		 goto redraw;
X
X	 goto Prompt;
X
X      case K_POST:
X	 if (post_menu()) goto redraw;
X	 goto Prompt;
X
X      case K_MAIL_OR_FORWARD:
X	 if (numa < 0) goto nextmenu;
X
X	 prompt("\1Article to be forwarded\1 (SP if none): ");
X
X	 if ((k_cmd = get_k_cmd()) == K_ARTICLE_ID) {
X	     if (answer(articles[firsta+article_id], K_MAIL_OR_FORWARD, 1))
X		 goto redraw;
X	 } else
X	 if (k_cmd == K_CONTINUE)
X	     if (answer((article_header *)NULL, K_MAIL_OR_FORWARD, 0))
X		 goto redraw;
X
X	 goto Prompt;
X
X      case K_CANCEL:
X	 if (numa < 0) goto nextmenu;
X
X	 if (current_group->group_flag & G_FOLDER) {
X	     prompt("\1Cancel Folder\1 Article: ");
X	     if (get_k_cmd() == K_ARTICLE_ID) {
X		 cura = article_id;
X		 fcancel(articles[firsta+article_id]);
X		 how = CANCEL;
X		 mark();
X	     }
X	     goto Prompt;
X	 }
X
X	 prompt("\1Cancel\1 Article: ");
X
X	 if (get_k_cmd() == K_ARTICLE_ID)
X	     if (cancel(articles[firsta+article_id]) & 1) goto redraw;
X	 goto Prompt;
X
X      case K_UNSUBSCRIBE:
X	 if (unsubscribe(current_group)) {
X	     if (!(current_group->group_flag & G_SUBSCRIPTION))
X		 menu_return(ME_NEXT);
X	     home();
X	     (*print_header)();
X	 }
X	 goto Prompt;
X
X      case K_GROUP_OVERVIEW:
X	 group_overview(0);
X	 goto redraw;
X
X      case K_KILL_HANDLING:
X	 kill_menu((article_header *)NULL);
X	 goto Prompt;
X
X      case K_CONTINUE:	/* goto next menu page or show the articles */
X	 if (nexta < n_articles && !seen_all) goto nextmenu;
X	 /* fall thru */
X
X      case K_READ_GROUP_UPDATE:
X      case K_READ_GROUP_THEN_SAME:
X	 no_raw();
X	 clrdisp();
X
X	 switch (show_articles()) {
X
X	  case SH_MENU:
X	     goto redraw;
X
X	  case SH_QUIT:
X	     menu_return(ME_QUIT);
X
X	  case SH_NO_SELECT:
X	     break;
X
X	  case SH_NEXT:
X	     menu_return(ME_NEXT);
X
X	  case SH_READ:
X	     if (k_cmd == K_READ_GROUP_THEN_SAME || also_read_articles) goto redraw;
X	     break;
X
X	  default:
X	     user_error("show_articles returned improper value");
X	 }
X
X	 menu_return(ME_READ);
X
X      case K_NEXT_GROUP_NO_UPDATE:
X	 menu_return(ME_NEXT);
X
X      case K_PREVIOUS:
X	 menu_return(ME_PREV);
X
X      case K_ADVANCE_GROUP:
X      case K_BACK_GROUP:
X	 if (merged_menu) {
X	     msg("No possible on merged menu");
X	     goto same_prompt;
X	 }
X	 /* FALL THRU */
X
X      case K_GOTO_GROUP:
X
X	 switch (goto_group(k_cmd, (article_header *)NULL)) {
X
X	  case ME_REDRAW:
X	     firsta = 0;
X	     goto redraw;
X
X	  case ME_NO_ARTICLES:
X	     msg("No selections made.");
X
X	  case ME_NO_REDRAW:
X	     goto Prompt;
X
X	  case ME_QUIT:
X	     menu_return( ME_QUIT );
X
X	  case ME_PREV:
X	     goto redraw;
X
X	  case ME_NEXT:
X	  case ME_READ:
X	     s_keyboard = 1;
X	     goto empty_menu_hack;
X	 }
X
X      case K_ARTICLE_ID:
X	 if (numa < 0) goto nextmenu;
X
X	 cura = article_id; 
X	 how = TOGGLE;
X	 mark();
X	 last_how = how;
X	 cura++;
X
X	 goto same_prompt;
X
X      case K_SELECT_INVERT:
X	 if (numa < 0) goto nextmenu;
X
X	 temp = cura;
X
X	 no_raw();	/* for x-on/x-off */
X	 for (cura = 0; cura <= numa; cura++) {
X	     how = TOGGLE;
X	     mark();
X	 }
X	 fl;
X
X	 REDRAW_CHECK;
X	 raw();
X
X	 how = TOGGLE; cura = temp;
X	 goto same_prompt;
X
X
X      case K_SELECT:
X	 if (numa < 0) goto nextmenu;
X
X	 how = TOGGLE;
X	 mark();
X	 last_how = how;
X	 cura++;
X	 goto same_prompt;
X
X      case K_UNSELECT_ALL:
X	 for (cura = -firsta; cura < n_articles - firsta; cura++) {
X	     how = OFF;
X	     mark();
X	 }
X	 fl;
X	 cura = 0;
X	 goto same_prompt;
X
X      case K_NEXT_LINE:
X	 if (numa < 0) goto nextmenu;
X
X	 cura++;
X	 how = TOGGLE;
X	 goto same_prompt;
X
X      case K_PREV_LINE:
X	 if (numa < 0) goto nextmenu;
X
X	 if (--cura < 0) cura = numa;
X	 how = TOGGLE;
X	 goto same_prompt;
X
X      case K_SELECT_SUBJECT:
X	 if (numa < 0) goto nextmenu;
X
X	 mark();
X
X	 while (firsta+cura > 0 && articles[firsta+cura]->flag & A_SAME) 
X	     cura--;
X
X	 do {
X	     mark();
X	     cura++;
X	     if (firsta+cura >= n_articles) break;
X	 } while (articles[firsta+cura]->flag & A_SAME);
X
X	 how = TOGGLE;
X	 goto same_prompt;
X
X      case K_SELECT_RANGE:
X	 if (numa < 0) goto nextmenu;
X
X	 if (last_k_cmd == K_ARTICLE_ID || last_k_cmd == K_SELECT) {
X	     how = last_how;
X	     cura--;
X	     if (cura < 0) cura = numa;
X	 } else
X	     how = articles[firsta+cura]->flag & A_SELECT ? OFF : ON;
X
X      range_again:
X
X	 prompt("\1%select range\1 %c-", how == ON ? "S" : "Des", ident[cura]);
X
X	 k_cmd = get_k_cmd();
X	 if (k_cmd == K_SELECT_RANGE) {
X	     how = !how;
X	     goto range_again;
X	 }
X
X	 if (k_cmd != K_ARTICLE_ID) goto Prompt;
X
X	 if (last_k_cmd != K_ARTICLE_ID && last_k_cmd != K_SELECT) 
X	     mark();
X
X	 if (article_id <= cura) {
X	     while (--cura >= article_id) mark();
X	     if (cura < 0) cura = 0;
X	 } else {
X	     while (++cura <= article_id) mark();
X	     if (cura > numa) cura = numa;
X	 }
X
X	 how = TOGGLE;
X	 goto Prompt;
X
X      case K_AUTO_SELECT:
X	 do_auto_select();
X	 goto same_prompt;
X
X      case K_NEXT_PAGE:
X	 if (nexta < n_articles) goto nextmenu;
X	 if (firsta == 0) goto same_prompt;
X
X	 seen_all++;
X	 nexta = 0;
X	 goto nextmenu;
X
X      case K_PREV_PAGE:
X	 if (firsta == 0 && nexta == n_articles) goto same_prompt;
X
X	 nexta = (firsta > 0 ? firsta : n_articles) - maxa;
X	 if (nexta <= 1) nexta = 0;
X	 goto nextmenu;
X
X      case K_FIRST_PAGE:
X	 if (firsta == 0) goto same_prompt;
X
X	 nexta = 0;
X	 goto nextmenu;
X
X      case K_LAST_PAGE:
X	 if (nexta == n_articles) goto same_prompt;
X
X	 nexta = n_articles - maxa;
X	 if (nexta <= 1) nexta = 0;
X	 goto nextmenu;
X
X      case K_PREVIEW:
X	 if (numa < 0) goto nextmenu;
X
X      preview_other:
X
X	 prompt("\1Preview article\1");
X	 k_cmd = get_k_cmd();
X
X	 if (k_cmd != K_ARTICLE_ID) {
X	     if (k_cmd != K_PREVIEW)
X		 goto Prompt;
X	     article_id = cura;
X	 }
X
X	 temp = prompt_line;
X
X      preview_next:
X	 ah = articles[firsta+article_id];
X	 cura = article_id + 1;
X	 was_selected = (ah->flag & A_SELECT);
X
X	 switch (more(ah, MM_PREVIEW, prompt_line)) {
X	     
X	  case MC_REDRAW:
X	     next_cura = cura;
X	     goto redraw;
X	     
X	  case MC_NO_REDRAW:
X	     break;
X	     
X	  case MC_QUIT:
X	     menu_return( ME_QUIT );
X
X	  case MC_NEXT:		/* article not found -- preview next */
X	     if (prompt_line == temp) 
X		 break; /* not redrawn -- return to menu instead */
X	     user_delay(1);
X	     /* FALL THRU */
X	     
X	  case MC_PREVIEW_NEXT:
X	     if (prompt_line < 0) {	/* redrawn screen ! */
X		 if ((firsta + cura) >= n_articles) goto redraw;
X		 prompt_line = Lines;
X	     } else {
X		 if ((ah->flag & A_SELECT) && was_selected == 0) {
X		     cura--;
X		     ah->flag &= ~A_SELECT;
X		     how = ON;
X		     mark();
X		     cura++;
X		 }
X		 if (cura > numa) break;
X		 prompt_line = temp;
X	     }
X	     article_id = cura;
X	     goto preview_next;
X	     
X	  case MC_PREVIEW_OTHER:
X	     prompt_line = temp;
X	     raw();
X	     goto preview_other;
X	     
X	  default:	
X	     break;
X	 }
X	 
X	 prompt_line = temp;
X	 goto build_prompt;
X	 
X      case K_LAYOUT:
X	 if (++fmt_linenum > 3) fmt_linenum = 0;
X	 goto redraw;
X	
X      default:
X	 msg("Command %d not supported", k_cmd);
X	 goto same_prompt;
X     }
X
X
X menu_exit:
X
X    firsta = o_firsta;
X    in_menu_mode = o_mode;
X    menu_level--;
X    
X    no_raw();
X    return menu_cmd;
X}
X
X
Xstatic show_articles()
X{
X    register cur, next, mode;
X    int cmd, prev = -1, again;
X    
X    do {
X	again = 0;
X	
X	for (cur = 0; cur < n_articles; cur++) {
X	    if (articles[cur]->flag & A_SELECT) break;
X	}
X	
X	while (cur < n_articles) {
X	    
X	    for (next = cur+1; next < n_articles; next++) {
X		if (articles[next]->flag & A_SELECT) break;
X	    }
X	    
X	    articles[cur]->flag &= ~A_SELECT;
X	    
X	 show:
X	    mode = 0;
X	    if (prev >= 0) mode |= MM_PREVIOUS;
X	    if (next == n_articles) mode |= MM_LAST_ARTICLE;
X	    
X	    cmd = more(articles[cur], mode, 0);
X	    
X	    switch(cmd) {
X		
X	     case MC_PREV:
X		if (prev == next) break;
X		
X		next = cur; cur = prev; prev = next;
X		goto show;
X		
X	     case MC_NEXTSUBJ:
X		for (next = cur+1; next < n_articles; next++) {
X		    if ((articles[next]->flag & A_SAME) == 0) break;
X		    articles[next]->flag &= ~A_SELECT;
X		}
X		for (; next < n_articles; next++) {
X		    if (articles[next]->flag & A_SELECT) break;
X		}
X		break;
X		
X	     case MC_ALLSUBJ:
X		for (next = cur+1; next < n_articles; next++) {
X		    if ((articles[next]->flag & A_SAME) == 0) break;
X		    articles[next]->flag |= A_SELECT;
X		}
X		for (next = cur+1; next < n_articles; next++)
X		    if (articles[next]->flag & A_SELECT) break;
X		break;
X		
X	     case MC_MENU:
X		articles[cur]->flag |= A_SELECT;
X		firsta = cur - 5;
X		if (firsta < 0) firsta = 0;
X		next_cura = cur - firsta;
X		
X		return SH_MENU;
X		
X	     case MC_QUIT:
X		return SH_QUIT;
X		
X	     case MC_NEXT:
X		if (articles[cur]->flag & A_SELECT) again++;
X		break;
X		
X	     case MC_NEXTGROUP:
X		return SH_NEXT;
X		
X	     case MC_READGROUP:
X		return SH_READ;
X	    }
X	    
X	    prev = cur; cur = next;
X	}
X
X	if (again > 1)
X	    delayed_msg = "Showing this and the following articles again";
X	else
X	    if (again == 1)
X		delayed_msg = "Showing article again";
X	
X    } while (again);
X    
X    return prev < 0 ? SH_NO_SELECT : SH_READ;
X}
X
X/*
X *	return article header for article on menu
X */
X
Xarticle_header *get_menu_article()
X{
X    register article_header *ah;
X    
X    fputs(" from article: ", stdout); fl;
X    
X    if (get_k_cmd() == K_ARTICLE_ID) {
X	ah = articles[firsta + article_id];
X	if (ah->a_group) init_group(ah->a_group);
X	return ah;
X    }
X    
X    return NULL;
X}
X
X
Xstatic get_purpose(purpose)
Xchar *purpose;
X{
X#ifdef NNTP
X    return;			/* newsgroups file is not available */
X#else    
X    FILE *f;
X    char line[256], group[80];
X    register char *cp, *pp;
X    register int len;
X    extern char news_active[];
X
X    strcpy(line, news_active);
X    if ((cp = strrchr(line, '/')) == NULL) return;
X    strcat(cp + 1, "newsgroups");
X
X    if ((f = fopen(line, "r")) == NULL) return;
X
X    sprintf(group, "%s\t", current_group->group_name);
X    len = current_group->group_name_length + 1;
X    
X    while (fgets(line, 256, f) != NULL) {
X	if (strncmp(line, group, len)) continue;
X	cp = line + len;
X	while (*cp && isspace(*cp)) cp++;
X	for (pp = purpose, len = 76; --len >= 0 && *cp && *cp != NL; )
X	    *pp++ = *cp++;
X	*pp = NUL;
X    }
X
X    fclose(f);
X#endif
X}
X
X/*
X *	perform auto selections that are not already selected
X *	if article is in range firsta..firsta+numa (incl) mark article
X */
X
Xstatic do_auto_select()
X{
X    register int i;
X    register article_header *ah, **ahp;
X    int count = 0, o_cura;
X    
X    o_cura = cura;
X    
X    for (i = 0, ahp = articles; i < n_articles; i++, ahp++) {
X	ah = *ahp;
X	if (auto_select_article(ah)) {
X	    count++;
X	    if (ah->flag & A_SELECT) continue;
X	    if (firsta <= i && i <= (firsta+numa)) {
X		cura = i - firsta;
X		how = ON;
X		mark();
X	    } else
X		ah->flag |= A_SELECT;
X	}
X    }
X    
X    msg(count == 0 ? "No selections" : "Selected %d article%s",
X	   count, count > 1 ? "s" : "");
X    cura = o_cura;
X}
X
X	    
X
X/*
X *	read command from command line
X */
X
Xalt_command()
X{
X    int ok_val, macro_cmd;
X    char *cmd;
X    extern char erase_key;
X    extern int get_from_macro;
X    extern int alt_completion();
X    
X    prompt(":");
X    ok_val = AC_PROMPT;
X    
X again:
X    
X    cmd = "?? ";
X    cmd[1] = erase_key;
X    
X    cmd = get_s(NONE, NONE, cmd, alt_completion);
X    if (cmd == NULL ||
X	*cmd == NUL || *cmd == SP || *cmd == erase_key)
X	return ok_val;
X
X    macro_cmd = get_from_macro;
X    
X    if (*cmd == '?') {
X	display_file("help.extended", CLEAR_DISPLAY);
X	ok_val = AC_REDRAW;
X	goto new_prompt;
X    }
X
X    ok_val = parse_command(cmd, ok_val, (FILE *)NULL);
X    if (ok_val != AC_REDRAW || !delay_redraw) return ok_val;
X    
X new_prompt:
X    if (macro_cmd) return ok_val;
X    
X    prompt_line = -1;
X    printf("\n\r:");
X    fl;
X    goto again;
X}
NO_NEWS_IS_GOOD_NEWS
chmod 0644 menu.c || echo "restore of menu.c fails"
set `wc -c menu.c`;Sum=$1
if test "$Sum" != "23564"
then echo original size 23564, current size $Sum;fi
echo "x - extracting menu.h (Text)"
sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > menu.h &&
X/* menu commands */
X
X#define ME_QUIT		0	/* quit nn				*/
X#define ME_NEXT		1	/* continue to next group		*/
X#define	ME_READ		2	/* read this group, cont to next 	*/
X#define ME_PREV		3	/* previous group			*/
X#define ME_NO_ARTICLES	4	/* no articles in group			*/
X#define ME_REDRAW	5	/* redraw screen after return */
X#define ME_NO_REDRAW	6	/* screen is not corrupted */
X
X/* show_articles commands */
X
X#define SH_QUIT		0	/* quit nn 				*/
X#define SH_NEXT		1	/* goto next group, no read		*/
X#define	SH_READ		2	/* articles has been read 		*/
X#define	SH_MENU		3	/* redraw menu				*/ 
X#define	SH_NO_SELECT	4	/* no articles was selected		*/
X
X
X/* more commands */
X
X#define MC_QUIT		0	/* quit nn */
X#define	MC_NEXT		1	/* next article */
X#define MC_MENU		2	/* return to menu */
X#define MC_PREV		3	/* previous article */
X#define MC_NEXTSUBJ	4	/* show next subject */
X#define MC_ALLSUBJ	5	/* show all with same subject */
X#define MC_NEXTGROUP	6	/* next group, no read */
X#define	MC_READGROUP	7	/* next group, mark as read */
X#define MC_PREVIEW_NEXT	8	/* preview next article */
X#define MC_PREVIEW_OTHER 9	/* preview another article */
X#define MC_REDRAW	10	/* redraw screen after return */
X#define MC_NO_REDRAW	11	/* screen is not corrupted */
X
X/* more modes */
X
X#define	MM_NORMAL	0	/* show article */
X#define MM_DIGEST	1	/* show full digest */
X#define MM_PREVIOUS	0x10	/* previous article exists */
X#define MM_LAST_ARTICLE	0x20	/* last article in group */
X#define MM_LAST_GROUP	0x40	/* last group */
X#define MM_PREVIEW	0x80	/* preview mode flag */
X
X/* alt_command return values */
X
X#define	AC_QUIT		0	/* quit nn */
X#define	AC_PROMPT	1	/* just redraw prompt line */
X#define	AC_REDRAW	2	/* redraw screen */
X#define AC_REORDER	3	/* articles have been reordered */
X#define	AC_HEADER	4	/* update header line + Prompt */
X#define AC_KEYCMD	5	/* alt_cmd_key contains command */
NO_NEWS_IS_GOOD_NEWS
chmod 0644 menu.h || echo "restore of menu.h fails"
set `wc -c menu.h`;Sum=$1
if test "$Sum" != "1853"
then echo original size 1853, current size $Sum;fi
echo "x - extracting mk_online_man (Text)"
sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > mk_online_man &&
X# convert a manual to a folder
X
Xsed 	-e 's/\\f[BPI]//g' \
X	-e 's/\\-/-/g' \
X	-e 's/\\&//' \
X	-e '/^\.\\"/d' \
X	-e '/^\.nf/d' \
X	-e '/^\.fi/d' \
X	-e 's/^\.[BI] //' "$@" |
Xawk '
XBEGIN {
X	l=""
X	o=""
X	m=72
X	a=0
X	h=""
X}
X/^\.SH / {
X	if (a) printf("%s\n\n", l)
X	a++
X	l=o=""
X	z=u=0
X	printf("From: %s\nSubject:", h);
X	for (i = 2; i <= NF; i++) printf(" %s", $i);
X	printf("\n\n");
X	next
X}
X/^\.TH / {
X	h=$2
X	next
X}
X/^\.UC / {
X	next
X}
X/^\.br/ {
X	if (l != o) printf("%s\n", l)
X	l=o
X	z=u
X	next
X}
X/^\.PP/ {
X	if (l != o) printf("%s\n", l)
X	printf("\n")
X	l="   "
X	z=3
X	o=""
X	u=0
X	next
X}
X/^\.LP/ || /^\.sp/ {
X	if (l != o) printf("%s\n", l)
X	printf("\n")
X	l=""
X	o=""
X	z=u=0
X	next
X}
X/^\.TP/ {
X	if (l != o) printf("%s\n", l)
X	printf("\n")
X	getline
X	l=$0
X	z=u=5
X	o="     "
X	if (length(l) >= 5) {
X		printf("%s\n", l)
X		l=o
X	} else while (length(l) < 4) l=l " "
X	next
X}
X{
X	s=1
X	p=" "
X	q=1
X}
X/^[ 	]/ {
X	if (l != o) printf("%s\n",l)
X	l=o "     "
X	z=u+5
X}
X/^\.[IB] / {
X	s=2
X}
X/^\.[IB]R / {
X	s=2
X	p=""
X	q=0
X}
X{
X	r=" "
X	while (s <= NF) {
X		k=length($s)
X		if ((z+k) > m) {
X			printf("%s\n", l)
X			l=o
X			z=u
X		}
X		if (l != o)
X			l=l r $s
X		else
X			l=l $s
X		z=z + q + k
X		r=p
X		s++
X	}
X}
XEND {
X	if (l != o) printf("%s\n\n", l)
X}'
NO_NEWS_IS_GOOD_NEWS
chmod 0644 mk_online_man || echo "restore of mk_online_man fails"
set `wc -c mk_online_man`;Sum=$1
if test "$Sum" != "1198"
then echo original size 1198, current size $Sum;fi
echo "x - extracting more.c (Text)"
sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > more.c &&
X#include "config.h"
X#include "news.h"
X#include "term.h"
X#include "menu.h"
X#include "keymap.h"
X#include "regexp.h"
X
Xexport int  monitor_mode = 0;
Xexport int  show_article_date = 1;
Xexport int  first_page_lines = 0;
Xexport int  overlap = 2;
Xexport int  mark_overlap = 0;
Xexport char *header_lines = NULL;
X
Ximport int  preview_window;
Ximport int  novice;
X
Ximport char *delayed_msg;
X
Xextern char *init_save();
X
Xstatic char rot13tab[128];
Xstatic int norot13 = 1, rot13;
Xstatic int compress_space;
X
Xstatic regexp *regular_expr = NULL;
X
X#define LINEMAX	5000	/* max no of lines backed up */
X
Xstatic struct header_def {
X    char field;
X    char *text;
X    char **news;
X    char **digest;
X} header_defs[] = {
X    'A', "Approved",	&news.ng_appr,		0,
X    'B', "Distribution",&news.ng_dist,		0,
X    'D', "Date",	&news.ng_date,		&digest.dg_date,
X    'F', "From",	&news.ng_from,		&digest.dg_from,
X    'I', "Message-Id",	&news.ng_ident,		0,
X    'K', "Keywords",	&news.ng_keyw,		0,
X    'L', "Lines",	&news.ng_xlines,	0,
X    'N', "Newsgroups",	&news.ng_groups,	0,
X    'O', "Organization",&news.ng_org,		0,
X    'P', "Path",	&news.ng_path,		0,
X    'R', "Reply-To",	&news.ng_reply,		0,
X    'S', "Subject",	&news.ng_subj,		&digest.dg_subj,
X    'W', "Followup-To",	&news.ng_follow,	0,
X    'X', "References",	&news.ng_ref,		0,
X    0
X};
X
X
Xmore(ah, mode, screen_offset)
Xarticle_header *ah;
Xint mode, screen_offset;
X{
X    register c, col, lno;
X    register FILE *art;
X    int more_cmd, eof, skip_spaces, has_space, window_lines;
X    int form_feed, ignore_nl;
X    off_t firstl, lastl;
X    off_t linepos[LINEMAX];
X    char linebuf[200], *lp;
X    int linenum, maxline, topline, print_lines, lno1;
X    int underline_line, fake_underline;
X    int match_lines, match_redraw, match_topline, match_botline;
X    int goto_line, prev_goto, stop_line, extra_lines;
X    int in_digest = ah->flag & A_DIGEST;
X    article_header digestah;
X    char *fname, *hdrline;
X    extern STANDOUT;
X    char pr_fmt[60], send_date[40];
X    int match_expr;
X    char *match_start, *match_end;
X    int open_modes, hdr_mode, o_mode;
X    struct header_def *hdef;
X    extern int alt_cmd_key, in_menu_mode, any_message;
X#ifdef RESIZING
X    int entry_col = Columns;
X#endif    
X    extern char *pct();
X    
X#define more_return(cmd) \
X    { more_cmd = cmd; goto more_exit; }
X
X    if (ah->a_group != NULL) init_group(ah->a_group);
X    
X    open_modes = SKIP_HEADER;
X    if (show_article_date || header_lines) {
X	open_modes |= FILL_NEWS_HEADER;
X	if (header_lines == NULL) 
X	    open_modes |= GET_DATE_ONLY;
X	else
X	    open_modes |= GET_ALL_FIELDS;
X	if (in_digest) open_modes |= FILL_DIGEST_HEADER;
X    }
X    
X    /* temporary use of linepos array as header buffers... */
X
X    art = open_news_article(ah, open_modes, (char *)&linepos[100], (char *)&linepos[LINEMAX/2]);
X
X    if (art == NULL) {
X	msg("Expired: \"%s: %-.50s\"", ah->sender, ah->subject);
X	if ((mode & MM_PREVIEW) == 0) user_delay(1);
X	return MC_NEXT;
X    }
X
X    o_mode = in_menu_mode;
X    in_menu_mode = 0;
X    
X    if (screen_offset)
X	if (preview_window < 1 && Lines - screen_offset < 6) 
X	    screen_offset = 0;
X        else {
X	    so_printxy(0, screen_offset++, "%s: %s ", ah->sender, ah->subject);
X	    if (!STANDOUT) screen_offset++;
X	    clrline();
X	}
X    
X    if (show_article_date) {
X	if (in_digest && digest.dg_date)
X	    strncpy(send_date, digest.dg_date, 40);
X	else
X	    if (news.ng_date) {
X		strncpy(send_date, news.ng_date, 40);
X	    } else
X		send_date[0] = NUL;
X	send_date[39] = NUL;
X	if (lp = strrchr(send_date, ':')) *lp = NUL;
X    }
X    
X    linepos[0] = ah->hpos;
X    linepos[1] = firstl = ah->fpos;
X    maxline = 1;
X    topline = 1;
X    hdrline = screen_offset == 0 ? header_lines : "";
X    
X    lastl = (ah->lpos - firstl + 99)/100;
X    if (lastl == 0) lastl = 1;	/* impossible ? */
X    
X    rot13 = 0;
X    compress_space = 0;
X    goto_line = -1, prev_goto = 1;
X    match_lines = match_redraw = match_expr = 0;
X    underline_line = -1;
X    fake_underline = 0;
X    
X    stop_line = first_page_lines ? first_page_lines : -1;
X
X    sprintf(pr_fmt,
X	   "\1\2-- %s%s %s-----%%s-----\1",
X	   (mode & MM_PREVIEW) ? "PREVIEW " : "",
X	   (mode & MM_DIGEST) ? "FULL DIGEST" :
X	   (mode & MM_LAST_ARTICLE) ? "LAST ARTICLE" : "ARTICLE",
X	   novice ? "-- help:? " : "");
X
X    if (screen_offset) goto safe_redraw;
X    
X redraw:    	/* redraw that will destroy whole screen */
X    screen_offset = 0;
X
X safe_redraw: 	/* redraw of "more window" only */
X    linenum = topline;
X    
X next_page:
X    no_raw();
X
X    s_keyboard = 0;
X
X    if (stop_line) {
X	
X	if (lno = screen_offset) {
X	    gotoxy(0, lno);
X	    clrpage(lno);
X	} else
X	    clrdisp();
X
X      print_header:
X	if (hdrline == NULL || *hdrline == '*') {
X	    if (hdrline && *++hdrline == NUL) hdrline = NULL;
X
X	    if (linenum <= 1) {
X		if (linenum == 0 || (mode & MM_DIGEST)) {
X		    if (screen_offset) {
X			lno--;
X			if (!STANDOUT) lno--;
X			gotoxy(0, lno);
X			clrpage(lno);
X		    }
X		    so_printxy(0, lno,
X			       "Newsgroup: %s, article: %ld%s",
X			       current_group->group_name,
X			       (long)(ah->a_number),
X			       ((mode & MM_DIGEST) || in_digest) 
X			       ? "  *DIGEST*" : "");
X/*		    fseek(art, linepos[0], 0); */
X		    
X		    lno++;
X		    if (!STANDOUT) lno++;
X		} else {
X		    if (screen_offset == 0 && linenum == 1) {
X			if (show_article_date) so_printxy(-1, 0, send_date);
X			
X			/* so_printxy will cut subject */
X			so_printxy(0, lno, "%s: %s ", ah->sender, ah->subject);
X			lno++;
X			if (!STANDOUT) lno++;
X		    }
X		}
X	    }
X	}
X
X	if (hdrline && screen_offset == 0) {
X		
X	    hdr_mode = 0;
X	    while (*hdrline) {
X		
X		if (*hdrline == '*') goto print_header;
X		
X		if (*hdrline == '=') {
X		    hdr_mode = 1;
X		    hdrline++;
X		    continue;
X		}
X		if (*hdrline == '_') {
X		    hdr_mode = 2;
X		    hdrline++;
X		    continue;
X		}
X		for (hdef = header_defs; hdef->field; hdef++) {
X		    if (hdef->field != *hdrline) continue;
X		    if (in_digest) {
X			if (hdef->digest == NULL) break;
X			if ((lp = *(hdef->digest)) == NULL)
X			    break;
X		    } else 
X			if ((lp = *(hdef->news)) == NULL)
X			    break;
X		    gotoxy(0, lno++);
X		    c = strlen(hdef->text) + 2;
X		    col = c + strlen(lp);
X		    if (col > Columns) lp[Columns - c] = 0;
X		    printf("%s: ", hdef->text);
X		    switch (hdr_mode) {
X		     case 0:
X			break;
X		     case 1:
X			highlight(1);
X			break;
X		     case 2:
X			underline(1);
X			break;
X		    }
X		    printf("%s", lp);
X		    switch (hdr_mode) {
X		     case 0:
X			break;
X		     case 1:
X			highlight(0);
X			break;
X		     case 2:
X			underline(0);
X			break;
X		    }
X		    break;
X		}
X		hdr_mode = 0;
X		hdrline++;
X	    }
X	    
X	    hdrline = NULL;
X	    putchar(NL);
X	    lno++;
X	}
X	    
X	lno1 = lno;
X	topline = linenum;
X	
X	window_lines = Lines - lno - 2;
X	print_lines = window_lines;
X	
X	ignore_nl = 1;	/* ignore blank lines at top op screen */
X    } else
X	print_lines = extra_lines;	/* LINT complaints here -- ignore */
X    
X    if (stop_line > 0) {
X	if (print_lines > stop_line) {
X	    extra_lines = print_lines - stop_line;
X	    print_lines = stop_line;
X	    underline_line = -1;
X	}
X	stop_line = 0;
X    } else
X	stop_line = -1;
X    
X next_line:
X
X    if (linenum == LINEMAX) {
X	/* THIS IS EXTREMELY DIRTY (like most quick hacks) */
X	/* the following definitions assume that LINEMAX >> START+SIZE  */
X#define	HACK_START	1000	/* line numbers > START_POS are wrong */
X#define	HACK_SIZE	1000	/* we simply delete HACK_SIZE lines */
X	for (linenum = HACK_START; linenum < (LINEMAX-HACK_SIZE); linenum++)
X	    linepos[linenum] = linepos[linenum+HACK_SIZE];
X	maxline = linenum - 1;
X	if (goto_line > 0) goto_line -= HACK_SIZE;
X	if (prev_goto > HACK_START)
X	    if (prev_goto > (HACK_START + HACK_SIZE))
X		prev_goto -= HACK_SIZE;
X	    else
X		prev_goto = HACK_START;
X    }
X	
X    if (goto_line == linenum) {
X	goto_line = -1;
X	goto next_page;
X    }
X	
X    eof = 0;
X
X    if (linenum > maxline)
X	linepos[++maxline] = ftell(art);
X    else
X    if (linenum > 0)
X	fseek(art, linepos[linenum], 0);
X	    
X
X    if (linepos[linenum] >= ah->lpos) {
X	if (match_expr) {
X	    match_expr = 0;
X	    topline = match_topline;	/* LINT complaints here -- ignore */
X	    linenum = match_botline;	/* LINT complaints here -- ignore */
X	    fseek(art, linepos[linenum], 0);
X	    msg("Not found");
X	    goto Prompt;
X	}
X	eof++;
X	if (goto_line > 0) {
X	    goto_line = -1;
X	    linenum -= window_lines/2;
X	    goto next_page;
X	}
X	goto Prompt;
X    }
X
X    if (linenum == 0) {
X	if (ftell(art) >= linepos[1]) {
X	    linenum = 2;	/* current line is 1st line ! */
X	    lno1 = lno;
X	}
X    } else
X	linenum++;
X    
X    lp = linebuf;
X    col = 0;
X    form_feed = 0;
X    
X next_char:
X
X    c = getc(art);
X    if (c == EOF) {
X	eof++;
X	if (lp == linebuf) goto Prompt;
X	goto end_line;
X    }
X    
X    if (c & 0200) {
X	col += 4;
X	if (col > Columns) {	/* then there is no room for M-^X */
X	    ungetc(c, art);
X	    goto long_line;
X	}
X	c &= 0177;
X	*lp++ = 'M';
X	*lp++ = '-';
X	if (c < SP) {
X	    *lp++ = '^';
X	    c += '@';
X	} else
X	    col--;
X    } else
X    if (c < SP) {
X	if (monitor_mode) {
X	    if (c == NL) {
X		*lp++ = '$';
X	        goto end_line;
X	    }
X	    if (col + 2 > Columns) {
X		*lp++ = '\\';
X		ungetc(c, art);
X		goto end_line;
X	    }
X	    *lp++ = '^';
X	    c += '@';
X	    col++;
X	} else
X	switch (c) {
X
X	 case '\f':
X	    if (lp == linebuf) {
X		if (goto_line && lno == lno1) goto next_line;
X		form_feed = 1;
X		goto Prompt;
X	    }
X	    form_feed = 1;
X	    goto end_line;
X	    
X	 case CR:
X	    if (lp == linebuf || ignore_nl) goto next_char;
X	    ignore_nl = 1;
X	    goto end_line;
X
X	 case NL:
X	    if (ignore_nl) {
X		ignore_nl = 0;
X		if (lp == linebuf) {
X		    if (lno == lno1) {
X			ignore_nl = 1;
X			goto next_line;
X		    }
X		    goto next_char;
X		}
X	    }
X	    goto end_line;
X	    
X	 case BS:
X	    if (col) {
X		lp--;
X		col--;
X	    }
X	    goto next_char;
X	    
X	 case TAB:
X	    if (col + 8 - (col & 07) >= Columns) 
X		goto long_line;
X
X	    do {
X		*lp++ = SP;
X		col++;
X	    } while (col & 07);
X	    goto next_char;
X	    
X	 default:
X	    if (col + 2 > Columns) {
X		ungetc(c, art);
X		goto long_line;
X	    }
X	    *lp++ = '^';
X	    c += '@';
X	    col++;
X	    break;
X	}
X    }
X    
X    *lp++ = c;
X    col++;
X    ignore_nl = 0;
X    
X    if (col < Columns) goto next_char;
X    
Xlong_line:
X    ignore_nl = 1;
X    
X end_line:
X    /* if we are seaching for a specific line, repeat until it is found */
X    if (goto_line >= linenum) goto next_line;
X
X    *lp++ = NUL;
X
X    if (match_expr) {
X	if (!regexec(regular_expr, linebuf))
X	    goto next_line;
X	match_expr = 0;
NO_NEWS_IS_GOOD_NEWS
echo "End of part 7"
echo "File more.c is continued in part 8"
echo "8" > s2_seq_.tmp
exit 0
---
Kim F. Storm        storm@texas.dk        Tel +45 429 174 00
Texas Instruments, Marielundvej 46E, DK-2730 Herlev, Denmark
	  No news is good news, but nn is better!

-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.
Use a domain-based address or give alternate paths, or you may lose out.