Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!seismo!lll-lcc!ptsfa!amdahl!rtech!bobm From: bobm@rtech.UUCP (Bob Mcqueer) Newsgroups: net.sources Subject: vn 12/86 (part 3 of 4) - reader.c / newsrc.c Message-ID: <571@rtech.UUCP> Date: Thu, 1-Jan-87 14:48:32 EST Article-I.D.: rtech.571 Posted: Thu Jan 1 14:48:32 1987 Date-Received: Fri, 2-Jan-87 20:43:41 EST Organization: Relational Technology, Alameda CA Lines: 1505 Bob McQueer {amdahl, sun, mtxinu, hoptoad, cpsc6a}!rtech!bobm cut here ----------------------------------- #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # reader.c # newsrc.c # This archive created: Thu Jan 1 11:15:26 1987 export PATH; PATH=/bin:$PATH echo shar: extracting "'reader.c'" '(18610 characters)' if test -f 'reader.c' then echo shar: will not over-write existing file "'reader.c'" else cat << \SHAR_EOF > 'reader.c' /* ** vn news reader. ** ** reader.c - article reading interface - "more" like. ** ** see copyright disclaimer / history in vn.c source file */ #include#include #include "tty.h" #include "config.h" #include "vn.h" #include "head.h" #include "reader.h" #define PERTAB 8 /* tab expansion factor */ #define BACKTRACK 24 extern char *Printer,*Editor,*Mailer,*Poster,*Orgdir,*Savefile,*Savedir,*Ccfile; extern int L_allow; extern int C_allow; extern int Rot; extern int Headflag; extern int Digest; extern char *No_msg; extern char *Roton_msg; extern char *Rotoff_msg; extern char *Hdon_msg; extern char *Hdoff_msg; extern char *T_head, *FT_head, *N_head, *L_head, *RT_head, *DIS_head; extern char *TO_head, *F_head, *P_head, *M_head, *R_head; extern char Cxrtoi[], Cxitor[]; static FILE *Fpread; static char *Fname; static char *Lookahead; static int Rlines; static int Hlines; #ifdef ADDRMUNGE static int Newaddr; #endif /* readstr routine is the "funnel" to the reading state, and controls signal setting. Some "session" context is passed along to allow jumping back to a different display WARNING: NOTHING below readstr should call strtok() */ readstr (s,crec,highrec,count) char *s; int *crec, *highrec; int count; { char *fnext, *strtok(); int pc; Fname = strtok(s,LIST_SEP); if (Fname != NULL) { term_set (ERASE); sig_set (BRK_READ,&Fpread); fnext = strtok(NULL,LIST_SEP); while (Fname != NULL && readfile(fnext,&pc) >= 0) { if (Digest) unlink (Fname); Fname = fnext; fnext = strtok (NULL,LIST_SEP); } if (Digest && Fname != NULL) unlink (Fname); if (pc != 0) forward (pc, crec, highrec); else { *crec += count; if (*crec >= *highrec) *crec = *highrec - 1; } sig_set (BRK_RFIN); show (); term_set (MOVE, 0, *crec); } else { preinfo ("%s",No_msg); term_set (MOVE, 0, *crec); } } /* readfile presents article: sn - name of next article, NULL if last. pages - pages to advance on return, if applicable returns 0 for "continue", <0 for "quit" */ static readfile (sn,pages) char *sn; int *pages; { FILE *fopen(); int lines,percent,artlin; long rew_pos, ftell(); char c, buf[RECLEN], mid[RECLEN], ngrp[RECLEN], dist[RECLEN]; char from[RECLEN], title[RECLEN], flto[RECLEN], reply[RECLEN]; char pstr[24], dgname[48], getpgch(), *index(), *digest_extract(); char *tgetstr(); *pages = 0; term_set(ERASE); if (Digest) { lines = atoi(Fname); if ((Fname = digest_extract(dgname,lines)) == NULL) { printf ("couldn't extract article %d",lines); return (0); } } if ((Fpread = fopen(Fname,"r")) == NULL) { printf ("couldn't open article %s",Fname); return (0); } Hlines = gethead (mid, from, title, ngrp, flto, reply, dist, &artlin); printf (ANFORM,Fname,Cxrtoi[PG_HELP]); lines = 1; rew_pos = ftell(Fpread); if (Headflag) { rewind(Fpread); Rlines = 0; } else { /* use do_out to guard against control sequences */ Rlines = Hlines; sprintf (buf,"%s%s\n",T_head,title); lines += do_out(buf,1); sprintf (buf,"%s%s\n",F_head,from); lines += do_out(buf,1); if (index(ngrp,',') != NULL) { sprintf (buf,"%s%s\n",N_head,ngrp); lines += do_out(buf,1); } if (*flto != '\0') { sprintf (buf,"%s%s\n",FT_head,flto); lines += do_out(buf,1); } printf ("%s%d\n",L_head,artlin); /* no controls */ ++lines; } /* will return out of outer while loop */ Lookahead = NULL; while (1) { /* ** lines counts folded lines from do_out. ** globals Hlines and Rlines refer to records. ** If Lookahead is null after this loop, we've ** hit EOF. */ lines += do_out(Lookahead,L_allow-lines); while (1) { if (Lookahead == NULL) { if (fgets(buf,RECLEN-1,Fpread) == NULL) break; Lookahead = buf; if (Rot != 0 && Rlines >= Hlines) rot_line(buf); ++Rlines; } if (lines >= L_allow) break; lines += do_out(buf,L_allow-lines); } if (Lookahead != NULL) { /* ** calculation is truncated rather than rounded, ** so we shouldn't get "100%". Subtract 2 for ** 1 line lookahead and empty line at beginning ** of article. */ if (Headflag) percent = ((Rlines-2)*100)/(artlin+Hlines); else percent = ((Rlines-Hlines-2)*100)/artlin; sprintf (pstr,PAGE_MID,percent); } else { if (sn == NULL) strcpy (pstr,PAGE_END); else strcpy (pstr,PAGE_NEXT); } c = getpgch(pstr,mid,from,reply,title,ngrp,flto,dist); /* handle user input: CAUTION!! return cases must close Fpread. */ switch (c) { case PG_NEXT: fclose (Fpread); return (0); case PG_FLIP: *pages = 1; /* fall through */ case PG_QUIT: fclose (Fpread); return (-1); case PG_REWIND: if (Headflag) { Rlines = 0; rewind (Fpread); } else { fseek (Fpread,rew_pos,0); Rlines = Hlines; } Lookahead = NULL; lines = 2 - RECBIAS; break; case PG_SEARCH: searcher(buf); lines = 2 - RECBIAS; lines += do_out(buf,L_allow-lines); break; case PG_WIND: fseek (Fpread,0L,2); lines = 2 - RECBIAS; Lookahead = NULL; break; case PG_STEP: if (Lookahead == NULL) { fclose (Fpread); return (0); } lines = L_allow - 1; break; default: if (Lookahead == NULL) { fclose (Fpread); return (0); } lines = 2 - RECBIAS; break; } } } /* gethead obtains subject, reply, message id, from, lines, newsgroup and followup-to lines of article for later use in mailing replies and posting followups, does not rewind, but leaves file at end of header lines. Returns number of header lines. */ static gethead (mid, from, title, ngrp, flto, reply, dist, lin) char *mid, *from, *title, *ngrp, *flto, *reply, *dist; int *lin; { int count; char buf [RECLEN], *index(); long pos,ftell(); #ifdef ADDRMUNGE Newaddr = 1; #endif *lin = 0; *dist = *mid = *from = *title = *ngrp = *flto = *reply = '\0'; /* for conditional is abnormal - expected exit is break */ for (count = 0; count < HDR_LINES && fgets(buf,RECLEN-1,Fpread) != NULL; ++count) { /* reset position and bail out at first non-header line */ if (index(buf,':') == NULL) { pos = ftell(Fpread); pos -= strlen(buf); fseek (Fpread,pos,0); break; } #ifdef MAILSMART if (strncmp(buf,RT_head,RTHDLEN) == 0) { buf [strlen(buf)-1] = '\0'; strcpy (reply,buf+RTHDLEN); continue; } #else if (strncmp(buf,P_head,PHDLEN) == 0) { buf [strlen(buf)-1] = '\0'; strcpy (reply,buf+PHDLEN); continue; } #endif if (strncmp(buf,DIS_head,DISHDLEN) == 0) { buf [strlen(buf)-1] = '\0'; strcpy (dist,buf+DISHDLEN); continue; } if (strncmp(buf,M_head,MHDLEN) == 0) { buf [strlen(buf)-1] = '\0'; strcpy (mid,buf+MHDLEN); continue; } if (strncmp(buf,F_head,FHDLEN) == 0) { buf [strlen(buf)-1] = '\0'; strcpy (from,buf+FHDLEN); continue; } if (strncmp(buf,T_head,THDLEN) == 0) { buf [strlen(buf)-1] = '\0'; strcpy (title,buf+THDLEN); continue; } if (strncmp(buf,N_head,NHDLEN) == 0) { buf [strlen(buf)-1] = '\0'; strcpy (ngrp,buf+NHDLEN); continue; } if (strncmp(buf,FT_head,FTHDLEN) == 0) { buf [strlen(buf)-1] = '\0'; strcpy (flto,buf+FTHDLEN); continue; } if (strncmp(buf,L_head,LHDLEN) == 0) { buf [strlen(buf)-1] = '\0'; *lin = atoi(buf+LHDLEN); continue; } } #ifdef MAILSMART if (*reply == '\0') strcpy(reply,from); #endif return (count); } /* getpgch prints prompt and gets command from user handles "mail", "save" and "followup" internally as well as flag resets. */ static char getpgch(prompt,mid,from,reply,title,ngrp,flto,dist) char *prompt, *mid, *from, *reply, *title, *ngrp, *flto, *dist; { char c; int ic; term_set (ONREVERSE); printf("%s\015",prompt); term_set (OFFREVERSE); while ((ic=getnoctl()) != EOF) { switch (c = Cxitor[ic]) { case SETROT: term_set (ZAP,0,PPR_MAX); if (Rot == 0) { Rot = 13; printf ("%s\n",Roton_msg); } else { Rot = 0; printf ("%s\n",Rotoff_msg); } if (Lookahead != NULL && Rlines > Hlines) rot_line(Lookahead); break; case HEADTOG: term_set (ZAP,0,PPR_MAX); if (Headflag) { Headflag = FALSE; printf ("%s\n",Hdoff_msg); } else { Headflag = TRUE; printf ("%s\n",Hdon_msg); } break; case PG_HELP: term_set (ZAP,0,PPR_MAX); help_pg (); break; case PG_REPLY: mail (reply,title,from); break; case PG_FOLLOW: followup (mid,title,ngrp,flto,from,dist); break; case SAVE: saver (); break; case PRINT: printr (); break; default: term_set (ZAP,0,PPR_MAX); return (c); } term_set (ONREVERSE); printf("%s\015",prompt); term_set (OFFREVERSE); } term_set (ZAP,0,PPR_MAX); return (c); } /* save article Like the savestr routine, it "loses" some storage every time the user specifies a new file, but this should not be significant */ static saver () { char *fn,cmd[RECLEN],*str_store(),*rprompt(); tty_set (SAVEMODE); sprintf (cmd,SAVFORM,Savefile); fn = rprompt(cmd,cmd); if (fn != NULL) Savefile = str_store(fn); if (*Savefile != '/' && *Savefile != '$') sprintf (cmd,"cat %s >>%s/%s",Fname,Savedir,Savefile); else sprintf (cmd,"cat %s >>%s",Fname,Savefile); system (cmd); tty_set (RESTORE); } /* invoke editor on new temp file, mail using reply line, possibly first allowing user to overide the reply (not INLETTER) */ static mail (p, t, f) char *p, *t, *f; { char *new, fn[L_tmpnam], cmd [RECLEN+60], *rprompt (); FILE *fp, *fopen(); tmpnam (fn); if ((fp = fopen(fn,"w")) == NULL) printex ("can't open %s\n",fn); if ((new = index(p, '(')) != NULL) *new = '\0'; /* a poor way of deleting comments */ #ifdef ADDRMUNGE if (Newaddr) { Newaddr = 0; ADDRMUNGE(p); } #endif if (strncmp(t, FPFIX, FPFLEN) == 0) t += FPFLEN; /* don't add multiple Re:s */ #ifdef INLETTER fprintf (fp,"%s%s\n%s%s%s\n\n%s:\n", TO_head, p, T_head, FPFIX, t, f); #else fprintf (fp,"%s%s%s\n\n%s:\n", T_head, FPFIX, t, f); #endif edcopy (fp); fclose (fp); tty_set (SAVEMODE); #ifndef INLETTER sprintf (cmd,"ADDRESS: %s\nreturn to accept, or input new address: ",p); if ((new = rprompt(cmd,cmd)) != NULL) strcpy (p,new); #endif sprintf (cmd,"%s %s", Editor, fn); chdir (Orgdir); system (cmd); cd_group (); new = rprompt ("still want to mail it ? ",cmd); if (new != NULL && (*new == 'y' || *new == 'Y')) { #ifndef INLETTER sprintf (cmd,"%s '%s' <%s", Mailer, p, fn); #else sprintf (cmd,"%s <%s", Mailer, fn); #endif system (cmd); printf ("given to mailer\n"); } else printf ("not mailed\n"); unlink (fn); tty_set (RESTORE); term_set (RESTART); } /* post a followup article, invoking editor for user after creating new temp file. remove after posting. Hack in ".followup" if posting newsgroup ends in ".general" - similar hack for preventing mod & announce groups - should really be more thorough and parse the whole string. User can change, anyway. */ static followup (m,t,n,ft,oa,dist) char *m, *t, *n, *ft, *oa, *dist; { char fn[L_tmpnam], *new, cmd [RECLEN], *rprompt(); FILE *f, *fopen(); char *rindex(); if (*ft != '\0') strcpy (cmd,ft); else strcpy (cmd,n); new = rindex(cmd,'.'); if (new != NULL && strcmp(new,".general") == 0) strcpy (new,".followup"); if ( strncmp(cmd, "mod.", 4) == 0 || strcmp(new, ".announce") == 0) { term_set (ONREVERSE); printf("Cannot post a follow-up to \"%s\", reply with mail to moderator\007\n", cmd); term_set (OFFREVERSE); return; } tmpnam (fn); if ((f = fopen(fn,"w")) == NULL) printex ("can't open %s\n",fn); if (strncmp(t, FPFIX, FPFLEN) == 0) t += FPFLEN; /* don't add multiple Re:s */ fprintf (f,"%s%s%s\n%s%s\n%s%s\n",T_head,FPFIX,t,N_head,cmd,R_head,m); if (*dist != '\0') fprintf(f,"%s%s\n",DIS_head,dist); fprintf (f,"\nin article %s, %s says:\n",m,oa); edcopy (f); fclose (f); tty_set (SAVEMODE); sprintf (cmd,"%s %s", Editor, fn); chdir (Orgdir); system (cmd); cd_group (); new = rprompt("still want to post it ? ",cmd); if (new != NULL && (*new == 'y' || *new == 'Y')) { sprintf (cmd,"%s <%s", Poster, fn); system (cmd); printf ("given to posting program\n"); save_article (fn); } else printf ("not posted\n"); unlink (fn); tty_set (RESTORE); term_set (RESTART); } /* get user buffer, return whitespace delimited token without using strtok(). buffer is allowed to overwrite prompt string. */ static char * rprompt(s,buf) char *s,*buf; { printf("%s",s); fgets (buf,RECLEN-1,stdin); while (*buf == ' ' || *buf == '\t') ++buf; if (*buf == '\n' || *buf == '\0') return (NULL); for (s = buf; *s != ' ' && *s != '\t' && *s != '\n' && *s != '\0'; ++s) ; *s = '\0'; return (buf); } /* edcopy copies article to file which user is editting for a reply or followup, so it may be referenced. It places ED_MARK in the left hand margin. */ edcopy(fp) FILE *fp; { long current; char buf[RECLEN]; int i; /* save position, rewind and skip over header lines */ current = ftell(Fpread); rewind (Fpread); for (i=0; i < HDR_LINES; ++i) { if (fgets(buf,RECLEN-1,Fpread) == NULL) break; if (strncmp(buf,L_head,LHDLEN) == 0) break; } /* if line already begins with ED_MARK, forget about the space */ while (fgets(buf,RECLEN-1,Fpread) != NULL) { if (buf[0] == ED_MARK) fprintf(fp,"%c%s",ED_MARK,buf); else fprintf(fp,"%c %s",ED_MARK,buf); } /* restore position */ fseek(Fpread,current,0); } /* help menus */ static help_pg() { h_print (Cxrtoi[PG_NEXT],HPG_NEXT); h_print (Cxrtoi[PG_QUIT],HPG_QUIT); h_print (Cxrtoi[PG_FLIP],HPG_FLIP); h_print (Cxrtoi[PG_REWIND],HPG_REWIND); h_print (Cxrtoi[PG_WIND],HPG_WIND); h_print (Cxrtoi[PG_SEARCH],HPG_SEARCH); h_print (Cxrtoi[PG_STEP],HPG_STEP); h_print (Cxrtoi[PG_REPLY],HPG_REPLY); h_print (Cxrtoi[PG_FOLLOW],HPG_FOLLOW); h_print (Cxrtoi[SAVE],HPG_SAVE); h_print (Cxrtoi[PRINT],HPG_PRINT); h_print (Cxrtoi[SETROT],HPG_ROT); h_print (Cxrtoi[HEADTOG],HPG_HEAD); h_print (Cxrtoi[PG_HELP],HPG_HELP); printf ("%s\n",HPG_DEF); } rot_line (s) unsigned char *s; { for ( ; *s != '\0'; ++s) { if (*s >= 'A' && *s <= 'Z') { *s += Rot; if (*s > 'Z') *s -= 26; continue; } if (*s >= 'a' && *s <= 'z') { *s += Rot; if (*s > 'z') *s -= 26; } } } /* ** output record. folds record to terminal width on word boundaries, ** returning number of lines output. If limit is reached, remainder ** of buffer waiting to be output is returned. Processes several ** special characters: ** form-feed - return "lim" lines so we stop on that line ** tabs - counts "expanded" width ** backspace - assumes they work, -1 width unless in first col. ** bell - pass through with zero width ** newline - end of record. ** del - turns into '_' ** other control - 'A' - 1 added ('01' = ctl-A). Makes escape = "[". ** (prevents "letter bombs" containing inappropriate control ** sequences for the terminal). ** ** Sets Lookahead pointer to remainder of line or NULL. */ static do_out(s,lim) char *s; int lim; { int len,i; char cs,*word,*start; Lookahead = NULL; if (s == NULL) return(0); len = 0; start = word = s; /* ** NOTE: "normal" return is buried inside switch, at newline ** ending record */ for (i=0; i < lim; ++i) { for ( ; len < C_allow; ++s) { switch (*s) { case '\n': *s = '\0'; /* fall through */ case '\0': printf("%s\n",start); return(i+1); case '\t': len = ((len/PERTAB)+1)*PERTAB; word = s; break; case '\b': if (len > 0) --len; break; case '\014': *s = ' '; i = lim-1; /* fall through */ case ' ': word = s+1; ++len; break; case '\177': *s = '_'; ++len; break; default: if (*s < ' ') *s += 'A' - 1; ++len; /* fall through */ case '\07': break; } } cs = *s; *s = '\0'; if ((len = strlen(word)) < BACKTRACK) { *s = cs; s = word; cs = *s; *s = '\0'; } else len = 0; printf("%s\n",start); start = s; *s = cs; } Lookahead = start; return(lim); } save_article(tempfname) char *tempfname; { FILE *in, *out; int c; time_t timenow, time(); char *today, *ctime(); if ((in = fopen(tempfname, "r")) == NULL) return; if ((out = fopen(Ccfile, "a")) == NULL) { fclose(in); return; } timenow = time((time_t)0); today = ctime(&timenow); fprintf(out,"From vn %s",today); while ((c=getc(in)) != EOF) putc(c, out); putc('\n', out); fclose(in); fclose(out); printf ("a copy has been saved in %s\n", Ccfile); } /* send article to printer */ static printr () { char cmd[RECLEN]; tty_set (SAVEMODE); printf("Sent to printer\n"); sprintf (cmd,"%s %s 2>/dev/null",Printer,Fname); system (cmd); tty_set (RESTORE); } /* search article for specified search pattern, returning the line on which it is found in buf, a null buffer otherwise. The input file will be positioned either after the line on which the pattern is found, or unaaltered if match fails. */ searcher (buf) char *buf; { static char searchstr[RECLEN] = ""; char lasave[RECLEN]; char *s, *reg, *rprompt(), *regcmp(), *regex(); long current; int orlines; /* save position, then request search pattern */ current = ftell(Fpread); orlines = Rlines; tty_set (SAVEMODE); sprintf (lasave,SEARCHFORM,searchstr); s = rprompt(lasave,lasave); tty_set (RESTORE); if (s != NULL) strcpy(searchstr, lasave); /* Now compile the search string */ if(( reg = regcmp(searchstr, (char *)0)) == NULL) { printf("Invalid search string \"%s\"\n", searchstr); *buf = '\0'; return; } /* try lookahead buffer first */ if (Lookahead != NULL && regex(reg,Lookahead) != NULL) { strcpy(buf,Lookahead); regfree(reg); return; } /* Lookahead can point into buf */ if (Lookahead != NULL) strcpy(lasave,Lookahead); /* now start reading lines, rotating if necessary and do search */ while (fgets(buf,RECLEN-1,Fpread) != NULL) { if (Rot != 0 && Rlines >= Hlines) rot_line(buf); ++Rlines; if( regex(reg, buf) != NULL ){ /* Got it */ term_set (ONREVERSE); printf("\n\tSkipping ....\n\n"); term_set (OFFREVERSE); regfree(reg); return; } } /* no dice, so restore position */ regfree(reg); term_set (ONREVERSE); printf("Cannot find string \"%s\" in remainder of article\007\n", searchstr); term_set (OFFREVERSE); fseek(Fpread,current,0); Rlines = orlines; if (Lookahead != NULL) strcpy(buf,lasave); else *buf = '\0'; return(0.0); } SHAR_EOF fi # end of overwriting check echo shar: extracting "'newsrc.c'" '(11576 characters)' if test -f 'newsrc.c' then echo shar: will not over-write existing file "'newsrc.c'" else cat << \SHAR_EOF > 'newsrc.c' /* ** vn news reader. ** ** newsrc.c - routines to deal with the newsrc file ** ** see copyright disclaimer / history in vn.c source file */ #include #include #include "config.h" #include "tty.h" #include "vn.h" extern NODE **Newsorder; extern char *Onews, *Newsrc; extern int Ncount, Lrec, C_allow; extern int Ntopt, Nntopt, Nwopt, Nnwopt; extern char *Topt[], *Negtopt[], *Wopt[], *Negwopt[]; extern int Nounsub, Listfirst; /* global flags signifying options set */ #define GF_ALL 1 /* -x option - scan everything */ #define GF_SPEC 2 /* -n option(s) - user specified groups */ #define GF_OVER 4 /* command line specification - overide marks */ static char *Options[OPTLINES]; static int New_idx, Max_name, Optlines; static unsigned Gflags = 0; /* routines for dealing with the .newsrc file and options */ /* command name argument is already omitted from argv argc in this routine. Only the option arguments are present. We process options before we scan the rest of .newsrc, which redoes Newsorder, ie. we don't clobber Ncount until options are processed. */ scan_newsrc (argc,argv) int argc; char **argv; { FILE *fp, *fopen(); static char marks[] = { NEWS_ON, NEWS_OFF, '\0' }; char *str_store (); int line, len, num; char buf [RECLEN], trail, optpflag, submark, *fret, *ptr, *strpbrk(), *strtok(); /* initialize hash table, open temp file, fill table with active articles */ hashinit (); fill_active (); temp_open(); if (argc > 0) { Gflags |= GF_OVER; arg_opt(argc,argv); optpflag = 'y'; } else optpflag = 'n'; if ((fp = fopen (Newsrc,"r")) == NULL) printex ("can't open %s for reading",Newsrc); Optlines = 0; for (line = 1; (fret = fgets(buf,RECLEN-1,fp)) != NULL && emptyline(buf) == 1; ++line) ; if (fret != NULL && strncmp (buf,"options",7) == 0) { Options[0] = str_store(buf); Optlines = 1; trail = buf [strlen(buf)-2]; for ( ; (fret = fgets(buf,RECLEN-1,fp)) != NULL; ++line) { if (trail != '\\' && buf[0] != ' ' && buf[0] != '\t') break; if (Optlines >= OPTLINES) printex ("%s - too many option lines (%d allowed)",Newsrc,OPTLINES); Options[Optlines] = str_store(buf); ++Optlines; if ((len = strlen(buf)) >= 2 && buf[len-2] != '\\') trail = buf[len-2]; else trail = '\0'; } } /* do the options from the newsrc file if there weren't command line args */ if (Optlines > 0 && optpflag == 'n') newsrc_opt (); Ncount = 0; for ( ; fret != NULL; ++line, fret = fgets(buf,RECLEN-1,fp)) { if (emptyline(buf) == 1) continue; if ((ptr = strpbrk(buf,marks)) == NULL) { fprintf (stderr,"\nwarning: line %d of %s (%s) - bad syntax\n", line,Newsrc,buf); continue; } submark = *ptr; *ptr = '\0'; ++ptr; num = 0; for (ptr = strtok(ptr," ,-\n"); ptr != NULL; ptr = strtok(NULL," ,-\n")) { len = atoi (ptr); for ( ; *ptr >= '0' && *ptr <= '9'; ++ptr) ; if (*ptr != '\0' || len < num) { num = -1; fprintf (stderr,"\nwarning: line %d of %s (%s) - bad syntax\n", line,Newsrc,buf); break; } num = len; } if (num < 0) continue; chkgroup (buf,submark,num); } fclose (fp); /* now take care of groups not specified in .newsrc */ art_active(); /* free up the option string storage */ for (num=0; num < Ntopt; ++num) regfree (Topt[num]); for (num=0; num < Nwopt; ++num) regfree (Wopt[num]); for (num=0; num < Nntopt; ++num) regfree (Negtopt[num]); for (num=0; num < Nnwopt; ++num) regfree (Negwopt[num]); Ntopt = Nwopt = Nntopt = Nnwopt = 0; } static emptyline(s) char *s; { while (isspace(*s)) ++s; if (*s == '\0') return (1); return (0); } /* fill hash table from active news group list temporarily makes "Newsorder" active list order. This is needed to be able to process options before scanning user order. */ static fill_active () { FILE *f,*fopen (); char *nread, act_rec[RECLEN], *strtok(); int num,lownum; Max_name = 0; if ((f = fopen (ACTFILE,"r")) == NULL) printex ("couldn't open %s\n",ACTFILE); while (fgets(act_rec, RECLEN-1, f) != NULL) { if (strtok (act_rec," \n") == NULL) continue; nread = strtok (NULL, " \n"); if (nread != NULL) num = atoi(nread); else num = 0; nread = strtok (NULL, " \n"); if (nread != NULL) lownum = atoi(nread); else lownum = 0; if (lownum > 0) --lownum; if (strlen(act_rec) > Max_name) Max_name = strlen(act_rec); hashenter (act_rec, num, lownum); } /* construct initial Newsorder */ entry_order(); fclose (f); } /* check active newsgroups not mentioned in NEWSRC file (FLG_SCAN not set) */ static art_active () { char act_rec[RECLEN], *strtok(); NODE *ptr,*hashfind(); FILE *f,*fopen(); if ((f = fopen (ACTFILE,"r")) == NULL) printex ("couldn't open %s\n",ACTFILE); New_idx = Ncount; while (fgets(act_rec, RECLEN-1, f) != NULL) { if (strtok (act_rec," \n") == NULL) continue; if ((ptr = hashfind (act_rec)) == NULL) printex("%s - unexpected hash table failure",act_rec); if ((ptr->state & FLG_SCAN) == 0) chkgroup (ptr->nd_name, NEWS_ON, 0); } } /* check group for new articles: s - group c - subscription indicator from NEWSRC n - number read */ static chkgroup (s,c,n) char *s,c; int n; { NODE *ptr, *hashfind(); int lold,lowart; lold = Lrec; if ((ptr = hashfind(s)) != NULL && (ptr->state & FLG_SCAN) == 0) { Newsorder [Ncount] = ptr; ++Ncount; ptr->pages = 0; ptr->state |= FLG_SCAN; if (c == NEWS_ON) ptr->state |= FLG_SUB; /* if "read" more than exist reset to zero */ if (n > ptr->art) n = 0; lowart = ptr->rdnum; if (n < ptr->rdnum) n = ptr->rdnum; ptr->orgrd = ptr->pgrd = ptr->rdnum = n; ptr->pgshwn = 0L; /* ** scan decision is rather complex, since GF_ALL setting ** overides "n" value, GF_SPEC indicates FLG_SPEC flag used. ** if GF_OVER set, FLG_SPEC overides subscription mark, else ** FLG_SPEC AND subscribed is neccesary. */ if ((Gflags & GF_SPEC) != 0) { if ((ptr->state & FLG_SPEC) == 0) c = NEWS_OFF; else { if ((Gflags & GF_OVER) != 0) c = NEWS_ON; } } if ((Gflags & GF_ALL) != 0) n = lowart; if (c == NEWS_ON && ptr->art > n) { outgroup (s,n,ptr->art); if (lold != Lrec) { ptr->pnum = lold+1; ptr->pages = Lrec - lold; ptr->state |= FLG_PAGE; } } } } /* wr_newsrc writes the .newsrc file */ wr_newsrc () { FILE *fp,*fopen(); NODE *p; char c; int i,rc; if (link(Newsrc,Onews) < 0) printex ("can't backup %s to %s before writing",Newsrc,Onews); if (unlink(Newsrc) < 0 || (fp = fopen(Newsrc,"w")) == NULL) printex ("can't open %s for writing (backed up in %s)",Newsrc,Onews); else { clearerr(fp); for (i=0; (rc = ferror(fp)) == 0 && i < Optlines; ++i) fprintf (fp,"%s",Options[i]); for (i=0; rc == 0 && i < Ncount; ++i) { p = Newsorder[i]; if ((p->state & FLG_SUB) == 0) c = NEWS_OFF; else c = NEWS_ON; #ifdef OLDRC fprintf (fp,"%s%c %d\n",p->nd_name,c,p->rdnum); #else if (p->rdnum > 0) fprintf (fp,"%s%c 1-%d\n",p->nd_name,c,p->rdnum); else fprintf (fp,"%s%c 0\n",p->nd_name,c); #endif rc = ferror(fp); } fclose (fp); if (rc != 0) printex ("write of %s failed, old copy stored in %s",Newsrc,Onews); else unlink (Onews); } } new_groups () { int i,wrem,w; char fs[24],c_end; if (New_idx >= Ncount || C_allow < (w = Max_name+1)) return (0); term_set (ERASE); printf (NEWGFORM,Newsrc); sprintf (fs,"%%-%ds%%c",Max_name); wrem = C_allow; for (i=New_idx; i < Ncount; ++i) { if ((wrem -= w) < w) { wrem = C_allow; c_end = '\n'; } else c_end = ' '; printf (fs,(Newsorder[i])->nd_name,c_end); } if ((++wrem) < C_allow) putchar ('\n'); return (i-New_idx); } /* arg_opt must be called prior to option scanning, since it uses the options array. This is a bit of a kludge, but it saves a bunch of work. NOTE - no command name argument */ static arg_opt (argc,argv) int argc; char **argv; { if (argc > OPTLINES) printex ("too many command line options (%d allowed)\n",OPTLINES); for (Optlines=0; Optlines < argc; ++Optlines) { Options[Optlines] = *argv; ++argv; } newsrc_opt(); } /* option setting routine: sets global flags: GF_ALL for -x option GF_SPEC for -n. sets up filter array for article scanning */ static newsrc_opt() { int i; char curopt,tmp[RECLEN],*tok,*strtok(),*index(); Nounsub = Listfirst = 0; Ntopt = Nwopt = Nnwopt = Nntopt = 0; curopt = '\0'; for (i=0; i < Optlines; ++i) { strcpy(tmp,Options[i]); for (tok = strtok(tmp,",\\ \t\n"); tok != NULL; tok = strtok(NULL,",\\ \t\n")) { if (*tok != '-') do_opt (curopt,tok); else { for (++tok; index("nwt",*tok) == NULL; ++tok) { /* options with no strings */ switch(*tok) { case 'S': Gflags &= ~GF_OVER; break; case '%': Listfirst = 1; break; case 'U': Nounsub = 1; break; #ifdef OLDRC case 'i': /* Treat "-i" as synonym for "-x" */ #endif case 'x': Gflags |= GF_ALL; default: break; } } curopt = *tok; if (*(++tok) != '\0') do_opt (curopt,tok); } } } } /* do_opt is for options with strings attached */ static do_opt (opt,str) char opt, *str; { switch (opt) { case 'n': Gflags |= GF_SPEC; specmark(str); break; case 'w': specfilter (FIL_AUTHOR,str); break; case 't': specfilter (FIL_TITLE,str); break; default: #ifdef OLDRC Gflags |= GF_SPEC; /* Assume anything else is newsgroup */ specmark(str); #endif break; } } static specfilter (comp,str) char comp,*str; { char *regcmp(); int *count; char **rex; /* ** we may set rex one past end of array. we will error before ** referencing it if that's the case, however. */ if (*str == '!') { if (comp == FIL_TITLE) { count = &Nntopt; rex = Negtopt + *count; } else { count = &Nnwopt; rex = Negwopt + *count; } ++str; } else { if (comp == FIL_TITLE) { count = &Ntopt; rex = Topt + *count; } else { count = &Nwopt; rex = Wopt + *count; } } if (*count >= NUMFILTER) printex ("too many %c options, %d allowed",comp,NUMFILTER); if ((*rex = regcmp(str,(char *) 0)) == NULL) printex ("%c option regular expression syntax: %s",comp,str); ++(*count); } /* handle the newsgroup specification string. ("all" convention - braack!!!) */ static specmark (s) char *s; { unsigned ormask,andmask; int i,len; char *ptr,*re,pattern[RECLEN],*regex(),*regcmp(); if (*s == '!') { ++s; ormask = 0; andmask = ~FLG_SPEC; if (*s == '\0') return; } else { ormask = FLG_SPEC; andmask = 0xffff; } /* convert "all" not bounded by alphanumerics to ".*". ".all" becomes ".*" */ for (ptr = s; (len = findall(ptr)) >= 0; ptr += len+1) { if (len > 0 && isalnum (s[len-1])) continue; if (isalnum (s[len+3])) continue; if (len > 0 && s[len-1] == '.') { --len; strcpy (s+len,s+len+1); } s[len] = '.'; s[len+1] = '*'; strcpy (s+len+2,s+len+3); } /* now use regular expressions */ sprintf (pattern,"^%s$",s); if ((re = regcmp(pattern,(char *) 0)) == NULL) printex ("n option regular expression syntax: %s",s); for (i=0; i < Ncount; ++i) { if (regex(re,(Newsorder[i])->nd_name) != NULL) { (Newsorder[i])->state |= ormask; (Newsorder[i])->state &= andmask; } } regfree (re); } static findall (s) char *s; { int len; for (len=0; *s != '\0'; ++s,++len) { if (*s == 'a' && strncmp(s,"all",3) == 0) return (len); } return (-1); } SHAR_EOF fi # end of overwriting check # End of shell archive exit 0