home *** CD-ROM | disk | FTP | other *** search
- Date: Tue, 7 May 85 13:43:09 pdt
- From: allegra!sdcrdcf!RDCF.SDC.UUCP!lwall (Larry Wall)
- Newsgroups: mod.sources
- Subject: rn version 4.3 (kit 3 of 9)
- Reply-To: lwall@sdcrdcf.UUCP
- Organization: System Development Corporation R&D, Santa Monica
-
- #! /bin/sh
-
- # Make a new directory for the rn sources, cd to it, and run kits 1 thru 9
- # through sh. When all 9 kits have been run, read README.
-
- echo "This is rn kit 3 (of 9). If kit 3 is complete, the line"
- echo '"'"End of kit 3 (of 9)"'" will echo at the end.'
- echo ""
- export PATH || (echo "You didn't use sh, you clunch." ; kill $$)
- echo Extracting intrp.c
- cat >intrp.c <<'!STUFFY!FUNK!'
- /* $Header: intrp.c,v 4.3 85/05/01 11:40:54 lwall Exp $
- *
- * $Log: intrp.c,v $
- * Revision 4.3 85/05/01 11:40:54 lwall
- * Baseline for release with 4.3bsd.
- *
- */
-
- #include "EXTERN.h"
- #include "common.h"
- #include "util.h"
- #include "search.h"
- #include "head.h"
- #include "rn.h"
- #include "artsrch.h"
- #include "ng.h"
- #include "util.h"
- #include "respond.h"
- #include "rcstuff.h"
- #include "bits.h"
- #include "artio.h"
- #include "term.h"
- #include "final.h"
- #include "INTERN.h"
- #include "intrp.h"
-
- char orgname[] = ORGNAME;
-
- /* name of this site */
- #ifdef GETHOSTNAME
- char *hostname;
- # undef SITENAME
- # define SITENAME hostname
- #else !GETHOSTNAME
- # ifdef DOUNAME
- # include <sys/utsname.h>
- struct utsname uts;
- # undef SITENAME
- # define SITENAME uts.nodename
- # else !DOUNAME
- # ifdef PHOSTNAME
- char *hostname;
- # undef SITENAME
- # define SITENAME hostname
- # else !PHOSTNAME
- # ifdef WHOAMI
- # undef SITENAME
- # define SITENAME sysname
- # endif WHOAMI
- # endif PHOSTNAME
- # endif DOUNAME
- #endif GETHOSTNAME
-
- #ifdef TILDENAME
- static char *tildename = Nullch;
- static char *tildedir = Nullch;
- #endif
-
- char *realname INIT(Nullch); /* real name of sender from /etc/passwd */
-
- char *dointerp();
- char *getrealname();
- #ifdef CONDSUB
- char *skipinterp();
- #endif
-
- static void abort_interp();
-
- void
- intrp_init(tcbuf)
- char *tcbuf;
- {
- char *getlogin();
-
- spool = savestr(filexp(SPOOL)); /* usually /usr/spool/news */
-
- getwd(tcbuf); /* find working directory name */
- origdir = savestr(tcbuf); /* and remember it */
-
- /* get environmental stuff */
-
- /* get home directory */
-
- homedir = getenv("HOME");
- if (homedir == Nullch)
- homedir = getenv("LOGDIR");
-
- dotdir = getval("DOTDIR",homedir);
-
- /* get login name */
-
- logname = getenv("USER");
- if (logname == Nullch)
- logname = getenv("LOGNAME");
- #ifdef GETLOGIN
- if (logname == Nullch)
- logname = savestr(getlogin());
- #endif
-
- /* get the real name of the person (%N) */
- /* Must be done after logname is read in because BERKNAMES uses that */
-
- strcpy(tcbuf,getrealname(getuid()));
- realname = savestr(tcbuf);
-
- /* name of header file (%h) */
-
- headname = savestr(filexp(HEADNAME));
-
- /* name of this site (%H) */
-
- #ifdef GETHOSTNAME
- gethostname(buf,sizeof buf);
- hostname = savestr(buf);
- #else
- #ifdef DOUNAME
- /* get sysname */
- uname(&uts);
- #else
- #ifdef PHOSTNAME
- {
- FILE *popen();
- FILE *pipefp = popen(PHOSTNAME,"r");
-
- if (pipefp == Nullfp) {
- printf("Can't find hostname\n");
- sig_catcher(0);
- }
- fgets(buf,sizeof buf,pipefp);
- buf[strlen(buf)-1] = '\0'; /* wipe out newline */
- hostname = savestr(buf);
- pclose(pipefp);
- }
- #endif
- #endif
- #endif
- sitename = savestr(SITENAME);
- }
-
- /* expand filename via %, ~, and $ interpretation */
- /* returns pointer to static area */
- /* Note that there is a 1-deep cache of ~name interpretation */
-
- char *
- filexp(s)
- register char *s;
- {
- static char filename[CBUFLEN];
- char scrbuf[CBUFLEN];
- register char *d;
-
- #ifdef DEBUGGING
- if (debug & DEB_FILEXP)
- printf("< %s\n",s) FLUSH;
- #endif
- interp(filename, (sizeof filename), s); /* interpret any % escapes */
- #ifdef DEBUGGING
- if (debug & DEB_FILEXP)
- printf("%% %s\n",filename) FLUSH;
- #endif
- s = filename;
- if (*s == '~') { /* does destination start with ~? */
- if (!*(++s) || *s == '/') {
- sprintf(scrbuf,"%s%s",homedir,s);
- /* swap $HOME for it */
- #ifdef DEBUGGING
- if (debug & DEB_FILEXP)
- printf("~ %s\n",scrbuf) FLUSH;
- #endif
- strcpy(filename,scrbuf);
- }
- else {
- #ifdef TILDENAME
- for (d=scrbuf; isalnum(*s); s++,d++)
- *d = *s;
- *d = '\0';
- if (tildedir && strEQ(tildename,scrbuf)) {
- strcpy(scrbuf,tildedir);
- strcat(scrbuf, s);
- strcpy(filename, scrbuf);
- #ifdef DEBUGGING
- if (debug & DEB_FILEXP)
- printf("r %s %s\n",tildename,tildedir) FLUSH;
- #endif
- }
- else {
- if (tildename) {
- free(tildename);
- free(tildedir);
- }
- tildedir = Nullch;
- tildename = savestr(scrbuf);
- #ifdef GETPWENT /* getpwnam() is not the paragon of efficiency */
- {
- struct passwd *getpwnam();
- struct passwd *pwd = getpwnam(tildename);
-
- sprintf(scrbuf,"%s%s",pwd->pw_dir,s);
- tildedir = savestr(pwd->pw_dir);
- #ifdef NEWSADMIN
- if (strEQ(newsadmin,tildename))
- newsuid = atoi(pwd->pw_uid);
- #endif
- strcpy(filename,scrbuf);
- #ifdef GETPWENT
- endpwent();
- #endif
- }
- #else /* this will run faster, and is less D space */
- { /* just be sure LOGDIRFIELD is correct */
- FILE *pfp = fopen("/etc/passwd","r");
- char tmpbuf[512];
- int i;
-
- if (pfp == Nullfp) {
- printf(cantopen,"passwd") FLUSH;
- sig_catcher(0);
- }
- while (fgets(tmpbuf,512,pfp) != Nullch) {
- d = cpytill(scrbuf,tmpbuf,':');
- #ifdef DEBUGGING
- if (debug & DEB_FILEXP)
- printf("p %s\n",tmpbuf) FLUSH;
- #endif
- if (strEQ(scrbuf,tildename)) {
- #ifdef NEWSADMIN
- if (strEQ(newsadmin,tildename))
- newsuid = atoi(index(d,':')+1);
- #endif
- for (i=LOGDIRFIELD-2; i; i--) {
- if (d)
- d = index(d+1,':');
- }
- if (d) {
- cpytill(scrbuf,d+1,':');
- tildedir = savestr(scrbuf);
- strcat(scrbuf,s);
- strcpy(filename,scrbuf);
- }
- break;
- }
- }
- fclose(pfp);
- }
- #endif
- }
- #else !TILDENAME
- #ifdef VERBOSE
- IF(verbose)
- fputs("~loginname not implemented.\n",stdout) FLUSH;
- ELSE
- #endif
- #ifdef TERSE
- fputs("~login not impl.\n",stdout) FLUSH;
- #endif
- #endif
- }
- }
- else if (*s == '$') { /* starts with some env variable? */
- d = scrbuf;
- *d++ = '%';
- if (s[1] == '{')
- strcpy(d,s+2);
- else {
- *d++ = '{';
- for (s++; isalnum(*s); s++) *d++ = *s;
- /* skip over token */
- *d++ = '}';
- strcpy(d,s);
- }
- #ifdef DEBUGGING
- if (debug & DEB_FILEXP)
- printf("$ %s\n",scrbuf) FLUSH;
- #endif
- interp(filename, (sizeof filename), scrbuf);
- /* this might do some extra '%'s but */
- /* that is how the Mercedes Benz */
- }
- #ifdef DEBUGGING
- if (debug & DEB_FILEXP)
- printf("> %s\n",filename) FLUSH;
- #endif
- return filename;
- }
-
- #ifdef CONDSUB
- /* skip interpolations */
-
- char *
- skipinterp(pattern,stoppers)
- register char *pattern;
- char *stoppers;
- {
-
- while (*pattern && (!stoppers || !index(stoppers,*pattern))) {
- #ifdef DEBUGGING
- if (debug & 8)
- printf("skipinterp till %s at %s\n",stoppers?stoppers:"",pattern);
- #endif
- if (*pattern == '%' && pattern[1]) {
- switch (*++pattern) {
- case '{':
- for (pattern++; *pattern && *pattern != '}'; pattern++)
- if (*pattern == '\\')
- pattern++;
- break;
- case '[':
- for (pattern++; *pattern && *pattern != ']'; pattern++)
- if (*pattern == '\\')
- pattern++;
- break;
- #ifdef CONDSUB
- case '(': {
- pattern = skipinterp(pattern+1,"!=");
- if (!*pattern)
- goto getout;
- for (pattern++; *pattern && *pattern != '?'; pattern++)
- if (*pattern == '\\')
- pattern++;
- if (!*pattern)
- goto getout;
- pattern = skipinterp(pattern+1,":)");
- if (*pattern == ':')
- pattern = skipinterp(pattern+1,")");
- break;
- }
- #endif
- #ifdef BACKTICK
- case '`': {
- pattern = skipinterp(pattern+1,"`");
- break;
- }
- #endif
- #ifdef PROMPTTTY
- case '"':
- pattern = skipinterp(pattern+1,"\"");
- break;
- #endif
- default:
- break;
- }
- pattern++;
- }
- else {
- if (*pattern == '^' && pattern[1])
- pattern += 2;
- else if (*pattern == '\\' && pattern[1])
- pattern += 2;
- else
- pattern++;
- }
- }
- getout:
- return pattern; /* where we left off */
- }
- #endif
-
- /* interpret interpolations */
-
- char *
- dointerp(dest,destsize,pattern,stoppers)
- register char *dest;
- register int destsize;
- register char *pattern;
- char *stoppers;
- {
- char *subj_buf = Nullch;
- char *ngs_buf = Nullch;
- char *refs_buf = Nullch;
- char *artid_buf = Nullch;
- char *reply_buf = Nullch;
- char *from_buf = Nullch;
- char *path_buf = Nullch;
- char *follow_buf = Nullch;
- char *dist_buf = Nullch;
- char *line_buf = Nullch;
- register char *s, *h;
- register int i;
- char scrbuf[512];
- bool upper = FALSE;
- bool lastcomp = FALSE;
- int metabit = 0;
-
- while (*pattern && (!stoppers || !index(stoppers,*pattern))) {
- #ifdef DEBUGGING
- if (debug & 8)
- printf("dointerp till %s at %s\n",stoppers?stoppers:"",pattern);
- #endif
- if (*pattern == '%' && pattern[1]) {
- upper = FALSE;
- lastcomp = FALSE;
- for (s=Nullch; !s; ) {
- switch (*++pattern) {
- case '^':
- upper = TRUE;
- break;
- case '_':
- lastcomp = TRUE;
- break;
- case '/':
- #ifdef ARTSRCH
- s = scrbuf;
- if (!index("/?g",pattern[-2]))
- *s++ = '/';
- strcpy(s,lastpat);
- s += strlen(s);
- if (pattern[-2] != 'g') {
- if (index("/?",pattern[-2]))
- *s++ = pattern[-2];
- else
- *s++ = '/';
- if (art_howmuch == 1)
- *s++ = 'h';
- else if (art_howmuch == 2)
- *s++ = 'a';
- if (art_doread)
- *s++ = 'r';
- }
- *s = '\0';
- s = scrbuf;
- #else
- s = nullstr;
- #endif
- break;
- case '{':
- pattern = cpytill(scrbuf,pattern+1,'}');
- if (s = index(scrbuf,'-'))
- *s++ = '\0';
- else
- s = nullstr;
- s = getval(scrbuf,s);
- break;
- case '[':
- pattern = cpytill(scrbuf,pattern+1,']');
- i = set_line_type(scrbuf,scrbuf+strlen(scrbuf));
- if (line_buf)
- free(line_buf);
- s = line_buf = fetchlines(art,i);
- break;
- #ifdef CONDSUB
- case '(': {
- COMPEX *oldbra_compex = bra_compex;
- COMPEX cond_compex;
- char rch;
- bool matched;
-
- init_compex(&cond_compex);
- pattern = dointerp(dest,destsize,pattern+1,"!=");
- rch = *pattern;
- if (rch == '!')
- pattern++;
- if (*pattern != '=')
- goto getout;
- pattern = cpytill(scrbuf,pattern+1,'?');
- if (!*pattern)
- goto getout;
- if (s = compile(&cond_compex,scrbuf,TRUE,TRUE)) {
- printf("%s: %s\n",scrbuf,s) FLUSH;
- pattern += strlen(pattern);
- goto getout;
- }
- matched = (execute(&cond_compex,dest) != Nullch);
- if (cond_compex.nbra) /* were there brackets? */
- bra_compex = &cond_compex;
- if (matched==(rch == '=')) {
- pattern = dointerp(dest,destsize,pattern+1,":)");
- if (*pattern == ':')
- pattern = skipinterp(pattern+1,")");
- }
- else {
- pattern = skipinterp(pattern+1,":)");
- if (*pattern == ':')
- pattern++;
- pattern = dointerp(dest,destsize,pattern,")");
- }
- s = dest;
- bra_compex = oldbra_compex;
- free_compex(&cond_compex);
- break;
- }
- #endif
- #ifdef BACKTICK
- case '`': {
- FILE *pipefp, *popen();
-
- pattern = dointerp(scrbuf,(sizeof scrbuf),pattern+1,"`");
- pipefp = popen(scrbuf,"r");
- if (pipefp != Nullfp) {
- int len;
-
- len = fread(scrbuf,sizeof(char),(sizeof scrbuf)-1,
- pipefp);
- scrbuf[len] = '\0';
- pclose(pipefp);
- }
- else {
- printf("\nCan't run %s\n",scrbuf);
- *scrbuf = '\0';
- }
- for (s=scrbuf; *s; s++) {
- if (*s == '\n') {
- if (s[1])
- *s = ' ';
- else
- *s = '\0';
- }
- }
- s = scrbuf;
- break;
- }
- #endif
- #ifdef PROMPTTTY
- case '"':
- pattern = dointerp(scrbuf,(sizeof scrbuf),pattern+1,"\"");
- fputs(scrbuf,stdout) FLUSH;
- resetty();
- gets(scrbuf);
- noecho();
- crmode();
- s = scrbuf;
- break;
- #endif
- case '~':
- s = homedir;
- break;
- case '.':
- s = dotdir;
- break;
- case '$':
- s = scrbuf;
- sprintf(s,"%d",getpid());
- break;
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- #ifdef CONDSUB
- s = getbracket(bra_compex,*pattern - '0');
- #else
- s = nullstr;
- #endif
- break;
- case 'a':
- s = scrbuf;
- sprintf(s,"%ld",(long)art);
- break;
- case 'A':
- #ifdef LINKART
- s = linkartname; /* so Eunice people get right file */
- #else
- s = scrbuf;
- sprintf(s,"%s/%s/%ld",spool,ngdir,(long)art);
- #endif
- break;
- case 'b':
- s = savedest;
- break;
- case 'B':
- s = scrbuf;
- sprintf(s,"%ld",(long)savefrom);
- break;
- case 'c':
- s = ngdir;
- break;
- case 'C':
- s = ngname;
- break;
- case 'd':
- s = scrbuf;
- sprintf(s,"%s/%s",spool,ngdir);
- break;
- case 'D':
- s = dist_buf = fetchlines(art,DIST_LINE);
- break;
- case 'f': /* from line */
- #ifdef ASYNC_PARSE
- parse_maybe(art);
- #endif
- if (htype[REPLY_LINE].ht_minpos >= 0) {
- /* was there a reply line? */
- if (!(s=reply_buf))
- s = reply_buf = fetchlines(art,REPLY_LINE);
- }
- else if (!(s = from_buf))
- s = from_buf = fetchlines(art,FROM_LINE);
- break;
- case 'F':
- #ifdef ASYNC_PARSE
- parse_maybe(art);
- #endif
- if (htype[FOLLOW_LINE].ht_minpos >= 0)
- /* is there a Followup-To line? */
- s = follow_buf = fetchlines(art,FOLLOW_LINE);
- else {
- int off;
-
- s = ngs_buf = fetchlines(art,NGS_LINE);
- if (h = instr(s,"net.general")) {
- off = h-s;
- strncpy(scrbuf,s,off+4);
- strcpy(scrbuf+off+4,"followup");
- safecpy(scrbuf+off+12,h+11,sizeof(scrbuf));
- s = scrbuf;
- }
- }
- break;
- case 'h': /* header file name */
- s = headname;
- break;
- case 'H': /* host name */
- s = sitename;
- break;
- case 'i':
- if (!(s=artid_buf))
- s = artid_buf = fetchlines(art,MESSID_LINE);
- if (*s != '<') {
- sprintf(scrbuf,"<%s>",artid_buf);
- s = scrbuf;
- }
- break;
- case 'I': /* ref article indicator */
- s = scrbuf;
- sprintf(scrbuf,"'%s'",indstr);
- break;
- case 'l': /* rn library */
- #ifdef NEWSADMIN
- s = newsadmin;
- #else
- s = "???";
- #endif
- break;
- case 'L': /* login id */
- s = logname;
- break;
- case 'm': /* current mode */
- s = scrbuf;
- *s = mode;
- s[1] = '\0';
- break;
- case 'M':
- #ifdef DELAYMARK
- sprintf(scrbuf,"%ld",(long)dmcount);
- s = scrbuf;
- #else
- s = nullstr;
- #endif
- break;
- case 'n': /* newsgroups */
- s = ngs_buf = fetchlines(art,NGS_LINE);
- break;
- case 'N': /* full name */
- s = getval("NAME",realname);
- break;
- case 'o': /* organization */
- s = getval("ORGANIZATION",orgname);
- #ifdef ORGFILE
- if (*s == '/') {
- FILE *ofp = fopen(s,"r");
-
- if (ofp) {
- fgets(scrbuf,sizeof scrbuf,ofp);
- fclose(ofp);
- s = scrbuf;
- s[strlen(s)-1] = '\0';
- }
- }
- #endif
- break;
- case 'O':
- s = origdir;
- break;
- case 'p':
- s = cwd;
- break;
- case 'P':
- s = spool;
- break;
- case 'r':
- #ifdef ASYNC_PARSE
- parse_maybe(art);
- #endif
- if (htype[REFS_LINE].ht_minpos >= 0) {
- refs_buf = fetchlines(art,REFS_LINE);
- refscpy(scrbuf,(sizeof scrbuf),refs_buf);
- }
- else
- *scrbuf = '\0';
- s = rindex(scrbuf,'<');
- break;
- case 'R':
- #ifdef ASYNC_PARSE
- parse_maybe(art);
- #endif
- if (htype[REFS_LINE].ht_minpos >= 0) {
- refs_buf = fetchlines(art,REFS_LINE);
- refscpy(scrbuf,(sizeof scrbuf),refs_buf);
- }
- else
- *scrbuf = '\0';
- if (!artid_buf)
- artid_buf = fetchlines(art,MESSID_LINE);
- if (artid_buf[0] == '<')
- safecat(scrbuf,artid_buf,sizeof(scrbuf));
- else {
- char tmpbuf[64];
-
- sprintf(tmpbuf,"<%s>",artid_buf);
- safecat(scrbuf,tmpbuf,sizeof(scrbuf));
- }
- s = scrbuf;
- break;
- case 's':
- if (!(s=subj_buf))
- s = subj_buf = fetchsubj(art,TRUE,TRUE);
- /* get subject handy */
- while ((*s=='R'||*s=='r')&&(s[1]=='E'||s[1]=='e')&&s[2]==':') {
- /* skip extra Re: */
- s += 3;
- if (*s == ' ')
- s++;
- }
- if (h = instr(s,"- (nf"))
- *h = '\0';
- break;
- case 'S':
- if (!(s=subj_buf))
- s = subj_buf = fetchsubj(art,TRUE,TRUE);
- /* get subject handy */
- if ((*s=='R'||*s=='r')&&(s[1]=='E'||s[1]=='e')&&s[2]==':') {
- /* skip extra Re: */
- s += 3;
- if (*s == ' ')
- s++;
- }
- break;
- case 't':
- case 'T':
- #ifdef ASYNC_PARSE
- parse_maybe(art);
- #endif
- if (htype[REPLY_LINE].ht_minpos >= 0) {
- /* was there a reply line? */
- if (!(s=reply_buf))
- s = reply_buf = fetchlines(art,REPLY_LINE);
- }
- else if (!(s = from_buf))
- s = from_buf = fetchlines(art,FROM_LINE);
- if (*pattern == 'T') {
- if (htype[PATH_LINE].ht_minpos >= 0) {
- /* should we substitute path? */
- s = path_buf = fetchlines(art,PATH_LINE);
- }
- i = strlen(sitename);
- if (strnEQ(sitename,s,i) && s[i] == '!')
- s += i + 1;
- }
- if ((h=index(s,'(')) != Nullch)
- /* strip garbage from end */
- *(h-1) = '\0';
- else if ((h=index(s,'<')) != Nullch) {
- /* or perhaps from beginning */
- s = h+1;
- if ((h=index(s,'>')) != Nullch)
- *h = '\0';
- }
- break;
- case 'u':
- sprintf(scrbuf,"%ld",(long)toread[ng]);
- s = scrbuf;
- break;
- case 'U':
- sprintf(scrbuf,"%ld",
- (long)(((ART_NUM)toread[ng]) - 1 + was_read(art)));
- s = scrbuf;
- break;
- case 'x': /* news library */
- s = lib;
- break;
- case 'X': /* rn library */
- s = rnlib;
- break;
- case 'z':
- #ifdef LINKART
- s = linkartname; /* so Eunice people get right file */
- #else
- s = scrbuf;
- sprintf(s,"%ld",(long)art);
- #endif
- if (stat(s,&filestat) < 0)
- filestat.st_size = 0L;
- sprintf(scrbuf,"%5ld",(long)filestat.st_size);
- s = scrbuf;
- break;
- default:
- if (--destsize <= 0)
- abort_interp();
- *dest++ = *pattern | metabit;
- s = nullstr;
- break;
- }
- }
- if (!s)
- s = nullstr;
- pattern++;
- if (upper || lastcomp) {
- char *t;
-
- if (s != scrbuf) {
- safecpy(scrbuf,s,(sizeof scrbuf));
- s = scrbuf;
- }
- if (upper || !(t=rindex(s,'/')))
- t = s;
- while (*t && !isalpha(*t))
- t++;
- if (islower(*t))
- *t = toupper(*t);
- }
- i = metabit; /* maybe get into register */
- if (s == dest) {
- while (*dest) {
- if (--destsize <= 0)
- abort_interp();
- *dest++ |= i;
- }
- }
- else {
- while (*s) {
- if (--destsize <= 0)
- abort_interp();
- *dest++ = *s++ | i;
- }
- }
- }
- else {
- if (--destsize <= 0)
- abort_interp();
- if (*pattern == '^' && pattern[1]) {
- ++pattern; /* skip uparrow */
- i = *pattern; /* get char into a register */
- if (i == '?')
- *dest++ = '\177' | metabit;
- else if (i == '(') {
- metabit = 0200;
- destsize++;
- }
- else if (i == ')') {
- metabit = 0;
- destsize++;
- }
- else
- *dest++ = i & 037 | metabit;
- pattern++;
- }
- else if (*pattern == '\\' && pattern[1]) {
- ++pattern; /* skip backslash */
- i = *pattern; /* get char into a register */
-
- /* this used to be a switch but the if may save space */
-
- if (i >= '0' && i <= '7') {
- i = 1;
- while (i < 01000 && *pattern >= '0' && *pattern <= '7') {
- i <<= 3;
- i += *pattern++ - '0';
- }
- *dest++ = i & 0377 | metabit;
- --pattern;
- }
- else if (i == 'b')
- *dest++ = '\b' | metabit;
- else if (i == 'f')
- *dest++ = '\f' | metabit;
- else if (i == 'n')
- *dest++ = '\n' | metabit;
- else if (i == 'r')
- *dest++ = '\r' | metabit;
- else if (i == 't')
- *dest++ = '\t' | metabit;
- else
- *dest++ = i | metabit;
- pattern++;
- }
- else
- *dest++ = *pattern++ | metabit;
- }
- }
- *dest = '\0';
- getout:
- if (subj_buf != Nullch) /* return any checked out storage */
- free(subj_buf);
- if (ngs_buf != Nullch)
- free(ngs_buf);
- if (refs_buf != Nullch)
- free(refs_buf);
- if (artid_buf != Nullch)
- free(artid_buf);
- if (reply_buf != Nullch)
- free(reply_buf);
- if (from_buf != Nullch)
- free(from_buf);
- if (path_buf != Nullch)
- free(path_buf);
- if (follow_buf != Nullch)
- free(follow_buf);
- if (dist_buf != Nullch)
- free(dist_buf);
- if (line_buf != Nullch)
- free(line_buf);
- return pattern; /* where we left off */
- }
-
- void
- interp(dest,destsize,pattern)
- char *dest;
- int destsize;
- char *pattern;
- {
- dointerp(dest,destsize,pattern,Nullch);
- #ifdef DEBUGGING
- if (debug & DEB_FILEXP)
- fputs(dest,stdout);
- #endif
- }
-
- /* copy a references line, normalizing as we go */
-
- void
- refscpy(dest,destsize,src)
- register char *dest, *src;
- register int destsize;
- {
- register char *dot, *at, *beg;
- char tmpbuf[64];
-
- while (*src) {
- if (*src != '<') {
- if (--destsize <= 0)
- break;
- *dest++ = '<';
- at = dot = Nullch;
- beg = src;
- while (*src && *src != ' ' && *src != ',') {
- if (*src == '.')
- dot = src;
- else if (*src == '@')
- at = src;
- if (--destsize <= 0)
- break;
- *dest++ = *src++;
- }
- if (destsize <= 0)
- break;
- if (dot && !at) {
- int len;
-
- *dest = *dot++ = '\0';
- sprintf(tmpbuf,"%s@%s.UUCP",dot,beg);
- len = strlen(tmpbuf);
- if (destsize > len) {
- strcpy(dest,tmpbuf);
- dest = dest + len;
- destsize -= len;
- }
- }
- if (--destsize <= 0)
- break;
- *dest++ = '>';
- }
- else {
- while (*src && --destsize > 0 && (*dest++ = *src++) != '>') ;
- if (destsize <= 0)
- break;
- }
- while (*src == ' ' || *src == ',') src++;
- if (*src && --destsize > 0)
- *dest++ = ' ';
- }
- *dest = '\0';
- }
-
- /* get the person's real name from /etc/passwd */
- /* (string is overwritten, so it must be copied) */
-
- char *
- getrealname(uid)
- int uid;
- {
- char *s, *c;
-
- #ifdef PASSNAMES
- #ifdef GETPWENT
- struct passwd *pwd = getpwuid(uid);
-
- s = pwd->pw_gcos;
- #else
- char tmpbuf[512];
- int i;
-
- getpw(uid, tmpbuf);
- for (s=tmpbuf, i=GCOSFIELD-1; i; i--) {
- if (s)
- s = index(s,':')+1;
- }
- if (!s)
- return nullstr;
- cpytill(tmpbuf,s,':');
- s = tmpbuf;
- #endif
- #ifdef BERKNAMES
- #ifdef BERKJUNK
- while (*s && !isalnum(*s) && *s != '&') s++;
- #endif
- if ((c = index(s, ',')) != Nullch)
- *c = '\0';
- if ((c = index(s, ';')) != Nullch)
- *c = '\0';
- s = cpytill(buf,s,'&');
- if (*s == '&') { /* whoever thought this one up was */
- strcat(buf,logname); /* in the middle of the night */
- strcat(buf,s+1); /* before the morning after */
- if (islower(*buf))
- *buf = toupper(*buf); /* gack and double gack */
- }
- #else
- if ((c = index(s, '(')) != Nullch)
- *c = '\0';
- if ((c = index(s, '-')) != Nullch)
- s = c;
- strcpy(buf,tmpbuf);
- #endif
- #ifdef GETPWENT
- endpwent();
- #endif
- return buf; /* return something static */
- #else
- if ((tmpfp=fopen(filexp(FULLNAMEFILE),"r")) != Nullfp) {
- fgets(buf,sizeof buf,tmpfp);
- fclose(tmpfp);
- buf[strlen(buf)-1] = '\0';
- return buf;
- }
- return "PUT YOUR NAME HERE";
- #endif
- }
-
- static void
- abort_interp()
- {
- fputs("\n% interp buffer overflow!\n",stdout) FLUSH;
- sig_catcher(0);
- }
- !STUFFY!FUNK!
- echo Extracting common.h
- cat >common.h <<'!STUFFY!FUNK!'
- /* $Header: common.h,v 4.3 85/05/01 11:37:11 lwall Exp $
- *
- * $Log: common.h,v $
- * Revision 4.3 85/05/01 11:37:11 lwall
- * Baseline for release with 4.3bsd.
- *
- */
-
- #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>
- #ifdef IOCTL
- #include <sys/ioctl.h>
- #endif IOCTL
-
- #ifdef FCNTL
- # include <fcntl.h>
- #endif
-
- #ifdef TERMIO
- # include <termio.h>
- #else
- # include <sgtty.h>
- #endif
-
- #ifdef GETPWENT
- # include <pwd.h>
- #endif
-
- #define BITSPERBYTE 8
- #define LBUFLEN 512 /* line buffer length */
- /* (don't worry, .newsrc lines can exceed this) */
- #ifdef pdp11
- # define CBUFLEN 256 /* command buffer length */
- # define PUSHSIZE 128
- #else
- # define CBUFLEN 512 /* command buffer length */
- # define PUSHSIZE 256
- #endif
- #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 <>
- * %I Inclusion indicator
- * %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 derived from Path:
- * %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
- * %z Size of current article in bytes.
- * %~ Home directory
- * %. Directory containing . files
- * %$ current process number
- * %{name} Environment variable "name". %{name-default} form allowed.
- * %[name] Header line beginning with "Name: ", without "Name: "
- * %"prompt"
- * Print prompt and insert what is typed.
- * %`command`
- * Insert output of command.
- * %(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 PUSHBACK /* macros and keymaps using pushback buffer */
- #define SPEEDOVERMEM /* use more memory to run faster */
- #define WORDERASE /* enable ^W to erase a word */
- #define MAILCALL /* check periodically for mail */
- #define CLEAREOL /* use clear to end-of-line instead of clear screen */
- #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 BACKTICK /* allow %`command` */
- #define PROMPTTTY /* allow %"prompt" */
- #define ULSMARTS /* catch _^H in text and do underlining */
- #define TERMMOD /* allow terminal type modifier on switches */
- #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 */
- #ifndef BSD42 /* 4.2 sites should just use groups for this */
- #define SETUIDGID /* substitute eaccess() for access() so that rn */
- /* can run setuid or setgid */
- /* if not setuid or setgid, you don't need it */
- #endif
- #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
-
- #ifdef DEBUGGING
- # define assert(ex) {if (!(ex)){fprintf(stderr,"Assertion failed: file %s, line %d\n", __FILE__, __LINE__);sig_catcher(0);}}
- #else
- # define assert(ex) ;
- #endif
-
- #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
-
- #ifdef CLEAREOL
- # define TCSIZE 512 /* capacity for termcap strings */
- #else
- # ifdef pdp11
- # define TCSIZE 256 /* capacity for termcap strings */
- # else
- # define TCSIZE 512 /* capacity for termcap srings */
- # 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
-
- /* system-wide RNINIT switches */
- #ifndef GLOBINIT
- # define GLOBINIT "%X/INIT"
- #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
-
- /* location of history file */
- #ifndef ARTFILE /* % and ~ */
- # define ARTFILE "%x/history"
- #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 macro file */
- #ifndef RNMACRO
- # ifdef PUSHBACK
- # define RNMACRO "%./.rnmac"
- # endif
- #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 "%./.newnewsrc"
- #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
-
- #ifdef INTERNET
- # 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
- #else
- # 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
- #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: %[keywords]\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 MININACT /* 2.10.2 site? */
- # define MBOXSAVER "%X/mbox.saver %A %P %c %a %B %C \"%b\" \"From %T %`date`\""
- # else
- # ifdef CONDSUB
- # define MBOXSAVER "%X/mbox.saver %A %P %c %a %B %C \"%b\" \"From %T %(%[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
- #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"
- #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 */
- #ifdef CLEAREOL
- EXT bool can_home_clear INIT(FALSE); /* fancy -e -- PWP */
- #endif CLEAREOL
- 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 */
-
- long atol(), fseek(), ftell();
- EXT bool in_ng INIT(FALSE); /* current state of rn */
- EXT char mode INIT('i'); /* 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");
- #ifdef STRICTCR
- EXT char badcr[] INIT("\nUnnecessary CR ignored.\n");
- #endif
- EXT char readerr[] INIT("rn read error");
- EXT char unsubto[] INIT("\n\nUnsubscribed to newsgroup %s\n");
- EXT char cantopen[] INIT("Can't open %s\n");
- EXT char cantcreate[] INIT("Can't create %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
-
- #ifdef NOLINEBUF
- #define FLUSH ,fflush(stdout)
- #else
- #define FLUSH
- #endif
-
- #ifdef lint
- #undef FLUSH
- #define FLUSH
- #undef putchar
- #define putchar(c)
- #endif
- !STUFFY!FUNK!
- echo Extracting bits.c
- cat >bits.c <<'!STUFFY!FUNK!'
- /* $Header: bits.c,v 4.3 85/05/01 11:36:15 lwall Exp $
- *
- * $Log: bits.c,v $
- * Revision 4.3 85/05/01 11:36:15 lwall
- * Baseline for release with 4.3bsd.
- *
- */
-
- #include "EXTERN.h"
- #include "common.h"
- #include "rcstuff.h"
- #include "head.h"
- #include "util.h"
- #include "final.h"
- #include "rn.h"
- #include "cheat.h"
- #include "ng.h"
- #include "artio.h"
- #include "intrp.h"
- #include "ngdata.h"
- #include "rcln.h"
- #include "kfile.h"
- #include "INTERN.h"
- #include "bits.h"
-
- #ifdef DBM
- # ifdef NULL
- # undef NULL
- # endif NULL
- # include <dbm.h>
- #endif DBM
- MEM_SIZE ctlsize; /* size of bitmap in bytes */
-
- void
- bits_init()
- {
- #ifdef DELAYMARK
- dmname = savestr(filexp(RNDELNAME));
- #else
- ;
- #endif
- }
-
- /* checkpoint the .newsrc */
-
- void
- checkpoint_rc()
- {
- #ifdef DEBUGGING
- if (debug & DEB_CHECKPOINTING) {
- fputs("(ckpt)",stdout);
- fflush(stdout);
- }
- #endif
- if (doing_ng)
- restore_ng(); /* do not restore M articles */
- if (rc_changed)
- write_rc();
- #ifdef DEBUGGING
- if (debug & DEB_CHECKPOINTING) {
- fputs("(done)",stdout);
- fflush(stdout);
- }
- #endif
- }
-
- /* reconstruct the .newsrc line in a human readable form */
-
- void
- restore_ng()
- {
- register char *s, *mybuf = buf;
- register ART_NUM i;
- ART_NUM count=0;
- int safelen = LBUFLEN - 16;
-
- strcpy(buf,rcline[ng]); /* start with the newsgroup name */
- s = buf + rcnums[ng] - 1; /* use s for buffer pointer */
- *s++ = rcchar[ng]; /* put the requisite : or !*/
- *s++ = ' '; /* put the not-so-requisite space */
- for (i=1; i<=lastart; i++) { /* for each article in newsgroup */
- if (s-mybuf > safelen) { /* running out of room? */
- safelen *= 2;
- if (mybuf == buf) { /* currently static? */
- *s = '\0';
- mybuf = safemalloc((MEM_SIZE)safelen + 16);
- strcpy(mybuf,buf); /* so we must copy it */
- s = mybuf + (s-buf);
- /* fix the pointer, too */
- }
- else { /* just grow in place, if possible */
- char *newbuf;
-
- newbuf = saferealloc(mybuf,(MEM_SIZE)safelen + 16);
- s = newbuf + (s-mybuf);
- mybuf = newbuf;
- }
- }
- if (!was_read(i)) /* still unread? */
- count++; /* then count it */
- else { /* article was read */
- ART_NUM oldi;
-
- sprintf(s,"%ld",(long)i); /* put out the min of the range */
- s += strlen(s); /* keeping house */
- oldi = i; /* remember this spot */
- do i++; while (i <= lastart && was_read(i));
- /* find 1st unread article or end */
- i--; /* backup to last read article */
- if (i > oldi) { /* range of more than 1? */
- sprintf(s,"-%ld,",(long)i);
- /* then it out as a range */
- s += strlen(s); /* and housekeep */
- }
- else
- *s++ = ','; /* otherwise, just a comma will do */
- }
- }
- if (*(s-1) == ',') /* is there a final ','? */
- s--; /* take it back */
- *s++ = '\0'; /* and terminate string */
- #ifdef DEBUGGING
- if (debug & DEB_NEWSRC_LINE && !panic) {
- printf("%s: %s\n",rcline[ng],rcline[ng]+rcnums[ng]) FLUSH;
- printf("%s\n",mybuf) FLUSH;
- }
- #endif
- free(rcline[ng]); /* return old rc line */
- if (mybuf == buf) {
- rcline[ng] = safemalloc((MEM_SIZE)(s-buf)+1);
- /* grab a new rc line */
- strcpy(rcline[ng], buf); /* and load it */
- }
- else {
- mybuf = saferealloc(mybuf,(MEM_SIZE)(s-mybuf)+1);
- /* be nice to the heap */
- rcline[ng] = mybuf;
- }
- *(rcline[ng] + rcnums[ng] - 1) = '\0';
- if (rcchar[ng] == NEGCHAR) { /* did they unsubscribe? */
- printf(unsubto,ngname) FLUSH;
- toread[ng] = TR_UNSUB; /* make line invisible */
- }
- else
- /*NOSTRICT*/
- toread[ng] = (ART_UNREAD)count; /* remember how many unread there are */
- }
-
- /* mark an article unread, keeping track of toread[] */
-
- void
- onemore(artnum)
- ART_NUM artnum;
- {
- #ifdef DEBUGGING
- if (debug && artnum < firstart) {
- printf("onemore: %d < %d\n",artnum,firstart) FLUSH;
- return;
- }
- #endif
- if (ctl_read(artnum)) {
- ctl_clear(artnum);
- ++toread[ng];
- }
- }
-
- /* mark an article read, keeping track of toread[] */
-
- void
- oneless(artnum)
- ART_NUM artnum;
- {
- #ifdef DEBUGGING
- if (debug && artnum < firstart) {
- printf("oneless: %d < %d\n",artnum,firstart) FLUSH;
- return;
- }
- #endif
- if (!ctl_read(artnum)) {
- ctl_set(artnum);
- if (toread[ng] > TR_NONE)
- --toread[ng];
- }
- }
-
- /* mark an article as unread, making sure that firstart is properly handled */
- /* cross-references are left as read in the other newsgroups */
-
- void
- unmark_as_read(artnum)
- ART_NUM artnum;
- {
- check_first(artnum);
- onemore(artnum);
- #ifdef MCHASE
- if (!parse_maybe(artnum))
- chase_xrefs(artnum,FALSE);
- #endif
- }
-
- #ifdef DELAYMARK
- /* temporarily mark article as read. When newsgroup is exited, articles */
- /* will be marked as unread. Called via M command */
-
- void
- delay_unmark(artnum)
- ART_NUM artnum;
- {
- if (dmfp == Nullfp) {
- dmfp = fopen(dmname,"w");
- if (dmfp == Nullfp) {
- printf(cantcreate,dmname) FLUSH;
- sig_catcher(0);
- }
- }
- oneless(artnum); /* set the correct bit */
- dmcount++;
- fprintf(dmfp,"%ld\n",(long)artnum);
- }
- #endif
-
- /* mark article as read. If article is cross referenced to other */
- /* newsgroups, mark them read there also. */
-
- void
- mark_as_read(artnum)
- ART_NUM artnum;
- {
- oneless(artnum); /* set the correct bit */
- checkcount++; /* get more worried about crashes */
- chase_xrefs(artnum,TRUE);
- }
-
- /* make sure we have bits set correctly down to firstart */
-
- void
- check_first(min)
- ART_NUM min;
- {
- register ART_NUM i = firstart;
-
- if (min < absfirst)
- min = absfirst;
- if (min < i) {
- for (i--; i>=min; i--)
- ctl_set(i); /* mark as read */
- firstart = min;
- }
- }
-
- /* bring back articles marked with M */
-
- #ifdef DELAYMARK
- void
- yankback()
- {
- register ART_NUM anum;
-
- if (dmfp) { /* delayed unmarks pending? */
- #ifdef VERBOSE
- printf("\nReturning %ld Marked article%s...\n",(long)dmcount,
- dmcount == 1 ? nullstr : "s") FLUSH;
- #endif
- fclose(dmfp);
- if (dmfp = fopen(dmname,"r")) {
- while (fgets(buf,sizeof buf,dmfp) != Nullch) {
- anum = (ART_NUM)atol(buf);
- /*NOSTRICT*/
- onemore(anum); /* then unmark them */
- #ifdef MCHASE
- chase_xrefs(anum,FALSE);
- #endif
- }
- fclose(dmfp);
- dmfp = Nullfp;
- UNLINK(dmname); /* and be tidy */
- }
- else {
- printf(cantopen,dmname) FLUSH;
- sig_catcher(0);
- }
- }
- dmcount = 0;
- }
- #endif
-
- /* run down xref list and mark as read or unread */
-
- int
- chase_xrefs(artnum,markread)
- ART_NUM artnum;
- int markread;
- {
- #ifdef ASYNC_PARSE
- if (parse_maybe(artnum)) /* make sure we have right header */
- return -1;
- #endif
- #ifdef DBM
- {
- datum lhs, rhs;
- datum fetch();
- register char *idp;
- char *ident_buf;
- static FILE * hist_file = Nullfp;
- #else
- if (
- #ifdef DEBUGGING
- debug & DEB_FEED_XREF ||
- #endif
- htype[XREF_LINE].ht_minpos >= 0) {
- /* are there article# xrefs? */
- #endif DBM
- char *xref_buf, *curxref;
- register char *xartnum;
- char *rver_buf = Nullch;
- static char *inews_site = Nullch;
- register ART_NUM x;
- char tmpbuf[128];
-
- #ifdef DBM
- rver_buf = fetchlines(artnum,NGS_LINE);
- /* get Newsgroups */
- if (!index(rver_buf,',')) /* if no comma, no Xref! */
- return 0;
- if (hist_file == Nullfp) { /* Init. file accesses */
- #ifdef DEBUGGING
- if (debug)
- printf ("chase_xref: opening files\n");
- #endif
- dbminit(filexp(ARTFILE));
- if ((hist_file = fopen (filexp(ARTFILE), "r")) == Nullfp)
- return 0;
- }
- xref_buf = safemalloc((MEM_SIZE)BUFSIZ);
- ident_buf = fetchlines(artnum,MESSID_LINE);
- /* get Message-ID */
- #ifdef DEBUGGING
- if (debug)
- printf ("chase_xref: Message-ID: %s\n", ident_buf);
- #endif
- idp = ident_buf;
- while (*++idp) /* make message-id case insensitive */
- if (isupper(*idp))
- *idp = tolower (*idp);
- lhs.dptr = ident_buf; /* look up article by id */
- lhs.dsize = strlen(lhs.dptr) + 1;
- rhs = fetch(lhs); /* fetch the record */
- if (rhs.dptr == NULL) /* if null, nothing there */
- goto wild_goose;
- fseek (hist_file, *((long *)rhs.dptr), 0);
- /* datum returned is position in hist file */
- fgets (xref_buf, BUFSIZ, hist_file);
- #ifdef DEBUGGING
- if (debug)
- printf ("Xref from history: %s\n", xref_buf);
- #endif
- curxref = cpytill(tmpbuf, xref_buf, '\t') + 1;
- curxref = cpytill(tmpbuf, curxref, '\t') + 1;
- #ifdef DEBUGGING
- if (debug)
- printf ("chase_xref: curxref: %s\n", curxref);
- #endif
- #else !DBM
- #ifdef DEBUGGING
- if (htype[XREF_LINE].ht_minpos >= 0)
- #endif
- xref_buf = fetchlines(artnum,XREF_LINE);
- /* get xrefs list */
- #ifdef DEBUGGING
- else {
- xref_buf = safemalloc((MEM_SIZE)100);
- printf("Give Xref: ") FLUSH;
- gets(xref_buf);
- }
- #endif
- #ifdef DEBUGGING
- if (debug & DEB_XREF_MARKER)
- printf("Xref: %s\n",xref_buf) FLUSH;
- #endif
- curxref = cpytill(tmpbuf,xref_buf,' ') + 1;
-
- /* Make sure site name on Xref matches what inews thinks site is.
- * Check first against last inews_site. If it matches, fine.
- * If not, fetch inews_site from current Relay-Version line and
- * check again. This is so that if the new administrator decides
- * to change the system name as known to inews, rn will still do
- * Xrefs correctly--each article need only match itself to be valid.
- */
- if (inews_site == Nullch || strNE(tmpbuf,inews_site)) {
- char *t;
-
- if (inews_site != Nullch)
- free(inews_site);
- rver_buf = fetchlines(artnum,RVER_LINE);
- if ((t = instr(rver_buf,"; site ")) == Nullch)
- inews_site = savestr(nullstr);
- else {
- char new_site[128];
-
- cpytill(new_site,t + 7,'.');
- inews_site = savestr(new_site);
- }
- if (strNE(tmpbuf,inews_site)) {
- #ifdef DEBUGGING
- if (debug)
- printf("Xref not from %s--ignoring\n",inews_site) FLUSH;
- #endif
- goto wild_goose;
- }
- }
- #endif DBM
- while (*curxref) {
- /* for each newsgroup */
- curxref = cpytill(tmpbuf,curxref,' ');
- #ifdef DBM
- xartnum = index(tmpbuf,'/');
- #else
- xartnum = index(tmpbuf,':');
- #endif DBM
- if (!xartnum) /* probably an old-style Xref */
- break;
- *xartnum++ = '\0';
- if (strNE(tmpbuf,ngname)) {/* not the current newsgroup? */
- x = atol(xartnum);
- if (x)
- if (markread) {
- if (addartnum(x,tmpbuf))
- goto wild_goose;
- }
- #ifdef MCHASE
- else
- subartnum(x,tmpbuf);
- #endif
- }
- while (*curxref && isspace(*curxref))
- curxref++;
- }
- wild_goose:
- free(xref_buf);
- #ifdef DBM
- free(ident_buf);
- #endif DBM
- if (rver_buf != Nullch)
- free(rver_buf);
- }
- return 0;
- }
-
- int
- initctl()
- {
- char *mybuf = buf; /* place to decode rc line */
- register char *s, *c, *h;
- register long i;
- register ART_NUM unread;
-
- #ifdef DELAYMARK
- dmcount = 0;
- #endif
- if ((lastart = getngsize(ng)) < 0) /* this cannot happen (laugh here) */
- return -1;
-
- absfirst = getabsfirst(ng,lastart); /* remember first existing article */
- if (!absfirst) /* no articles at all? */
- absfirst = 1; /* pretend there is one */
- #ifndef lint
- ctlsize = (MEM_SIZE)(OFFSET(lastart)/BITSPERBYTE+20);
- #endif lint
- ctlarea = safemalloc(ctlsize); /* allocate control area */
-
- /* now modify ctlarea to reflect what has already been read */
-
- for (s = rcline[ng] + rcnums[ng]; *s == ' '; s++) ;
- /* find numbers in rc line */
- i = strlen(s);
- #ifndef lint
- if (i >= LBUFLEN-2) /* bigger than buf? */
- mybuf = safemalloc((MEM_SIZE)(i+2));
- #endif lint
- strcpy(mybuf,s); /* make scratch copy of line */
- mybuf[i++] = ','; /* put extra comma on the end */
- mybuf[i] = '\0';
- s = mybuf; /* initialize the for loop below */
- if (strnEQ(s,"1-",2)) { /* can we save some time here? */
- firstart = atol(s+2)+1; /* ignore first range thusly */
- s=index(s,',') + 1;
- }
- else
- firstart = 1; /* all the bits are valid for now */
- if (absfirst > firstart) { /* do we know already? */
- firstart = absfirst; /* no point calling getngmin again */
- }
- else if (artopen(firstart) == Nullfp) {
- /* first unread article missing? */
- i = getngmin(".",firstart); /* see if expire has been busy */
- if (i) { /* avoid a bunch of extra opens */
- firstart = i;
- }
- }
- #ifdef PENDING
- # ifdef CACHESUBJ
- subj_to_get = firstart;
- # endif
- #endif
- unread = lastart - firstart + 1; /* assume this range unread */
- for (i=OFFSET(firstart)/BITSPERBYTE; i<ctlsize; i++)
- ctlarea[i] = 0; /* assume unread */
- #ifdef DEBUGGING
- if (debug & DEB_CTLAREA_BITMAP) {
- printf("\n%s\n",mybuf) FLUSH;
- for (i=1; i <= lastart; i++)
- if (! was_read(i))
- printf("%ld ",(long)i) FLUSH;
- }
- #endif
- for ( ; (c = index(s,',')) != Nullch; s = ++c) {
- /* for each range */
- ART_NUM min, max;
-
- *c = '\0'; /* do not let index see past comma */
- if ((h = index(s,'-')) != Nullch) { /* is there a -? */
- min = atol(s);
- max = atol(h+1);
- if (min < firstart) /* make sure range is in range */
- min = firstart;
- if (max > lastart)
- max = lastart;
- if (min <= max) /* non-null range? */
- unread -= max - min + 1;/* adjust unread count */
- for (i=min; i<=max; i++) /* for all articles in range */
- ctl_set(i); /* mark them read */
- }
- else if ((i = atol(s)) >= firstart && i <= lastart) {
- /* is single number reasonable? */
- ctl_set(i); /* mark it read */
- unread--; /* decrement articles to read */
- }
- #ifdef DEBUGGING
- if (debug & DEB_CTLAREA_BITMAP) {
- printf("\n%s\n",s) FLUSH;
- for (i=1; i <= lastart; i++)
- if (! was_read(i))
- printf("%ld ",(long)i) FLUSH;
- }
- #endif
- }
- #ifdef DEBUGGING
- if (debug & DEB_CTLAREA_BITMAP) {
- fputs("\n(hit CR)",stdout) FLUSH;
- gets(cmd_buf);
- }
- #endif
- if (mybuf != buf)
- free(mybuf);
- toread[ng] = unread;
- return 0;
- }
-
- void
- grow_ctl()
- {
- ART_NUM newlast;
- ART_NUM tmpfirst;
- MEM_SIZE newsize;
- register ART_NUM i;
-
- forcegrow = FALSE;
- newlast = getngsize(ng);
- if (newlast > lastart) {
- ART_NUM tmpart = art;
- #ifndef lint
- newsize = (MEM_SIZE)(OFFSET(newlast)/BITSPERBYTE+2);
- #else
- newsize = Null(MEM_SIZE);
- #endif lint
- if (newsize > ctlsize) {
- newsize += 20;
- ctlarea = saferealloc(ctlarea,newsize);
- ctlsize = newsize;
- }
- toread[ng] += (ART_UNREAD)(newlast-lastart);
- for (i=lastart+1; i<=newlast; i++)
- ctl_clear(i); /* these articles are unread */
- #ifdef CACHESUBJ
- if (subj_list != Null(char**)) {
- #ifndef lint
- subj_list = (char**)saferealloc((char*)subj_list,
- (MEM_SIZE)((OFFSET(newlast)+2)*sizeof(char *)) );
- #endif lint
- for (i=lastart+1; i<=newlast; i++)
- subj_list[OFFSET(i)] = Nullch;
- }
- #endif
- tmpfirst = lastart+1;
- lastart = newlast;
- #ifdef KILLFILES
- #ifdef VERBOSE
- IF(verbose)
- sprintf(buf,
- "%ld more article%s arrived--looking for more to kill...\n\n",
- (long)(lastart - firstart + 1),
- (lastart > firstart ? "s have" : " has" ) );
- ELSE /* my, my, how clever we are */
- #endif
- #ifdef TERSE
- strcpy(buf, "More news--killing...\n\n");
- #endif
- kill_unwanted(tmpfirst,buf,TRUE);
- #endif
- art = tmpart;
- }
- }
-
- !STUFFY!FUNK!
- echo Extracting NEW
- cat >NEW <<'!STUFFY!FUNK!'
- NEW FEATURES WITH RN 4.3
-
- New commands
- TAB (pager) scan for end of quoted text.
- && (anywhere) set or display macros.
- Q (art level) exit this newsgroup but stay on it.
- x (ng level) exit rn without changing .newsrc.
-
- New switch
- -=TERM-switch apply switch if terminal is TERM.
-
- New environment variables
- RNMACRO name of your macro and keymap file, if any.
- SUBJLINE controls format of = article listing.
-
- New % interpolations.
- %I inclusion indicator (-F argument).
- %m current mode of rn (newsgroup, pager, etc.)
- %z length of current article.
- %"prompt" prompt for input from keyboard.
- %`command` same as shell backquotes.
- ^char now produces control-char.
-
- Macros and Keymaps
- You may now define macros of any reasonable length and map those
- macros onto your keyboard in any way. You can completely remap the
- keyboard if you wish. Macros may contain % interpolations.
-
- Global RNINIT file
- You can now set pseudo-environment variables on a system-wide basis
- in the file %X/INIT. You don't have to recompile rn when you want
- to try something different.
-
- Pnews
- Can append your .signature if you like.
- Now knows how to mail to moderators.
- Runs somewhat faster now when invoked with -h.
- Will use %x/distributions if it exists.
- Doesn't ask for Distribution on local newsgroups.
- Doesn't ask for editor if EDITOR or VISUAL is set.
-
- Terminal handling
- -L switch uses erase-to-end-of-line to leave info on screen as long
- as possible.
- rn -c will not flush typeahead in your login script now.
- In multi-character commands, \ now quotes the next character.
- Support for non-line-buffered machines. Certain V7 machines will
- appreciate the speedup.
-
- Configure
- Lets the poor people without job control do shell escapes.
- Now remembers your old answers and uses them for defaults.
- Searches much more widely for libraries.
- Looks for Mcc or cc -M if it needs to.
- Finds pg if it needs to. (Note, pg users: you can use macros to
- reverse the sense of CR and SP in rn now.)
- Figures out where manual pages go.
- Figures out where mail is spooled.
- Looks for ioctl.h, if any.
- Determines if you have a builtin echo that works differently than
- /bin/echo.
- Asks if your mail takes Internet addresses.
- Works reasonably on more systems, such as "Pyramids".
-
- Miscellaneous
- Commands may be typed directly to a help menu or subject list without
- having to type 'q' first.
- - command on first displayed article of a newsgroup takes you out to
- the previous newsgroup. (Someday it will take you to the
- previous article in the previous newsgroup.)
- You can now easily get into a newsgroup with a KILL file and no
- unread articles.
- The catchup command at the top level now asks for confirmation.
- Interpretation routines now check for output buffer overflow.
- The pager no longer get hung up on non-initial ^L.
- The negative unread articles bug was fixed.
- Numerous small bug fixes.
- !STUFFY!FUNK!
- echo Extracting INIT
- cat >INIT <<'!STUFFY!FUNK!'
- -ESAMPLE="sample"
- !STUFFY!FUNK!
- echo ""
- echo "End of kit 3 (of 9)"
- cat /dev/null >kit3isdone
- config=true
- for iskit in 1 2 3 4 5 6 7 8 9; 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
-
-