amiga-request@ab20.larc.nasa.gov (Amiga Sources/Binaries Moderator) (03/14/91)
Submitted-by: eyal@echo.canberra.edu.au (Eyal Lebedinsky)
Posting-number: Volume 91, Issue 050
Archive-name: news/vn-res-1.1-2/part04
#!/bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of archive 4 (of 6)."
# Contents: reader.c session.c
# Wrapped by tadguy@ab20 on Wed Mar 13 19:10:11 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'reader.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'reader.c'\"
else
echo shar: Extracting \"'reader.c'\" \(18826 characters\)
sed "s/^X//" >'reader.c' <<'END_OF_FILE'
X/*
X** vn news reader.
X**
X** reader.c - article reading interface - "more" like.
X**
X** see copyright disclaimer / history in vn.c source file
X*/
X
X#include <stdio.h>
X#include <sys/types.h>
X#include <ctype.h>
X#include <time.h>
X#include "tty.h"
X#include "config.h"
X#include "tune.h"
X#include "head.h"
X#include "reader.h"
X#include "brk.h"
X#include "node.h"
X#include "page.h"
X#include "vn.h"
X
X#ifdef amiga
X#define system(a) Execute(a, 0, 0)
Xextern char pr_buf[];
Xextern ttputc ();
X#endif
X
X#define PERTAB 8 /* tab expansion factor */
X#define BACKTRACK 24
X
Xextern char *Printer,*Editor,*Mailer,*Poster,*Orgdir,*Savefile,*Savedir,*Ccfile;
Xextern int L_allow;
Xextern int C_allow;
Xextern int Rot;
Xextern int Headflag;
Xextern int Digest;
Xextern int More;
Xextern char *No_msg;
Xextern char *Roton_msg;
Xextern char *Rotoff_msg;
Xextern char *Hdon_msg;
Xextern char *Hdoff_msg;
Xextern char *Def_smode;
X
Xextern PAGE Page;
X
Xextern int (*Massage)();
Xextern int (*Postfunc)();
Xextern int (*Mailfunc)();
Xextern int (*Savemode)();
Xextern int (*Hookfunc)();
X
Xextern char Cxrtoi[], Cxitor[];
X
Xstatic FILE *Fpread;
Xstatic char *Fname;
Xstatic char *Lookahead;
Xstatic int Rlines;
Xstatic int Hlines;
Xstatic long Rew_pos;
X
Xstatic void save2_article (), followup (), printr (), searcher (), mail ();
Xstatic saver (), edcopy (), rot_line (), do_out (), rerrmsg ();
Xstatic char getpgch (), *rprompt ();
X
X
X/*
X readfile presents article:
X fn = name of article.
X sn - name of next article, NULL if last.
X pages - pages to advance on return, if applicable
X returns 0 for "continue", <0 for "quit"
X
X calls sig_set(BRK_READ / BRK_RFIN) around reading article.
X*/
Xreadfile (fn,sn,pages)
Xchar *fn;
Xchar *sn;
Xint *pages;
X{
X ARTHEADER hdr;
X#ifndef amiga
X FILE *fopen();
X long ftell();
X#endif
X int lines,percent;
X int i;
X int top, bottom;
X int step;
X char c, buf[RECLEN];
X char lasave[RECLEN];
X char pstr[24], dgname[48];
X char getpgch(), *index(), *dige_extract(), *tgetstr();
X char *any;
X FILE *vns_aopen();
X
X Fname = fn;
X *pages = 0;
X step = FALSE; /* Boolean; to indicate user input a <RET> (PG_STEP) */
X
X term_set(ERASE);
X sig_set(BRK_READ,&Fpread);
X
X any = "any key to continue .... ";
X
X if (Digest)
X {
X lines = atoi(Fname);
X if ((Fname = dige_extract(dgname,lines,&hdr,&Rew_pos)) == NULL)
X {
X rerrmsg("couldn't extract article %d from digest",lines);
X#ifdef amiga
X sprintf(pr_buf,any);
X tputs(pr_buf,1,ttputc);
X#else
X printf(any);
X#endif
X getnoctl();
X sig_set(BRK_RFIN);
X return (0);
X }
X if ((Fpread = fopen(Fname,"r")) == NULL)
X {
X rerrmsg("couldn't open %s",Fname);
X#ifdef amiga
X sprintf(pr_buf,any);
X tputs(pr_buf,1,ttputc);
X#else
X printf(any);
X#endif
X getnoctl();
X sig_set(BRK_RFIN);
X return (0);
X }
X fseek(Fpread,Rew_pos,0);
X }
X else
X {
X if ((Fpread = vns_aopen(atoi(Fname),&hdr)) == NULL)
X {
X rerrmsg("couldn't open article %s",Fname);
X#ifdef amiga
X sprintf(pr_buf,any);
X tputs(pr_buf,1,ttputc);
X#else
X printf(any);
X#endif
X getnoctl();
X sig_set(BRK_RFIN);
X return (0);
X }
X Rew_pos = ftell(Fpread);
X }
X
X Hlines = hdr.hlines;
X#ifdef amiga
X sprintf (pr_buf,ANFORM,Fname,Cxrtoi[PG_HELP]);
X tputs(pr_buf,1,ttputc);
X#else
X printf (ANFORM,Fname,Cxrtoi[PG_HELP]);
X#endif
X
X lines = 0;
X
X if (Headflag)
X {
X rewind(Fpread);
X Rlines = 0;
X }
X else
X {
X /* use do_out to guard against control sequences */
X Rlines = Hlines;
X for (i=0; i < hdr.show_num; ++i)
X lines += do_out((hdr.show)[i],L_allow-lines);
X lines += do_out("",L_allow-lines);
X }
X
X /* will return out of outer while loop */
X Lookahead = NULL;
X while (1)
X {
X /*
X ** lines counts folded lines from do_out.
X ** globals Hlines and Rlines refer to records.
X ** If Lookahead is null after this loop, we've
X ** hit EOF.
X */
X if (Lookahead != NULL && More && !step)
X {
X char *looktmp;
X
X /*
X ** Save Lookahead because `do_out' nukes it.
X ** Perhaps we could just use `printf' here
X ** but for now we'll play it safe. - GKE 12/26/87
X */
X looktmp = Lookahead;
X term_set(ERASE);
X /*
X ** The following presents the last line of the
X ** previous page in reversed video, as the first line
X ** of the current page, `rn'-stylee. Since `rn'
X ** uses an option to enable/disable this, remove the
X ** two `term_set's if not to your liking.
X */
X term_set(ONREVERSE);
X do_out(lasave,1);
X term_set(OFFREVERSE);
X Lookahead = looktmp;
X }
X lines += do_out(Lookahead,L_allow-lines);
X while (1)
X {
X if (Lookahead == NULL)
X {
X if (fgets(buf,RECLEN-1,Fpread) == NULL)
X break;
X Lookahead = buf;
X if (Rot != 0 && Rlines >= Hlines)
X rot_line(buf);
X ++Rlines;
X }
X if (lines >= L_allow)
X break;
X if (More)
X strcpy(lasave,Lookahead);
X lines += do_out(Lookahead,L_allow-lines);
X }
X
X if (Lookahead != NULL)
X {
X /*
X ** calculation is truncated rather than rounded,
X ** so we shouldn't get "100%". Subtract 2 for
X ** 1 line lookahead and empty line at beginning
X ** of article.
X */
X if (Headflag)
X {
X top = (Rlines-2);
X bottom = hdr.lines + Hlines;
X }
X else
X {
X top = (Rlines-Hlines-2);
X bottom = hdr.lines;
X }
X /*
X ** protect against division by zero -
X ** shouldn't actually come up zero at this
X ** point if vns_aopen is sane. 999 will let user
X ** know the percentage is obviously wrong.
X */
X if (bottom != 0)
X percent = (top*100L)/bottom;
X else
X percent = 999;
X sprintf (pstr,PAGE_MID,percent);
X }
X else
X {
X if (sn == NULL)
X strcpy (pstr,PAGE_END);
X else
X strcpy (pstr,PAGE_NEXT);
X }
X c = getpgch(pstr,&hdr);
X
X /*
X handle user input:
X CAUTION!! return cases must close Fpread.
X */
X step = FALSE;
X switch (c)
X {
X case PG_NEXT:
X if (Digest)
X {
X fclose (Fpread);
X unlink (Fname);
X }
X else
X vns_aclose (Fpread);
X sig_set(BRK_RFIN);
X return (0);
X case PG_FLIP:
X *pages = 1; /* fall through */
X case PG_QUIT:
X if (Digest)
X {
X fclose (Fpread);
X unlink (Fname);
X }
X else
X vns_aclose (Fpread);
X sig_set(BRK_RFIN);
X return (-1);
X case PG_REWIND:
X if (Headflag)
X {
X Rlines = 0;
X rewind (Fpread);
X }
X else
X {
X fseek (Fpread,Rew_pos,0);
X Rlines = Hlines;
X }
X Lookahead = NULL;
X lines = 2 - RECBIAS;
X break;
X case PG_SEARCH:
X searcher(buf);
X lines = 2 - RECBIAS;
X lines += do_out(buf,L_allow-lines);
X break;
X case PG_WIND:
X fseek (Fpread,0L,2);
X lines = 2 - RECBIAS;
X Lookahead = NULL;
X break;
X case PG_STEP:
X if (Lookahead == NULL)
X {
X if (Digest)
X {
X fclose (Fpread);
X unlink (Fname);
X }
X else
X vns_aclose (Fpread);
X sig_set(BRK_RFIN);
X return (0);
X }
X lines = L_allow - 1;
X step = TRUE; /* Temporarily disable paging */
X break;
X default:
X if (Lookahead == NULL)
X {
X if (Digest)
X {
X fclose (Fpread);
X unlink (Fname);
X }
X else
X vns_aclose (Fpread);
X sig_set(BRK_RFIN);
X return (0);
X }
X lines = 2 - RECBIAS;
X break;
X }
X }
X}
X
X/*
X getpgch prints prompt and gets command from user
X handles "mail", "save" and "followup" internally
X as well as flag resets.
X*/
Xstatic char
Xgetpgch(prompt,hdr)
Xchar *prompt;
XARTHEADER *hdr;
X{
X char c;
X int ic;
X int i;
X char mbuf[RECLEN];
X
X term_set (ONREVERSE);
X#ifdef amiga
X sprintf(pr_buf,"%s\015",prompt);
X tputs(pr_buf,1,ttputc);
X#else
X printf("%s\015",prompt);
X#endif
X term_set (OFFREVERSE);
X while ((ic=getnoctl()) != EOF)
X {
X c = Cxitor[ic];
X if (Hookfunc != NULL && (i = (*Hookfunc)(c,1,1,mbuf)) >= 0)
X {
X if (i == 0)
X {
X term_set (ZAP,0,PPR_MAX);
X#ifdef amiga
X sprintf(pr_buf,"%s\n",mbuf);
X tputs(pr_buf,1,ttputc);
X#else
X printf("%s\n",mbuf);
X#endif
X }
X term_set (ONREVERSE);
X#ifdef amiga
X sprintf(pr_buf,"%s\015",prompt);
X tputs(pr_buf,1,ttputc);
X#else
X printf("%s\015",prompt);
X#endif
X term_set (OFFREVERSE);
X continue;
X }
X switch (c)
X {
X case SETROT:
X term_set (ZAP,0,PPR_MAX);
X if (Rot == 0)
X {
X Rot = 13;
X#ifdef amiga
X sprintf (pr_buf,"%s\n",Roton_msg);
X tputs(pr_buf,1,ttputc);
X#else
X printf ("%s\n",Roton_msg);
X#endif
X }
X else
X {
X Rot = 0;
X#ifdef amiga
X sprintf (pr_buf,"%s\n",Rotoff_msg);
X tputs(pr_buf,1,ttputc);
X#else
X printf ("%s\n",Rotoff_msg);
X#endif
X }
X if (Lookahead != NULL && Rlines > Hlines)
X rot_line(Lookahead);
X break;
X case HEADTOG:
X term_set (ZAP,0,PPR_MAX);
X if (Headflag)
X {
X Headflag = FALSE;
X#ifdef amiga
X sprintf (pr_buf,"%s\n",Hdoff_msg);
X tputs(pr_buf,1,ttputc);
X#else
X printf ("%s\n",Hdoff_msg);
X#endif
X }
X else
X {
X Headflag = TRUE;
X#ifdef amiga
X sprintf (pr_buf,"%s\n",Hdon_msg);
X tputs(pr_buf,1,ttputc);
X#else
X printf ("%s\n",Hdon_msg);
X#endif
X }
X break;
X case PG_HELP:
X term_set (ZAP,0,PPR_MAX);
X help_rd ();
X break;
X case PG_REPLY:
X mail (hdr);
X break;
X case PG_FOLLOW:
X followup (hdr);
X break;
X case SAVE:
X saver ();
X break;
X case PRINT:
X printr ();
X break;
X default:
X term_set (ZAP,0,PPR_MAX);
X return (c);
X }
X
X term_set (ONREVERSE);
X#ifdef amiga
X sprintf(pr_buf,"%s\015",prompt);
X tputs(pr_buf,1,ttputc);
X#else
X printf("%s\015",prompt);
X#endif
X term_set (OFFREVERSE);
X }
X term_set (ZAP,0,PPR_MAX);
X return (c);
X}
X
X/*
X save article. Like its "session" counterpart, this loses storage
X if the user specifies a new file, but it should not be significant
X*/
Xstatic
Xsaver ()
X{
X char buf[RECLEN],msg[RECLEN],*str_store();
X
X user_str (buf,"save file ? ",0,Savefile);
X if (buf[0] != '\0' && buf[0] != '|')
X Savefile = str_store(buf);
X if (save_art(Fname,buf,msg) != 0)
X rerrmsg(msg);
X else {
X#ifdef amiga
X sprintf(pr_buf,"%s\n",msg);
X tputs(pr_buf,1,ttputc);
X#else
X printf("%s\n",msg);
X#endif
X }
X}
X
X/*
X invoke editor on new temp file, mail using reply line,
X possibly first allowing user to overide the reply (not INLETTER)
X*/
Xstatic
Xvoid
Xmail (hdr)
XARTHEADER *hdr;
X{
X char *new, fn[L_tmpnam], cmd [RECLEN+60];
X char *rprompt ();
X int i;
X FILE *fp;
X#ifndef amiga
X FILE *fopen();
X#endif
X
X if (Massage != NULL)
X (*Massage)(hdr);
X
X if (hdr->mail_err != NULL)
X {
X rerrmsg(hdr->mail_err);
X return;
X }
X
X tmpnam (fn);
X if ((fp = fopen(fn,"w")) == NULL)
X {
X rerrmsg("can't open temp file, %s",fn);
X return;
X }
X
X for (i = 0; i < hdr->mail_num; ++i)
X fprintf(fp,"%s\n",(hdr->mail)[i]);
X fprintf(fp,"\n");
X
X fprintf(fp,"%s:\n",hdr->from);
X edcopy (fp);
X fclose (fp);
X
X tty_set (SAVEMODE);
X
X sprintf (cmd,"%s %s", Editor, fn);
X chdir (Orgdir);
X system (cmd);
X vns_gset (Page.h.name);
X
X new = rprompt ("still want to mail it ? ",cmd);
X if (new != NULL && (*new == 'y' || *new == 'Y'))
X {
X if (Mailfunc == NULL)
X {
X sprintf (cmd, hdr->mailcmd, fn);
X system (cmd);
X#ifdef amiga
X sprintf (pr_buf,"given to mailer\n");
X tputs(pr_buf,1,ttputc);
X#else
X printf ("given to mailer\n");
X#endif
X }
X else
X (*Mailfunc)(hdr,fn);
X }
X else {
X#ifdef amiga
X sprintf (pr_buf,"not mailed\n");
X tputs(pr_buf,1,ttputc);
X#else
X printf ("not mailed\n");
X#endif
X }
X
X unlink (fn);
X
X tty_set (RESTORE);
X term_set (RESTART);
X}
X
X/*
X post a followup article, invoking editor for user after creating
X new temp file. remove after posting.
X*/
Xstatic
Xvoid
Xfollowup (hdr)
XARTHEADER *hdr;
X{
X char fn[L_tmpnam], *new, cmd [RECLEN], *rprompt();
X int i;
X FILE *f;
X#ifndef amiga
X FILE *fopen();
X#endif
X char *rindex();
X
X if (hdr->post_err != NULL)
X {
X rerrmsg(hdr->post_err);
X return;
X }
X
X tmpnam (fn);
X if ((f = fopen(fn,"w")) == NULL)
X {
X rerrmsg("can't open temp file, %s",fn);
X return;
X }
X
X for (i=0; i < hdr->post_num; ++i)
X fprintf(f,"%s\n",(hdr->post)[i]);
X fprintf(f,"\n");
X
X fprintf(f,"From article %s, by %s:\n", hdr->artid, hdr->from);
X
X edcopy (f);
X fclose (f);
X tty_set (SAVEMODE);
X sprintf (cmd,"%s %s", Editor, fn);
X chdir (Orgdir);
X system (cmd);
X vns_gset (Page.h.name);
X
X new = rprompt("still want to post it ? ",cmd);
X if (new != NULL && (*new == 'y' || *new == 'Y'))
X {
X if (Postfunc == NULL)
X {
X sprintf (cmd, hdr->postcmd, fn);
X system (cmd);
X#ifdef amiga
X sprintf (pr_buf,"given to posting program\n");
X tputs(pr_buf,1,ttputc);
X#else
X printf ("given to posting program\n");
X#endif
X }
X else
X (*Postfunc)(hdr,fn);
X save2_article (fn);
X }
X else {
X#ifdef amiga
X sprintf (pr_buf,"not posted\n");
X tputs(pr_buf,1,ttputc);
X#else
X printf ("not posted\n");
X#endif
X }
X unlink (fn);
X tty_set (RESTORE);
X term_set (RESTART);
X}
X
X/*
X get user buffer, return whitespace delimited token
X buffer is allowed to overwrite prompt string. This routine
X should only be used when the terminal is in cooked mode.
X In raw, use user_str().
X*/
Xstatic char *
Xrprompt(s,buf)
Xchar *s,*buf;
X{
X char *strtok();
X
X#ifdef amiga
X sprintf(pr_buf,"%s",s);
X tputs(pr_buf,1,ttputc);
X#else
X printf("%s",s);
X#endif
X fgets (buf,RECLEN-1,stdin);
X return (strtok(buf," \t\n"));
X}
X
X/*
X edcopy copies article to file which user is editting for
X a reply or followup, so it may be referenced. It places
X ED_MARK in the left hand margin.
X*/
Xstatic
Xedcopy(fp)
XFILE *fp;
X{
X long current;
X char buf[RECLEN];
X
X /* save position, and seek to top of article */
X current = ftell(Fpread);
X fseek (Fpread,Rew_pos,0);
X
X /* if line already begins with ED_MARK, forget about the space */
X while (fgets(buf,RECLEN-1,Fpread) != NULL)
X {
X if (buf[0] == ED_MARK)
X fprintf(fp,"%c%s",ED_MARK,buf);
X else
X fprintf(fp,"%c %s",ED_MARK,buf);
X }
X
X /* restore position */
X fseek(Fpread,current,0);
X}
X
Xstatic
Xrot_line (s)
Xunsigned char *s;
X{
X for ( ; *s != '\0'; ++s)
X {
X if (isupper(*s))
X {
X *s += Rot;
X if (!isupper(*s))
X *s -= 26;
X continue;
X }
X if (islower(*s))
X {
X *s += Rot;
X if (!islower(*s))
X *s -= 26;
X }
X }
X}
X
X/*
X** output record. folds record to terminal width on word boundaries,
X** returning number of lines output. If limit is reached, remainder
X** of buffer waiting to be output is returned. Processes several
X** special characters:
X** form-feed - return "lim" lines so we stop on that line
X** tabs - counts "expanded" width
X** backspace - assumes they work, -1 width unless in first col.
X** bell - pass through with zero width
X** newline - end of record.
X** del - turns into '_'
X** other control - turned into '?'
X** (prevents "letter bombs" containing inappropriate control
X** sequences for the terminal).
X**
X** Sets Lookahead pointer to remainder of line or NULL.
X*/
Xstatic
Xdo_out(s,lim)
Xchar *s;
Xint lim;
X{
X int len,i;
X char cs,*word,*start;
X
X Lookahead = NULL;
X if (s == NULL)
X return(0);
X len = 0;
X start = word = s;
X
X /*
X ** NOTE: "normal" return is buried inside switch, at newline
X ** ending record
X */
X for (i=0; i < lim; ++i)
X {
X for ( ; len < C_allow; ++s)
X {
X switch (*s)
X {
X case '\n':
X *s = '\0'; /* fall through */
X case '\0':
X#ifdef amiga
X sprintf(pr_buf,"%s\n",start);
X tputs(pr_buf,1,ttputc);
X#else
X printf("%s\n",start);
X#endif
X return(i+1);
X case '\t':
X len = ((len/PERTAB)+1)*PERTAB;
X word = s;
X break;
X case '\b':
X if (len > 0)
X --len;
X break;
X case '\014':
X *s = ' ';
X i = lim-1; /* fall through */
X case ' ':
X word = s+1;
X ++len;
X break;
X case '\177':
X *s = '_';
X ++len;
X break;
X default:
X if (iscntrl(*s))
X *s = '?';
X ++len; /* fall through */
X case '\07':
X break;
X }
X }
X cs = *s;
X *s = '\0';
X if ((len = strlen(word)) < BACKTRACK)
X {
X *s = cs;
X s = word;
X cs = *s;
X *s = '\0';
X }
X else
X len = 0;
X#ifdef amiga
X sprintf(pr_buf,"%s\n",start);
X tputs(pr_buf,1,ttputc);
X#else
X printf("%s\n",start);
X#endif
X start = s;
X *s = cs;
X }
X Lookahead = start;
X return(lim);
X}
X
Xstatic
Xvoid
Xsave2_article(tempfname)
Xchar *tempfname;
X{
X FILE *in, *out;
X int c;
X time_t timenow;
X#ifndef amiga
X time_t time();
X char *ctime();
X#endif
X char *today;
X
X if ((in = fopen(tempfname, "r")) == NULL)
X return;
X if ((out = fopen(Ccfile, "a")) == NULL)
X {
X fclose(in);
X return;
X }
X timenow = time((time_t)0);
X today = ctime(&timenow);
X fprintf(out,"From vn %s",today);
X while ((c=getc(in)) != EOF)
X putc(c, out);
X putc('\n', out);
X fclose(in);
X fclose(out);
X#ifdef amiga
X sprintf (pr_buf,"a copy has been saved in %s\n", Ccfile);
X tputs(pr_buf,1,ttputc);
X#else
X printf ("a copy has been saved in %s\n", Ccfile);
X#endif
X}
X
X/*
X send article to printer
X*/
Xstatic
Xvoid
Xprintr ()
X{
X char cmd[RECLEN];
X char fn[L_tmpnam];
X long savepos;
X FILE *f;
X
X tmpnam (fn);
X if ((f = fopen(fn,"w")) == NULL)
X {
X rerrmsg("can't open temp file, %s",fn);
X return;
X }
X
X savepos = ftell(Fpread);
X rewind(Fpread);
X while (fgets(cmd,RECLEN-1,Fpread) != NULL)
X fputs(cmd,f);
X fclose(f);
X fseek(Fpread,savepos,0);
X
X tty_set (SAVEMODE);
X#ifdef amiga
X sprintf(pr_buf,"Sent to printer\n");
X tputs(pr_buf,1,ttputc);
X#else
X printf("Sent to printer\n");
X#endif
X#ifdef amiga
X sprintf (cmd,"%s >null: %s",Printer,fn);
X#else
X sprintf (cmd,"%s %s 2>/dev/null",Printer,fn);
X#endif
X system (cmd);
X tty_set (RESTORE);
X unlink (fn);
X}
X
X/*
X search article for specified search pattern, returning the line on which
X it is found in buf, a null buffer otherwise. The input file will
X be positioned either after the line on which the pattern is
X found, or unaaltered if match fails.
X*/
Xstatic
Xvoid
Xsearcher (buf)
Xchar *buf;
X{
X static char searchstr[RECLEN] = "";
X char lasave[RECLEN];
X char *reg, *regcmp(), *regex();
X long current;
X int orlines;
X
X /* save position, then request search pattern */
X current = ftell(Fpread);
X orlines = Rlines;
X
X sprintf (lasave,SEARCHFORM,searchstr);
X user_str (searchstr,lasave,0,searchstr);
X
X /* Now compile the search string */
X if(( reg = regcmp(searchstr, (char *)0)) == NULL) {
X rerrmsg("Invalid search string \"%s\"", searchstr);
X *buf = '\0';
X return;
X }
X
X /* try lookahead buffer first */
X if (Lookahead != NULL && regex(reg,Lookahead) != NULL)
X {
X strcpy(buf,Lookahead);
X regfree(reg);
X return;
X }
X
X /* Lookahead can point into buf */
X if (Lookahead != NULL)
X strcpy(lasave,Lookahead);
X
X /* now start reading lines, rotating if necessary and do search */
X while (fgets(buf,RECLEN-1,Fpread) != NULL)
X {
X if (Rot != 0 && Rlines >= Hlines)
X rot_line(buf);
X ++Rlines;
X if( regex(reg, buf) != NULL ){ /* Got it */
X#ifdef MINIX
X/* inverse video mucks up this line somehow */
X rerrmsg("\tSkipping ...\n\n");
X#else
X rerrmsg("\n\tSkipping ....\n\n");
X#endif
X regfree(reg);
X return;
X }
X }
X
X /* no dice, so restore position */
X regfree(reg);
X rerrmsg("Cannot find string \"%s\" in remainder of article", searchstr);
X fseek(Fpread,current,0);
X Rlines = orlines;
X if (Lookahead != NULL)
X strcpy(buf,lasave);
X else
X *buf = '\0';
X}
X
X/*
X** print a reverse video error message while reading an article.
X*/
Xstatic
Xrerrmsg(s,a,b,c,d,e)
Xchar *s;
Xlong a,b,c,d,e;
X{
X term_set (ONREVERSE);
X#ifdef amiga
X sprintf(pr_buf,"\n ");
X tputs(pr_buf,1,ttputc);
X sprintf(pr_buf,s,a,b,c,d,e);
X tputs(pr_buf,1,ttputc);
X sprintf(pr_buf," \07\n");
X tputs(pr_buf,1,ttputc);
X#else
X printf("\n ");
X printf(s,a,b,c,d,e);
X printf(" \07\n");
X#endif
X term_set (OFFREVERSE);
X}
END_OF_FILE
if test 18826 -ne `wc -c <'reader.c'`; then
echo shar: \"'reader.c'\" unpacked with wrong size!
fi
# end of 'reader.c'
fi
if test -f 'session.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'session.c'\"
else
echo shar: Extracting \"'session.c'\" \(24544 characters\)
sed "s/^X//" >'session.c' <<'END_OF_FILE'
X/*
X** vn news reader.
X**
X** session.c - top session loop
X**
X** see copyright disclaimer / history in vn.c source file
X*/
X#include <stdio.h>
X#include <setjmp.h>
X#include <ctype.h>
X#include "config.h"
X#include "tty.h"
X#include "brk.h"
X#include "head.h"
X#include "tune.h"
X#include "node.h"
X#include "page.h"
X#include "vn.h"
X
X#ifdef amiga
X#define system(a) Execute(a, 0, 0)
X#undef getchar
X#define getchar ttgetc
Xextern char pr_buf[];
Xextern ttputc ();
X#endif
X
Xextern NODE **Newsorder;
Xextern char Erasekey, Killkey;
Xextern int Rot;
Xextern char *Ps1,*Printer;
Xextern char *Orgdir,*Savefile;
Xextern int Ncount, Cur_page, Lrec, L_allow, C_allow;
Xextern int Headflag;
Xextern PAGE Page;
Xextern int Digest;
Xextern char *No_msg;
Xextern char *Hdon_msg;
Xextern char *Hdoff_msg;
Xextern char *Roton_msg;
Xextern char *Rotoff_msg;
Xextern char Cxitop[], Cxptoi[];
Xextern char *Aformat;
Xextern char *Contstr;
Xextern char *Kl,*Kr,*Ku,*Kd;
Xextern int Nounsub, Listfirst;
Xextern char *List_sep;
Xextern char *Version, *Vns_version;
X
Xextern char (*Marker)();
Xextern int (*Hookfunc)();
X
Xextern char *strtok ();
X
Xstatic int C_info;
Xstatic int Dskip, Drec;
X
Xstatic char *Unsub_msg = "Unsubscribed";
Xstatic char *Egroup_msg = "Entire newsgroup";
X
Xstatic int Crec;
Xstatic int Highrec;
X
Xstatic show (), wr_show (), spec_group (), tot_list (), do_update (),
X new_read (), new_sub (), markstr (), forward (), genlist (),
X printstr (), savestr ();
X
X#ifdef MSDOS
X#undef getchar
X#define getchar getraw
X#endif
X
X
X
X/*
X main session handler processing input commands
X
X NOTE: this is where a setjmp call is made to set the break reentry
X location. Keep the possible user states in mind.
X*/
Xsession ()
X{
X char alist [RECLEN], c;
X int newg, i, j, count;
X jmp_buf brkbuf;
X
X newg = new_groups();
X tty_set (RAWMODE);
X find_page (0);
X Digest = 0;
X
X /* reentry point for break from within session interaction */
X setjmp (brkbuf);
X sig_set (BRK_SESS,brkbuf);
X Headflag = FALSE;
X Rot = 0;
X
X /* done this way so that user gets "really quit?" break treatment */
X if (newg > 0)
X {
X#ifdef amiga
X sprintf (pr_buf,"\n%s",Contstr);
X tputs(pr_buf,1,ttputc);
X#else
X printf ("\n%s",Contstr);
X#endif
X getnoctl();
X newg = 0;
X }
X
X /* list preview option - clear after first time for long jumps */
X if (Listfirst)
X {
X /* tot_list settings will be overwritten in this case */
X tot_list();
X Listfirst = 0;
X }
X
X /* if breaking from a digest, recover original page */
X if (Digest)
X {
X find_page(Cur_page);
X Digest = 0;
X }
X show ();
X Crec = RECBIAS;
X Highrec = Page.h.artnum + RECBIAS;
X term_set (MOVE,0,Crec);
X
X /*
X handle commands until QUIT, update global/local status
X and display for each.
X */
X for (count = getkey(&c); c != QUIT; count = getkey(&c))
X {
X if (Hookfunc != NULL)
X {
X if ((i = (*Hookfunc)(c,0,1,alist)) >= 0)
X {
X if (i == 0)
X prinfo(alist);
X else
X {
X term_set(ERASE);
X show();
X }
X term_set (MOVE,0,Crec);
X continue;
X }
X }
X
X if ( srch_help(c,&i) != 0 || (Digest != 0 && i == 0))
X {
X preinfo (UDKFORM,Cxptoi[HELP]);
X term_set (MOVE, 0, Crec);
X continue;
X }
X
X switch (c)
X {
X case HEADTOG:
X if (Headflag)
X {
X Headflag = FALSE;
X prinfo (Hdoff_msg);
X }
X else
X {
X Headflag = TRUE;
X prinfo (Hdon_msg);
X }
X term_set (MOVE,0,Crec);
X break;
X case SETROT:
X if (Rot == 0)
X {
X Rot = 13;
X prinfo (Roton_msg);
X }
X else
X {
X Rot = 0;
X prinfo (Rotoff_msg);
X }
X term_set (MOVE,0,Crec);
X break;
X case SSTAT:
X count_msg ();
X term_set (MOVE,0,Crec);
X break;
X case GRPLIST:
X tot_list ();
X show();
X term_set (MOVE,0,Crec);
X break;
X case REDRAW:
X show();
X term_set (MOVE,0,Crec);
X break;
X case UNSUBSCRIBE:
X new_sub(Page.h.group,0);
X do_update(Unsub_msg);
X term_set (MOVE,0,Crec);
X break;
X
X case UPDATE:
X new_read(Page.h.group,Page.b[Crec-RECBIAS].art_id);
X wr_show ();
X do_update("Updated to cursor");
X term_set (MOVE,0,Crec);
X break;
X case UPALL:
X new_read(Page.h.group,(Page.h.group)->highnum);
X wr_show();
X do_update(Egroup_msg);
X term_set (MOVE,0,Crec);
X break;
X case ORGGRP:
X new_read(Page.h.group,(Page.h.group)->orgrd);
X wr_show();
X do_update(Egroup_msg);
X term_set (MOVE,0,Crec);
X break;
X case UPSEEN:
X up_seen();
X wr_show();
X do_update("All pages displayed to this point updated");
X term_set (MOVE,0,Crec);
X break;
X case ORGSTAT:
X for (i = 0; i < Ncount; ++i)
X new_read(Newsorder[i],(Newsorder[i])->orgrd);
X wr_show();
X do_update("Original data recovered");
X term_set (MOVE,0,Crec);
X break;
X case TOPMOVE:
X Crec = RECBIAS;
X term_set (MOVE, 0, Crec);
X break;
X case BOTMOVE:
X case ALTBOTTOM:
X Crec = Highrec - 1;
X term_set (MOVE, 0, Crec);
X break;
X case MIDMOVE:
X Crec = (RECBIAS + Highrec - 1) / 2;
X if (Crec < RECBIAS)
X Crec = RECBIAS;
X if (Crec >= Highrec)
X Crec = Highrec - 1;
X term_set (MOVE, 0, Crec);
X break;
X case UP:
X if (Crec != RECBIAS)
X {
X Crec -= count;
X if (Crec < RECBIAS)
X Crec = RECBIAS;
X term_set (MOVE, 0, Crec);
X }
X else
X putchar ('\07');
X break;
X case DOWN:
X if (Crec < (Highrec - 1))
X {
X Crec += count;
X if (Crec >= Highrec)
X Crec = Highrec - 1;
X term_set (MOVE, 0, Crec);
X }
X else
X putchar ('\07');
X break;
X case MARKSTRING:
X (Page.h.group)->flags |= FLG_ACC;
X userlist (alist);
X markstr (alist,c);
X term_set (MOVE, 0, Crec);
X write_page ();
X break;
X case MARK:
X case ART_MARK:
X genlist (alist,Crec-RECBIAS,count);
X markstr (alist,c);
X term_set (MOVE, 0, Crec);
X write_page ();
X break;
X case UNMARK:
X for (i=0; i < Page.h.artnum; ++i)
X {
X if (Page.b[i].art_mark != ' ')
X {
X if (Marker == NULL)
X Page.b[i].art_mark = ' ';
X else
X Page.b[i].art_mark =
X (*Marker)(Page.h.group,
X Page.b[i].art_id,
X Page.b[i].art_mark, c);
X term_set (MOVE, 0, i+RECBIAS);
X putchar (' ');
X }
X }
X term_set (MOVE, 0, Crec);
X write_page ();
X break;
X case BACK:
X count *= -1; /* fall through */
X case FORWARD:
X if (forward (count) >= 0)
X show();
X else
X preinfo ("No more pages");
X term_set (MOVE,0,Crec);
X break;
X case GRPBACK:
X j = (Page.h.group)->order;
X for (i = j-1; count > 0 && i >= 0; --i)
X {
X if ((Newsorder[i])->pages > 0)
X {
X j = i;
X --count;
X }
X }
X if (j == (Page.h.group)->order)
X preinfo ("No more newsgroups");
X else
X {
X forward ((Newsorder[j])->pnum - Cur_page);
X show();
X }
X term_set (MOVE,0,Crec);
X break;
X case GRPFORWARD:
X j = (Page.h.group)->order;
X for (i= j+1; count > 0 && i < Ncount; ++i)
X {
X if ((Newsorder[i])->pages > 0)
X {
X j = i;
X --count;
X }
X }
X if (j == (Page.h.group)->order)
X preinfo ("No more newsgroups");
X else
X {
X forward ((Newsorder[j])->pnum - Cur_page);
X show();
X }
X term_set (MOVE,0,Crec);
X break;
X case DIGEST:
X if (Digest)
X {
X Digest = 0;
X find_page (Cur_page);
X show();
X Crec = Drec + RECBIAS + 1;
X Highrec = Page.h.artnum + RECBIAS;
X if (Crec >= Highrec)
X Crec = Highrec - 1;
X term_set (MOVE,0,Crec);
X break;
X }
X (Page.h.group)->flags |= FLG_ACC;
X Dskip = count - 1;
X Drec = Crec - RECBIAS;
X if (dige_page(Drec,Dskip) >= 0)
X {
X show();
X Crec = RECBIAS;
X Highrec = Page.h.artnum + RECBIAS;
X term_set (MOVE,0,Crec);
X break;
X }
X Digest = 0;
X preinfo ("Can't unpack the article");
X term_set (MOVE,0,Crec);
X break;
X case NEWGROUP:
X if ((i = spec_group()) < 0)
X {
X term_set (MOVE,0,Crec);
X break;
X }
X Digest = 0;
X show();
X Crec = RECBIAS;
X Highrec = Page.h.artnum + RECBIAS;
X term_set (MOVE,0,Crec);
X break;
X
X case SAVE:
X (Page.h.group)->flags |= FLG_ACC;
X genlist (alist,Crec-RECBIAS,count);
X savestr (alist);
X term_set (MOVE,0,Crec);
X break;
X case SAVEALL:
X (Page.h.group)->flags |= FLG_ACC;
X genlist (alist,0,L_allow);
X savestr (alist);
X term_set (MOVE,0,Crec);
X break;
X case SAVESTRING:
X case ALTSAVE:
X (Page.h.group)->flags |= FLG_ACC;
X userlist (alist);
X savestr (alist);
X term_set (MOVE,0,Crec);
X break;
X case READ:
X case ALTREAD:
X (Page.h.group)->flags |= FLG_ACC;
X genlist (alist,Crec-RECBIAS,count);
X readstr (alist,count);
X break;
X case READALL:
X (Page.h.group)->flags |= FLG_ACC;
X genlist (alist,0,L_allow);
X readstr (alist,0);
X break;
X case READSTRING:
X (Page.h.group)->flags |= FLG_ACC;
X userlist (alist);
X readstr (alist,0);
X break;
X case PRINT:
X (Page.h.group)->flags |= FLG_ACC;
X genlist (alist,Crec-RECBIAS,count);
X printstr (alist);
X term_set (MOVE,0,Crec);
X break;
X case PRINTALL:
X (Page.h.group)->flags |= FLG_ACC;
X genlist (alist,0,L_allow);
X printstr (alist);
X term_set (MOVE, 0, Crec);
X break;
X case PRINTSTRING:
X (Page.h.group)->flags |= FLG_ACC;
X userlist (alist);
X printstr (alist);
X term_set (MOVE, 0, Crec);
X break;
X
X case HELP:
X help ();
X show ();
X term_set (MOVE, 0, Crec);
X break;
X case UNESC:
X user_str (alist,Ps1,1,"");
X term_set (ERASE);
X#ifdef amiga
X ttflush ();
X#else
X fflush (stdout);
X#endif
X tty_set (SAVEMODE);
X if (chdir(Orgdir) < 0) {
X#ifdef amiga
X sprintf (pr_buf,"change to original directory, %s, failed",Orgdir);
X tputs(pr_buf,1,ttputc);
X#else
X printf ("change to original directory, %s, failed",Orgdir);
X#endif
X } else
X {
X system (alist);
X tty_set (RESTORE);
X term_set (RESTART);
X }
X#ifdef amiga
X sprintf (pr_buf,Contstr);
X tputs(pr_buf,1,ttputc);
X#else
X printf (Contstr);
X#endif
X getnoctl ();
X vns_gset(Page.h.name);
X show ();
X term_set (MOVE, 0, Crec);
X break;
X case PRTVERSION:
X prinfo("%s %s", Version, Vns_version);
X term_set (MOVE, 0, Crec);
X break;
X default:
X preinfo("Unhandled key: %c", c);
X break;
X }
X }
X
X Digest = 0;
X for (i=0; i < Ncount; ++i)
X {
X if ((Newsorder[i])->rdnum < (Newsorder[i])->pgrd)
X break;
X }
X if (i < Ncount)
X {
X user_str (alist,"Some displayed pages not updated - update ? ",
X 1, QUIT_ANSWER);
X if (alist[0] == 'y')
X up_seen();
X }
X sig_set (BRK_OUT);
X}
X
X/*
X** update status of Newsgroups to all seen pages
X*/
Xup_seen()
X{
X int i;
X
X for (i = 0; i < Ncount; ++i)
X {
X if (Nounsub && ((Newsorder[i])->flags & FLG_SUB) == 0)
X {
X new_read(Newsorder[i],(Newsorder[i])->highnum);
X continue;
X }
X if ((Newsorder[i])->rdnum < (Newsorder[i])->pgrd)
X new_read(Newsorder[i],(Newsorder[i])->pgrd);
X }
X}
X
X/*
X count_msg displays count information
X*/
Xcount_msg ()
X{
X int i, gpnum, gscan, gpage;
X unsigned long mask;
X gpnum = 1;
X for (gscan = gpage = i = 0; i<Ncount; ++i)
X {
X if (((Newsorder[i])->flags & FLG_PAGE) != 0)
X {
X if (((Newsorder[i])->pnum + (Newsorder[i])->pages - 1) < Cur_page)
X ++gpnum;
X ++gpage;
X for (mask=1; mask != 0L; mask <<= 1)
X if (((Newsorder[i])->pgshwn & mask) != 0L)
X ++gscan;
X }
X }
X prinfo (CFORMAT,Cur_page+1,Lrec+1,gscan,gpnum,gpage);
X}
X
X/*
X forward utility handles paging
X*/
Xstatic
Xforward (count)
Xint count;
X{
X if (!Digest)
X {
X if ((count < 0 && Cur_page <= 0) || (count > 0 && Cur_page >= Lrec))
X return (-1);
X Cur_page += count;
X if (Cur_page < 0)
X Cur_page = 0;
X if (Cur_page > Lrec)
X Cur_page = Lrec;
X find_page (Cur_page);
X Crec = RECBIAS;
X Highrec = Page.h.artnum + RECBIAS;
X return (0);
X }
X /*
X ** in digests, paging past the end of the digest returns to
X ** page extracted from.
X */
X if (Dskip > 0 && (Dskip + count*L_allow) < 0)
X Dskip = 0;
X else
X Dskip += count * L_allow;
X find_page (Cur_page);
X if (Dskip >= 0)
X {
X if (dige_page(Drec,Dskip) >= 0)
X {
X Crec = RECBIAS;
X Highrec = Page.h.artnum + RECBIAS;
X return (0);
X }
X }
X Digest = 0;
X Crec = Drec + RECBIAS + 1;
X Highrec = Page.h.artnum + RECBIAS;
X if (Crec >= Highrec)
X Crec = Highrec - 1;
X return (0);
X}
X
X/*
X generate list of articles on current page,
X count articles, starting with first.
X*/
Xstatic
Xgenlist (list,first,count)
Xchar *list;
Xint first,count;
X{
X int i;
X for (i=first; i < Page.h.artnum && count > 0; ++i)
X {
X sprintf (list,"%d ",Page.b[i].art_id);
X list += strlen(list);
X --count;
X }
X}
X
X/*
X send list of articles to printer
X*/
Xstatic
Xprintstr (s)
Xchar *s;
X{
X char cmd [RECLEN];
X char fn[L_tmpnam];
X char dsave[RECLEN]; /* save list for unlinking */
X
X prinfo ("preparing print command ....");
X
X if (Digest)
X {
X dig_list (s);
X strcpy(dsave,s);
X }
X
X if (*s != '\0')
X {
X tmpnam(fn);
X if (art_xfer(fn,s,"w",NULL) != 0)
X {
X preinfo("Couldn't open temporary file");
X return;
X }
X#ifdef amiga
X sprintf (cmd,"%s >null: %s",Printer,fn);
X if (system (cmd) != 0)
X prinfo ("Sent to printer");
X#else
X sprintf (cmd,"%s %s 2>/dev/null",Printer,fn);
X if (system (cmd) == 0)
X prinfo ("Sent to printer");
X#endif
X else
X preinfo ("Print failed");
X unlink(fn);
X }
X else
X preinfo (No_msg);
X
X if (Digest)
X dig_ulist (dsave);
X}
X
X/*
X read a list of articles.
X*/
Xreadstr (s,count)
Xchar *s;
Xint count;
X{
X char *strtok();
X char *fn[MAXARTLIST+1];
X int pc, num, i;
X
X /* we pre-process tokens to release strtok() for further use */
X fn[0] = strtok(s,List_sep);
X for (num=0; fn[num] != NULL; fn[(++num)] = strtok(NULL,List_sep))
X if (num >= MAXARTLIST)
X break;
X fn[num] = NULL;
X
X if (fn[0] != NULL)
X {
X term_set (ERASE);
X for (i=0; i < num && readfile(fn[i], fn[i+1] ,&pc) >= 0; ++i)
X {
X#ifndef MINIX
X/* I don't believe this code is correct at all!!! */
X if (Digest)
X unlink (fn[i]);
X#endif /*!MINIX*/
X }
X
X#ifndef MINIX
X/* I don't believe this code is correct at all!!! */
X if (Digest && fn[i] != NULL)
X unlink (fn[i]);
X#endif /*!MINIX*/
X if (pc != 0)
X forward (pc);
X else
X {
X Crec += count;
X if (Crec >= Highrec)
X Crec = Highrec - 1;
X }
X show ();
X term_set (MOVE, 0, Crec);
X }
X else
X {
X preinfo ("%s",No_msg);
X term_set (MOVE, 0, Crec);
X }
X}
X
X/*
X concatenate articles to save file with appropriate infoline messages.
X prompt for save file, giving default. If save file begins with "|"
X handle as a filter to pipe to. NOTE - every user specification of
X a new Savefile "loses" some storage, but it shouldn't be a very great
X amount.
X*/
Xstatic
Xsavestr (s)
Xchar *s;
X{
X char *ptr, newfile [MAX_C+1], msg[RECLEN];
X char *str_store();
X char dsave[RECLEN];
X
X if (Digest)
X {
X dig_list (s);
X strcpy(dsave,s);
X }
X
X if (*s != '\0')
X {
X user_str (newfile,"save file ? ",1,Savefile);
X ptr = newfile;
X if (*ptr == '|')
X {
X term_set (ERASE);
X#ifdef amiga
X ttflush ();
X#else
X fflush (stdout);
X#endif
X save_art(s,ptr,msg);
X#ifdef amiga
X sprintf (pr_buf,"%s\n%s",msg,Contstr);
X tputs(pr_buf,1,ttputc);
X#else
X printf ("%s\n%s",msg,Contstr);
X#endif
X getnoctl ();
X show ();
X }
X else
X {
X prinfo("saving ....");
X if (*ptr == '\0')
X ptr = Savefile;
X else
X Savefile = str_store(ptr);
X if (save_art(s,Savefile,msg) != 0)
X preinfo(msg);
X else
X prinfo(msg);
X }
X }
X else
X preinfo (No_msg);
X
X if (Digest)
X dig_ulist (dsave);
X}
X
X/*
X basic page display routine. erase screen and format current page
X*/
Xstatic
Xshow ()
X{
X int i;
X unsigned long mask;
X char helpstr[40];
X
X term_set (ERASE);
X C_info = 0;
X i = Cur_page - (Page.h.group)->pnum + 1;
X if (Digest) {
X#ifdef amiga
X sprintf (pr_buf,DHFORMAT,Page.h.name);
X tputs(pr_buf,1,ttputc);
X#else
X printf (DHFORMAT,Page.h.name);
X#endif
X } else {
X#ifdef amiga
X sprintf (pr_buf,HFORMAT,Page.h.name,i,(Page.h.group)->pages);
X tputs(pr_buf,1,ttputc);
X#else
X printf (HFORMAT,Page.h.name,i,(Page.h.group)->pages);
X#endif
X }
X
X mask = 1L << (i-1);
X (Page.h.group)->pgshwn |= mask;
X mask = 1;
X for (--i; i > 0 && (mask & (Page.h.group)->pgshwn) != 0 ; --i)
X mask <<= 1;
X if (i <= 0)
X (Page.h.group)->pgrd = Page.b[(Page.h.artnum)-1].art_id;
X
X for (i=0; i < Page.h.artnum; ++i)
X {
X if (Digest)
X {
X#ifdef amiga
X sprintf(pr_buf,Aformat,Page.b[i].art_mark,ART_UNWRITTEN,Page.b[i].art_id);
X tputs(pr_buf,1,ttputc);
X sprintf(pr_buf,"%s",Page.b[i].art_t);
X tputs(pr_buf,1,ttputc);
X#else
X printf(Aformat,Page.b[i].art_mark,ART_UNWRITTEN,Page.b[i].art_id);
X printf("%s",Page.b[i].art_t);
X#endif
X continue;
X }
X
X if ((Page.h.group)->rdnum >= Page.b[i].art_id) {
X#ifdef amiga
X sprintf(pr_buf,Aformat,Page.b[i].art_mark,ART_WRITTEN,Page.b[i].art_id);
X tputs(pr_buf,1,ttputc);
X#else
X printf(Aformat,Page.b[i].art_mark,ART_WRITTEN,Page.b[i].art_id);
X#endif
X } else {
X#ifdef amiga
X sprintf(pr_buf,Aformat,Page.b[i].art_mark,ART_UNWRITTEN,Page.b[i].art_id);
X tputs(pr_buf,1,ttputc);
X#else
X printf(Aformat,Page.b[i].art_mark,ART_UNWRITTEN,Page.b[i].art_id);
X#endif
X }
X#ifdef amiga
X sprintf(pr_buf,"%s",Page.b[i].art_t);
X tputs(pr_buf,1,ttputc);
X#else
X printf("%s",Page.b[i].art_t);
X#endif
X }
X
X sprintf(helpstr,HELPFORM,Cxptoi[HELP]);
X if (!Digest && ((Page.h.group)->flags & FLG_SUB) == 0)
X prinfo ("%s, %s",Unsub_msg,helpstr);
X else
X prinfo (helpstr);
X}
X
X/*
X update written status marks on screen
X*/
Xstatic
Xwr_show ()
X{
X int i,row;
X char c;
X
X row = RECBIAS;
X for (i=0; i < Page.h.artnum; ++i)
X {
X term_set (MOVE,WRCOL,row);
X if ((Page.h.group)->rdnum >= Page.b[i].art_id)
X c = ART_WRITTEN;
X else
X c = ART_UNWRITTEN;
X#ifdef amiga
X sprintf(pr_buf,"%c",c);
X tputs(pr_buf,1,ttputc);
X#else
X printf("%c",c);
X#endif
X ++row;
X }
X}
X
X/*
X obtain user input of group name, becomes current page if valid.
X returns -1 or page number. calling routine does the show, if needed
X*/
Xstatic
Xspec_group ()
X{
X char nbuf [MAX_C + 1];
X NODE *p, *hashfind();
X
X user_str(nbuf,"Newsgroup ? ",1,"");
X
X if (*nbuf == '\0' || (p = hashfind(nbuf)) == NULL)
X {
X preinfo ("Not a newsgroup");
X return (-1);
X }
X if ((p->flags & FLG_PAGE) == 0)
X {
X if ((p->flags & FLG_SUB) == 0)
X {
X new_sub(p,FLG_SUB);
X do_update("Not subscribed: resubscribed for next reading session");
X }
X else
X prinfo ("No news for that group");
X return (-1);
X }
X if ((p->flags & FLG_SUB) == 0)
X {
X new_sub(p,FLG_SUB);
X do_update("Resubscribed");
X }
X find_page (p->pnum);
X return (p->pnum);
X}
X
X/*
X obtain user input with prompt p. Optionally on info line.
X handle erase and kill characters, suppresses leading
X white space. Use defstr as the editable default user input.
X If on info line, cursor is not moved anywhere whe done, otherwise
X a <CR><LF> is done after input. Should be in raw mode to use
X this routine. Used from outside this source file so that we
X only have to do erase / kill key stuff one place.
X*/
Xuser_str (s,p,iline,defstr)
Xchar *s;
Xchar *p;
Xint iline;
Xchar *defstr;
X{
X int i,idx,len;
X char c;
X
X if (iline)
X {
X prinfo ("%s%s",p,defstr);
X idx = C_info;
X }
X else
X {
X#ifdef amiga
X sprintf (pr_buf,"%s%s",p,defstr);
X tputs(pr_buf,1,ttputc);
X#else
X printf ("%s%s",p,defstr);
X#endif
X idx = strlen(p);
X }
X
X len = strlen(defstr);
X for (i=0; i < len; i++)
X s[i] = defstr[i];
X
X for (i=len; idx < C_allow; ++i)
X {
X s[i] = getchar();
X c = s[i] & CHMASK;
X if (c == '\015' || c == '\012')
X break;
X if (c == Erasekey)
X {
X if (i > 0)
X {
X term_set (RUBSEQ);
X i -= 2;
X --idx;
X }
X else
X i = -1;
X continue;
X }
X if (c == Killkey)
X {
X if (iline)
X {
X prinfo ("%s",p);
X idx = C_info;
X }
X else
X {
X#ifdef amiga
X sprintf (pr_buf,"\r%s",p);
X tputs(pr_buf,1,ttputc);
X#else
X printf ("\r%s",p);
X#endif
X term_set(ZAP,strlen(p),idx);
X#ifdef amiga
X ttflush ();
X#else
X fflush(stdout);
X#endif
X idx = strlen(p);
X }
X i = -1;
X continue;
X }
X /* no leading spaces */
X if (c == ' ' && i == 0)
X {
X i = -1;
X putchar('\07');
X continue;
X }
X /* no controls */
X if (iscntrl(c))
X {
X --i;
X putchar('\07');
X continue;
X }
X ++idx;
X putchar (s[i]);
X#ifdef MINIX
X fflush(stdout);
X#endif
X }
X
X if (iline)
X C_info = idx;
X else {
X#ifdef amiga
X sprintf(pr_buf,"\r\n");
X tputs(pr_buf,1,ttputc);
X#else
X printf("\r\n");
X#endif
X }
X
X s[i] = '\0';
X}
X/*
X print something on the information line,
X clearing any characters not overprinted.
X preinfo includes reverse video and a bell for error messages.
X*/
Xpreinfo (s,a,b,c,d,e,f)
Xchar *s;
X{
X int l;
X char buf[RECLEN];
X
X term_set (MOVE,0,INFOLINE);
X putchar ('\07');
X term_set (ONREVERSE);
X sprintf (buf,s,a,b,c,d,e,f);
X#ifdef amiga
X sprintf (pr_buf," %s",buf);
X tputs(pr_buf,1,ttputc);
X#else
X printf (" %s ",buf);
X#endif
X term_set (OFFREVERSE);
X l = strlen(buf) + 2;
X if (l < C_info)
X term_set (ZAP,l,C_info);
X C_info = l;
X#ifdef amiga
X ttflush ();
X#else
X fflush(stdout);
X#endif
X}
X
Xprinfo (s,a,b,c,d,e,f)
Xchar *s;
Xlong a,b,c,d,e,f;
X{
X int l;
X char buf[RECLEN];
X term_set (MOVE,0,INFOLINE);
X sprintf (buf,s,a,b,c,d,e,f);
X#ifdef amiga
X sprintf (pr_buf,"%s",buf);
X tputs(pr_buf,1,ttputc);
X#else
X printf ("%s ",buf);
X#endif
X l = strlen(buf);
X if (l < C_info)
X term_set (ZAP,l,C_info);
X C_info = l;
X#ifdef amiga
X ttflush ();
X#else
X fflush(stdout);
X#endif
X}
X
Xstatic
Xtot_list ()
X{
X int i,max,len;
X char c;
X char ff[MAX_C+1];
X
X term_set (ERASE);
X
X for (max=i=0; i < Ncount; ++i)
X {
X if ((Newsorder[i])->pages == 0)
X continue;
X if ((len = strlen((Newsorder[i])->nd_name)) > max)
X max = len;
X }
X
X sprintf (ff,"%%4d %%%ds: %%3d new %%3d updated\n",max);
X
X for (len=i=0; i < Ncount; ++i)
X {
X if ((Newsorder[i])->pages == 0)
X continue;
X#ifdef amiga
X sprintf (pr_buf,ff, i, (Newsorder[i])->nd_name,
X (Newsorder[i])->highnum - (Newsorder[i])->orgrd,
X (Newsorder[i])->rdnum - (Newsorder[i])->orgrd);
X tputs(pr_buf,1,ttputc);
X#else
X printf (ff, i, (Newsorder[i])->nd_name,
X (Newsorder[i])->highnum - (Newsorder[i])->orgrd,
X (Newsorder[i])->rdnum - (Newsorder[i])->orgrd);
X#endif
X ++len;
X if (len == L_allow && i < (Ncount-1))
X {
X#ifdef amiga
X sprintf(pr_buf,"\nr - return, n - new group, other to continue ... ");
X tputs(pr_buf,1,ttputc);
X#else
X printf("\nr - return, n - new group, other to continue ... ");
X#endif
X if ((c = getnoctl()) == 'r' || c == 'n')
X break;
X printf ("\n\n");
X len = 0;
X }
X }
X if (i >= Ncount)
X {
X#ifdef amiga
X sprintf(pr_buf,"n - new group, other to return ... ");
X tputs(pr_buf,1,ttputc);
X#else
X printf("n - new group, other to return ... ");
X#endif
X c = getnoctl();
X }
X
X /* c will remain 'n' while user chooses bad newsgroups */
X while (c == 'n')
X {
X#ifdef amiga
X sprintf(pr_buf,"\n");
X tputs(pr_buf,1,ttputc);
X#else
X printf("\n");
X#endif
X user_str(ff,"Newsgroup number ? ",0,"");
X i = atoi(ff);
X if (i < 0 || i >= Ncount || (Newsorder[i])->pages == 0)
X {
X#ifdef amiga
X sprintf(pr_buf,"\nBad newsgroup number\n");
X tputs(pr_buf,1,ttputc);
X sprintf(pr_buf,"n - new group, other to return ... ");
X tputs(pr_buf,1,ttputc);
X#else
X printf("\nBad newsgroup number\n");
X printf("n - new group, other to return ... ");
X#endif
X c = getnoctl();
X continue;
X }
X find_page((Newsorder[i])->pnum);
X Crec = RECBIAS;
X Highrec = Page.h.artnum + RECBIAS;
X c = '\0';
X }
X}
X
X/*
X** call vns_write if anything has changed, then wipe FLG_ECHG bits
X** also produce message(s)
X*/
Xstatic
Xdo_update(msg)
Xchar *msg;
X{
X int i;
X
X for (i=0; i < Ncount; ++i)
X if(((Newsorder[i])->flags & FLG_ECHG) != 0)
X break;
X if (i < Ncount)
X {
X prinfo("Writing news status");
X vns_write(Newsorder,Ncount);
X for (i=0; i < Ncount; ++i)
X (Newsorder[i])->flags &= ~FLG_ECHG;
X }
X prinfo(msg);
X}
X
X/*
X** set a new rdnum value. If a change, set FLG_ECHG
X*/
Xstatic
Xnew_read(n,rd)
XNODE *n;
Xint rd;
X{
X if (n->rdnum != rd)
X {
X n->rdnum = rd;
X n->flags |= FLG_ECHG;
X }
X}
X
X/*
X** set a new subscription bit. bit argument is either 0 or FLG_SUB.
X*/
Xstatic
Xnew_sub(n,bit)
XNODE *n;
Xunsigned bit;
X{
X /*
X ** since bit is 0 or FLG_SUB, we could get tricky with ^
X ** but this is clearer
X */
X if (bit != 0 && (n->flags & FLG_SUB) == 0)
X n->flags |= FLG_SUB|FLG_ECHG;
X else
X {
X if (bit == 0 && (n->flags & FLG_SUB) != 0)
X {
X n->flags &= ~FLG_SUB;
X n->flags |= FLG_ECHG;
X }
X }
X}
X
X/*
X** utility to mark articles. depends on fact that article numbers are
X** in ascending order on page.
X*/
Xstatic
Xmarkstr (list,ckey)
Xchar *list;
Xchar ckey;
X{
X char *tok;
X int art, count;
X BODY *b;
X
X count = 1;
X b = Page.b;
X for (tok = strtok(list,List_sep); tok != NULL;
X tok = strtok(NULL,List_sep))
X {
X art = atoi(tok);
X while (count < Page.h.artnum && b->art_id < art)
X {
X ++count;
X ++b;
X }
X if (b->art_id == art)
X {
X /*
X ** Can't call Marker inside digests
X */
X if (Marker == NULL || Digest)
X {
X if (b->art_mark != ART_MARK)
X b->art_mark = ART_MARK;
X else
X b->art_mark = ' ';
X }
X else
X {
X b->art_mark =
X (*Marker)(Page.h.group, art,
X b->art_mark, ckey);
X }
X term_set (MOVE, 0, count-1+RECBIAS);
X#ifdef amiga
X sprintf (pr_buf,"%c\010",b->art_mark);
X tputs(pr_buf,1,ttputc);
X#else
X printf ("%c\010",b->art_mark);
X#endif
X }
X }
X}
END_OF_FILE
if test 24544 -ne `wc -c <'session.c'`; then
echo shar: \"'session.c'\" unpacked with wrong size!
fi
# end of 'session.c'
fi
echo shar: End of archive 4 \(of 6\).
cp /dev/null ark4isdone
MISSING=""
for I in 1 2 3 4 5 6 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 6 archives.
rm -f ark[1-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0
--
Mail submissions (sources or binaries) to <amiga@uunet.uu.net>.
Mail comments to the moderator at <amiga-request@uunet.uu.net>.
Post requests for sources, and general discussion to comp.sys.amiga.misc.