[comp.sources.unix] v19i069: NN, a Usenet news reader, Part08/15

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

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

#!/bin/sh
# this is part 8 of a multipart archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file more.c continued
#
CurArch=8
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 more.c"
sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' >> more.c
X	match_lines = 1;
X	if (linenum > match_botline) {
X	    match_redraw = 0;
X	    linenum -= 5;
X	    goto next_page;
X	} 
X	match_redraw = (stop_line < 0);
X	stop_line = -1;
X	lno = lno1 + linenum - topline - 1;
X	print_lines = window_lines - lno + lno1;
X    }
X    
X    /* now print the line */
X
X    if (match_lines && underline_line != linenum && 
X	regexec(regular_expr, linebuf)) {
X	match_start = regular_expr->startp[0];
X	match_end = regular_expr->endp[0];
X    } else {
X	if (match_redraw) goto no_print;
X	match_start = NULL;
X    }
X
X    gotoxy(0, lno);
X
X    if (mark_overlap && underline_line == linenum)
X	if (!underline(1))
X	    fake_underline = 1;
X    skip_spaces = has_space = 0;
X    
X    for (lp = linebuf; c = *lp; lp++) {
X
X	if (match_start) {
X	    if (lp == match_start) highlight(1);	    
X	    if (lp == match_end) {
X		highlight(0);
X		match_start = NULL;
X		if (match_redraw) goto no_print;
X	    }
X	}
X
X	if (c == SP) {
X	    if (skip_spaces) {
X		if (has_space) continue;
X		has_space++;
X	    }
X	    if (fake_underline) c = '_';
X	} else {
X	    if (compress_space && c != ' ') {
X		skip_spaces = 1;
X		has_space = 0;
X	    }
X	    if (rot13) c = rot13tab[c];
X	}
X
X	putchar(c);
X    }
X
X    if (match_start) highlight(0);
X    
X    if (mark_overlap && underline_line == linenum) {
X	while (lp - linebuf < 10) {
X	    putchar(fake_underline ? '_' : ' ');
X	    lp++;
X	}
X	underline(0);
X	underline_line = -1;
X	fake_underline = 0;
X    }
X
Xno_print:
X    
X    ++lno;
X    if (--print_lines > 0 && s_keyboard == 0 && form_feed == 0) goto next_line;
X
X    if (!eof && linenum >= maxline) {
X	if (ignore_nl) {
X	    c = getc(art);
X	    if (c == EOF)
X		eof++;
X	    else if (c != NL)
X		ungetc(c, art);
X	    else
X		ignore_nl = 0;
X	}
X	
X	if (!eof && ftell(art) >= ah->lpos) eof++;
X    }
X    
X    match_redraw = 0;
X
X Prompt:
X    
X    raw();
X 
X    prompt_line = lno;
X
X dflt_prompt:
X
X    prompt(pr_fmt,
X	   pct((long)(ah->fpos), (long)(ah->lpos), 
X	       (long)(linepos[topline]), (long)ftell(art)));
X
X    if (delayed_msg != NULL) {
X	msg(delayed_msg);
X	delayed_msg = NULL;
X    }
X    
X same_prompt:
X
X    if ((c = get_c()) & GETC_COMMAND)
X	c &= ~GETC_COMMAND;
X    else
X	c = more_key_map[c];
X
X    if (s_hangup) c = K_QUIT;
X    
X    if (any_message) clrmsg(0);
X    
X    if (c & K_MACRO) {
X	m_invoke(c & ~K_MACRO);
X	goto same_prompt;
X    }
X    
X alt_key:
X
X    switch (c) {
X     case K_UNBOUND:
X	ding();
X	goto same_prompt;
X	
X     case K_REDRAW:
X#ifdef RESIZING
X	if (Columns != entry_col) {
X	    entry_col = Columns;
X	    maxline = topline = 1;
X	}
X#endif	
X	 goto redraw;
X	
X     case K_CONTINUE:
X	if (eof) break;
X	if (screen_offset == 0 && form_feed == 0 && stop_line) {
X	    if (linenum > overlap) {
X		underline_line = linenum;
X		linenum -= overlap;
X	    }
X	}
X	goto next_page;
X
X     case K_LAST_MESSAGE:
X	msg((char *)NULL);
X	goto dflt_prompt;
X	
X     case K_HELP:
X	display_help("more");
X	goto redraw;
X	
X     case K_SHELL:
X	putchar(CR);
X	if (shell_escape()) goto redraw;
X	goto dflt_prompt;
X	
X     case K_EXTENDED_CMD:
X	switch (alt_command()) {
X
X	 case AC_QUIT:
X	    more_return( MC_QUIT );
X
X	 case AC_PROMPT:
X	 case AC_HEADER:
X	    goto dflt_prompt;
X
X	 case AC_REORDER:
X	    more_return( MC_MENU );
X	    
X	 case AC_REDRAW:
X	    goto redraw;
X
X	 case AC_KEYCMD:
X	    c = alt_cmd_key;
X	    goto alt_key;
X	}
X	
X     case K_QUIT:
X	more_return( MC_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	putchar(CR);
X	if (init_save(c, (char **)NULL) != NULL) {
X	    if (c == K_UNSHAR) 
X		prompt_line = Lines - 2;
X	    
X	    save(ah);
X	    end_save();
X	}
X
X	goto Prompt;
X	
X     case K_REPLY:
X     case K_FOLLOW_UP:
X     case K_MAIL_OR_FORWARD:
X	if (answer(ah, c, -1)) clrdisp();
X	goto Prompt;
X
X     case K_POST:
X	if (post_menu()) clrdisp();
X	goto Prompt;
X	
X     case K_CANCEL:
X	if (current_group->group_flag & G_FOLDER) {
X	    prompt("%s this folder entry",
X		   (ah->flag & A_CANCEL) ? "UNcancel" : "Cancel");
X	    if (yes(0)) fcancel(ah);
X	    goto Prompt;
X	}
X	
X	if (cancel(ah) == 0) goto Prompt;
X	more_return(MC_NEXT);
X
X     case K_UNSUBSCRIBE:
X	if (!unsubscribe(current_group)) goto Prompt;
X	if (current_group->group_flag & G_SUBSCRIPTION) goto Prompt;
X	more_return(MC_NEXTGROUP);
X
X     case K_GROUP_OVERVIEW:
X	group_overview(0);
X	goto redraw;
X	
X     case K_KILL_HANDLING:
X	kill_menu(ah);
X	goto Prompt;
X	
X     case K_READ_GROUP_UPDATE:
X	if (mode & MM_PREVIEW) more_return(MC_MENU);
X	prompt("Mark rest of current group as read?");
X	if (yes(1) <= 0) goto Prompt;
X	more_return(MC_READGROUP);
X
X     case K_NEXT_GROUP_NO_UPDATE:
X	if (mode & MM_PREVIEW) more_return(MC_MENU);
X	prompt("Skip to next group (current group is not updated) ?");
X	if (yes(0) <= 0) goto Prompt;
X	more_return(MC_NEXTGROUP);
X
X     case K_BACK_TO_MENU:
X	more_return(MC_MENU);
X	
X     case K_PREVIOUS:
X	if ((mode & MM_PREVIOUS) == 0) {
X	    msg("No previous article");
X	    goto dflt_prompt;
X	}
X	more_return(MC_PREV);
X	
X     case K_ADVANCE_GROUP:
X     case K_BACK_GROUP:
X     case K_GOTO_GROUP:
X	switch (goto_group(c, ah)) {
X	 case ME_NO_REDRAW:
X	    goto Prompt;
X
X	 case ME_QUIT:
X	    more_return( ME_QUIT );
X
X	 default:
X	    goto redraw;
X	}
X
X     case K_NEXT_LINE:
X	if (eof) break;
X	if (screen_offset) goto same_prompt;
X	
X	print_lines = 1;
X	goto scroll;
X	
X     case K_NEXT_HALF_PAGE:
X	if (eof) break;
X	if (screen_offset) goto same_prompt;
X
X	print_lines = window_lines/2;
X
X     scroll:
X	gotoxy(0, prompt_line);
X	clrpage(prompt_line);
X	no_raw();
X	
X	if (print_lines + lno < Lines)
X	    goto next_page;
X	    
X	gotoxy(0, Lines-1);
X	c = print_lines + lno - Lines + 1;
X	while (--c >= 0) {
X	    putchar(NL);
X	    if (--lno1 < 0) topline++;
X	    prompt_line--;
X	}
X	if (lno1 < 0) lno1 = 0;
X	if (prompt_line < 0) prompt_line = 0;
X	lno = prompt_line;
X	goto next_line;
X	
X     case K_PREV_HALF_PAGE:
X	if (topline <= 1) goto Prompt;
X	linenum = topline - window_lines/2;
X	if (linenum < 1) linenum = 1;
X	goto next_page;
X	
X     case K_PREV_PAGE:
X	if (topline <= 1) goto Prompt;
X	linenum = topline - window_lines + overlap; /* not perfect after FF */
X	underline_line = topline;
X	if (linenum < 1) linenum = 1;
X	goto next_page;
X	
X     case K_GOTO_LINE:
X	prompt("\1Go to line:\1 ");
X	if ((fname = get_s(NONE, NONE, "$^", NO_COMPLETION)) == NULL) 
X	    goto Prompt;
X
X	if (*fname == NUL) {
X	    if (prev_goto < 0) goto Prompt;
X	    goto_line = prev_goto;
X
X	} else
X	if (*fname == '$')
X	    goto_line = 30000;
X	else
X	if (*fname == '^')
X	    goto_line = 1;
X	else {
X	    goto_line = atoi(fname);
X	    if (goto_line <= 0) {
X		goto_line = -1;
X		goto Prompt;
X	    }
X	}
X
X     goto_page:
X	prev_goto = topline;
X	
X	if (goto_line <= maxline)
X	    linenum = goto_line;
X	
X	goto next_page;    
X
X     case K_SELECT_SUBJECT:
X	more_return(MC_ALLSUBJ);
X
X     case K_HEADER_PAGE:
X	fseek(art, linepos[0], 0);
X	goto_line = 0;
X	goto goto_page;
X	
X     case K_FIRST_PAGE:
X	goto_line = 1;
X	goto goto_page;
X
X     case K_LAST_PAGE:
X	goto_line = 30000;
X	goto goto_page;
X
X     case K_GOTO_MATCH:
X	prompt("\1/\1");
X	if ((fname = get_s(NONE, NONE, "/", NO_COMPLETION)) == NULL) 
X	    goto Prompt;
X
X	if (*fname && *fname != '/') {
X	    if (regular_expr) free(regular_expr);
X	    regular_expr = regcomp(fname);
X	}
X
X     case K_NEXT_MATCH:
X	if (regular_expr == NULL) {
X	    msg("No previous expression");
X	    goto Prompt;
X	}
X	
X	match_expr = 1;
X	if (match_topline != topline) prev_goto = topline;
X	match_topline = topline;
X	match_botline = linenum;
X	if (match_lines == 0 && topline <= 1) linenum = topline;
X	match_lines = 0;
X	goto next_line;		/* don't clear the screen if no match */
X	
X     case K_FULL_DIGEST:
X	if (mode & MM_DIGEST) 
X	    more_return( MC_NO_REDRAW );
X
X	if (!in_digest) 
X	    goto same_prompt;
X	
X	/* could do something more clever here later */
X	digestah = *ah;
X	digestah.flag &= ~A_DIGEST;
X	digestah.hpos = digestah.fpos = 0;
X	fseek(art, 0L, 2);
X	digestah.lpos = ftell(art);
X	
X	switch (more(&digestah, mode | MM_DIGEST, screen_offset)) {
X	    
X	 case MC_REDRAW:
X	    goto redraw;
X	    
X	 case MC_NO_REDRAW:
X	    goto safe_redraw;
X	    
X	 case MC_QUIT:
X	    more_return( MC_QUIT );
X	    
X	 default:
X	    goto safe_redraw;
X	}
X
X     case K_LEAVE_ARTICLE:
X	ah->flag |= A_SELECT;
X	/* fall thru */
X
X     case K_NEXT_ARTICLE:
X	if ((mode & MM_PREVIEW) == 0) break;
X	more_return(MC_PREVIEW_NEXT);
X
X     case K_NEXT_SUBJECT:
X	more_return(MC_NEXTSUBJ);
X	
X     case K_ROT13:
X	if (norot13) {
X	    register i;
X	    for (i=0; i<=127; i++) {
X		c = i;
X		if (c >= 'a' && c <= 'm') c += 13;
X		else if (c >= 'n' && c <= 'z') c -= 13;
X		else if (c >= 'A' && c <= 'M') c += 13;
X		else if (c >= 'N' && c <= 'Z') c -= 13;
X		rot13tab[i] = c;
X	    }
X	    norot13 = 0;
X	}
X	
X	rot13 = !rot13;
X	goto safe_redraw;
X	
X     case K_COMPRESS:
X	compress_space = !compress_space;
X	goto safe_redraw;
X	
X     case K_PREVIEW:
X	if (mode & MM_PREVIEW)
X	    more_return(MC_PREVIEW_OTHER);
X
X	/* fall thru to "default" */
X
X     default:
X	msg("Command %d not supported", c);
X	goto dflt_prompt;
X    }
X
X    more_return(MC_NEXT);
X
X more_exit:
X    in_menu_mode = o_mode;
X    
X    no_raw();
X    fclose(art);
X
X    if ((mode & MM_PREVIEW) && more_cmd != MC_QUIT) {
X	gotoxy(0, screen_offset);
X	clrpage(screen_offset);
X	if (more_cmd == MC_PREVIEW_NEXT) {
X	    if (screen_offset == 0) prompt_line = -1;
X	} else {
X	    if (screen_offset == 0) return MC_REDRAW;
X	    if (more_cmd != MC_PREVIEW_OTHER) return MC_NO_REDRAW;
X	}
X    }
X    
X    return more_cmd;
X}
X
NO_NEWS_IS_GOOD_NEWS
echo "File more.c is complete"
chmod 0644 more.c || echo "restore of more.c fails"
set `wc -c more.c`;Sum=$1
if test "$Sum" != "19863"
then echo original size 19863, current size $Sum;fi
echo "x - extracting news.c (Text)"
sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > news.c &&
X#include "config.h"
X#include "news.h"
X
Xexport retry_on_error = 0;
X
X
XFILE *open_news_article(art, modes, buffer1, buffer2)
Xarticle_header 		*art;
Xint 			modes;
Xnews_header_buffer	buffer1, buffer2;
X{
X    char *body;
X    char *digest_buffer;
X    char *parse_header(), **art_hdr_field();
X    struct stat statb;
X    int retry;
X    FILE *f;
X#ifdef NNTP
X    FILE *nntp_get_article();
X#endif /* NNTP */
X
X    if (art->flag & A_FOLDER) {
X	f = open_file(group_path_name, OPEN_READ);
X	if (f == NULL) return NULL;
X	fseek(f, art->hpos, 0);
X#ifdef NNTP    
X    } else
X    if (use_nntp) {
X	f = nntp_get_article(art->a_number);
X	if (f == NULL) return NULL;
X#endif /* NNTP */
X    } else {
X	sprintf(group_file_name, "%d", art->a_number);
X
X	retry = retry_on_error;
X	while ((f = open_file(group_path_name, OPEN_READ)) == NULL)
X	    if (--retry < 0) return NULL;
X
X	/* necessary because empty files wreak havoc */
X	if (fstat(fileno(f), &statb) < 0 ||
X	    statb.st_size < art->lpos || statb.st_size <= (off_t)0) {
X	    fclose(f);
X	    return NULL;
X	}
X    }
X    
X    digest_buffer = buffer1;
X    
X    if (modes & FILL_NEWS_HEADER) {
X
X	news.ng_from 	= NULL;
X	news.ng_reply 	= NULL;
X	news.ng_name 	= NULL;
X	news.ng_subj 	= NULL;
X	news.ng_groups 	= NULL;
X	news.ng_ref 	= NULL;
X
X	news.ng_xlines 	= NULL;
X
X	if (modes & GET_ALL_FIELDS) {
X	    news.ng_path 	= NULL;
X	    news.ng_reply 	= NULL;
X	    news.ng_ident 	= NULL;
X	    news.ng_follow 	= NULL;
X	    news.ng_keyw 	= NULL;
X	    news.ng_dist 	= NULL;
X	    news.ng_org 	= NULL;
X	    news.ng_appr 	= NULL;
X	    news.ng_date	= NULL;
X	}
X
X	if (modes & GET_DATE_ONLY)
X	    news.ng_date	= NULL;
X	
X	body = parse_header(f, art_hdr_field, modes, buffer1);
X    
X	news.ng_lines = news.ng_xlines ? atoi(news.ng_xlines) : -1;
X    
X	if (modes & FILL_OFFSETS) {
X	    art->fpos = news.ng_fpos = ftell(f);
X
X	    fseek(f, (off_t)0, 2);
X	    news.ng_lpos = ftell(f);
X	}
X
X	news.ng_flag = 0;
X
X	if (news.ng_appr) news.ng_flag |= N_MODERATED;
X    
X	if (modes & DIGEST_CHECK && is_digest(body))
X	    news.ng_flag |= N_DIGEST;
X	
X	digest_buffer = buffer2;
X    }
X
X    if (modes & FILL_DIGEST_HEADER) {
X	fseek(f, art->hpos, 0);
X	parse_digest_header(f, modes & GET_ALL_FIELDS, digest_buffer);
X    }
X
X    fseek(f, (modes & SKIP_HEADER) ? art->fpos : art->hpos, 0);
X    
X    return f;
X}
X
X
X
Xchar *parse_header(f, hdr_field, modes, hdrbuf)
XFILE 			*f;
Xchar 			**(*hdr_field)();
Xint 			modes;
Xnews_header_buffer	hdrbuf;
X{
X    register char *bp, **fptr;
X    int siz, all, date_only;
X    off_t pos;
X    
X    pos = ftell(f);
X
X/* read first NEWS_HEADER_BUFFER bytes (should be more than enough) */
X
X    all 	= modes & GET_ALL_FIELDS;
X    date_only 	= modes & GET_DATE_ONLY;
X    
X    siz = fread(hdrbuf, sizeof(char), NEWS_HEADER_BUFFER, f);
X    
X    bp = hdrbuf;
X    bp[siz-1] = NUL;
X    
X    /* decode subarticle header */
X    while (*bp) {
X
X	if (*bp == NL) {	/* empty line following header */
X	    ++bp;
X	    fseek(f, pos + (bp - hdrbuf), 0);
X	    return bp;
X	}
X	
X	if (*bp == SP) {	/* for comp.ai.neural-nets digests */
X	    bp++;		/* which have <NL><space><NL> after header */
X	    continue;
X	}
X
X	if (date_only && *bp != 'D')
X	    fptr = NULL;
X	else
X	    if (fptr = (*hdr_field)(bp, all)) {
X		while (*bp && *bp != ':' && isascii(*bp) && !isspace(*bp))
X		    bp++;
X		bp++;
X		while (*bp && isascii(*bp) && isspace(*bp)) bp++;
X		*fptr = bp;
X	    }
X	while (*bp && *bp != NL) bp++;
X	if (fptr && bp == *fptr) *fptr = NULL;
X	if (*bp) *bp++ = NUL;
X    }
X
X    return bp;
X}
X
X
Xstatic char **art_hdr_field(lp, all)
Xregister char *lp;
Xint all;
X{
X    
X#define check(name, lgt, field) \
X    if (strncmp(name, lp, lgt) == 0) return &news.field
X
X    switch (*lp++) {
X
X     case 'A':
X	if (!all) break;
X	check("pproved: ",	 9, ng_appr);
X	break;
X
X     case 'D':
X	check("ate: ", 		 5, ng_date);
X	if (!all) break;
X	check("istribution: ", 	13, ng_dist);
X	break;
X
X     case 'F':
X	check("rom: ",		 5, ng_from);
X	if (!all) break;
X	check("ollowup-To: ",	12, ng_follow);
X	break;
X
X     case 'K':
X	if (!all) break;
X	check("eywords: ",	 9, ng_keyw);
X	break;
X
X     case 'L':
X	check("ines: ",	 	 6, ng_xlines);
X	break;
X
X     case 'M':
X	if (!all) break;
X	check("essage-ID: ",	11, ng_ident);
X	break;
X
X     case 'N':
X	check("ewsgroups: ",	11, ng_groups);
X	break;
X
X     case 'O':
X	if (!all) break;
X	check("rganization: ",	13, ng_org);
X	check("rganisation: ",	13, ng_org);
X	break;
X
X     case 'P':
X	if (!all) break;
X	check("ath: ",		 5, ng_path);
X	break;
X
X     case 'R':
X	check("eply-To: ",	 9, ng_reply);
X	check("eferences: ",	11, ng_ref);
X	break;
X
X     case 'S':
X	check("ubject: ",	 8, ng_subj);
X	if (news.ng_from == NULL)
X	    check("ender: ",	 7, ng_from);
X	break;
X
X     case 'T':
X	check("itle: ",	 	 6, ng_subj);
X	break;
X    }
X
X    return NULL;
X
X#undef check
X}
X
X
Xis_header_line(line)
Xchar *line;
X{
X    return art_hdr_field(line, 0) != (char **)NULL;
X}
NO_NEWS_IS_GOOD_NEWS
chmod 0644 news.c || echo "restore of news.c fails"
set `wc -c news.c`;Sum=$1
if test "$Sum" != "4805"
then echo original size 4805, current size $Sum;fi
echo "x - extracting news.h (Text)"
sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > news.h &&
X
X
Xstruct news_header {
X
X	int	ng_flag;	/* flags:			*/
X#	  define N_DIGEST 1	/*   article is part of a digest*/
X#	  define N_MODERATED 2	/*   group is moderated		*/
X
X	off_t	ng_fpos;	/* position of article text	*/
X	off_t	ng_lpos;	/* last text offset
X				/* header lines:		*/
X	char	*ng_from;	/*   from			*/
X	char	*ng_name;	/*   senders name		*/
X	char	*ng_subj;	/*   subject			*/
X	char	*ng_groups;	/*   newsgroups			*/
X	char	*ng_path;	/*   path			*/
X	char	*ng_reply;	/*   reply-to			*/
X	char	*ng_ident;	/*   message id			*/
X	char	*ng_follow;	/*   followup to		*/
X	char	*ng_ref;	/*   references			*/
X	char	*ng_keyw;	/*   keywords			*/
X	char	*ng_dist;	/*   distibution		*/
X	char	*ng_org;	/*   organization		*/
X	char	*ng_appr;	/*   approved			*/
X
X	char	*ng_date;	/*   date			*/
X	
X	char	*ng_xlines;	/*   lines (from header)	*/
X	int	ng_lines;	/*   lines (decoded)		*/
X} news;
X
X
X/*
X * digest article subheader
X */
X
Xstruct digest_header {
X	off_t	dg_hpos;	/* position of article header	*/
X	off_t	dg_fpos;	/* position of article text	*/
X	off_t	dg_lpos;	/* last text position		*/
X				/* header lines:		*/
X	char	*dg_date;	/*   date			*/
X	char	*dg_from;	/*   from			*/
X	char	*dg_subj;	/*   subject			*/
X	char	*dg_to;		/*   to				*/
X	
X	int	dg_lines;	/*   lines (pseudo field)	*/
X} digest;
X
X
X#define	NEWS_HEADER_BUFFER	2048
X
Xtypedef char	news_header_buffer[NEWS_HEADER_BUFFER];
X
X
XFILE *open_news_article(/* header, modes [, buffer1 [, buffer2]] */);
X
X/* modes */
X
X#define	FILL_NEWS_HEADER	0x0001	/* parse first header -> buffer1 */
X#define	FILL_DIGEST_HEADER	0x0002	/* parse second header -> buffer[12] */
X
X
X#define	GET_ALL_FIELDS		0x0010	/* get all fields (otherwise only   */
X					/* name, subj, groups, lines	    */
X
X#define	GET_DATE_ONLY		0x0020	/* get Date field		    */
X
X#define	FILL_OFFSETS		0x0080	/* fill ng_[hfl]pos */
X
X
X#define	DIGEST_CHECK		0x0100	/* set N_DIGEST if "digest" in subj */
X					/* only valid with FILL_NEWS_HEADER */
X
X
X#define	SKIP_HEADER		0x1000	/* position after (sub) header */
X
X
NO_NEWS_IS_GOOD_NEWS
chmod 0644 news.h || echo "restore of news.h fails"
set `wc -c news.h`;Sum=$1
if test "$Sum" != "1990"
then echo original size 1990, current size $Sum;fi
echo "x - extracting nn.1 (Text)"
sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > nn.1 &&
X.TH NN 1 "Release 6.3"
X.\" (c) Copyright 1988, Kim F. Storm, Texas Instruments A/S, Denmark
X.\" 
X.\" NOTICE:  Some versions of the -man package may have problems with
X.\" =======  the @ characters in this manual.  Fix your man package by
X.\"          substituting ALL occurrences of the @ character in
X.\"          tmac.an (or perhaps tmac.an.new) by a BEL (^G) character.
X.\" 
X.UC 4
X.SH NAME
Xnn \- efficient net news interface (No News is good news)
X.SH SYNOPSIS
X.B nn
X[ \fIoptions\fP ]  [ -g ] [ \fInewsgroup\fP  |  +\fIfolder\fP  |  \fIfile\fP ]...
X.SH DESCRIPTION
X\fINn\fP is yet another net news reader.  Like the other news readers,
X\fInn\fP will let you read the new (unread) articles in one news group at a
Xtime, but unlike other similar programs, \fInn\fP has a menu based article 
Xselection prior to reading the articles in the news group.
X.PP
XWhen a news group is entered, \fInn\fP will locate all the presently
Xunread articles in the group, and extract their sender, subject, and
Xother relevant information.  This information is then rearranged,
Xsorted, and marked in various ways to give it a pleasant format when
Xit is presented to the user at the terminal.
X.PP
XThis will be done very quickly, because \fInn\fP uses its own database
Xto maintain all the necessary information on a directly accessible
Xform (this database is built and maintained by the
X.IR nnmaster (1M)
Xprogram).
X.PP
XWhen the article menu appears on the screen, \fInn\fP will be in
Xa mode called \fBselection mode\fP, which will be described in full
Xdetail later.  In this mode, the articles which seems to be
Xinteresting can be selected by single keystrokes (using the keys a-z
Xand 0-9).  When all the interesting articles among the ones presently
Xdisplayed have been selected, the space bar is hit, which causes
X\fInn\fP to enter \fBreading mode\fP.
X.PP
XIn the reading mode, each of the selected articles will be presented
Xto the user, who simply use the space bar to go on to the next page of
Xthe current article, or to the next article.  (Of course, there are
Xall sorts of commands to scroll text up and down, skip to the next
Xarticle, responding to an article, decrypt an article, and so on).
X.PP
XWhen all the selected articles in the current group have been read,
Xthe last hit on the space bar will cause \fInn\fP will continue to the
Xnext group with unread articles, and enter selection mode on that group.
X.SH COMMAND LINE OPTIONS
X\fInn\fP accepts a lot of command line options, but only a few of
Xthese are used regularly.  Options can also be set permanently by
Xincluding appropriate 
X.I variable
Xsettings in the
X.I init
Xfile described later, so the less used options
Xare therefore presented after the description of the
Xcorresponding variables in the sections on Variables and Options towards
Xthe end of this manual.
X.LP
XThe frequently used command line options are:
X.TP
X\-\fBa0\fP
XMark 
X.I all
Xunread articles as read. \fInn\fP will ask whether all groups should
Xbe updated (unconditionally), or whether it should prompt for
Xconfirmation for each group.  In the latter case, terminating the
Xinput or breaking the program will cause \fInn\fP to ask whether the
Xrest of the groups should be updated unconditionally or whether they
Xshould remain unread.  (This options is a special case of the
X\-\fBa\fP\fIN\fP option described later.)
X.TP
X\-\fBg\fP
XPrompt for the name of a news group or folder to be entered (with
Xcompletion).
X.TP
X\-\fBl\fP\fIN\fP
XPrint only the first \fIN\fP lines of the first page of each article
Xbefore prompting to continue.  This is useful on slow terminals and
Xmodem lines to be able to see the first few lines of longer articles.
X.TP
X\-\fBs\fP\fIWORD\fP
XCollect only articles which contain the string
X.I WORD
Xin their subject (case is ignored).  This is normally combined with
Xthe -x and -m options to find all articles on a specific subject.
X.TP
X\-\fBs/\fP\fIregexp\fP
XCollect only articles whose subject matches the regular expression
X.IR regexp .
XThis is normally combined with the -x and -m options to find all
Xarticles on a specific subject.
X.TP
X\-\fBm\fP 
XMerge all articles into one `meta group' instead of showing
Xthem one group at a time.  This is normally used together with the -x
Xand -s options to get all the articles on a specific subject presented
Xon a single menu (when you don't care about which group they belong
Xto).  When -m is used, no articles will be marked as read.
X.TP
X\-\fBx\fP[\fIN\fP]
XPresent (or scan) all (or the last \fIN\fP) unread as well as
Xread articles.  This will 
X.I never
Xmark unread articles as read.
X.TP
X\fInews.group\fP  or  \fIfile\fP  or  \fI+folder\fP 
XIf none of these arguments are given, all subscribed news groups will
Xbe used.  Otherwise, only the specified news groups and/or files will
Xbe collected and presented.  In specifying a news groups, the
Xfollowing `meta notation' can be used: If the news group ends with a
X\&`.' (or `.all'), all subgroups of the news group will be collected,
Xe.g.
X.br
X	comp.sources.
X.br
XIf a news group starts with a `.' (or `all.'), all the matching
Xsubgroups will be collected, e.g.
X.br
X	\&.sources.unix
X.br
XThese notations cannot be mixed (yet)!
X.SH COMMAND INPUT
XIn general, \fInn\fP commands consist of one or two key-strokes, and \fInn\fP
Xreacts instantly to the commands you give it; you don't have to enter 
X.B return
Xafter each command (except where explicitly stated).
X.LP
XSome commands have more serious effects than others, and therefore
X\fInn\fP 
Xrequests you to confirm the command.  You confirm by hitting the
Xthe
X.B y
Xkey, and reject by hitting the
X.B n
Xkey.  Some `trivial' requests may also be confirmed simply by hitting 
X.B space.
XFor example, to confirm the creation of a save file, just hit 
X.B space,
Xbut to unsubscribe to a news group, you must enter
X.B y.
X.LP
XMany commands will require that you enter a line of text, e.g. a file
Xname or a shell command.  If you enter
X.B space
Xas the first character on a line, the line will be
Xfilled with a default value (if one is defined).  For example, the
Xdefault value for a file name is the last file name you have entered,
Xand the default shell command is your previous shell command.  You can
Xedit this default value as well as a directly typed text, using the
Xfollowing editing commands.  The \fBerase\fP,
X\fBkill\fP, and \fBinterrupt\fP keys are the keys
Xdefined by the current tty settings.  On systems without job control,
Xthe
X.B suspend
Xkey will be
X.B control-Z
Xwhile it is the current suspend character on system with job control.
X.TP
X.B erase
X.br
XDelete the last character on the line.
X.TP
X\fBdelete-word\fP   (normally ^W)
X.br
XDelete the last word or component of the input.
X.TP
X.B kill
X.br
XDelete all characters on the line.
X.TP
X\fBinterrupt\fP  and  \fBcontrol-G\fP
X.br
XCancel the command which needs the input.
X.TP
X\fBsuspend\fP
XSuspend \fInn\fP if supported by the system.  Otherwise, spawn an
Xinteractive shell.
X.TP
X.B return
X.br
XTerminate the line, and continue with the command.
X.SH BASIC COMMANDS
XThe are numerous commands in \fInn\fP, and most of them can be invoked
Xby a single keystroke.  The descriptions in this manual are based on
Xthe standard bindings of the commands to the keys, but it is possible
Xto customize these using the 
X.B map
Xcommand described later.  For each of the keystroke commands described
Xin this manual, the corresponding command name will also be shown in
Xcurly braces, e.g. {\fBcommand\fP}.
X.LP
XThe following commands work in both selection
Xmode and in reading mode.  The notation ^X means `control X':
X.TP
X\&\fB?\fP	{\fBhelp\fP}
XHelp.  Gives a one page overview of the commands available in the
Xcurrent mode.
X.TP
X\&\fB^L\fP	{\fBredraw\fP}
XRedraw screen.
X.TP
X\&\fB^R\fP	{\fBredraw\fP}
XRedraw screen (Same as ^L).
X.TP
X\&\fB^P\fP	{\fBmessage\fP}
XRepeat the last message shown on the message line.
X.TP
X\&\fB!\fP	{\fBshell\fP}
XShell escape.  The user is prompted for a command which is executed
Xby your favorite shell (see the 
X.B shell
Xvariable).  Shell escapes are described in detail later on.
X.TP
X\&\fBQ\fP	{\fBquit\fP}
XQuit \fInn\fP without marking \fIcurrent\fP group as read.  If you
Xhave selected any articles in the current group, \fInn\fP will offer
Xyou to use the same selections the next time you are about to read
Xthat group.  So, when you use the
X.B Q
Xcommand, you neither lose the current group nor the selections you
Xmight have made (unless the articles are expired in the meantime of
Xcourse).  \fInn\fP will also remember which menu pages you have
Xalready seen, and attempt to start at the last displayed menu page the
Xnext time the group is entered (if you confirm to "use old selections"
Xwhen asked).
X.TP
X\&\fBV\fP	{\fBversion\fP}
XPrint release and version information.
X.TP
X\fB:\fP\fIcommand\fP  {\fBcommand\fP}
XExecute the \fIcommand\fP by name.  This form can be used to invoke
Xany of \fInn\fP's commands, also those which cannot be bound to a key
X(such as
X.BR coredump ),
Xor those which are not bound to a key by default (such as
X.B post
Xand
X.BR unshar ).
X.SH SELECTION MODE
XIn selection mode, the screen is divided into four parts: the header
Xline showing the name of the news group and the number of articles,
Xthe menu lines which show the collected articles - one article
Xper line, the prompt line where you enter commands, and the message
Xline where \fInn\fP prints various messages to you.
X.LP
XEach menu line begins with an \fIarticle id\fP which is a unique
Xletter (or digit if your screen has more than ~30 lines).  To select
Xan articles for reading, you simply enter the corresponding \fIid\fP,
Xand the menu line will high-light to indicate that the article is
Xselected.  When you have selected all the interesting articles on the
Xpresent menu, you simply hit
X.B space.
XIf there are more articles collected for the current group than could 
Xbe presented on one screenful of text, you will
Xbe presented with the next portion of articles to select from.  When
Xyou have had the opportunity to select among all the articles in the
Xgroup, hitting
X.B space
Xwill enter reading mode.
X.LP
XIf no articles have been selected in the current group, hitting
X.B space
Xwill enter selection mode on the next news group, or exit \fInn\fP
Xif the current group was the last news group with unread articles.
XIt is thus possible to go through ALL
Xunread articles (without reading any of them) just by hitting
X.B space
Xa few times.
X.LP
XThe articles will be presented on the menu using one of the following
Xlayouts:
X.sp 0.5v
X.TP
X0:
X\fIx Name.........  Subject.............. +123\fP
X.TP
X1:
X\fIx Name.........   123  Subject..............\fP
X.TP
X2:
X\fIx 123  Subject...................................\fP
X.TP
X3:
X\fIx Subject...........................................\fP
X.LP
XHere \fIx\fP is the letter or digit that must be entered to select the
Xarticle, \fIName\fP is the real name of the sender (or the mail
Xaddress if the real name cannot be found), \fISubject\fP is the
Xcontents of the "Subject:" line in the article, and \fI123\fP is the number
Xof lines in the article.  
X.LP
XLayout 0 and 1 are just two ways to present the same information,
Xwhile layout 2 and 3 are intended for groups whose articles have very
Xlong subject lines, e.g. comp.sources.
X.LP
XLayout 1 is the default layout, and an alternative menu line layout is
Xselected using the \-\fBL\fP option or by setting the
X.B layout
Xvariable.  Once \fInn\fP is
Xstarted the layout can be changed at any time using the 
X.B L
Xkey {\fBlayout\fP}.
X.LP
XThe \fIName\fP is limited to 16 characters, and to make maximum use of
Xthis space, \fInn\fP will perform a series of simplifications on the
Xname, e.g. changing first names into initials, removing domain names
Xfrom mail addresses (if the real name is not found) etc.  It does a
Xgood job, but some people on the net put weird things into the From:
Xfield (or actually into their password file) which result in \fInn\fP
Xproducing quite cryptic "names"; these people have themselves to blame
X- not me!
X.LP
XThe \fISubject\fP is limited to ~60 characters (~75 in layout 3) and
Xis thus only an approximation to the actual subject line which may be
Xmuch longer.  To get as much out of this space, \fIRe:\fP prefixes (in
Xvarious forms) are recognized and replaced by an equivalent number of
X\&`>' characters.
X.PP
XSince articles are sorted accoring to the subject, two or more
Xadjacent articles may share the same subject (ignoring any `>'s).  In
Xthis case, only the first article will show the subject of the
Xarticle; the rest will only show the `>' characters in the subject
Xfield (or a `-' if there are no `>'s at the beginning of the line).  A
Xtypical menu will thus only show each subject once, saving a lot of
Xtime in scanning the news articles.
X.SH SELECTION MODE COMMANDS
XThe primary purpose of the selection mode is of course to select the
Xarticles to be read, but a number of other commands may also be
Xperformed in this mode: saving of articles in files, replying and
Xfollowing up on articles, mailing/forwarding articles, shell escapes
Xetc.
X.PP
XThe selected articles are marked either by showing the corresponding
Xmenu line in standout mode (reverse video), or if the terminal does
Xnot have this capability by placing an asterisk (*) after the
Xselection letter or digit.
X.LP
XThe basic article selection commands are:
X.TP
X\&\fBabc...z 01..9\fP  {\fIcannot be reassigned\fP}
XSelect the article with the given identification letter or digit, or
Xif the article is already selected, deselect it.
X.TP
X\&\fBspace\fP	{\fBcontinue\fP}
XContinue to next menu page, or if on last menu page, read the selected
Xarticles.  If no articles have been selected, continue to the next news
Xgroup.  (The 
X.B newline 
Xand 
X.B return
Xkeys have the same effect in selection
Xmode, but not in reading mode).
X.TP
X\&\fB@\fP	{\fBselect-invert\fP}
X.br
XReverse selections.  All selected articles on the current page are
Xdeselected, and vice-versa.  This is the quickest way to select all
Xarticles.
X.TP
X\&\fB~\fP	{\fBunselect-all\fP}
XDeselect all articles in the group (this works across all menu pages).
X.TP
X\&\fB+\fP	{\fBselect-auto\fP}
XPerform auto-selections in the group (see the section on "auto
Xkill/select" below).
X.LP
XDuring selection, the cursor will normally be placed on the article
Xfollowing the last selected article (initially the first article).
XThe article pointed out by the cursor is called the "current article".
XThe following commands work relative to the current cursor
Xposition.  
X.TP
X\&\fB.\fP	{\fBselect\fP}
XSelect or deselect the current article and move the cursor to the next
Xarticle.
X.TP
X\&\fB,\fP	{\fBline+1\fP}
XMove the cursor to the next article.  You can use the 
X.I down arrow
Xas well.
X.TP
X\&\fB/\fP	{\fBline-1\fP}
XMove cursor to previous article.  You can use the 
X.I up arrow
Xas well.
X.TP
X\&\fB*\fP	{\fBselect-subject\fP}
XSelect (or deselect) all articles with same subject as current
Xarticle.  This will work across several menu pages if necessary.
X.TP
X\&\fB-\fP\fIx\fP	{\fBselect-range\fP}
XSelect (or deselect) all articles between current article and the
Xarticle specified by
X.IR x .
XThis is normally used to select a range of articles, e.g. from 
X.I e
Xto 
X.I k
Xby simply typing 
X.BR e-k .
X.LP
XThe following commands move between the pages belonging to the same
Xnews group when there are more articles than will fit on a single page.
X.TP
X\&\fB>\fP	{\fBpage+1\fP}
XGoto next menu page.
X.TP
X\&\fB<\fP	{\fBpage-1\fP}
XGoto previous menu page, or to last menu page if on first menu page.
X.TP
X\&\fB$\fP	{\fBpage=$\fP}
XGoto last menu page.
X.TP
X\&\fB^\fP	{\fBpage=1\fP}
XGoto first menu page.
X.LP
XThe following commands are used to enter reading mode for the selected
Xarticles, and to move between news groups (in selection mode).
X.TP
X\&\fBspace\fP	{\fBcontinue\fP}
XEnter reading mode, or goto next menu page in current group or first
Xmenu page of next group.
X.TP
X\&\fBZ\fP	{\fBread-return\fP}
XEnter reading mode
X.I immediately
Xwith the currently selected articles.  When all
Xarticles have been read, return to selection mode in the
X.I current 
Xgroup.
X.TP
X\&\fBX\fP	{\fBread-skip\fP}
XEnter reading mode
X.I immediately
Xwith the currently selected articles.  When all
Xarticles have been read, enter selection mode in the
X.I next
Xnews group.  \fBWhen no articles are selected, it goes directly to the next
Xgroup\fP.
XThis can be used to skip all the articles in a large news group
Xwithout having to go through all the menu pages.
X.LP
XWhen the selected articles (if any) in a group have been read,
X.I all
Xarticles in that group will be marked as read!
X.LP
XIt is not possible to have single articles in a group marked `unread'.
X(New articles received after \fInn\fP was invoked are not seen by
X\fInn\fP, and of course they are not marked as read).
X.LP
XThe only alternative to marking all articles as read is to mark none
Xof the current collection as read.  This is done by the following
Xcommands:
X.TP
X\&\fBN\fP	{\fBnext-group\fP}
XGoto next news group without marking the articles in the current group
Xas read.  This can be used in combination with 
X.B Z
Xto read some articles in a group, because the
X.B Z
Xcommand does not mark the articles as read. 
X.TP
X\&\fBP\fP	{\fBprevious\fP}
XGoto previous group.  This command will enter selection mode on the
Xprevious active group (two P commands in sequence will bring you to
Xthe current group).
X.SH READING MODE COMMANDS
XIn reading mode, the articles are presented one page at a time.  To
Xget the next page of an article, simply hit
X.BR space ,
Xand when you are on the last page of an article, hit
X.B space
Xto get to the next article.  When you are on the last page of the
Xlast article, hit
X.B space
Xto enter selection mode on the next group (or the current group if
Xreading mode was entered using the
X.B Z
Xcommand).
X.LP
XThe following text scrolling commands are available:
X.TP
X\&\fBspace\fP	{\fBcontinue\fP}
XScroll
X.I one\ page\ forward
Xor continue with the next article or group as described above.
X.TP
X\&\fBbackspace / delete\fP  {\fBpage-1\fP}
XGo 
X.I one\ page\ backwards
Xin article.
X.TP
X\&\fBd\fP	{\fBpage+1/2\fP}
XScroll one
X.IR half\ page\ forward .
X.TP
X\&\fBu\fP	{\fBpage-1/2\fP}
XGo one
X.IR half\ page\ backwards .
X.TP
X\&\fBreturn\fP	{\fBline+1\fP}
XScroll 
X.I one\ line\ forward
Xin the article.
X.TP
X\&\fB^\fP	{\fBpage=1\fP}
XGoto the first page (excluding the header) of the article.
X.TP
X\&\fB$\fP	{\fBpage=$\fP}
XGoto the last page of the article.
X.TP
X\&\fBg\fP\fIN\fP	{\fBline=@\fP}
XGoto line 
X.I N
Xin the article.
X.TP
X\&\fB/\fP\fIregexp\fP	{\fBfind\fP}
XSearch forward for text matching the regular expression
X.I regexp
Xin the article.  If a matching text is found, it will be high-lighted.
X.TP
X\&\fB.\fP	{\fBfind-next\fP}
XRepeat search for last regular expression.
X.TP
X\&\fBh\fP	{\fBpage=0\fP}
XShow the 
X.I header 
Xof the article, and continue from the top of the
Xarticle.
X.TP
X\&\fBH\fP	{\fBfull-digest\fP}
XIf the current article is extracted from
Xa digest, show the entire digest article including its header.
XAnother 
X.B H 
Xcommand will return to the current subarticle.
X.TP
X\&\fBD\fP	{\fBrot13\fP}
XTurn rot13 (caesar) decryption on and off for the current article, and
Xredraw current page.
X.TP
X\&\fBc\fP	{\fBcompress\fP} 
XTurn compression on and off for the current
Xarticle.  With compression turned on, multiple spaces and tabs are
Xshown as a single space.  This makes it much easier to read right
Xjustified text which separate words with several spaces.  Redraws
Xcurrent page.
X.LP
XThe following commands are used to move among the selected articles.
X.TP
X\&\fBn\fP	{\fBnext-article\fP}
XGoto next article.  This command skips the rest of the current article
Xand jumps directly to the first page of the next article (or to the
Xnext group if it is the last article).
X.TP
X\&\fBl\fP	{\fBleave-article\fP}
XLeave current article and goto next.
XThis command behaves like the \fBnext-article\fP command, but the
Xarticle will still be selected, and when all the selected articles
Xin the group have been read as usual, these `left over' articles will
Xbe presented once more.  This is useful if you see an article which
Xyou may want to respond to unless one the following articles is
Xalready saying what you intended to say.
X.TP
X\&\fBp\fP	{\fBprevious\fP}
XGoto previous article.
X.TP
X\&\fBk\fP	{\fBnext-subject\fP}
XKill subject.  Skips rest of current article, and all following
Xarticles with the same subject.
X.br
XNote: this is not a permanent kill subject command (see the \fBK\fP command).
X.TP
X\&\fB*\fP	{\fBselect-subject\fP}
XShow next article with \fIsame\fP subject (even if it is not
Xselected).  This command will
X.I select
Xall following articles with the same subject as the current article
X(similar to the `*' command in selection mode).  This can be used to
Xselect only the first article on a subject in selection mode, and then
Xselect all follow-ups in reading mode if you find the article
Xinteresting.
X.LP
XThe following commands perform an 
Ximmediate return from reading mode to selection mode in
Xthe
X.I current
Xgroup or skip to the next group.
X.TP
X\&\fB=\fP	{\fBgoto-menu\fP}
XReturn to selection mode in the current group (think of = as the
X\&"icon" of the selection menu).  The articles already
Xread will no longer be selected on the menu (excluding the current
Xarticle).
X.TP
X\&\fBN\fP	{\fBnext-group\fP}
XSkip the rest of the selected articles in the current group and go
Xdirectly to the next group.  The unread articles in the current group are
X.I not
Xmarked as read.  (You will be asked to confirm this command.)
X.TP
X\&\fBX\fP	{\fBread-skip\fP}
XMark current group as read and go directly to the next group.  (You
Xwill be asked to confirm this command.)
X.SH PREVIEWING ARTICLES IN SELECTION MODE
XIn selection mode, it is possible to read a specific article on the
Xmenu without entering reading mode for all the selected articles on
Xthe menu.  Using the commands described below will enter reading mode
Xfor one article only, and then return to the menu mode immediately
Xafter.
X.PP
XIf there are more than 5 free lines at the bottom of the menu screen,
X\fInn\fP will use that space to show the article (a minimal preview
Xwindow can be permanently allocated with the
X.B window
Xvariable).  Otherwise,
Xthe screen will be cleared to show the article.
X.PP
XAfter previewing an article, the following article will become the
Xcurrent article.
X.TP
X\&\fB%\fP\fIx\fP	{\fBpreview\fP}
XPreview article 
X.IR x .
X.TP
X\&\fB%%\fP	{\fBpreview\fP}
XPreview the current article.
X.LP
XWhen the article is being shown, the following reading mode commands
Xare very useful:
X.TP
X\&\fB=\fP	{\fBgoto-menu\fP}
XSkip the rest of the current article, and return to menu mode.
X.TP
X\&\fBn\fP	{\fBnext-article\fP}
XSkip the rest of the current article, and \fIpreview the next article\fP.
X.TP
X\&\fBl\fP	{\fBleave-article\fP}
XSelect the article on the menu, then skip the rest of the current
Xarticle, and preview the next article.
X.TP
X\&\fB%\fP\fIy\fP	{\fBpreview\fP}
XPreview article 
X.I y .
X.SH SAVING ARTICLES
X\fInn\fP allows you to save articles in a number of ways.
X.LP
XFirst, the save commands will prompt for a file name which is expanded
Xaccording to the rules described in the section on file name expansion
Xbelow.  If the 
X.B quick-save
Xvariable is set, \fInn\fP will only prompt for a save file name when
Xthe current articles are inside a folder; otherwise, the default save
Xfile defined in the init file will be used unconditionally (except if
Xan alternative save file has been specified for the group in the group
Xpresentation sequence described later on).
X.LP
XIf the file (and directories in the path) does not exist,
X\fInn\fP
Xwill ask whether the file (and the directories) should be created.
X.LP
XIf the file name ends in an asterisk, e.g.
X.br
X	part.*
X.br
X\fInn\fP will save each of the articles in uniquely named files
Xconstructed by replacing the asterisk by numbers from the sequence 1,
X2, 3, etc.  (The format of the string that replaces the * can be
Xchanged with the
X.B save-counter
Xvariable.)
X.LP
XThe saved articles will be
X.I appended
Xto the specified file(s) followed by an empty line each.
X.LP
XWhen an article has been saved in a file, a message reporting the
Xnumber of lines saved will be shown.  This can be disabled by
Xunsetting the 
X.B save-report
Xvariable.
X.LP
XThe following commands are available in both selection mode and in
Xreading mode, but their use differs between the two modes:
X.LP
XIn
X.I reading
Xmode, the commands will just save the 
X.I current
Xarticle in the specified file.
X.LP
XIn 
X.I selection
Xmode, they prompt you for the identifier of an article you want to
Xsave.  During the saving of the article the message
X.br
X	Processing article x...
X.br
Xappears, and when the article has been saved, the displayed article
Xidentifier changes from a lower case letter to an upper case letter
X(digits are changed into the `&' character).  You will then be prompted
Xfor another article to be saved.  Just hit
X.B space 
Xwhen you don't want to save more articles.
X.LP
XIf you enter an asterisk `*' when you are prompted for an article
Xidentifier, \fInn\fP will automatically save all the \fIselected\fP
Xarticles on the \fIcurrent\fP menu page (and deselect the articles).
X.LP
XLikewise, if you enter a plus `+', \fInn\fP will save all the selected
Xarticles on \fIall\fP menu pages (and deselect the articles).
X.LP
XThis is very useful in combination with the \fIsave selected articles\fP
Xfeature to save a selection of articles in separate, successively
Xnumbered files.  Do not confuse these two concepts!  The 
X.B S*
Xand
X.B S+
Xcommands can be used to save the selected articles in a single file as
Xwell as in separate files, and the \fIsave in separate files\fP
Xfeature can be used also when saving individual articles, either in
Xthe selection mode, or in the article reading mode.
X.LP
XWhen articles are saved in a file with a full or partial header, any
Xheader lines in the
X.I body
Xof the article will be escaped by a tilde (e.g. ~From: ...) to enable
X\fInn\fP to split the folder into separate articles.  Otherwise,
X\fInn\fP might be fooled into splitting a folder into too many articles.
X.LP
XArticles can be saved in a mail compatible format by setting the 
X.B mail-format
Xvariable.
X.LP
XThe save commands are:
X.TP
X\&\fBS\fP	{\fBsave-full\fP}
XSave articles including the full article header.
X.TP
X\&\fBO\fP	{\fBsave-short\fP}
XSave articles with a short header
Xcontaining only the name of the sender, the subject, and the posting
Xdate of the article.
X.TP
X\&\fBW\fP	{\fBsave-body\fP}
XWrite article
X.I without
Xa header.
X.TP
X\&\fB:print\fP	{\fBprint\fP}
XPrint article.  Instead of a file name,
Xthis command will prompt for the print command to which the current
Xarticle will be piped.  The default print command is specified at
Xcompile time, but it can be changed by setting the
X.B printer 
Xvariable.  The output will be identical to that of the 
X.B O
Xcommand.
X.TP
X\&\fB:patch\fP	{\fBpatch\fP} 
XSend articles through \fBpatch\fP(1) (or the program defined in the
X\fBpatch-cmd\fP variable).  Instead of a file name, you will be
Xprompted for the name of a directory in which you want the patch
Xcommand to be executed.  \fInn\fP will then pipe the body of the
Xarticle through the patch command. 
X  The output from the patch process will be piped through the pager
Xdefined in the \fBpager\fP variable and appear on the screen.
X.TP
X\&\fB:unshar\fP	{\fBunshar\fP}
XUnshar articles.  You will be prompted for the name of a directory in
Xwhich you want \fInn\fP to unshar the articles. \fInn\fP will then
Xpipe the proper parts of the article body into a Bourne Shell whose
Xworking directory will be set to the specified directory.
X  During the unpacking, the normal output from the unshar process will
Xappear on the screen, and the menu or article text will be redrawn when
Xthe process is finished.
X.LP
XIn reading mode, the following keys can also be used to invoke the
Xsave commands:
X.TP
X.B s
XSame as
X.BR S .
X.TP
X.B o
XSame as
X.BR O .
X.TP
X.B w
XSame as
X.BR W .
X.TP
X.B P
XSame as
X.BR :print .
X.SH FILE NAME EXPANSION
XWhen the save commands prompts for a file name, the following file
Xname expansions are performed on the file name you enter:
X.TP
X\fB+\fP\fIfolder\fP
XThe 
X.B +
Xis replaced by the contents of the 
X.B folder
Xvariable (default value "~/News/") resulting in the name of a file in the
X.I folder
X.IR directory .
XExamples:
X.br
X	+emacs, +nn, +sources/shar/nn
X.TP
X\fB+\fP
XA single plus is replaced by the expansion of the file name contained in the 
X.B default-save-file
Xvariable.
X.TP
X\fB~/\fP\fIfile\fP
XThe
X.B ~
Xis replaced by the contents of the environment variable HOME, i.e. the
Xpath name of your home directory.
XExamples:
X.br
X	~/News/emacs, ~/News/nn, ~/src/shar/nn
X.TP
X\fB|\fP\fIcommand-line\fP
XInstead of writing to a file, the articles are piped to the given
Xshell (/bin/sh) command-line.  Each save or write command will create a
Xseparate pipe, but all articles saved or written in one command (in
Xselection mode) are given
Xas input to the same shell command.  Example:
X.br
X	| pr | lp
X.br
XThis will print the articles on the printer after they have been piped
Xthrough pr.
X    It is possible to create separate pipes for each saved article by
Xusing a double pipe symbol in the beginning of the command, e.g.
X.br
X	|| cd ~/src/nn ; patch
X.br
X.LP
XThe following symbols are expanded in a file name:
X.TP
X.B $F
Xwill be expanded to the name of the current group with the periods
Xreplaced by slashes, e.g. rec/music/synth.
X.TP
X.B $G
Xwill be expanded to the name of the current group.
X.TP
X.B $L
Xwill be expanded to the \fIlast component\fP of the name of the
Xcurrent group.  You may use this to create default save file names
Xlike +src/$L in the comp.sources groups.
X.TP
X.B $N
Xwill be expanded to the (local) article number, e.g. 1099.  In
Xselection mode it is only allowed at the end of the file name!
X.LP
XUsing these symbols, a simple naming scheme for `default folder name' is
X.B +$G
Xwhich will use the group name as folder name.  Another possibility is
X.BR +$F/$N .
X.LP
XAs mentioned above, you can also instruct \fInn\fP to save a series of
Xfiles in separate, unique files.  All that is required is that the
Xfile name ends in an asterisk, e.g.
X.br
X	+src/hype/part.*
X.br
XThis will cause each of the articles to be saved in separate, unique files
Xnamed part.1, part.2, and so on, always choosing a suffix number that
Xresults in a unique file name (i.e. if part.1 did already exist, the
Xfirst article would be saved in part.2, the next in part.3, and so on).
NO_NEWS_IS_GOOD_NEWS
echo "End of part 8"
echo "File nn.1 is continued in part 9"
echo "9" > 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.