lwall@sdcrdcf.UUCP (Larry Wall) (10/03/84)
#! /bin/sh # Make a new directory for the rn sources, cd to it, and run kits 1 thru 8 # through sh. When all 8 kits have been run, read README. echo "This is rn kit 3 (of 8). If kit 3 is complete, the line" echo '"'"End of kit 3 (of 8)"'" will echo at the end.' echo "" export PATH || (echo "You didn't use sh, you clunch." ; kill $$) echo Extracting art.c cat >art.c <<'!STUFFY!FUNK!' /* $Header: art.c,v 4.1 84/09/24 11:40:12 lwall Exp $ * * $Log: art.c,v $ * Revision 4.1 84/09/24 11:40:12 lwall * Real baseline. * * Revision 4.0.1.5 84/09/19 17:06:19 lwall * Ifdef'ed some stuff that should have been. * * Revision 4.0.1.4 84/09/18 16:04:45 lwall * Fixed INNERSEARCH commands. * * Revision 4.0.1.3 84/09/10 14:49:44 lwall * Delinted. * * Revision 4.0.1.2 84/09/06 08:26:07 lwall * Include util.h to define instr. * * Revision 4.0.1.1 84/09/05 17:07:19 lwall * Treat restart correctly. * * Revision 4.0 84/09/04 09:49:21 lwall * Baseline for netwide release * */ #include "EXTERN.h" #include "common.h" #include "rn.h" #include "ngstuff.h" #include "head.h" #include "cheat.h" #include "help.h" #include "search.h" #include "artio.h" #include "ng.h" #include "bits.h" #include "final.h" #include "artstate.h" #include "rcstuff.h" #include "term.h" #include "sw.h" #include "util.h" #include "backpage.h" #include "intrp.h" #include "INTERN.h" #include "art.h" /* page_switch() return values */ #define PS_NORM 0 #define PS_ASK 1 #define PS_RAISE 2 #define PS_TOEND 3 bool special = FALSE; /* is next page special length? */ int slines = 0; /* how long to make page when special */ ART_LINE highlight = -1; /* next line to be highlighted */ char *restart = Nullch; /* if nonzero, the place where last */ /* line left off on line split */ char *blinebeg; /* where in buffer current line began */ ART_POS alinebeg; /* where in file current line began */ #ifdef INNERSEARCH ART_POS innersearch = 0; /* artpos of end of line we found */ /* for 'g' command */ ART_LINE isrchline = 0; /* last line to display */ bool hide_everything = FALSE; /* if set, do not write page now, */ /* but refresh when done with page */ COMPEX gcompex; /* in article search pattern */ #endif bool firstpage; /* is this the 1st page of article? */ void art_init() { ; } int do_article() { register char *s; ART_POS artsize; /* size in bytes of article */ char art_buf[LBUFLEN]; /* place for article lines */ bool hide_this_line = FALSE; /* hidden header line? */ ART_LINE linenum; /* line # on page, 1 origin */ #ifdef ULSMARTS bool under_lining = FALSE; /* are we underlining a word? */ #endif register char *bufptr = art_buf; /* pointer to input buffer */ register int outpos; /* column position of output */ static char prompt_buf[64]; /* place to hold prompt */ bool notesfiles = FALSE; /* might there be notesfiles junk? */ #ifdef INNERSEARCH register int outputok; #endif if (fstat(artfp->_file,&filestat)) /* get article file stats */ return DA_CLEAN; artsize = filestat.st_size; /* from that get article size */ sprintf(prompt_buf, "%%sEnd of article %ld (of %ld)--what next? [%%s]", (long)art,(long)lastart); /* format prompt string */ prompt = prompt_buf; int_count = 0; /* interrupt count is 0 */ firstpage = (topline < 0); for (;;) { /* for each page */ assert(art == openart); if (do_fseek) { artpos = vrdary(artline); if (artpos < 0) artpos = -artpos; /* labs(), anyone? */ fseek(artfp,artpos,0); if (artpos < htype[PAST_HEADER].ht_minpos) in_header = SOME_LINE; do_fseek = FALSE; restart = Nullch; } if (firstpage) { if (firstline) { interp(art_buf,firstline); fputs(art_buf,stdout); } else { ART_NUM i; printf("Article %ld",(long)art); i = (((ART_NUM)toread[ng]) - 1 + was_read(art)); #ifdef DELAYMARK if (i || dmcount) { printf(" (%ld more",(long)i); if (dmcount) printf(" + %ld Marked to return)",(long)dmcount); putchar(')'); } #else if (i) printf(" (%ld more)",(long)i); #endif if (htype[NGS_LINE].ht_flags & HT_HIDE) printf(" in %s", ngname); fputs(":\n",stdout); } start_header(art); forcelast = FALSE; /* we will have our day in court */ restart = Nullch; artline = 0; /* start counting lines */ artpos = 0; vwtary(artline,artpos); /* remember pos in file */ } for (linenum=(firstpage?2:1); in_header || ( #ifdef INNERSEARCH innersearch ? innermore() : #endif linenum<(firstpage?initlines:(special?slines:LINES)) ); linenum++) { /* for each line on page */ if (int_count) { /* exit via interrupt? */ putchar('\n'); /* get to left margin */ int_count = 0; /* reset interrupt count */ return DA_NORM; /* skip out of loops */ } if (restart) { /* did not finish last line? */ bufptr = restart; /* then start again here */ restart = Nullch; /* and reset the flag */ } else { /* not a restart */ if (fgets(art_buf,LBUFLEN,artfp)==Nullch) { /* if all done */ return DA_NORM; /* skip out of loops */ } bufptr = art_buf; /* so start at beginning */ art_buf[LBUFLEN-1] = '\0'; /* make sure string ends */ } blinebeg = bufptr; /* remember where we began */ alinebeg = artpos; /* both in buffer and file */ if (in_header && bufptr == art_buf) hide_this_line = parseline(art_buf,do_hiding,hide_this_line); else if (notesfiles && do_hiding && bufptr == art_buf && *art_buf == '#' && isupper(art_buf[1]) && art_buf[2] == ':' ) { fgets(art_buf,sizeof(art_buf),artfp); if (index(art_buf,'!') != Nullch) fgets(art_buf,sizeof(art_buf),artfp); htype[PAST_HEADER].ht_minpos = ftell(artfp); /* exclude notesfiles droppings */ hide_this_line = TRUE; /* and do not print either */ notesfiles = FALSE; } if (in_header && htype[in_header].ht_flags & HT_MAGIC) { if (in_header == NGS_LINE) { hide_this_line = (index(art_buf,',') == Nullch && do_hiding); } else if (in_header == EXPIR_LINE) { if (!(htype[EXPIR_LINE].ht_flags & HT_HIDE)) hide_this_line = (strlen(art_buf) < 10 && do_hiding); } } if (in_header == SUBJ_LINE && htype[SUBJ_LINE].ht_flags & HT_MAGIC) { /* is this the subject? */ int length; length = strlen(art_buf)-1; artline++; art_buf[length] = '\0'; /* wipe out newline */ #ifdef NOFIREWORKS no_ulfire(); #endif notesfiles = (instr(&art_buf[length-10]," - (nf") != Nullch); if (oldsubject) { length += 7; fputs("(SAME) ",stdout); oldsubject = FALSE; } if (length+UG > COLS) { /* rarely true */ linenum++; vwtary(artline,vrdary(artline-1)+COLS); artline++; } s = art_buf + 8; *s++ = '\0'; /* make into 2 strings */ fputs(art_buf,stdout); /* print up through : */ if (!UG) putchar(' '); underprint(s); /* print subject underlined */ putchar('\n'); /* and finish the line */ } else if (hide_this_line) { /* do not print line? */ linenum--; /* compensate for linenum++ */ if (!in_header) hide_this_line = FALSE; } else { /* just a normal line */ if (highlight==artline) { /* this line to be highlit? */ if (marking == STANDOUT) { #ifdef NOFIREWORKS if (erase_screen) no_sofire(); #endif standout(); } else { #ifdef NOFIREWORKS if (erase_screen) no_ulfire(); #endif underline(); } if (*bufptr == '\n') putchar(' '); } #ifdef INNERSEARCH outputok = !hide_everything; /* get it into register, hopefully */ #endif for (outpos = 0; outpos < COLS; ) { /* while line has room */ if (*bufptr >= ' ') { /* normal char? */ #ifdef ULSMARTS if (*bufptr == '_') { if (bufptr[1] == '\b') { if (!under_lining && highlight!=artline #ifdef INNERSEARCH && outputok #endif ) { under_lining++; if (UG) { if (bufptr != buf && bufptr[-1] == ' ') { outpos--; backspace(); } } underline(); } bufptr += 2; } } else { if (under_lining) { under_lining = 0; un_underline(); if (UG) { if (*bufptr == ' ') goto skip_put; outpos++; } } } #endif #ifdef INNERSEARCH if (outputok) #endif { #ifdef ROTATION if (rotate && !in_header && isalpha(*bufptr)) { if ((*bufptr & 31) <= 13) putchar(*bufptr+13); else putchar(*bufptr-13); } else #endif putchar(*bufptr); } if (*UC && ((highlight==artline && marking == 1) #ifdef ULSMARTS || under_lining #endif )) { backspace(); underchar(); } skip_put: bufptr++; outpos++; } else if (*bufptr == '\n' || !*bufptr) { /* newline? */ #ifdef ULSMARTS if (under_lining) { under_lining = 0; un_underline(); } #endif #ifdef DEBUGGING if (debug & DEB_INNERSRCH && outpos < COLS - 6) { standout(); printf("%4d",artline); un_standout(); } #endif #ifdef INNERSEARCH if (outputok) #endif putchar('\n'); restart = 0; outpos = 1000; /* signal normal \n */ } else if (*bufptr == '\t') { /* tab? */ #ifdef INNERSEARCH if (outputok) #endif putchar(*bufptr); bufptr++; outpos += 8 - outpos % 8; } else if (*bufptr == '\f') { /* form feed? */ #ifdef INNERSEARCH if (outputok) #endif fputs("^L",stdout); if (highlight != artline) linenum = 32700; /* how is that for a magic number? */ bufptr++; outpos += 2; } else { /* other control char */ #ifdef INNERSEARCH if (outputok) #endif { putchar('^'); if (highlight == artline && *UC && marking == 1) { backspace(); underchar(); putchar(*bufptr+64); backspace(); underchar(); } else putchar(*bufptr+64); } bufptr++; outpos += 2; } } /* end of column loop */ if (outpos < 1000) {/* did line overflow? */ restart = bufptr; /* restart here next time */ if (AM) { /* automatic margins on tty? */ if (!XN && *bufptr == '\n') /* need we simulate XN? */ restart = 0; /* skip the newline */ } else { /* cursor just hangs there */ #ifdef INNERSEARCH if (outputok) #endif putchar('\n'); /* so move it down ourselves */ if (*bufptr == '\n') restart = 0; /* simulate XN if need be */ } } /* handle normal end of output line formalities */ if (highlight == artline) { /* were we highlighting line? */ if (marking == STANDOUT) un_standout(); else un_underline(); highlight = -1; /* no more we are */ } artline++; /* count the line just printed */ if (artline - LINES + 1 > topline) /* did we just scroll top line off? */ topline = artline - LINES + 1; /* then recompute top line # */ } /* determine actual position in file */ if (restart) /* stranded somewhere in the buffer? */ artpos += restart - blinebeg; /* just calculate position */ else /* no, ftell will do */ artpos = ftell(artfp); /* so do ftell */ vwtary(artline,artpos); /* remember pos in file */ } /* end of line loop */ #ifdef INNERSEARCH innersearch = 0; if (hide_everything) { hide_everything = FALSE; *buf = Ctl('l'); goto fake_command; } #endif if (linenum >= 32700)/* did last line have formfeed? */ vwtary(artline-1,-vrdary(artline-1)); /* remember by negating pos in file */ special = FALSE; /* end of page, so reset page length */ firstpage = FALSE; /* and say it is not 1st time thru */ /* extra loop bombout */ if (artpos == artsize) /* did we just now reach EOF? */ return DA_NORM; /* avoid --MORE--(100%) */ /* not done with this article, so pretend we are a pager */ reask_pager: standout(); /* enter standout mode */ printf("--MORE--(%ld%%)",(long)(artpos*100/artsize)); un_standout(); /* leave standout mode */ fflush(stdout); /* reinp_pager: /* unused, commented for lint */ eat_typeahead(); #ifdef DEBUGGING if (debug & DEB_CHECKPOINTING) { printf("(%d %d %d)",checkcount,linenum,artline); fflush(stdout); } #endif if (checkcount >= docheckwhen && linenum == LINES && (artline > 40 || checkcount >= docheckwhen+10) ) { /* while he is reading a whole page */ /* in an article he is interested in */ checkcount = 0; checkpoint_rc(); /* update .newsrc */ } collect_subjects(); /* loads subject cache until */ /* input is pending */ getcmd(buf); if (errno) { if (LINES < 100 && !int_count) *buf = '\f';/* on CONT fake up refresh */ else { *buf = 'q'; /* on INTR or paper just quit */ } } putchar('\r'); /* put cursor at beginning of line */ erase_eol(); /* and erase the prompt */ fflush(stdout); fake_command: /* used by innersearch */ /* parse and process pager command */ switch (page_switch()) { case PS_ASK: /* reprompt "--MORE--..." */ goto reask_pager; case PS_RAISE: /* reparse on article level */ return DA_RAISE; case PS_TOEND: /* fast pager loop exit */ return DA_TOEND; case PS_NORM: /* display more article */ break; } } /* end of page loop */ } /* process pager commands */ int page_switch() { register char *s; switch (*buf) { case 'd': case Ctl('d'): /* half page */ special = TRUE; slines = LINES / 2 + 1; if (marking && *blinebeg != '\f') { up_line(); highlight = --artline; restart = blinebeg; artpos = alinebeg; } return PS_NORM; case '!': /* shell escape */ escapade(); return PS_ASK; #ifdef INNERSEARCH case Ctl('g'): gline = 3; compile(&gcompex,"^Subject:",TRUE,TRUE); goto caseG; case 'g': /* in-article search */ if (!finish_command(FALSE))/* get rest of command */ return PS_ASK; s = buf+1; if (isspace(*s)) s++; if ((s = compile(&gcompex,s,TRUE,TRUE)) != Nullch) { /* compile regular expression */ printf("\n%s\n",s); return PS_ASK; } putchar('\r'); /* put cursor at beginning of line */ erase_eol(); /* and erase the prompt */ /* FALL THROUGH */ caseG: case 'G': { /* ART_LINE lines_to_skip = 0; */ ART_POS start_where; if (gline < 0 || gline > LINES-2) gline = LINES-2; #ifdef DEBUGGING if (debug & DEB_INNERSRCH) printf("Start here? %d >=? %d\n",topline + gline + 1,artline); #endif if (topline+gline+1 >= artline) start_where = artpos; /* in case we had a line wrap */ else { start_where = vrdary(topline+gline+1); if (start_where < 0) start_where = -start_where; } if (start_where < htype[PAST_HEADER].ht_minpos) start_where = htype[PAST_HEADER].ht_minpos; fseek(artfp,(long)start_where,0); innersearch = 0; /* assume not found */ while (fgets(buf, sizeof buf, artfp) != Nullch) { /* lines_to_skip++; NOT USED NOW */ #ifdef DEBUGGING if (debug & DEB_INNERSRCH) printf("Test %s",buf); #endif if (execute(&gcompex,buf) != Nullch) { innersearch = ftell(artfp); break; } } if (!innersearch) { fseek(artfp,artpos,0); fputs("(Not found)",stdout); return PS_ASK; } #ifdef DEBUGGING if (debug & DEB_INNERSRCH) printf("On page? %ld <=? %ld\n",(long)innersearch,(long)artpos); #endif if (innersearch <= artpos) { /* already on page? */ if (innersearch < artpos) { artline = topline+1; while (vrdary(artline) < innersearch) artline++; } highlight = artline - 1; #ifdef DEBUGGING if (debug & DEB_INNERSRCH) printf("@ %d\n",highlight); #endif topline = highlight - gline; if (topline < -1) topline = -1; *buf = '\f'; /* fake up a refresh */ innersearch = 0; return page_switch(); } else { /* who knows how many lines it is? */ do_fseek = TRUE; hide_everything = TRUE; } return PS_NORM; } #else case 'g': case 'G': case Ctl('g'): notincl("g"); return PS_ASK; #endif case '\n': /* one line */ special = TRUE; slines = 2; return PS_NORM; #ifdef ROTATION case 'X': rotate = !rotate; /* FALL THROUGH */ #endif case 'l': case '\f': /* refresh screen */ #ifdef DEBUGGING if (debug & DEB_INNERSRCH) { printf("Topline = %d",topline); gets(buf); } #endif clear(); do_fseek = TRUE; artline = topline; if (artline < 0) artline = 0; firstpage = (topline < 0); return PS_NORM; case 'b': case Ctl('b'): { /* back up a page */ ART_LINE target; clear(); do_fseek = TRUE; /* reposition article file */ target = topline - (LINES - 2); artline = topline; do { artline--; } while (artline >= 0 && artline > target && vrdary(artline-1) >= 0); topline = artline; /* remember top line of screen */ /* (line # within article file) */ if (artline < 0) artline = 0; firstpage = (topline < 0); return PS_NORM; } case 'h': /* help */ help_page(); return PS_ASK; case '\177': case '\0': /* treat del,break as 'n' */ *buf = 'n'; /* FALL THROUGH */ case 'k': case 'K': case 'n': case 'N': case Ctl('n'): case 's': case 'S': case 'u': case 'w': case 'W': case '|': mark_as_read(art); /* mark article as read */ /* FALL THROUGH */ case '#': case '$': case '&': case '-': case '.': case '/': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '=': case '?': case 'c': case 'C': case 'f': case 'F': case 'j': case Ctl('k'): case 'm': case 'M': case 'p': case 'P': case Ctl('p'): case 'r': case 'R': case Ctl('r'): case 'v': case 'Y': #ifndef ROTATION case 'x': case 'X': #endif case Ctl('x'): case '^': #ifdef ROTATION rotate = FALSE; #endif reread = FALSE; do_hiding = TRUE; if (index("nNpP",*buf) == Nullch && index("wWsS!&|/?123456789.",*buf) != Nullch) { setdfltcmd(); standout(); /* enter standout mode */ printf(prompt,mailcall,dfltcmd); /* print prompt, whatever it is */ un_standout(); /* leave standout mode */ putchar(' '); fflush(stdout); } return PS_RAISE; /* and pretend we were at end */ #ifdef ROTATION case 'x': rotate = TRUE; /* FALL THROUGH */ #endif case 'y': case ' ': /* continue current article */ if (erase_screen) { /* -e? */ clear(); /* clear screen */ if (*blinebeg != '\f') { restart = blinebeg; artline--; /* restart this line */ artpos = alinebeg; if (marking) /* and mark repeated line */ highlight = artline; } topline = artline; /* and remember top line of screen */ /* (line # within article file) */ } else if (marking && *blinebeg != '\f') { /* are we marking repeats? */ up_line(); /* go up one line */ highlight = --artline;/* and get ready to highlight */ restart = blinebeg; /* the old line */ artpos = alinebeg; } return PS_NORM; case 'q': /* quit this article? */ do_hiding = TRUE; return PS_TOEND; default: fputs(hforhelp,stdout); return PS_ASK; } } #ifdef INNERSEARCH bool innermore() { if (artpos < innersearch) { /* not even on page yet? */ #ifdef DEBUGGING if (debug & DEB_INNERSRCH) printf("Not on page %ld < %ld\n",(long)artpos,(long)innersearch); #endif return TRUE; } if (artpos == innersearch) { /* just got onto page? */ isrchline = artline; /* remember first line after */ highlight = artline - 1; #ifdef DEBUGGING if (debug & DEB_INNERSRCH) printf("There it is %ld = %ld, %d @ %d\n",(long)artpos,(long)innersearch,hide_everything,highlight); #endif if (hide_everything) { /* forced refresh? */ topline = highlight - gline; if (topline < -1) topline = -1; return FALSE; /* let refresh do it all */ } } #ifdef DEBUGGING if (debug & DEB_INNERSRCH) printf("Not far enough? %d <? %d + %d\n",artline,isrchline,gline); #endif if (artline < isrchline + gline) { return TRUE; } return FALSE; } #endif !STUFFY!FUNK! echo Extracting common.h cat >common.h <<'!STUFFY!FUNK!' /* $Header: common.h,v 4.1 84/09/24 11:44:27 lwall Exp $ * * $Log: common.h,v $ * Revision 4.1 84/09/24 11:44:27 lwall * Real baseline. * * Revision 4.0.1.6 84/09/22 16:51:29 lwall * 2.10.2 inews moved. * * Revision 4.0.1.5 84/09/13 12:11:19 lwall * UNLINK for Eunice. * * Revision 4.0.1.4 84/09/12 17:47:14 lwall * Moved some includes here. * * Revision 4.0.1.3 84/09/10 15:09:09 lwall * Delinted. * * Revision 4.0.1.2 84/09/05 13:48:13 lwall * More LOCKART stuff. * * Revision 4.0.1.1 84/09/04 15:10:52 lwall * LINKART option for poor Eunice sites. * * Revision 4.0 84/09/04 09:50:08 lwall * Baseline for netwide release * */ #include "config.h" /* generated by installation script */ #ifdef WHOAMI # include <whoami.h> #endif #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <ctype.h> #ifndef isalnum # define isalnum(c) (isalpha(c) || isdigit(c)) #endif #include <errno.h> #include <signal.h> #include <sys/ioctl.h> #ifdef TERMIO # include <termio.h> #else # include <sgtty.h> #endif #ifdef GETPWENT # include <pwd.h> #endif #define BITSPERBYTE 8 #define TCSIZE 256 /* capacity for termcap strings */ #define LBUFLEN 512 /* line buffer length */ /* (don't worry, .newsrc lines can exceed this) */ #define CBUFLEN 256 /* command buffer length */ #ifdef pdp11 # define MAXFILENAME 128 #else # define MAXFILENAME 512 #endif #define LONGKEY 15 /* longest keyword: currently "posting-version" */ #define FINISHCMD 0177 /* some handy defs */ #define bool char #define TRUE (1) #define FALSE (0) #define Null(t) ((t)0) #define Nullch Null(char *) #define Nullfp Null(FILE *) #define Ctl(ch) (ch & 037) #define strNE(s1,s2) (strcmp(s1,s2)) #define strEQ(s1,s2) (!strcmp(s1,s2)) #define strnNE(s1,s2,l) (strncmp(s1,s2,l)) #define strnEQ(s1,s2,l) (!strncmp(s1,s2,l)) /* Things we can figure out ourselves */ #ifdef SIGTSTP # define BERKELEY /* include job control signals? */ #endif #ifdef SIGPROF # define BSD42 /* do we have Berkeley 4.2? */ #endif #ifdef FIONREAD # define PENDING #else # ifdef O_NDELAY # define PENDING # endif #endif #ifdef EUNICE # define LINKART /* add 1 level of possible indirection */ # define UNLINK(victim) while (!unlink(victim)) #else # define UNLINK(victim) unlink(victim) #endif /* Valid substitutions for strings marked with % comment are: * %a Current article number * %A Full name of current article (%P/%c/%a) * (if LINKART defined, is the name of the real article) * %b Destination of a save command, a mailbox or command * %B The byte offset to the beginning of the article for saves * with or without the header * %c Current newsgroup, directory form * %C Current newsgroup, dot form * %d %P/%c * %D Old Distribution: line * %f Old From: line or Reply-To: line * %F Newsgroups to followup to from Newsgroups: and Followup-To: * %h Name of header file to pass to mail or news poster * %H Host name (yours) * %i Old Message-I.D.: line, with <> * %l News administrator login name * %L Login name (yours) * %M Number of articles markd with M * %n Newsgroups from source article * %N Full name (yours) * %o Organization (yours) * %O Original working directory (where you ran rn from) * %p Your private news directory (-d switch) * %P Public news spool directory (SPOOLDIR) * %r Last reference (parent article id) * %R New references list * %s Subject, with all Re's and (nf)'s stripped off * %S Subject, with one Re stripped off * %t New To: line derived from From: and Reply-To (Internet always) * %T New To: line (Internet only if INTERNET is defined) * %u Number of unread articles * %U Number of unread articles disregarding current article * %x News library directory, usually /usr/lib/news * %X Rn library directory, usually %x/rn * %~ Home directory * %. Directory containing . files * %$ current process number * %{name} Environment variable "name". %{name-default} form allowed. * %[name] Header line beginning with "Name: ", without "Name: " * %(test_text=pattern?if_text:else_text) * Substitute if_text if test_text matches pattern, otherwise * substitute else_text. Use != for negated match. * % substitutions are done on test_text, if_text, and else_text. * (Note: %() only works if CONDSUB defined.) * %digit Substitute the text matched by the nth bracket in the last * pattern that had brackets. %0 matches the last bracket * matched, in case you had alternatives. * * Put ^ in the middle to capitalize the first letter: %^C = Net.jokes * Put ` in the middle to capitalize last component: %`c = net/Jokes * * ~ interpretation in filename expansion happens after % expansion, so * you could put ~%{NEWSLOGNAME-news} and it will expand correctly. */ /* *** System Dependent Stuff *** */ /* NOTE: many of these are defined in the config.h file */ /* name of organization */ #ifndef ORGNAME # define ORGNAME "ACME Widget Company, Widget Falls, Southern North Dakota" #endif #ifndef MBOXCHAR # define MBOXCHAR 'F' /* how to recognize a mailbox by 1st char */ #endif #ifndef ROOTID # define ROOTID 0 /* uid of superuser */ #endif #ifdef NORMSIG # define sigset signal # define sigignore(sig) signal(sig,SIG_IGN) #endif #ifndef LOGDIRFIELD # define LOGDIRFIELD 6 /* Which field (origin 1) is the */ /* login directory in /etc/passwd? */ /* (If it is not kept in passwd, */ /* but getpwnam() returns it, */ /* define the symbol GETPWENT) */ #endif #ifndef GCOSFIELD # define GCOSFIELD 5 #endif #ifndef NEGCHAR # define NEGCHAR '!' #endif /* Space conservation section */ /* To save D space, cut down size of MAXRCLINE, NGMAX, VARYSIZE. */ #define MAXRCLINE 500 /* number of lines allowed in .newsrc */ /* several parallel arrays affected. */ /* (You can have more lines in the active file, */ /* just not in the .newsrc) */ #define HASHSIZ 547 /* should be prime, and at least MAXRCLINE + 10% */ #define NGMAX 100 /* number of newsgroups allowed on command line */ /* undefine ONLY symbol to disable "only" feature */ #define VARYSIZE 256 /* this makes a block 1024 bytes long in DECville */ /* (used by virtual array routines) */ /* Undefine any of the following features to save both I and D space */ /* In general, earlier ones are easier to get along without */ /* Pdp11's without split I and D may have to undefine them all */ #define DEBUGGING /* include debugging code */ #define SPEEDOVERMEM /* use more memory to run faster */ #define WORDERASE /* enable ^W to erase a word */ #define MAILCALL /* check periodically for mail */ #define NOFIREWORKS /* keep whole screen from flashing on certain */ /* terminals such as older Televideos */ #define VERIFY /* echo the command they just typed */ #define HASHNG /* hash newsgroup lines for fast lookup-- */ /* linear search used if not defined */ #define CONDSUB /* allow %(cond?text:text) */ #define ULSMARTS /* catch _^H in text and do underlining */ #define BAUDMOD /* allow baudrate modifier on switches */ #define GETLOGIN /* use getlogin() routine as backup to environment */ /* variables USER or LOGNAME */ #define ORGFILE /* if organization begins with /, look up in file */ #define TILDENAME /* allow ~logname expansion */ #define SETENV /* allow command line environment variable setting */ #define GETWD /* use our getwd() instead of piped in pwd */ #define SETUIDGID /* substitute eaccess() for access() so that rn */ /* can run setuid or setgid */ /* if not setuid or setgid, you don't need it */ #define MAKEDIR /* use our makedir() instead of shell script */ #define MEMHELP /* keep help messages in memory */ #define VERBOSE /* compile in more informative messages */ #define TERSE /* compile in shorter messages */ /* (Note: both VERBOSE and TERSE can be defined; -t * sets terse mode. One or the other MUST be defined. */ #ifndef pdp11 # define CACHESUBJ /* cache subject lines in memory */ /* without this ^N still works but runs really slow */ /* but you save lots and lots of D space */ # define CACHEFIRST /* keep absolute first article numbers in memory */ /* cost: about 2k */ #endif #define ROTATION /* enable x, X and ^X commands to work */ #define DELBOGUS /* ask if bogus newsgroups should be deleted */ #define RELOCATE /* allow newsgroup rearranging */ #define ESCSUBS /* escape substitutions in multi-character commands */ #define DELAYMARK /* allow articles to be temporarily marked as read */ /* until exit from current newsgroup or Y command */ #define MCHASE /* unmark xrefed articles on m or M */ #define MUNGHEADER /* allow alternate header formatting via */ /* environment variable ALTHEADER (not impl) */ #define ASYNC_PARSE /* allow parsing headers asyncronously to reading */ /* used by MCHASE and MUNGHEADER */ #define FINDNEWNG /* check for new newsgroups on startup */ #define FASTNEW /* do optimizations on FINDNEWNG for faster startup */ /* (this optimization can make occasional mistakes */ /* if a group is removed and another group of the */ /* same length is added, and if no softpointers are */ /* affected by said change.) */ #define INNERSEARCH /* search command 'g' with article */ #define CATCHUP /* catchup command at newsgroup level */ #define NGSEARCH /* newsgroup pattern matching */ #define ONLY /* newsgroup restrictions by pattern */ #define KILLFILES /* automatic article killer files */ #define ARTSEARCH /* pattern searches among articles */ /* /, ?, ^N, ^P, k, K */ /* some dependencies among options */ #ifndef ARTSEARCH # undef KILLFILES # undef INNERSEARCH # undef CACHESUBJ #endif #ifndef DELAYMARK # ifndef MCHASE # ifndef MUNGHEADER # undef ASYNC_PARSE # endif # endif #endif #ifndef SETUIDGID # define eaccess access #endif #ifdef ONLY /* idiot lint doesn't grok #if */ # define NGSORONLY #else # ifdef NGSEARCH # define NGSORONLY # endif #endif #ifdef VERBOSE # ifdef TERSE # define IF(c) if (c) # define ELSE else # else !TERSE # define IF(c) # define ELSE # endif #else !VERBOSE # ifndef TERSE # define TERSE # endif # define IF(c) "IF" outside of VERBOSE??? # define ELSE "ELSE" outside of VERBOSE??? #endif #ifndef DEBUGGING # define NDEBUG #endif #include <assert.h> #ifdef SPEEDOVERMEM # define OFFSET(x) (x) #else # define OFFSET(x) ((x)-absfirst) #endif /* If you're strapped for space use the help messages in shell scripts */ /* if {NG,ART,PAGER,SUBS}HELP is undefined, help messages are in memory */ #ifdef MEMHELP /* undef MEMHELP above to get them all as sh scripts */ # undef NGHELP # undef ARTHELP # undef PAGERHELP # undef SUBSHELP #else # ifndef NGHELP /* % and ~ */ # define NGHELP "%X/ng.help" # endif # ifndef ARTHELP /* % and ~ */ # define ARTHELP "%X/art.help" # endif # ifndef PAGERHELP /* % and ~ */ # define PAGERHELP "%X/pager.help" # endif # ifndef SUBSHELP /* % and ~ */ # define SUBSHELP "%X/subs.help" # endif #endif /* Additional ideas: * Make the do_newsgroup() routine a separate process. * Keep .newsrc on disk instead of in memory. * Overlays, if you have them. * Get a bigger machine. */ /* End of Space Conservation Section */ /* More System Dependencies */ /* news library */ #ifndef LIB /* ~ and %l only ("~%l" is permissable) */ # define LIB "/usr/lib/news" #endif /* path to private executables */ #ifndef RNLIB /* ~, %x and %l only */ # define RNLIB "%x/rn" #endif /* where to find news files */ #ifndef SPOOL /* % and ~ */ # define SPOOL "/usr/spool/news" #endif /* file containing list of active newsgroups and max article numbers */ #ifndef ACTIVE /* % and ~ */ # define ACTIVE "%x/active" #endif /* command to setup a new .newsrc */ #ifndef NEWSETUP /* % and ~ */ # define NEWSETUP "newsetup" #endif /* command to display a list of un-subscribed-to newsgroups */ #ifndef NEWSGROUPS /* % and ~ */ # define NEWSGROUPS "newsgroups" #endif /* preferred shell for use in doshell routine */ /* ksh or sh would be okay here */ #ifndef PREFSHELL # define PREFSHELL "/bin/csh" #endif /* path to fastest starting shell */ #ifndef SH # define SH "/bin/sh" #endif /* path to default editor */ #ifndef DEFEDITOR # define DEFEDITOR "/usr/ucb/vi" #endif /* location of full name */ #ifndef FULLNAMEFILE # ifndef PASSNAMES # define FULLNAMEFILE "%./fullname" # endif #endif /* virtual array file name template */ #ifndef VARYNAME /* % and ~ */ # define VARYNAME "/tmp/rnvary.%$" #endif /* file to pass header to followup article poster */ #ifndef HEADNAME /* % and ~ */ # define HEADNAME "~/.rnhead" /* or alternately #define HEADNAME "/tmp/rnhead.%$" */ #endif #ifndef MAKEDIR /* shell script to make n-deep subdirectories */ # ifndef DIRMAKER /* % and ~ */ # define DIRMAKER "%X/makedir" # endif #endif /* location of newsrc file */ #ifndef RCNAME /* % and ~ */ # define RCNAME "%./.newsrc" #endif /* temporary newsrc file in case we crash while writing out */ #ifndef RCTNAME /* % and ~ */ # define RCTNAME "%./#.newsrc" #endif /* newsrc file at the beginning of this session */ #ifndef RCBNAME /* % and ~ */ # define RCBNAME "%./.oldnewsrc" #endif /* if existent, contains process number of current or crashed rn */ #ifndef LOCKNAME /* % and ~ */ # define LOCKNAME "%./.rnlock" #endif /* information from last invocation of rn */ #ifndef LASTNAME /* % and ~ */ # define LASTNAME "%./.rnlast" #endif /* file with soft pointers into the active file */ #ifndef SOFTNAME /* % and ~ */ # define SOFTNAME "%./.rnsoft" #endif /* list of article numbers to mark as unread later (see M and Y cmmands) */ #ifndef RNDELNAME /* % and ~ */ # define RNDELNAME "%./.rndelay" #endif /* a motd-like file for rn */ #ifndef NEWSNEWSNAME /* % and ~ */ # define NEWSNEWSNAME "%X/newsnews" #endif /* command to send a reply */ #ifndef MAILPOSTER /* % and ~ */ # define MAILPOSTER "Rnmail -h %h" #endif #ifndef MAILHEADER /* % */ # ifdef CONDSUB # define MAILHEADER "To: %T\nSubject: Re: %S\nNewsgroups: %n\nIn-Reply-To: %i\n%(%[references]!=^$?References\\: %[references]\n)Organization: %o\nCc: \nBcc: \n\n" # else # define MAILHEADER "To: %T\nSubject: Re: %S\nNewsgroups: %n\nIn-Reply-To: %i\nReferences: %[references]\nCc: \nBcc: \n\n" # endif #endif #ifndef YOUSAID /* % */ # define YOUSAID "In article %i you write:" #endif /* command to submit a followup article */ #ifndef NEWSPOSTER /* % and ~ */ # define NEWSPOSTER "Pnews -h %h" #endif #ifndef NEWSHEADER /* % */ # define NEWSHEADER "Newsgroups: %F\nSubject: Re: %S\nSummary: \nExpires: \nReferences: %R\nSender: \nReply-To: %L@%H.UUCP (%N)\nFollowup-To: \nDistribution: %D\nOrganization: %o\nKeywords: \n\n" #endif #ifndef ATTRIBUTION /* % */ # define ATTRIBUTION "In article %i %f writes:" #endif #ifndef PIPESAVER /* % */ # ifdef CONDSUB # define PIPESAVER "%(%B=^0$?<%A:tail +%Bc %A |) %b" # else # define PIPESAVER "tail +%Bc %A | %b" # endif #endif #ifndef NORMSAVER /* % and ~ */ # define NORMSAVER "%X/norm.saver %A %P %c %a %B %C \"%b\"" #endif #ifndef MBOXSAVER /* % and ~ */ # ifdef CONDSUB # define MBOXSAVER "%X/mbox.saver %A %P %c %a %B %C \"%b\" \"From: %T %(%[posted]!=^$?%[posted]:%(%[date]=^\\(\\w*\\), \\(\\w*\\)-\\(\\w*\\)-\\(\\w*\\) \\([^ ]*\\)?%1 %3 %(%2=..?%2: %2) %5 19%4))\"" /* header munging with a vengeance */ # else # define MBOXSAVER "%X/mbox.saver %A %P %c %a %B %C \"%b\" \"From: %T %[posted]\"" # endif #endif #ifdef MKDIRS # ifndef SAVEDIR /* % and ~ */ # define SAVEDIR "%p/%c" # endif # ifndef SAVENAME /* % */ # define SAVENAME "%a" # endif #else # ifndef SAVEDIR /* % and ~ */ # define SAVEDIR "%p" # endif # ifndef SAVENAME /* % */ # define SAVENAME "%^C" # endif #endif #ifndef KILLGLOBAL /* % and ~ */ # define KILLGLOBAL "%p/KILL" #endif #ifndef KILLLOCAL /* % and ~ */ # define KILLLOCAL "%p/%c/KILL" #endif /* how to cancel an article */ #ifndef CANCEL # ifdef MININACT /* 2.10.2 ? */ # define CANCEL "%x/inews -h < %h" # else # define CANCEL "inews -h < %h" # endif #endif /* how to cancel an article, continued */ #ifndef CANCELHEADER # define CANCELHEADER "Newsgroups: %n\nSubject: cmsg cancel %i\nReferences: %R\nReply-To: %L@%H.UUCP (%N)\nDistribution: %D\nOrganization: %o\n\n%i cancelled from rn.\n" #endif /* where to find the mail file */ #ifndef MAILFILE # define MAILFILE "/usr/spool/mail/%L" #endif /* some important types */ typedef int NG_NUM; /* newsgroup number */ typedef long ART_NUM; /* article number */ #ifdef pdp11 typedef short ART_UNREAD; /* ordinarily this should be long */ /* like ART_NUM, but assuming that */ /* we stay less than 32767 articles */ /* behind saves a lot of space. */ /* NOTE: do not make unsigned. */ #else typedef long ART_UNREAD; #endif typedef long ART_POS; /* char position in article file */ typedef int ART_LINE; /* line position in article file */ typedef short ACT_POS; /* char position in active file */ typedef unsigned int MEM_SIZE; /* for passing to malloc */ /* *** end of the machine dependent stuff *** */ /* GLOBAL THINGS */ /* file statistics area */ EXT struct stat filestat; /* various things of type char */ char *index(); char *rindex(); char *getenv(); char *strcat(); char *strcpy(); char *sprintf(); EXT char buf[LBUFLEN+1]; /* general purpose line buffer */ EXT char cmd_buf[CBUFLEN]; /* buffer for formatting system commands */ EXT char *indstr INIT(">"); /* indent for old article embedded in followup */ EXT char *cwd INIT(Nullch); /* current working directory */ EXT char *dfltcmd INIT(Nullch); /* 1st char is default command */ /* switches */ #ifdef DEBUGGING EXT int debug INIT(0); /* -D */ # define DEB_INNERSRCH 32 # define DEB_FILEXP 64 # define DEB_HASH 128 # define DEB_XREF_MARKER 256 # define DEB_CTLAREA_BITMAP 512 # define DEB_SOFT_POINTERS 1024 # define DEB_NEWSRC_LINE 2048 # define DEB_SEARCH_AHEAD 4096 # define DEB_CHECKPOINTING 8192 # define DEB_FEED_XREF 16384 #endif #ifdef ARTSEARCH EXT int scanon INIT(0); /* -S */ #endif EXT bool mbox_always INIT(FALSE); /* -M */ EXT bool norm_always INIT(FALSE); /* -N */ EXT bool checkflag INIT(FALSE); /* -c */ EXT bool suppress_cn INIT(FALSE); /* -s */ EXT int countdown INIT(5); /* how many lines to list before invoking -s */ EXT bool muck_up_clear INIT(FALSE); /* -loco */ EXT bool erase_screen INIT(FALSE); /* -e */ EXT bool findlast INIT(FALSE); /* -r */ EXT bool typeahead INIT(FALSE); /* -T */ #ifdef VERBOSE # ifdef TERSE EXT bool verbose INIT(TRUE); /* +t */ # endif #endif #ifdef VERIFY EXT bool verify INIT(FALSE); /* -v */ #endif #define NOMARKING 0 #define STANDOUT 1 #define UNDERLINE 2 EXT int marking INIT(NOMARKING); /* -m */ EXT ART_LINE initlines INIT(0); /* -i */ /* miscellania */ EXT bool in_ng INIT(FALSE); /* current state of rn */ EXT FILE *tmpfp INIT(Nullfp); /* scratch fp used for .rnlock, .rnlast, etc. */ EXT NG_NUM nextrcline INIT(0); /* 1st unused slot in rcline array */ /* startup to avoid checking twice in a row */ extern errno; /* Factored strings */ EXT char nullstr[] INIT(""); EXT char sh[] INIT(SH); EXT char defeditor[] INIT(DEFEDITOR); EXT char hforhelp[] INIT("Type h for help.\n"); EXT char badcr[] INIT("\nUnnecessary CR ignored.\n"); EXT char readerr[] INIT("rn read error"); EXT char unsubto[] INIT("\n\nUnsubscribed to newsgroup %s\n"); #ifdef VERBOSE EXT char nocd[] INIT("Can't chdir to directory %s\n"); #else EXT char nocd[] INIT("Can't find %s\n"); #endif !STUFFY!FUNK! echo Extracting rcstuff.c cat >rcstuff.c <<'!STUFFY!FUNK!' /* $Header: rcstuff.c,v 4.1 84/09/24 12:05:08 lwall Exp $ * * $Log: rcstuff.c,v $ * Revision 4.1 84/09/24 12:05:08 lwall * Real baseline. * * Revision 4.0.1.7 84/09/22 17:01:33 lwall * Suppressed soft pointer message on -c. * * Revision 4.0.1.6 84/09/18 16:39:18 lwall * Instructed relocate_newsgroup() about ngmax[]. * * Revision 4.0.1.5 84/09/13 12:05:28 lwall * UNLINK for Eunice. * * Revision 4.0.1.4 84/09/10 15:24:22 lwall * Delinted. * * Revision 4.0.1.3 84/09/10 08:30:24 lwall * Newsgroup relocation now disables starthere optimization. * * Revision 4.0.1.2 84/09/06 13:13:51 lwall * Turned = into L. * * Revision 4.0.1.1 84/09/05 09:31:26 lwall * Made 'm' command force soft pointer writing. * * Revision 4.0 84/09/04 09:52:07 lwall * Baseline for netwide release * */ #include "EXTERN.h" #include "common.h" #include "util.h" #include "ngdata.h" #include "term.h" #include "final.h" #include "rn.h" #include "intrp.h" #include "only.h" #include "rcln.h" #include "INTERN.h" #include "rcstuff.h" char *rcname INIT(Nullch); /* path name of .newsrc file */ char *rctname INIT(Nullch); /* path name of temp .newsrc file */ char *rcbname INIT(Nullch); /* path name of backup .newsrc file */ char *softname INIT(Nullch); /* path name of .rnsoft file */ FILE *rcfp INIT(Nullfp); /* .newsrc file pointer */ #ifdef HASHNG short hashtbl[HASHSIZ]; #endif bool rcstuff_init() { register NG_NUM newng; register char *s; register int i; register bool foundany = FALSE; char *some_buf; long length; #ifdef HASHNG for (i=0; i<HASHSIZ; i++) hashtbl[i] = -1; #endif /* make filenames */ rcname = savestr(filexp(RCNAME)); rctname = savestr(filexp(RCTNAME)); rcbname = savestr(filexp(RCBNAME)); softname = savestr(filexp(SOFTNAME)); /* make sure the .newsrc file exists */ newsrc_check(); /* open .rnsoft file containing soft ptrs to active file */ tmpfp = fopen(softname,"r"); if (tmpfp == Nullfp) writesoft = TRUE; /* read in the .newsrc file */ for (nextrcline = 0; (some_buf = get_a_line(buf,LBUFLEN,rcfp)) != Nullch; nextrcline++) { /* for each line in .newsrc */ char tmpbuf[10]; newng = nextrcline; /* get it into a register */ length = len_last_line_got; /* side effect of get_a_line */ if (length <= 1) { /* only a newline??? */ nextrcline--; /* compensate for loop increment */ continue; } if (newng >= MAXRCLINE) { /* check for overflow */ fputs("Too many lines in .newsrc\n",stdout); finalize(1); } if (tmpfp != Nullfp && fgets(tmpbuf,10,tmpfp) != Nullch) softptr[newng] = atoi(tmpbuf); else softptr[newng] = 0; some_buf[--length] = '\0'; /* wipe out newline */ if (some_buf == buf) { rcline[newng] = savestr(some_buf); /* make a semipermanent copy */ } else { /*NOSTRICT*/ some_buf = saferealloc(some_buf,(MEM_SIZE)(length+1)); rcline[newng] = some_buf; } #ifdef NOTDEF if (strnEQ(some_buf,"to.",3)) { /* is this a non-newsgroup? */ nextrcline--; /* destroy this line */ continue; } #endif if (*some_buf == ' ' || *some_buf == '\t' || strnEQ(some_buf,"options",7)) { /* non-useful line? */ toread[newng] = TR_JUNK; rcchar[newng] = ' '; rcnums[newng] = 0; continue; } for (s = rcline[newng]; *s && *s != ':' && *s != NEGCHAR; s++) ; if (!*s) { rcline[newng] = saferealloc(rcline[newng],(MEM_SIZE)length+2); s = rcline[newng] + length; *s = ':'; *(s+1) = '\0'; } rcchar[newng] = *s; /* salt away the : or ! */ rcnums[newng] = (char)(s - rcline[newng]); rcnums[newng]++; /* remember where it was */ *s = '\0'; /* null terminate newsgroup name */ #ifdef HASHNG if (!checkflag) sethash(newng); #endif if (rcchar[newng] == NEGCHAR) { toread[newng] = TR_UNSUB; continue; } /* now find out how much there is to read */ if (!inlist(buf) || (suppress_cn && foundany && !paranoid)) toread[newng] = TR_NONE; /* no need to calculate now */ else set_toread(newng); #ifdef VERBOSE if (!checkflag && softmisses == 1) { softmisses++; /* lie a little */ fputs("(Revising soft pointers--be patient.)\n",stdout); } #endif if (toread[newng] > TR_NONE) { /* anything unread? */ if (!foundany) { starthere = newng; foundany = TRUE; /* remember that fact*/ } if (suppress_cn) { /* if no listing desired */ if (checkflag) { /* if that is all they wanted */ finalize(1); /* then bomb out */ } } else { #ifdef VERBOSE IF(verbose) printf("Unread news in %-20s %5ld article%s\n", rcline[newng],(long)toread[newng], toread[newng]==TR_ONE ? nullstr : "s"); ELSE #endif #ifdef TERSE printf("%s: %ld article%s\n", rcline[newng],(long)toread[newng], toread[newng]==TR_ONE ? nullstr : "s"); #endif if (int_count) { countdown = 1; int_count = 0; } if (countdown) { if (! --countdown) { fputs("etc.\n",stdout); if (checkflag) finalize(1); suppress_cn = TRUE; } } } } } fclose(rcfp); /* close .newsrc */ if (tmpfp != Nullfp) fclose(tmpfp); /* close .rnsoft */ if (paranoid) cleanup_rc(); if (checkflag) { /* were we just checking? */ finalize(foundany); /* tell them what we found */ } #ifdef DEBUGGING if (debug & DEB_HASH) { page_line = 1; for (i=0; i<HASHSIZ; i++) { sprintf(buf,"%d %d",i,hashtbl[i]); print_lines(buf,NOMARKING); } } #endif return foundany; } /* try to find or add an explicitly specified newsgroup */ /* returns TRUE if found or added, FALSE if not. */ /* assumes that we are chdir'ed to SPOOL */ bool get_ng(what,do_reloc) char *what; bool do_reloc; { char *ntoforget; char promptbuf[128]; #ifdef VERBOSE IF(verbose) ntoforget = "Type n to forget about this newsgroup.\n"; ELSE #endif #ifdef TERSE ntoforget = "n to forget it.\n"; #endif set_ngname(what); ng = find_ng(ngname); if (ng == nextrcline) { /* not in .newsrc? */ if (eaccess(ngdir,0)) { #ifdef VERBOSE IF(verbose) printf("\n\007Newsgroup %s does not exist!\n",ngname); ELSE #endif #ifdef TERSE printf("\n\007No %s!\n",ngname); #endif sleep(2); return FALSE; } #ifdef VERBOSE IF(verbose) sprintf(promptbuf,"\nNewsgroup %s not in .newsrc--add? [yn] ",ngname); ELSE #endif #ifdef TERSE sprintf(promptbuf,"\nAdd %s? [yn] ",ngname); #endif reask_add: in_char(promptbuf); putchar('\n'); setdef(buf,"y"); #ifdef VERIFY printcmd(); #endif if (*buf == 'h') { #ifdef VERBOSE IF(verbose) printf("Type y or SP to add %s to your .newsrc.\n", ngname); ELSE #endif #ifdef TERSE fputs("y or SP to add\n",stdout); #endif fputs(ntoforget,stdout); goto reask_add; } else if (*buf == 'n' || *buf == 'q') { return FALSE; } else if (*buf == 'y') { ng = add_newsgroup(ngname); do_reloc = FALSE; } else { fputs(hforhelp,stdout); goto reask_add; } } else if (rcchar[ng] == NEGCHAR) { /* unsubscribed? */ #ifdef VERBOSE IF(verbose) sprintf(promptbuf, "\nNewsgroup %s is currently unsubscribed to--resubscribe? [yn] ",ngname); ELSE #endif #ifdef TERSE sprintf(promptbuf,"\n%s unsubscribed--resubscribe? [yn] ",ngname); #endif reask_unsub: in_char(promptbuf); putchar('\n'); setdef(buf,"y"); #ifdef VERIFY printcmd(); #endif if (*buf == 'h') { #ifdef VERBOSE IF(verbose) printf("Type y or SP to resubscribe to %s.\n", ngname); ELSE #endif #ifdef TERSE fputs("y or SP to resubscribe.\n",stdout); #endif fputs(ntoforget,stdout); goto reask_unsub; } else if (*buf == 'n' || *buf == 'q') { return FALSE; } else if (*buf == 'y') { rcchar[ng] = ':'; } else { fputs(hforhelp,stdout); goto reask_unsub; } } /* now calculate how many unread articles in newsgroup */ set_toread(ng); #ifdef RELOCATE if (do_reloc) ng = relocate_newsgroup(ng,-1); #endif return toread[ng] >= TR_NONE; } /* add a newsgroup to the .newsrc file (eventually) */ NG_NUM add_newsgroup(ngn) char *ngn; { register NG_NUM newng = nextrcline++; /* increment max rcline index */ rcnums[newng] = strlen(ngn) + 1; rcline[newng] = safemalloc((MEM_SIZE)(rcnums[newng] + 1)); strcpy(rcline[newng],ngn); /* and copy over the name */ *(rcline[newng] + rcnums[newng]) = '\0'; rcchar[newng] = ':'; /* call it subscribed */ toread[newng] = TR_NONE; /* just for prettiness */ #ifdef HASHNG sethash(newng); /* so we can find it again */ #endif #ifdef RELOCATE return relocate_newsgroup(newng,-1); #else return newng; #endif } #ifdef RELOCATE NG_NUM relocate_newsgroup(ngx,newng) NG_NUM ngx; NG_NUM newng; { char *dflt = (ngx!=current_ng ? "$^.L" : "$^L"); char *tmprcline; ART_UNREAD tmptoread; char tmprcchar; char tmprcnums; ACT_POS tmpsoftptr; register NG_NUM i; #ifdef DEBUGGING ART_NUM tmpngmax; #endif starthere = 0; /* Disable this optimization */ writesoft = TRUE; /* Update soft pointer file */ if (ngx < nextrcline-1) { #ifdef HASHNG for (i=0; i<HASHSIZ; i++) { if (hashtbl[i] > ngx) --hashtbl[i]; else if (hashtbl[i] == ngx) hashtbl[i] = nextrcline-1; } #endif tmprcline = rcline[ngx]; tmptoread = toread[ngx]; tmprcchar = rcchar[ngx]; tmprcnums = rcnums[ngx]; tmpsoftptr = softptr[ngx]; #ifdef DEBUGGING tmpngmax = ngmax[ngx]; #endif for (i=ngx+1; i<nextrcline; i++) { rcline[i-1] = rcline[i]; toread[i-1] = toread[i]; rcchar[i-1] = rcchar[i]; rcnums[i-1] = rcnums[i]; softptr[i-1] = softptr[i]; #ifdef DEBUGGING ngmax[i-1] = ngmax[i]; #endif } rcline[nextrcline-1] = tmprcline; toread[nextrcline-1] = tmptoread; rcchar[nextrcline-1] = tmprcchar; rcnums[nextrcline-1] = tmprcnums; softptr[nextrcline-1] = tmpsoftptr; #ifdef DEBUGGING ngmax[nextrcline-1] = tmpngmax; #endif } if (current_ng > ngx) current_ng--; if (newng < 0) { reask_reloc: #ifdef VERBOSE IF(verbose) printf("\nPut newsgroup where? [%s] ", dflt); ELSE #endif #ifdef TERSE printf("\nPut where? [%s] ", dflt); #endif fflush(stdout); reinp_reloc: eat_typeahead(); getcmd(buf); if (errno || *buf == '\f') { /* if return from stop signal */ goto reask_reloc; /* give them a prompt again */ } setdef(buf,dflt); #ifdef VERIFY printcmd(); #endif if (*buf == 'h') { #ifdef VERBOSE IF(verbose) { printf("\n\n\ Type ^ to put the newsgroup first (position 0).\n\ Type $ to put the newsgroup last (position %d).\n", nextrcline-1); printf("\ Type . to put it before the current newsgroup (position %d).\n", current_ng); printf("\ Type -newsgroup name to put it before that newsgroup.\n\ Type +newsgroup name to put it after that newsgroup.\n\ Type a number between 0 and %d to put it at that position.\n", nextrcline-1); printf("\ Type L for a listing of newsgroups and their positions.\n"); } ELSE #endif #ifdef TERSE { printf("\n\n\ ^ to put newsgroup first (pos 0).\n\ $ to put last (pos %d).\n", nextrcline-1); printf("\ . to put before current newsgroup (pos %d).\n", current_ng); printf("\ -newsgroup to put before newsgroup.\n\ +newsgroup to put after.\n\ number in 0-%d to put at that pos.\n", nextrcline-1); printf("\ L for list of .newsrc.\n"); } #endif goto reask_reloc; } else if (*buf == 'L') { putchar('\n'); list_newsgroups(); goto reask_reloc; } else if (isdigit(*buf)) { if (!finish_command(TRUE)) /* get rest of command */ goto reinp_reloc; newng = atoi(buf); if (newng < 0) newng = 0; if (newng >= nextrcline) return nextrcline-1; } else if (*buf == '^') { putchar('\n'); newng = 0; } else if (*buf == '$') { putchar('\n'); return nextrcline-1; } else if (*buf == '.') { putchar('\n'); newng = current_ng; } else if (*buf == '-' || *buf == '+') { if (!finish_command(TRUE)) /* get rest of command */ goto reinp_reloc; newng = find_ng(buf+1); if (newng == nextrcline) { fputs("Not found.",stdout); goto reask_reloc; } if (*buf == '+') newng++; } else { printf("\n%s",hforhelp); goto reask_reloc; } } if (newng < nextrcline-1) { #ifdef HASHNG for (i=0; i<HASHSIZ; i++) { if (hashtbl[i] == nextrcline-1) hashtbl[i] = newng; else if (hashtbl[i] >= newng) ++hashtbl[i]; } #endif tmprcline = rcline[nextrcline-1]; tmptoread = toread[nextrcline-1]; tmprcchar = rcchar[nextrcline-1]; tmprcnums = rcnums[nextrcline-1]; tmpsoftptr = softptr[nextrcline-1]; #ifdef DEBUGGING tmpngmax = ngmax[nextrcline-1]; #endif for (i=nextrcline-2; i>=newng; i--) { rcline[i+1] = rcline[i]; toread[i+1] = toread[i]; rcchar[i+1] = rcchar[i]; rcnums[i+1] = rcnums[i]; softptr[i+1] = softptr[i]; #ifdef DEBUGGING ngmax[i+1] = ngmax[i]; #endif } rcline[newng] = tmprcline; toread[newng] = tmptoread; rcchar[newng] = tmprcchar; rcnums[newng] = tmprcnums; softptr[newng] = tmpsoftptr; #ifdef DEBUGGING ngmax[newng] = tmpngmax; #endif } if (current_ng >= newng) current_ng++; return newng; } #endif /* List out the newsrc with annotations */ void list_newsgroups() { register NG_NUM i; char tmpbuf[2048]; static char *status[] = {"(READ)","(UNSUB)","(BOGUS)","(JUNK)"}; putchar('\n'); page_line = 1; print_lines("\ # Status Newsgroup\n\ ",STANDOUT); for (i=0; i<nextrcline && !int_count; i++) { if (toread[i] >= 0) set_toread(i); *(rcline[i] + rcnums[i] - 1) = rcchar[i]; if (toread[i] > 0) sprintf(tmpbuf,"%3d %6d ",i,toread[i]); else sprintf(tmpbuf,"%3d %7s ",i,status[-toread[i]]); safecpy(tmpbuf+13,rcline[i],2034); *(rcline[i] + rcnums[i] - 1) = '\0'; if (print_lines(tmpbuf,NOMARKING)) break; } int_count = 0; } /* find a newsgroup in .newsrc */ NG_NUM find_ng(ngnam) char *ngnam; { register NG_NUM ngnum; #ifdef HASHNG register int hashix = hash(ngnam); register int incr = 1; while ((ngnum = hashtbl[hashix]) >= 0) { if (strEQ(rcline[ngnum], ngnam) && toread[ngnum] >= TR_UNSUB) return ngnum; hashix = (hashix + incr) % HASHSIZ; incr += 2; /* offsets from original are in n*2 */ } return nextrcline; /* = notfound */ #else /* just do linear search */ for (ngnum = 0; ngnum < nextrcline; ngnum++) { if (strEQ(rcline[ngnum],ngnam)) break; } return ngnum; #endif } void cleanup_rc() { register NG_NUM ngx; register NG_NUM bogosity = 0; #ifdef VERBOSE IF(verbose) fputs("Checking out your .newsrc--hang on a second...\n",stdout); ELSE #endif #ifdef TERSE fputs("Checking .newsrc--hang on...\n",stdout); #endif for (ngx = 0; ngx < nextrcline; ngx++) { if (toread[ngx] >= TR_UNSUB) { set_toread(ngx); /* this may reset newsgroup */ /* or declare it bogus */ } if (toread[ngx] == TR_BOGUS) bogosity++; } for (ngx = nextrcline-1; ngx >= 0 && toread[ngx] == TR_BOGUS; ngx--) bogosity--; /* discount already moved ones */ if (nextrcline > 5 && bogosity > nextrcline / 2) { fputs( "It looks like the active file is messed up. Contact your news administrator,\n\ ",stdout); fputs( "leave the \"bogus\" groups alone, and they may come back to normal. Maybe.\n\ ",stdout); } #ifdef RELOCATE else if (bogosity) { #ifdef VERBOSE IF(verbose) fputs("Moving bogus newsgroups to the end of your .newsrc.\n", stdout); ELSE #endif #ifdef TERSE fputs("Moving boguses to the end.\n",stdout); #endif for (; ngx >= 0; ngx--) { if (toread[ngx] == TR_BOGUS) relocate_newsgroup(ngx,nextrcline-1); } #ifdef DELBOGUS reask_bogus: in_char("Delete bogus newsgroups? [ny] "); putchar('\n'); setdef(buf,"n"); #ifdef VERIFY printcmd(); #endif if (*buf == 'h') { #ifdef VERBOSE IF(verbose) fputs("\ Type y to delete bogus newsgroups.\n\ Type n or SP to leave them at the end in case they return.\n\ ",stdout); ELSE #endif #ifdef TERSE fputs("y to delete, n to keep\n",stdout); #endif goto reask_bogus; } else if (*buf == 'n' || *buf == 'q') ; else if (*buf == 'y') { while (toread[nextrcline-1] == TR_BOGUS && nextrcline > 0) --nextrcline; /* real tough, huh? */ } else { fputs(hforhelp,stdout); goto reask_bogus; } #endif } #else #ifdef VERBOSE IF(verbose) fputs("You should edit bogus newsgroups out of your .newsrc.\n", stdout); ELSE #endif #ifdef TERSE fputs("Edit boguses from .newsrc.\n",stdout); #endif #endif paranoid = FALSE; } #ifdef HASHNG /* make an entry in the hash table for the current newsgroup */ void sethash(thisng) NG_NUM thisng; { register int hashix = hash(rcline[thisng]); register int incr = 1; #ifdef DEBUGGING static int hashhits = 0, hashtries = 0; #endif #ifdef DEBUGGING hashtries++; #endif while (hashtbl[hashix] >= 0) { #ifdef DEBUGGING hashhits++; if (debug & DEB_HASH) { printf(" Hash hits: %d / %d\n",hashhits, hashtries); } hashtries++; #endif hashix = (hashix + incr) % HASHSIZ; incr += 2; /* offsets from original are in n*2 */ } hashtbl[hashix] = thisng; } short prime[] = {1,2,-3,-5,7,11,-13,-17,19,23,-29,-31,37,41,-43,-47,53,57,-59, -61,67,71,-73,-79,83,89,-97,-101,1,1,1,1,1,1,1,1,1,1,1,1}; int hash(ngnam) register char *ngnam; { register int i = 0; register int ch; register int sum = 0; #ifdef DEBUGGING char *ngn = ngnam; #endif while (ch = *ngnam++) { sum += (ch + i) * prime[i]; /* gives ~ 10% hits at 25% full */ i++; } #ifdef DEBUGGING if (debug & DEB_HASH) printf("hash(%s) => %d => %d\n",ngn, sum, (sum<0?-sum:sum)%HASHSIZ); #endif if (sum < 0) sum = -sum; return sum % HASHSIZ; } #endif void newsrc_check() { rcfp = fopen(rcname,"r"); /* open it */ if (rcfp == Nullfp) { /* not there? */ #ifdef VERBOSE IF(verbose) fputs("\ Trying to set up a .newsrc file--running newsetup...\n\n\ ",stdout); ELSE #endif #ifdef TERSE fputs("Setting up .newsrc...\n",stdout); #endif if (doshell(sh,filexp(NEWSETUP)) || (rcfp = fopen(rcname,"r")) == Nullfp) { #ifdef VERBOSE IF(verbose) fputs("\ Can't create a .newsrc--you must do it yourself.\n\ ",stdout); ELSE #endif #ifdef TERSE fputs("(Fatal)\n",stdout); #endif finalize(1); } } else { UNLINK(rcbname); /* unlink backup file name */ link(rcname,rcbname); /* and backup current name */ } } /* write out the (presumably) revised .newsrc */ void write_rc() { register NG_NUM tmpng; register char *delim; rcfp = fopen(rctname, "w"); /* open .newsrc */ /* write out each line*/ for (tmpng = 0; tmpng < nextrcline; tmpng++) { if (rcnums[tmpng]) { delim = rcline[tmpng] + rcnums[tmpng] - 1; *delim = rcchar[tmpng]; } else delim = Nullch; #ifdef DEBUGGING if (debug & DEB_NEWSRC_LINE) printf("%s\n",rcline[tmpng]); #endif fprintf(rcfp,"%s\n",rcline[tmpng]); if (delim) *delim = '\0'; /* might still need this line */ } fclose(rcfp); /* close .newsrc */ UNLINK(rcname); link(rctname,rcname); UNLINK(rctname); if (writesoft) { tmpfp = fopen(filexp(softname), "w"); /* open .rnsoft */ for (tmpng = 0; tmpng < nextrcline; tmpng++) { fprintf(tmpfp,"%ld\n",(long)softptr[tmpng]); } fclose(tmpfp); } } !STUFFY!FUNK! echo Extracting art.help.SH cat >art.help.SH <<'!STUFFY!FUNK!' case $CONFIG in '') . config.sh ;; esac echo "Extracting art.help (with variable substitutions)" $spitshell >art.help <<!GROK!THIS! $startsh # $Header: art.help.SH,v 4.1 84/09/24 11:41:43 lwall Exp $ # # $Log: art.help.SH,v $ # Revision 4.1 84/09/24 11:41:43 lwall # Real baseline. # # Revision 4.0.1.1 84/09/12 15:19:06 lwall # Housekeeping. # # Revision 4.0 84/09/04 09:49:29 lwall # Baseline for netwide release # # $pager <<'EOT' Article Selection commands: n,SP Scan forward for next unread article. N Go to next article. ^N Scan forward for next unread article with same subject. p,P,^P Same as n,N,^N, only going backwards. - Go to previously displayed article. number Go to specified article. range{,range} command{:command} Apply one or more commands to one or more ranges of articles. Ranges are of the form: number | number-number. You may use . for the current article, and $ for the last article. Valid commands are: j, m, M, s, S, and !. /pattern/modifiers Scan forward for article containing pattern in the subject line. (Use ?pat? to scan backwards; append h to scan headers, a to scan entire articles, r to scan read articles, c to make case sensitive. /pattern/modifiers:command{:command} Apply one or more commands to the set of articles matching pattern. Use a K modifier to save entire command to the KILL file for this newsgroup. Commands m and M, if first, imply an r modifier. Valid commands are: j, m, M, s, S, and !. f,F Submit a followup article (F = include this article). r,R Reply through net mail (R = include this article). s ... Save to file or pipe via sh. S ... Save via preferred shell. w,W Like s and S but save without the header. | ... Same as s|... C Cancel this article, if yours. ^R,v Restart article (v=verbose). ^X Restart article, rot13 mode. c Catch up (mark all articles as read). ^B Back up one page. ^L Refresh the screen. You can get back to the pager with this. X Refresh screen in rot13 mode. ^ Go to first unread article. Disables subject search mode. $ Go to end of newsgroup. Disables subject search mode. # Print last article number. & Print current values of command-line switches. &switch {switch} Set or unset more switches. j Junk this article (mark it read). Stays at end of article. m Mark article as still unread. M Mark article as still unread upon exiting newsgroup or Y command. Y Yank back articles marked temporarily read via M. k Mark current SUBJECT as read. K Mark current SUBJECT as read, and save command in KILL file. = List subjects of unread articles. u Unsubscribe to this newsgroup. ^K Edit local KILL file (the one for this newsgroup). q Quit this newsgroup for now. EOT !GROK!THIS! $eunicefix art.help chmod 755 art.help !STUFFY!FUNK! echo "" echo "End of kit 3 (of 8)" cat /dev/null >kit3isdone config=true for iskit in 1 2 3 4 5 6 7 8; do if test -f kit${iskit}isdone; then echo "You have run kit ${iskit}." else echo "You still need to run kit ${iskit}." config=false fi done case $config in true) echo "You have run all your kits. Please read README and then type Configure." chmod 755 Configure ;; esac : I do not append .signature, but someone might mail this. exit