sources-request@genrad.UUCP (01/25/85)
# From: ka@hou3c # # Welcome to vnews release 2.11-B 1/17/85. # This is part 3 out of 7. # Feed me into sh (NOT csh). if test ! -d lib then mkdir lib fi cat > lib/gethead.c <<\!E!O!F! #include <stdio.h> #include <sys/types.h> #include "config.h" #include "defs.h" #include "arthead.h" static char *hdname[NHDNAME + 1] = { "Relay-Version", "Posting-Version", "Path", "From", "Newsgroups", "Subject", "Message-ID", "Date", "Article-I.D.", "Posted", "Date-Received", "Expires", "References", "Control", "Sender", "Reply-To", "Followup-To", "Distribution", "Organization", "Lines", "Keywords", "Approved", "Summary", "Priority", 0 }; FILE * gethead(hp, fp) register struct arthead *hp ; FILE *fp ; { char line[LBUFLEN] ; register char *p ; register char **pp ; register int i ; char *spnext ; int spleft ; int spnum ; int unreccnt ; extern char FULLSYSNAME[] ; char *index(), *ckmalloc() ; char *hfgets() ; for (pp = &hp->h_from, i = NHDNAME + NUNREC ; --i >= 0 ; *pp++ = 0) ; unreccnt = 0 ; spleft = 0 ; spnum = 0 ; while (hfgets(line, LBUFLEN, fp) != NULL && line[0] != '\n') { if ((p = index(line, ':')) == NULL) goto bad ; *p = '\0' ; if (index(line, ' ') != NULL) /* this test unnecessary */ goto bad ; for (pp = hdname ; *pp ; pp++) { if (**pp == line[0] && strcmp(*pp, line) == 0) break ; } if (*pp) { while (*++p == ' ') ; if (pp == hdname + 2) { /* Path: */ if (prefix(p, FULLSYSNAME) && index(NETCHRS, p[i = strlen(FULLSYSNAME)])) p += i + 1 ; } pp = &hp->h_relayversion + (pp - hdname) ; } else { *p = ':' ; p = line ; if (unreccnt >= NUNREC) continue ; /* ignore if won't fit */ pp = &hp->h_unrec[unreccnt++] ; } nstrip(p) ; i = strlen(p) + 1; if (i > spleft) { if (spnum >= 8) xerror("Out of header space") ; if (hp->h_space[spnum] == NULL) hp->h_space[spnum] = ckmalloc(H_SPACE) ; spnext = hp->h_space[spnum++] ; spleft = H_SPACE ; } *pp = spnext ; strcpy(spnext, p) ; spnext += i ; spleft -= i ; } if (hp->h_from != NULL && hp->h_path != NULL && hp->h_subdate != NULL && hp->h_ident != NULL) return fp ; bad: return NULL ; } !E!O!F! cat > lib/getopt.c <<\!E!O!F! /* * getopt - get option letter from argv * This version of getopt was written by Henry Spencer * and is in the public domain. */ #include <stdio.h> #include "config.h" char *optarg; /* Global argument pointer. */ int optind = 0; /* Global argv index. */ static char *scan = NULL; /* Private scan pointer. */ extern char *index(); int getopt(argc, argv, optstring) int argc; char *argv[]; char *optstring; { register char c; register char *place; optarg = NULL; if (scan == NULL || *scan == '\0') { if (optind == 0) optind++; place = argv[optind]; if (optind >= argc || place[0] != '-' || place[1] == '\0') return(EOF); optind++; if (strcmp(place, "--")==0) { return(EOF); } scan = place + 1; } c = *scan++; place = index(optstring, c); if (place == NULL || c == ':') { fprintf(stderr, "%s: unknown option -%c\n", argv[0], c); return('?'); } place++; if (*place == ':') { if (*scan != '\0') { optarg = scan; scan = NULL; } else { if ((optarg = argv[optind]) == NULL) { fprintf(stderr, "%s: no arg for -%c option\n", c); return('?'); } optind++; } } return(c); } !E!O!F! cat > lib/getuser.c <<\!E!O!F! /* * Get the user's name and home directory. */ #include "config.h" #include <stdio.h> getuser() { extern char *username, *userhome; extern char *getenv(); #if USGREL > 6 username = getenv("LOGNAME") ; #else username = getenv("USER") ; #endif if ((userhome = getenv("HOME")) == NULL) userhome = getenv("LOGDIR") ; /* PWB??? */ /* if not in environment, get from /etc/passwd file */ if (username == NULL || userhome == NULL) pgetuser() ; } !E!O!F! cat > lib/gfopen.c <<\!E!O!F! #include <stdio.h> #include "defs.h" #include "libextern.h" FILE *ngfp ; int maxng ; gfopen() { char buf[FPATHLEN] ; sprintf(buf, "%s/groupfile", LIB); if ((ngfp = fopen(buf, "r")) == NULL && (sleep(2), ngfp = fopen(buf, "r")) == NULL) xerror("can't open newsgroup file") ; if (fgets(buf, sizeof buf, ngfp) == NULL) xerror("newsgroup file is empty") ; maxng = atoi(buf) ; } gfclose() { fclose(ngfp) ; ngfp = NULL ; } !E!O!F! cat > lib/hash.c <<\!E!O!F! /* * Hashing function. * First arg is the string, second is the number of elements in the table. * Currently, we use a CRC. */ int hash(string, nelem) char *string ; { register unsigned char *p ; register int h ; h = 0 ; for (p = string ; *p ; ) { h = (long)(((long)h << 8) + *p++) % nelem ; } return h ; } !E!O!F! cat > lib/hfgets.c <<\!E!O!F! #include <stdio.h> /* * hfgets is like fgets, but deals with continuation lines. * It also ensures that even if a line that is too long is * received, the remainder of the line is thrown away * instead of treated like a second line. */ char * hfgets(buf, len, fp) char *buf; int len; register FILE *fp; { register int c; register char *cp; cp = fgets(buf, len, fp); if (cp == NULL || *cp == '\n') return cp; c = strlen(cp); len -= c; cp += c - 1; if (*cp != '\n') { /* Line too long - part read didn't fit into a newline */ while ((c = getc(fp)) != '\n' && c != EOF); } while ((c = getc(fp)) == ' ' || c == '\t') { /* for each cont line */ /* Continuation line. */ while ((c = getc(fp)) == ' ' || c == '\t'); /* skip white space */ if (--len > 0) *cp++ = ' '; do { if (--len > 0) *cp++ = c ; } while ((c = getc(fp)) != '\n' && c != EOF) ; } *cp++ = '\n'; *cp++ = '\0'; if (c != EOF) /* Bug in Apollo UN*X */ ungetc(c, fp); /* push back first char of next header */ return buf; } !E!O!F! cat > lib/hfree.c <<\!E!O!F! /* * Free up the storage used by a header. */ #include <stdio.h> #include <sys/types.h> #include "arthead.h" hfree(hp) struct arthead *hp ; { register int i ; register char **p ; for (i = 8, p = hp->h_space ; --i >= 0 ; p++) { if (*p != NULL) { free(*p) ; *p = NULL ; } } } !E!O!F! cat > lib/hxchg.c <<\!E!O!F! /* * Exchange two headers. */ #include <stdio.h> #include <sys/types.h> #include "arthead.h" hxchg(hp1, hp2) struct arthead *hp1, *hp2 ; { register char *p, *q ; register char c ; register int i ; p = (char *)hp1, q = (char *)hp2 ; for (i = sizeof(struct arthead) ; --i >= 0 ; ) c = *p, *p++ = *q, *q++ = c ; } !E!O!F! cat > lib/index.c <<\!E!O!F! /* * Return the ptr in sp at which the character c appears; * NULL if not found * * These are the v7 index and rindex routines. The makefile does not * place them it the library because every version of UN*X that is * supported by this release of netnews has these routines (possibly * named strchr/strrchr). If you are running V6, use these routines. */ char * index(sp, c) register char *sp, c; { do { if (*sp == c) return(sp); } while (*sp++); return(NULL); } /* * Return the ptr in sp at which the character c last * appears; NULL if not found */ char * rindex(sp, c) register char *sp, c; { register char *r; r = NULL; do { if (*sp == c) r = sp; } while (*sp++); return(r); } !E!O!F! cat > lib/isadmin.c <<\!E!O!F! #include <stdio.h> #include "defs.h" #ifndef ROOTID #include <pwd.h> #endif /* * Return 1 if the user is the superuser or the netnews administrator. */ isadmin() { int uid ; #ifndef ROOTID struct passwd *pw ; #endif if ((uid = getuid()) == 0) /* superuser */ return 1 ; #ifdef ROOTID return uid == ROOTID ; #else return (pw = getpwnam(ADMIN)) != NULL && pw->pw_uid == uid ; #endif } /* The following code is better for backward compatability, but too complex for my liking: (* * No hardwired administrator ID, so we have to do this the * hard way. First we find the person to be notified. If * that fails, we try the user HOME. *) #ifdef NOTIFY char notify[64] ; char fname[64] ; FILE *nfd ; sprintf(fname, "%s/notify", LIB); nfd = fopen(fname, "r"); if (nfd == NULL) strcpy(notify, NOTIFY) ; else if (fscanf(nfd, "%s", TELLME) == EOF) goto nonotify; if ((pw = getpwnam(notify)) == NULL) goto nonotify; return pw->pw_uid == uid; #endif nonotify: #ifdef HOME return (pw = getpwnam(HOME)) != NULL && pw->pw_uid == uid; #else return 0; #endif #endif ROOTID } */ !E!O!F! cat > lib/isre.c <<\!E!O!F! /* * Check for "Re: " at beginning of string. */ isre(t) register char *t ; { if (t == 0) /* delete this later */ return 0 ; if (strncmp(t, "Re:", 3) == 0 || strncmp(t, "re:", 3) == 0 || strncmp(t, "RE:", 3) == 0) return 1 ; return 0 ; } !E!O!F! cat > lib/launder.c <<\!E!O!F! /* * nglist is the list of newsgroups in an article we want to follow up. * Do any special fascist processing to prevent certain kinds of followups. * In this case, there are two things we want to do: * All followups to "net.general" are fed to "net.followup". * However, if "net.general" is mentioned along with "net.news.group", * just remove the net.general. */ #include "config.h" char *index(); launder(nglist) char *nglist; { char *cp; char outbuf[128]; int seen_group = 0; for (cp = index(nglist, 'n'); cp; cp = index(cp + 1, 'n')) if (strncmp("news.group", cp, 10) == 0) seen_group++; for (cp = index(nglist, 'n'); cp; cp = index(cp + 1, 'n')) if (strncmp("net.general", cp, 11) == 0) { /* 11 = strlen("net.general") */ strcpy(outbuf, cp + 11); if (!seen_group) { strcpy(cp, "net.followup"); cp += 12; /* 12 = strlen("net.followup") */ } if (cp[-1] == ',' && outbuf[0] == ',') cp--; strcpy(cp, outbuf); } } !E!O!F! cat > lib/lcase.c <<\!E!O!F! #include <ctype.h> #ifdef _tolower #define tolower(c) _tolower(c) #endif lcase(s) register char *s; { register char *ptr; for (ptr = s; *ptr; ptr++) if (isupper(*ptr)) *ptr = tolower(*ptr); } !E!O!F! cat > lib/letter <<\!E!O!F! To: cbosgd!uucp-news Subject: Vnews status I have done quite a bit to the vnews internals. Vnews now generates the article index for a newsgroup using a file called artfile instead of openning each article in the newsgroup; this makes entering a new newsgroup faster. Currently records are added to artfile by a program called afinsert which is invoked from the sys file. This requires a mod to inews to pass the history line to afinsert. There is a program called afbuild which rebuilds artfile from the history file. Since afbuild has to open all the articles in the spool file, it takes about as long to run as the expire program does, which I hope is acceptable. Of course, expire could be rewritten to deal with both artfile and the history file at some point. I have changed the vnews source around quite a bit. I have squeezed it to the point where it should fit on a PDP-11. One problem I faced was that the files funcs.c and rfuncs.c contained a number of routines that were not needed for netnews, so vnews currently does not share any source code with the rest of netnews. What I have done, however, is to take many of the vnews routines and put them in a library called rlib.a so that they can be used by other netnews programs. The file /usr/local/src/cmd/news/lib/routines.doc on cbosgd contains a copy of the documentation on the routines in rlib.a. I can mail a copy to this list if people don't have access to cbosgd. The library comes with a shell program called setup to handle compila- tion options. This is hopefully a simpler approach than the localize.sh stuff that comes with release 2.10. (For example, if you do not specify which version of UNIX you are running under, setup figures it out.) Setup creates files named config.h and newsdefs.h, which specify the oeprating system and other news parameters, respectively. It also creates a file called makedefs, which can be prepended to a makefile or shell procedure. Setup currently does not define everything that pro- grams like inews need, but it could be expanded without too much difficulty. The "ud" (unsibscribe to discussion) command has been installed in vnews but needs a little work. The rest of vnews appears to be in pretty good shape at this point. I am not going to be able to do much on vnews for the next several weeks, but I would like to try to get a release of netnews out sometime in the forseeable future. How are other pieces coming? Kenneth Almquist !E!O!F! cat > lib/libextern.h <<\!E!O!F! /* * Extern variables defined by library routines. */ extern char LIB[]; /* /usr/lib/news */ extern char SPOOL[]; /* spool directory */ extern char FULLSYSNAME[]; /* system name */ extern char DOMAIN[]; /* append to FULLSYSNAME to get domain name */ extern char MAILPARSER[]; /* recmail program */ extern char XINEWS[]; /* inews program */ extern char CAESAR[]; /* caesar decryption program */ extern char newsrc[]; /* name of .newsrc file */ extern char *username; /* user's login name */ extern char *userhome; /* user's login directory */ extern char bfr[]; /* general purpose buffer */ !E!O!F! cat > lib/logdir.c <<\!E!O!F! /* * UNIX shell - logdir routine * * Joe Steffen * Bell Telephone Laboratories * * This routine does not use the getpwent(3) library routine * because the latter uses the stdio package. The allocation of * storage in this package destroys the integrity of the shell's * storage allocation. * * Modified 2/82 by DJ Molny * * This routine now implements name cacheing, so multiple requests * for the same logdir do not result in multiple open/reads of * /etc/passwd. If the previous request was successful and the name * is the same as the last request, the same login directory is returned. */ #define BUFSIZ 160 static char line[BUFSIZ+1]; char * logdir(name) char *name; { int pwf; static char lastname[BUFSIZ+1]; static char lastdir[BUFSIZ+1]; register char *p; register int i, j; char *field(); if (*lastdir && !strcmp(lastname,name)) /* djm */ return(lastdir); strcpy(lastname,name); /* djm */ strcpy(lastdir,""); /* djm */ /* attempt to open the password file */ if ((pwf = open("/etc/passwd", 0)) == -1) return(0); /* find the matching password entry */ do { /* get the next line in the password file */ i = read(pwf, line, BUFSIZ); for (j = 0; j < i; j++) if (line[j] == '\n') break; /* return a null pointer if the whole file has been read */ if (j >= i) return(0); line[++j] = 0; /* terminate the line */ lseek(pwf, (long) (j - i), 1); /* point at the next line */ p = field(line); /* get the logname */ } while (strcmp(name, line) != 0); close(pwf); /* skip the intervening fields */ p = field(p); p = field(p); p = field(p); p = field(p); /* return the login directory */ field(p); strcpy(lastdir,p); /* djm */ return(p); } static char * field(p) register char *p; { while (*p && *p != ':') ++p; if (*p) *p++ = 0; return(p); } !E!O!F! cat > lib/lookup.c <<\!E!O!F! #include <stdio.h> #include "af.h" /* * Look up an article using the article id. */ DPTR lookart(id, a) char *id ; struct artrec *a ; { DPTR dp ; dp = readptr(hashid(id)) ; while (dp != DNULL) { readrec(dp, a) ; if (equal(id, a->a_ident)) { /*printf("lookart %s succeeded\n", id) ; /*DEBUG*/ return dp ; } dp = a->a_idchain ; } /*printf("lookart %s failed\n", id) ; /*DEBUG*/ return DNULL ; } !E!O!F! cat > lib/makehimask.c <<\!E!O!F! /* * Unless the newsgroup is asked for explicitly, delete it from the * subscription list. */ #include <stdio.h> #include "config.h" #include "str.h" makehimask(sublist, ngrp) register char *sublist ; char *ngrp ; { char c, *p ; char *index() ; for (;;) { if (prefix(sublist, ngrp) && (c = sublist[strlen(ngrp)]) == '\0' || c == ',') return ; if ((p = index(sublist, ',')) == NULL) break ; sublist = p + 1 ; } while (*sublist) sublist++ ; if (sublist[-1] != ',') *sublist++ = ',' ; *sublist++ = '!' ; scopy(ngrp, sublist) ; } !E!O!F! cat > lib/mkconfig <<\!E!O!F! #!/bin/sh if test "$1" = "" then echo "Usage: mkconfig dir" echo "where dir is the directory containing the 2.10.1 source" exit 1 fi if test ! -d $1 then echo "mkconfig: $1: no such directory" exit 1 fi ( sed -n -e 's/^NEWSUSR *= */newsusr /p' \ -e 's/^NEWSGRP *= */newsgrp /p' \ -e 's/^LIBDIR *= */lib /p' \ -e 's/^BINDIR *= */bin /p' \ -e 's/^SPOOLDIR *= */spool /p' \ $1/Makefile sed -n -e 's/^#define[ ]NOTIFY[ ]*"\([^"]*\)".*/notify \1/p' \ -e 's/^#define[ ]MYDOMAIN[ ]*"\([^"]*\)".*/mydomain \1/p' \ -e 's/^#define[ ]MYORG[ ]*"\([^"]*\)".*/myorg \1/p' \ -e 's/^#define[ ]DFLTSUB[ ]*"\([^"]*\)".*/dfltsub \1/p' \ -e 's/^#define[ ]ADMSUB[ ]*"\([^"]*\)".*/admsub \1/p' \ -e 's/^#define[ ]UNAME.*/uname/p' \ -e 's/^#define[ ]GHNAME.*/ghname/p' \ -e 's/^\/\*[ ]*#define[ ]INTERNET.*/internet no/p' \ -e 's/^\/\*[ ]*#define[ ]V7MAIL.*/v7mail no/p' \ -e 's/^#define[ ]X[ ]*"\([^"]*\)".*/x \1/p' \ $1/defs.h rootid=`sed -n -e 's/^#define[ ]ROOTID[ ]*\([0-9]*\).*/\1/p' $1/defs.h` rootname=`sed -n -e "/^[^:]*:[^:]*:$rootid:/s/:.*//p" /etc/passwd | sed '2,$d'` if test "$rootname" != "" then echo admin $rootname fi ) | sed -e '/lib \/usr\/lib\/news/d' \ -e '/bin \/usr\/bin/d' \ -e '/spool \/usr\/spool\/news/d' \ -e '/dfltsub all/d' \ -e '/admsub general,all\.announce/d' \ > config !E!O!F! chmod +x lib/mkconfig cat > lib/mypathinit.c <<\!E!O!F! #include <stdio.h> #include "config.h" #include "defs.h" #ifdef HOME char SPOOL[FPATHLEN]; char LIB[FPATHLEN-15]; char CAESAR[FPATHLEN]; #else char SPOOL[] = SPOOLDIR"; char LIB[] = LIBDIR"; char CAESAR[] = LIBDIR/caesar"; #endif HOME #ifdef MYNAME char FULLSYSNAME[] = MYNAME; #else #ifdef UNAME #include <sys/utsname.h> char FULLSYSNAME[9]; #else char FULLSYSNAME[20]; #endif UNAME #endif MYNAME char DOMAIN[] = MYDOMAIN; #ifdef SENDMAIL char MAILPARSER[] = SENDMAIL; #else #ifdef HOME char MAILPARSER[FPATHLEN]; #else char MAILPARSER[] = LIBDIR/recmail"; #endif HOME #endif SENDMAIL char XINEWS[] = INEWS; static char verpfx[4] = {'@', '(', '#', ')'}; char NEWS_VERSION[] = news_version; pathinit() { #ifdef HOME /* Relative to the home directory of user HOME */ sprintf(SPOOL, "%s/%s", logdir(HOME), SPOOLDIR"); sprintf(LIB, "%s/%s", logdir(HOME), LIBDIR"); #endif if (strlen(LIB) >= FPATHLEN-15) xerror("LIB too long"); if (strlen(SPOOL) > FPATHLEN) xerror("SPOOL too long"); #if defined(HOME) && !defined(SENDMAIL) sprintf(MAILPARSER, "%s/recmail", LIB); #endif #ifndef MYNAME #ifdef UNAME { struct utsname ubuf; uname(&ubuf); strcpy(FULLSYSNAME, ubuf.nodename); } #else #ifdef GHNAME gethostname(FULLSYSNAME, sizeof FULLSYSNAME); #else whoami(); #endif GHNAME #endif UNAME #endif MYNAME } #if !defined(UNAME) && !defined(GHNAME) && !defined(MYNAME) #define HDRFILE "/usr/include/whoami.h" whoami() { char buf[BUFSIZ]; FILE *fd; fd = fopen(HDRFILE, "r"); if (fd == NULL) { fprintf(stderr, "Cannot open %s\n", HDRFILE); exit(1); } for (;;) { /* each line in the file */ if (fgets(buf, sizeof buf, fd) == NULL) { fprintf(stderr, "no sysname in %s\n", HDRFILE); fclose(fd); exit(2); } if (sscanf(buf, "#define sysname \"%[^\"]\"", FULLSYSNAME) == 1) { fclose(fd); return; } } } #endif !E!O!F! cat > lib/ndir.h <<\!E!O!F! #if BSDREL >= 42 #include <sys/dir.h> #else #if defined(pdp11) || USGREL == 30 #define DIRBLKSIZ 512 #else #define DIRBLKSIZ 1024 #endif struct direct { long d_ino; /* inode number of entry */ short d_namlen; /* length of string in d_name */ char d_name[16]; /* name must be no longer than this */ }; /* * Definitions for library routines operating on directories. */ typedef struct { int dd_fd; int dd_nleft; char *dd_nextc; char dd_buf[DIRBLKSIZ]; } DIR; #ifndef NULL #define NULL 0 #endif extern DIR *opendir(); extern struct direct *readdir(); extern void closedir(); #endif !E!O!F! cat > lib/newer.c <<\!E!O!F! /* * Program to determine whether file2 needs to be updated from file1. * that another one. Usage: newer file1 file2 * Returns: * 1 file2 is newer than file1. * 0 file2 is older than file1 or one of the files does not exist. * 8 arg count. */ #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> main(argc, argv) char **argv ; { struct stat st1, st2; if (argc != 3) { fputs("Usage: newer file1 file2\n", stderr); exit(8); } if (stat(argv[1], &st1) < 0) { fputs("newer: can't stat ", stderr); fputs(argv[1], stderr); fputs("\n", stderr); exit(0); /* force update attempt */ } if (stat(argv[2], &st2) < 0 || st2.st_mtime < st1.st_mtime) exit(0); exit(1); /* up to date */ } !E!O!F! cat > lib/newsrc.doc <<\!E!O!F! 1. FORMAT OF .NEWSRC FILE Since the .newsrc file is shared between a number of news reading programs, care should be taken to allow for the evolution of this file. Lines in the file fall into several types. 1) Newsgroups lines. A newsgroup line consists of a newsgroup name, followed by subscription indication, followed by a flags field, followed by a list of article numbers. A line should not be considered to be a newsgroup line unless the first character of the line is a lowercase letter and the subscription indication immediately follows the newsgroup name. The subscription indication consists of a ':' to indicate that the user subscribes to this group, or an '!' to indicate that the user does not subscribe to this group. The flags field is currently unused but is reserved for future use. It consists of a word not beginning with a digit, and terminated by a space. The list of article numbers should not have any spaces in it. It consists of a comma separated list of articles which have been read. A range of articles may be indicated by two numbers separated by a minus sign. Ideally, newsgroups should be presented in the order in which they appear in the .newsrc file, and newsgroups not appearing in the .newsrc file should be shown last. At any rate, the order of newsgroups in the .newrc file should not be disturbed. The crash recovery code writes updated lines to the end of the .newsrc file as they are modified. Therefore, the last entry in the .newsrc file should be believed. However, the first occurence of a newsgroup in the .newsrc file gives it's display position. 2) Unsubscribed discussions. Any line beginning with a '<' contains a message-ID of a discussion which has been unsubscribed to. Followups to such articles should not be shown. 3) Comment lines. All other lines should be treated as comment lines. When the .newsrc file is rewritten, comment lines should be output first. 2.10 deletes certain comment lines; this is unacceptable. !E!O!F! cat > lib/newsrc.h <<\!E!O!F! #define MAXUNSUB 200 /* max number discussion unsubscribed from */ #define MAXRCJUNK 128 /* maximum number of comment lines */ #define NG_UNSUB 01 struct ngentry { /* newsgroup entry */ char *ng_name; /* name of newsgroup */ char *ng_bits; /* which articles have been read */ struct ngentry *ng_next;/* next newgroup in .newsrc order */ char ng_unsub; /* set if we have unsubscribed */ }; #define ng_num(ngp) ((ngp) - ngtable) #define numtong(num) (&ngtable[num]) #ifdef DEBUG #define isunread(i) (i > 0 && i <= maxartno ? _isunread(i) : abort()) #define clrunread(i) (i > 0 && i <= maxartno ? _clrunread(i) : abort()) #define setunread(i) (i > 0 && i <= maxartno ? _setunread(i) : abort()) #define _isunread(i) (bitmap[(i-1) >> 3] & (1 << (i-1) % 8)) #define _setunread(i) (bitmap[(i-1) >> 3] |= (1 << (i-1) % 8)) #define _clrunread(i) (bitmap[(i-1) >> 3] &= ~(1 << (i-1) % 8)) #else #define isunread(i) (bitmap[(i-1) >> 3] & (1 << (i-1) % 8)) #define setunread(i) (bitmap[(i-1) >> 3] |= (1 << (i-1) % 8)) #define clrunread(i) (bitmap[(i-1) >> 3] &= ~(1 << (i-1) % 8)) #endif struct ngentry *findgroup(); struct ngentry *prevgrp(), *nextgrp(); extern struct ngentry ngtable[MAXGROUPS]; extern struct ngentry *curng, *firstng, *lastng; extern int ndunsub; extern long dunsub[MAXUNSUB]; extern char *rcjunk[MAXRCJUNK]; extern char **nextrcjunk; extern int minartno; extern int maxartno; extern char *bitmap; !E!O!F! cat > lib/nextgrp.c <<\!E!O!F! #include <stdio.h> #include "defs.h" #include "newsrc.h" struct ngentry * nextgrp(ngp) struct ngentry *ngp; { if (ngp == NULL) return firstng; else return ngp->ng_next; } !E!O!F! cat > lib/ng.h <<\!E!O!F! #define MAXNGNAME 32 #define G_MOD 01 /* indicates moderated or fa.all group */ struct ngrec { char g_name[MAXNGNAME]; /* newsgroup name */ short g_num; /* newsgroup number */ short g_flags; /* various flags */ } ; extern int maxng; /* max value for g_num */ extern FILE *ngfp; #define ALL_GROUPS(ngrec) for (nginit() ; ngread(&(ngrec)) ; ) !E!O!F! cat > lib/ngchain.c <<\!E!O!F! /* * Routines step through all the elements of a newsgroup. * Called by the BNG macro. */ #include <stdio.h> #include "af.h" DPTR nglnext ; DPTR nglfirst(ngnum) { return nglnext = readptr(ngchain(ngnum)) ; } ARTNO ngltest(ngnum, a) int ngnum ; struct artrec *a ; { register int i ; if (nglnext == DNULL) return -1 ; readrec(nglnext, a) ; for (i = 0 ; i < a->a_ngroups ; i++) { if (a->a_group[i].a_ngnum == ngnum) { nglnext = a->a_group[i].a_ngchain ; return a->a_group[i].a_artno ; } } xerror("bad newsgroup chain") ; } !E!O!F! cat > lib/ngmatch.c <<\!E!O!F! #include "defs.h" /* * News group matching. * * nglist is a list of newsgroups. * sublist is a list of subscriptions. * sublist may have "meta newsgroups" in it. * All fields are NGDELIM separated, * * Currently implemented glitches: * sublist uses 'all' like shell uses '*', and '.' like shell '/'. * If subscription X matches Y, it also matches Y.anything. */ ngmatch(nglist, sublist) register char *nglist, *sublist; { register char *n, *s; register int rc; rc = 0; for (n = nglist; *n != '\0' && rc == 0;) { for (s = sublist; *s != '\0';) { if (*s != NEGCHAR) rc |= ptrncmp(s, n); else rc &= ~ptrncmp(s+1, n); while (*s && *s++ != NGDELIM); } while (*n && *n++ != NGDELIM); } return(rc); } /* * Compare two newsgroups for equality. * The first one may be a "meta" newsgroup. */ ptrncmp(ng1, ng2) register char *ng1, *ng2; { while (*ng1 && *ng1 != NGDELIM) { if (ng1[0]=='a' && ng1[1]=='l' && ng1[2]=='l') { ng1 += 3; while (*ng2 && *ng2 != NGDELIM && *ng2 != '.') if (ptrncmp(ng1, ng2++)) return(1); return (ptrncmp(ng1, ng2)); } else if (*ng1++ != *ng2++) return(0); } return (*ng2 == '\0' || *ng2 == '.' || *ng2 == NGDELIM); } !E!O!F! cat > lib/nsavestr.c <<\!E!O!F! /* * Make a copy of a string. The copy cannot be freed. */ #include "str.h" #define BLOCKSIZE 1024 static char *savearea; static char *savep; char * nsavestr(s) char *s ; { int size = strlen(s) + 1; char *p ; char *ckmalloc() ; if (size > BLOCKSIZE) return savestr(s) ; if (savearea == 0 || savearea + BLOCKSIZE - savep < size) { nsaveclean() ; savearea = savep = ckmalloc(BLOCKSIZE) ; } scopy(s, p = savep) ; savep += size ; return p ; } /* * Release unused storage. */ nsaveclean() { char *realloc() ; if (savearea) { if (realloc(savearea, savep - savearea) != savearea) xerror("realloc blew it") ; } savearea = 0 ; } !E!O!F! cat > lib/nstrip.c <<\!E!O!F! /* * Strip trailing newlines, blanks, and tabs from 's'. * Return 1 if newline was found, else 0. */ nstrip(s) register char *s; { register char *p; register int rc; rc = 0; p = s; while (*p) if (*p++ == '\n') rc = 1; while (--p >= s && (*p == '\n' || *p == ' ' || *p == '\t')); *++p = '\0'; return(rc); } !E!O!F! cat > lib/openrc.c <<\!E!O!F! /* * Open the .newsrc file, creating it if necessary. */ #include <stdio.h> #include "defs.h" #include "libextern.h" char newsrc[64] ; FILE * openrc() { register char *myrc ; register FILE *rcfp ; static char READ[] = "r" ; char *getenv() ; if ((myrc = getenv("NEWSRC")) != NULL) strcpy(newsrc, myrc); else sprintf(newsrc, "%s/%s", userhome, NEWSRC); if ((rcfp = fopen(newsrc, READ)) == NULL) { newrc() ; if ((rcfp = fopen(newsrc, READ)) == NULL) xerror("Can't create .newsrc file") ; } return rcfp ; } newrc() { register FILE *fp; char users[FPATHLEN]; if (close(creat(newsrc, 0666))) { xerror("Cannot create %s", newsrc); } sprintf(users, "%s/users", LIB); if ((fp = fopen(users, "a")) != NULL) { fprintf(fp, "%s\n", username); fclose(fp); chmod(users, 0666); } } !E!O!F! cat > lib/pgetuser.c <<\!E!O!F! /* * Get user name and home directory. This version always goes to the * password file, so it cannot be subverted by modifying the environment. */ #include <stdio.h> #include <pwd.h> char *username, *userhome; pgetuser() { register struct passwd *p; char *savestr(); struct passwd *getpwuid(); if ((p = getpwuid(getuid())) == NULL) xerror("Cannot get user's name"); username = savestr(p->pw_name); userhome = savestr(p->pw_dir); } !E!O!F! cat > lib/prefix.c <<\!E!O!F! int prefix(full, pref) register char *full, *pref ; { register char c ; while ((c = *pref++) != '\0') if (*full++ != c) return 0 ; return 1 ; } !E!O!F! cat > lib/prevgrp.c <<\!E!O!F! #include <stdio.h> #include "defs.h" #include "newsrc.h" struct ngentry * prevgrp(ngp) struct ngentry *ngp; { register struct ngentry *p; if (ngp == NULL) return NULL; for (p = ngtable ; p->ng_next != ngp ; p++) if (p >= ngtable + MAXGROUPS - 1) return NULL; return p; } !E!O!F! cat > lib/process.c <<\!E!O!F! /* * process - process options for readnews */ static char *SccsId = "%W% %G%"; #include <stdio.h> #include <ctype.h> #include "roptions.h" #define TRUE 1 #define FALSE 0 int mode = UNKNOWN; procopt(argv) register char **argv; { register int state = OPTION; register char *p; register struct optable *optpt; extern char *progname; char *savestr(), *realloc(); /* loop once per arg. */ while (*argv != NULL) { if (state == OPTION) { if (**argv != '-') { xerror("Bad option string \"%s\"", *argv); } while (*++*argv != '\0') { for (optpt = options; optpt->optlet != '\0'; ++optpt) { if (optpt->optlet == **argv) goto found; } /* unknown option letter */ fprintf(stderr, "Usage: %s [ -a [ date ]] [ -n newsgroups ] [ -t titles ] [ -lprxhfuM ]\n", progname); fprintf(stderr, "\t[ -c [ ``mailer'' ]]\n\n"); fprintf(stderr, " %s -s\n", progname); exit(1); found:; if (mode != UNKNOWN && (mode&optpt->oldmode) == 0) { xerror("Bad %c option", **argv); } if (mode == UNKNOWN) mode = optpt->newmode; optpt->flag = TRUE; state = optpt->newstate; } argv++; /* done with this option arg. */ } else { /* * Pick up a piece of a string and put it into * the appropriate buffer. */ if (**argv == '-') { state = OPTION; continue; } p = optpt->buf; if (state == STRING) { if (optpt->buf != NULL) free(optpt->buf); optpt->buf = savestr(*argv); state++; } else { if ((p = realloc(p, strlen(p) + strlen(*argv) + 2)) == NULL) xerror("No space"); optpt->buf = p; while (*p) p++; *p++ = optpt->filchar; strcpy(p, *argv); } argv++; } } /* * At this point, we are done with vanilla flag processing. * Now deal with defaults and upward compatibility stuff. */ return; } /* * Process a string containing options. The string is broken up into * space separated options and then passed to procopt. */ #define MAXOPTS 63 procostr(rcbuf) char *rcbuf; { register char *ptr; char *rcline[MAXOPTS + 1]; int line = -1; strcat(rcbuf, " \1"); ptr = rcbuf; while (*++ptr) if (isspace(*ptr)) *ptr = '\0'; for (ptr = rcbuf; ; ptr++) { if (!*ptr) continue; if (*ptr == '\1') break; if (++line >= MAXOPTS) xerror("Too many options"); rcline[line] = ptr; while (*ptr) ptr++; } rcline[++line] = NULL; procopt(rcline); } !E!O!F! cat > lib/read.c <<\!E!O!F! #include <stdio.h> #include "af.h" #include "libextern.h" /* defines bfr */ long lseek() ; /* * Read in an article record. */ readrec(dp, a) DPTR dp ; struct artrec *a ; { register int len ; int i ; register char *p ; register char *q ; char **pp ; /*printf("readrec %ld\n", (long)dp) ; /*DEBUG*/ if (lseek(affd, (long)dp, 0) < 0) xerror("seek %ld failed, readrec\n", dp) ; len = BSIZE - ((int)dp & (BSIZE - 1)) ; if (len <= 1 + A_WRTLEN + MAXNG * sizeof(struct artgroup)) #if BSIZE == 512 len += BSIZE ; #else len = 1 + sizeof(struct artrec) ; #endif if ((len = read(affd, bfr, len)) < 1 + A_WRTLEN + MAXNG * sizeof(struct artgroup)) { printf("read returned %d\n", len) ; xerror("Bad read in readrec, %ld", dp) ; } if (bfr[0] != (char)A_PREFIX) { printf("len=%d, dp=%ld\n", len, (long)dp); fprintf(stderr, "bfr: %o %o %o %o %o\n", bfr[0], bfr[1], bfr[2], bfr[3], bfr[4]); fprintf(stderr, "A_PREFIX = %o, (char)A_PREFIX = %o\n", A_PREFIX, (char)A_PREFIX); xerror("bad article pointer %ld", dp) ; } bcopy(bfr + 1, (char *)a, A_WRTLEN) ; bcopy(bfr + 1 + A_WRTLEN, (char *)a->a_group, i = a->a_ngroups * sizeof(*a->a_group)) ; pp = &a->a_ident ; p = bfr + 1 + A_WRTLEN + i ; q = a->a_space ; len -= 1 + A_WRTLEN + i ; i = (a->a_flags & A_DUMMY)? 1 : 4 + a->a_nkwords ; while (--i >= 0) { *pp++ = q ; do if (--len < 0) { read(affd, bfr, 512) ; len = 512 ; p = bfr ; } while (*q++ = *p++) ; } } /* * Read a pointer from the article file */ DPTR readptr(dp) DPTR dp ; { DPTR new ; if (lseek(affd, (long)dp, 0) < 0) xerror("seek %ld failed, readptr\n", dp) ; if (read(affd, (char *)&new, sizeof(new)) != sizeof(new)) xerror("read failed, readptr(%ld)\n", dp) ; return new ; } !E!O!F! cat > lib/readinrc.c <<\!E!O!F! /* * Read in the .newsrc file and the newsgroups file. If rcfp is NULL, * only the newsgroups file is read. */ #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <ctype.h> #include "defs.h" #include "artfile.h" #include "ng.h" #include "newsrc.h" #include "libextern.h" #include "str.h" static int rcmode; /* file modes for .newsrc file */ int rcreadok; /* .newsrc file has been read */ int rcsaved; /* .newsrc file has been backed up */ char *rcjunk[MAXRCJUNK]; /* comment lines in .newsrc file */ char **nextrcjunk = rcjunk; /* first unused entry in rcjunk */ struct ngentry ngtable[MAXGROUPS]; /* newsgroup table */ int ndunsub; /* number of discussions unsubscribed to */ DPTR dunsub[MAXUNSUB]; /* discussions unsubscribed to */ struct ngentry *firstng, *lastng; /* articles in .newsrc file */ struct ngentry *curng; /* current newsgroup */ struct ngentry **nghashtab, *hashng(); readinrc(rcfp) FILE *rcfp; { register struct ngentry *ngp; register char *p; char unsub; int i; DPTR dp; struct artrec a; struct ngrec g; struct stat statb; gfopen(); if (maxng >= MAXGROUPS) xerror("Too many groups, increase MAXGROUPS"); nghashtab = ckmalloc(i = (MAXGROUPS * 2 + 1) * sizeof *nghashtab); bzero((char *)nghashtab, i); ALL_GROUPS(g) { ngtable[g.g_num].ng_name = nsavestr(g.g_name); hashng(g.g_name, &ngtable[g.g_num]); } gfclose(); if (rcfp == NULL) goto out; if (fstat(fileno(rcfp), &statb) >= 0) rcmode = statb.st_mode; while (fgets(bfr, LBUFLEN, rcfp) != NULL) { if (!nstrip(bfr)) xerror(".newsrc line too long"); if (bfr[0] == '<') { char ident[NAMELEN]; scopyn(bfr, ident, NAMELEN); if (ndunsub >= MAXUNSUB) xerror("Unsubscribed to too many discussions"); if ((dp = lookart(ident, &a)) != DNULL) dunsub[ndunsub++] = dp; } else if (islower(bfr[0])) { /* newsgroup line? */ for (p = bfr ; *p != ':' && *p != '!' ; p++) if (*p == '\0' || *p == ' ' || *p == '\t') goto junk; unsub = (*p == '!'); *p++ = '\0'; if (*p == ' ') p++; ngp = hashng(bfr, (struct ngentry *)0); if (ngp != NULL) { if (ngp->ng_bits != NULL) { free(ngp->ng_bits); } else { addrc(ngp); } ngp->ng_bits = savestr(p); ngp->ng_unsub = unsub; } } else { junk: if (nextrcjunk >= &rcjunk[MAXRCJUNK]) xerror("Too many lines in .newsrc"); *nextrcjunk++ = savestr(bfr); } } free(nghashtab); rcreadok = 1; out: /* add new groups to the .newsrc file */ for (ngp = ngtable ; ngp < ngtable + MAXGROUPS ; ngp++) { if (ngp->ng_name != NULL && ngp->ng_bits == NULL && wewant(ngp->ng_name)) addrc(ngp); } } /* * Write out the .newsrc file. */ writeoutrc() { FILE *rcfp; register int i; char **jp; struct ngentry *ngp; char newstmp[FPATHLEN]; char newsbak[FPATHLEN]; struct artrec a; FILE *ckfopen(); if (!rcreadok) return; updaterc(); sprintf(newstmp, "%s.tmp", newsrc); rcfp = ckfopen(newstmp, "w"); if (rcmode) chmod(newstmp, rcmode); /* Write out options line, continuations, and comments. */ for (jp = rcjunk ; jp < nextrcjunk ; jp++) fprintf(rcfp, "%s\n", *jp); /* Write out the newsgroup lines. */ for (ngp = firstng ; ngp != NULL ; ngp = ngp->ng_next) { fprintf(rcfp, "%s%c", ngp->ng_name, ngp->ng_unsub? '!' : ':'); if (ngp->ng_bits != NULL && *ngp->ng_bits != '\0') fprintf(rcfp, " %s", ngp->ng_bits); putc('\n', rcfp); } /* write out a list of discussions we have unsubscribed to */ for (i = 0 ; i < ndunsub ; i++) { readrec(dunsub[i], &a); fprintf(rcfp, "%s\n", a.a_ident); } if (ferror(rcfp) || fclose(rcfp) == EOF) xerror("write error on .newsrc.tmp"); sprintf(newsbak, "%s.bak", newsrc); if (! rcsaved) { rename(newsrc, newsbak); rcsaved++; } if (rename(newstmp, newsrc) < 0) xerror("rename .newsrc.tmp to .newsrc failed"); } struct ngentry * hashng(name, entry) char *name; struct ngentry *entry; { register char *p; register int i; register struct ngentry *ngp; i = 0; for (p = name ; *p ; i += *p++); if (p > name + 2) i += (p[-2] << 2) + (p[-1] << 1); i &= 077777; /* protect against negetive chars */ for (i = i % (MAXGROUPS * 2 + 1) ; (ngp = nghashtab[i]) != NULL ; ) { if (strcmp(ngp->ng_name, name) == 0) return ngp; if (++i >= (MAXGROUPS * 2 + 1)) i = 0; } if (entry != NULL) nghashtab[i] = entry; return ngp; } !E!O!F! cat > lib/rename.c <<\!E!O!F! #include <errno.h> #include "config.h" #if BSDREL < 42 int rename(from, to) char *from, *to ; { extern int errno ; if (link(from, to) < 0) { if (errno != EEXIST) return -1 ; if (unlink(to) < 0 || link(from, to) < 0) return -1 ; } return unlink(from) ; } #endif !E!O!F! cat > lib/replyname.c <<\!E!O!F! /* * Generate an address for replying to this article */ #include <stdio.h> #include "config.h" #include "defs.h" #include <sys/types.h> #include "arthead.h" char * replyname(hptr, tbuf) struct arthead *hptr; char tbuf[PATHLEN]; { register char *ptr; extern char FULLSYSNAME[]; char *getaddr(); #ifndef INTERNET strcpy(tbuf, hptr->h_path); /* * Play games stripping off multiple berknet * addresses (a!b!c:d:e => a!b!d:e) here. */ for (ptr=tbuf; *ptr; ptr++) if (index(NETCHRS, *ptr) && *ptr == ':' && index(ptr+1, ':')) strcpy(ptr, index(ptr+1, ':')); #else ptr = hptr->h_from; if (hset(hptr->h_replyto)) ptr = hptr->h_replyto; getaddr(ptr, tbuf); #endif return tbuf; } !E!O!F! cat > lib/rewinddir.c <<\!E!O!F! #include "config.h" #if BSDREL < 42 #include <sys/types.h> #include <sys/param.h> #include "ndir.h" /* * Go back to the beginning of a directory. */ rewinddir(dirp) DIR *dirp; { dirp->dd_nleft = 0; lseek(dirp->dd_fd, 0L, 0); } #endif !E!O!F! cat > lib/rmnf.c <<\!E!O!F! /* * Zap the notesfile indicator. */ #define equal(s1, s2) (strcmp(s1, s2) == 0) rmnf(title) char *title ; { register char *p ; p = title + strlen(title) - 7 ; if (p > title && equal(p, " - (nf)")) { *p = '\0' ; return 1 ; } return 0 ; } !E!O!F! cat > lib/roptions.c <<\!E!O!F! #include <stdio.h> #include "config.h" #include "defs.h" #include "roptions.h" char *savestr(), *getenv(), *index(), *hfgets(); struct optable options[] = { /* optlet filchar flag newstate oldmode newmode buf */ 'p', '\0', FALSE, OPTION, UNKNOWN, UNKNOWN,NULL, 't', '\1', FALSE, STRING, ANY, UNKNOWN,NULL, 'a', ' ', FALSE, STRING, ANY, UNKNOWN,NULL, 'n', NGDELIM, FALSE, STRING, ANY, UNKNOWN,NULL, 'c', ' ', FALSE, STRING, UNKNOWN, UNKNOWN,NULL, 'l', ' ', FALSE, OPTION, UNKNOWN, UNKNOWN,NULL, 'r', '\0', FALSE, OPTION, ANY, UNKNOWN,NULL, /* the s option used to read a list of newsgroups. Not any more */ 's', NGDELIM, FALSE, OPTION, ANY, UNKNOWN,NULL, 'x', '\0', FALSE, OPTION, ANY, UNKNOWN,NULL, 'h', '\0', FALSE, OPTION, ANY, UNKNOWN,NULL, 'M', '\0', FALSE, OPTION, UNKNOWN, MAIL, NULL, 'f', '\0', FALSE, OPTION, ANY, UNKNOWN,NULL, 'u', '\0', FALSE, OPTION, ANY, UNKNOWN,NULL, 'e', '\0', FALSE, OPTION, ANY, UNKNOWN,NULL, '1', '\0', FALSE, OPTION, ANY, UNKNOWN,NULL, '2', '\0', FALSE, OPTION, ANY, UNKNOWN,NULL, 'A', '\0', FALSE, OPTION, ANY, UNKNOWN,NULL, '\0', '\0', 0, 0, 0, 0, NULL }; char *progname ; char *titles[10] ; /* list of titles */ extern char bfr[] ; roptions(argv, rcfp) char **argv ; FILE *rcfp ; { char *p ; char **pp ; progname = *argv++ ; if ((p = getenv("NEWSOPTS")) != NULL) { scopyn(p, bfr, LBUFLEN - 2) ; procostr(bfr) ; } if (rcfp != NULL && hfgets(bfr, LBUFLEN - 2, rcfp) != NULL && prefix(bfr, "options ")) { procostr(bfr + 8) ; } if (sublist == NULL) sublist = savestr(DFLTSUB); #ifdef ADMSUB sprintf(bfr, "%s,%s", sublist, ADMSUB); free(sublist); sublist = savestr(bfr); #endif procopt(argv) ; if (cflag) { oneflag = FALSE; twoflag = TRUE; } if (pflag) { oneflag = FALSE; twoflag = FALSE; } if (!oneflag && !twoflag && !pflag) { oneflag = TRUE; twoflag = TRUE; } if (oneflag && !twoflag) cflag = 1; strcpy(bfr, sublist); makehimask(bfr, "junk"); makehimask(bfr, "control"); /* makehimask(bfr, "test"); */ free(sublist); sublist = savestr(bfr); if (toptbuf) { pp = titles ; p = toptbuf ; for (;;) { if (pp >= titles + 9) xerror("Too many titles") ; *pp++ = p ; if ((p = index(p, '\1')) == NULL) break ; *p++ = '\0' ; } } } !E!O!F! cat > lib/roptions.h <<\!E!O!F! /* flags for readnews */ #define pflag options[0].flag #define tflag options[1].flag #define toptbuf options[1].buf #define aflag options[2].flag #define datebuf options[2].buf #define nflag options[3].flag #define sublist options[3].buf #define cflag options[4].flag #define coptbuf options[4].buf #define lflag options[5].flag #define rflag options[6].flag #define sflag options[7].flag #define xflag options[8].flag #define hflag options[9].flag #define Mflag options[10].flag #define fflag options[11].flag #define uflag options[12].flag #define eflag options[13].flag #define oneflag options[14].flag #define twoflag options[15].flag #define Aflag options[16].flag #define UNKNOWN 0001 /* possible modes for news program */ #define MAIL 0004 #define ANY 0007 #define OPTION 0 /* pick up an option string */ #define STRING 1 /* pick up a string of arguments */ struct optable { /* options table. */ char optlet; /* option character. */ char filchar; /* if to pickup string, fill character. */ int flag; /* TRUE if have seen this opt. */ int newstate; /* STRING if takes arg, else OPTION */ int oldmode; /* OR of legal input modes. */ int newmode; /* output mode. */ char *buf; /* string buffer */ }; extern struct optable options[]; extern int mode; !E!O!F! cat > lib/savestr.c <<\!E!O!F! /* * Make a copy of a string */ char *savestr(s) char *s ; { char *p ; char *ckmalloc() ; p = ckmalloc(strlen(s) + 1) ; strcpy(p, s) ; return p ; } !E!O!F! cat > lib/schar.c <<\!E!O!F! /* * Convert a character to an integer, performing sign extension even on * machines that don't provide hardware support for signed characters. * This routine should be replaced by the macro * #define schar(c) ((char)(c)) * for compilers that support signed characters. */ /* The high bit of a character */ #define SIGNBIT (int)((unsigned char)(-1) &~ ((unsigned char)(-1) >> 1)) #define EXTBITS (int)(-1 &~ (unsigned char)(-1)) int schar(c) char c ; { return (c & SIGNBIT) ? c | EXTBITS : c ; } !E!O!F! cat > lib/scopyn.c <<\!E!O!F! scopyn(from, to, n) register char *from, *to ; register int n ; { while (--n > 0 && (*to++ = *from++) != '\0') ; *to = '\0' ; } !E!O!F! cat > lib/scopyn.pdp <<\!E!O!F! / SCOPYN(FROM, TO, N) CHAR *FROM, *TO; / / Copy string "from" to string "to", truncating "to" to n - 1 / characters to avoid overflow. / .globl _scopyn _scopyn: mov sp, r0 / prepare to access args mov r2, -(sp) / save r2 tst (r0)+ / mov (r0)+, r1 / get from mov (r0)+, r2 / get to mov (r0)+, r0 / get n br 2f / enter middle of loop 1: movb (r1)+, (r2)+ / copy a byte beq 3f / until a nul is encountered 2: sob r0, 1b / or count is exhausted 3: clrb (r2) / nul terminate "to" string mov (sp)+, r2 / restore r2 rts pc / and return !E!O!F! cat > lib/scopyn.u3b <<\!E!O!F! .file "scopyn.u3b" # give me a break! .globl scopyn .align 4 scopyn: save &1 # save r8 movw 0(%ap), %r0 # get from movw 4(%ap), %r1 # get to subw3 &1, 8(%ap), %r2 # get count - 1 to leave room for nul movw &0, %r8 # string terminator movcce %r0, %r2, %r1, %r8 # copy the string movb &0, 0(%r1) # append nul terminator ret &1 # and return !E!O!F! cat > lib/scopyn.vax <<\!E!O!F! # SCOPYN(SRC, DEST, N) CHAR *SRC, *DEST # # Copy src to dest, truncating the source string to n - 1 charaters # if necessary. Dest will always get a nul terminator. # .globl _scopyn .align 2 _scopyn:.word 0 # no registers saved movq 4(ap), r4 # get src and dest subl3 $1, 12(ap), r0 # get n, leaving space for nul locc $0, r0, (r4) # scan until nul or count exhausted subl2 r4, r1 # find length movc3 r1, (r4), (r5) # move the characters clrb (r3) # nul terminate dest ret # and return !E!O!F! cat > lib/setup <<\!E!O!F! #!/bin/sh : This shell procedure reads in the config file, generates defaults for : all the values not specified, and generated the config.h, newsdefs.h, : makedefs, and archive. It should be run to bring up a new system. : : This shell procedure uses the value ",,,," to indicate that a variable : has not been set. exec 3<&0 if test ! -f config then echo "Please create config file and run again." exit 1 fi : figure out who is running this program user=${LOGNAME-${USER-,,,,}} if test "$user" = ,,,, then ls -l config > junk exec < junk read x y user rest rm -f junk if test "$user" = "" then user=news fi fi : look for other setup programs setups= special= for x in ../* do if test -f $x/config.parms then setups="$setups $x/setup" special="$special`cat $x/config.parms` " fi done : set up all the defaults lib=/usr/lib/news spool=/usr/spool/news bin=/usr/bin admin=,,,, compadmin=no newsusr=,,,, newsgrp=,,,, home=,,,, sys=,,,, cpu=,,,, small=,,,, umask=000 dftexp=14 tmail=,,,, mailer=,,,, dftsub=all admsub=general,all.announce page=,,,, notify=,,,, dfteditor=,,,, manually= internet= mydomain=,,,, myname=,,,, myorg=,,,, sendmail=,,,, uname=,,,, ghname=,,,, v7mail= newsrc=.newsrc maxgroups=350 buflen=,,,, lbuflen=1024 pathlen=512 datelen=48 namelen=64 fpathlen=64 termcap=,,,, : read in the config file exec <config while read name value do case $name in path) PATH=$value ;; lib) lib=$value ;; spool) spool=$value ;; bin) bin=$value ;; admin) admin=$value ;; compadmin) compadmin=$value ;; newsusr) newsusr=$value ;; newsgrp) newsgrp=$value ;; home) home=$value ;; sys) sys=$value ;; cpu) cpu=$value ;; small) small=$value ;; umask) umask=$value ;; dftexp) dftexp=$value ;; tmail) tmail=$value ;; mailer) mailer=$value ;; dftsub) dftsub=$value ;; dfltsub) dftsub=$value ;; admsub) admsub=$value ;; page) page=$value ;; notify) notify=$value ;; dfteditor) dfteditor=$value ;; manually) manually=$value ;; internet) internet=$value ;; mydomain) mydomain=$value ;; myname) myname=$value ;; myorg) myorg=$value ;; uname) uname=$value ;; ghname) ghname=$value ;; v7mail) v7mail=$value ;; newsrc) newsrc=$value ;; maxgroups) maxgroups=$value ;; buflen) buflen=$value ;; lbuflen) lbuflen=$value ;; pathlen) pathlen=$value ;; datelen) datelen=$value ;; namelen) namelen=$value ;; fpathlen) fpathlen=$value ;; termcap) termcap=$value ;; "") ;; "#"*) ;; *) for x in $special do if test "$name" = "$x" then name= fi done if test "$name" != "" then echo "Unknown config keyword: $name" exit 2 fi ;; esac done if test "$sys" = ,,,, then if test -f /usr/include/termio.h then if test -f /bin/shl -o -f /usr/bin/shl then sys=sys5r2 elif test -f /usr/bin/cflow then sys=sys5 else sys=sys3 fi else if test -f /usr/include/sys/time.h then sys=4.2bsd elif test -d /usr/ucb then sys=4.1bsd else sys=v7 fi fi echo system assumed to be $sys. fi case "$sys" in sys3) USGREL=30 BSDREL=6 ;; sys5) USGREL=50 BSDREL=6 ;; sys5r2) USGREL=52 BSDREL=6 ;; v7) BSDREL=7 USGREL=6 ;; 4.1bsd) BSDREL=41 USGREL=6 ;; 4.2bsd) BSDREL=42 USGREL=6 ;; *) echo "Unknown system type $sys" exit 1 ;; esac if test "$cpu" = ,,,, then cc -P cpu.c cpu=`sed -n s/X//p cpu.i` /bin/rm -f cpu.i fi case "$cpu" in pdp11|vax|u3b|other) ;; "") cpu=other ;; *) echo "Unknown cpu type $cpu" exit 1 ;; esac if test "$small" = ,,,, -a $cpu = pdp11 then small=yes fi if test "$buflen" = ,,,, then if test "$small" = "no" -o "$small" = ,,,, then buflen=256 else buflen=128 fi fi if test "$uname" = ,,,, -a $USGREL -ge 20 then uname=yes fi if test "$ghname" = ,,,, -a $BSDREL -ge 42 then ghname=yes fi : check all the boolean flags for x in manually internet uname ghname v7mail small compadmin do eval y=\$$x case "$y" in no|,,,,)eval $x=,,,, ;; ""|yes) eval $x= ;; *) echo $x is a boolean flag. exit 1 ;; esac done : check that all numeric parameters are set and are numbers for x in umask dftexp maxgroups buflen lbuflen pathlen datelen namelen fpathlen do eval y=\$$x case "$y" in [0-9]|[0-9][0-9]|[0-9][0-9][0-9]|[0-9][0-9][0-9][0-9]|[0-9][0-9][0-9][0-9][0-9]) ;; ,,,,) echo "$x not set" exit 1 ;; *) echo "$x value should be numeric" exit 1 ;; esac done : Check that required values are specified for x in myorg mydomain newsusr newsgrp do eval y=\$$x if test "$y" = ,,,, then echo $x not set exit 1 fi done case "$mydomain" in ""|.*) ;; *) echo domain name should begin with a dot. exit 1 ;; esac if test "$admin" = ,,,, then admin=$user fi if test "$notify" = "" then notify=$admin fi if test "$termcap" = ,,,, then if test -f /usr/lib/libtermcap.a then termcap=-ltermcap elif test -f /usr/lib/libtermlib.a then termcap=-ltermlib elif test -f /usr/lib/libcurses.a then termcap=-lcurses else termcap=-ltermcap fi fi if test "$sendmail" = ,,,, then if test -f /usr/lib/sendmail then sendmail=/usr/lib/sendmail fi fi : on BSD systems, prefer /bin/mail over /usr/ucb/mail if test "$mailer" = ,,,, -a -f /bin/mail then mailer=/bin/mail fi : do some path searches y= for x in page more page pg dfteditor vi dfteditor ed mailer mail do if test "$y" = "" then y=$x else eval v=\$$y if test "$v" = ,,,, then IFS=: for z in $PATH do if test -f $z/$x then eval $y=$z/$x break fi done IFS=' ' fi y= fi done if test "$mailer" = ,,, then echo Can\'t find mail exit 1 fi if test "$dfteditor" = ,,,, then echo Can\'t find ed exit 1 fi for x in admsub page sendmail do eval y=\$$x if test "$y" = "" then eval $x=,,,, fi done if test "$compadmin" = "" then adminid=,,,, else adminid=`sed -n "s/^$admin:[^:]*:\([^:]*\):.*/\1/p" /etc/passwd` if test "$adminid" = "" then echo Can\'t find $admin in /etc/passwd file. exit 1 fi fi : 2.10.2 moved inews [Grrr!] if test -f $lib/inews then inews=$lib/inews else inews=$bin/inews fi if test $USGREL -ge 30 then index=strchr rindex=strrchr usg= else index=,,,, rindex=,,,, usg=,,,, fi grep -v ,,,, > config.h.tmp <<! #define USGREL $USGREL #define BSDREL $BSDREL #define USG$usg #define SMALL$small #define index $index #define rindex $rindex ! grep -v ,,,, > newsdefs.h.tmp <<! /* * newsdefs.h - defines for news related programs. * * This file is created by the setup program, and should be changed * by modifying the entries in config. */ #define N_UMASK $umask #define DFLTEXP ($dftexp*24L*3600L) #define DFTEDITOR "$dfteditor" #define DFLTSUB "$dftsub" #define ADMSUB "$admsub" #define PAGE "$page" #define TMAIL "$tmail" #define MAILER "$mailer" #define INEWS "$inews" #define RNEWS "$bin/rnews" #define POSTNM "$bin/postnm" #define LIBDIR "$lib #define SPOOLDIR "$spool #define BINDIR "$bin #define HOME "$home" #define NOTIFY "$notify" #define ADMIN "$admin" #define ROOTID $adminid #define MANUALLY$manually #define INTERNET$internet #define MYDOMAIN "$mydomain" #define MYNAME "$myname" #define UNAME$uname #define GHNAME$ghname #define SENDMAIL "$sendmail" #define V7MAIL$v7mail #define MYORG "$myorg" #define NEWSRC "$newsrc" #define MAXGROUPS $maxgroups #define BUFLEN $buflen #define LBUFLEN $lbuflen #define PATHLEN $pathlen #define DATELEN $datelen #define NAMELEN $namelen #define FPATHLEN $fpathlen ! if test "$home" != ,,,, then hdir=`logdir $home`/ else hdir= fi grep -v ,,,, > makedefs.tmp <<! LIBDIR=$hdir$lib SPOOLDIR=$hdir$spool BINDIR=$bin NEWSUSR=$newsusr NEWSGRP=$newsgrp HOME=$home CPU=$cpu USGREL=$USGREL BSDREL=$BSDREL TERMCAP=$termcap ! if cmp -s config.h.tmp config.h then /bin/rm config.h.tmp else /bin/mv config.h.tmp config.h fi if cmp -s newsdefs.h.tmp newsdefs.h then /bin/rm newsdefs.h.tmp else /bin/mv newsdefs.h.tmp newsdefs.h fi if cmp -s makedefs.tmp makedefs then /bin/rm makedefs.tmp else /bin/mv makedefs.tmp makedefs fi for x in $setups do $x -M done echo 'The modified time of this file indicates when setup was last run.' > setuptime sed -e 's/B,,,,/no/' -e 's/B$/yes/' -e '/,,,,/s/^/#/' -e 's/[ ],,,,//' > config.used <<! path $PATH lib $lib spool $spool bin $bin admin $admin compadmin B$compadmin newsusr $newsusr newsgrp $newsgrp home $home sys $sys cpu $cpu small B$small umask $umask dftexp $dftexp tmail $tmail mailer $mailer dftsub $dftsub admsub $admsub page $page notify $notify dfteditor $dfteditor manually B$manually mydomain $mydomain myname $myname myorg $myorg uname B$uname ghname B$ghname v7mail B$v7mail newsrc $newsrc maxgroups $maxgroups buflen $buflen lbuflen $lbuflen pathlen $pathlen datelen $datelen namelen $namelen fpathlen $fpathlen termcap $termcap ! !E!O!F! chmod +x lib/setup echo Part 3 of 7 extracted.