sources-request@genrad.UUCP (01/26/85)
# From: ka@hou3c # # Welcome to vnews release 2.11-B 1/17/85. # This is part 4 out of 7. # Feed me into sh (NOT csh). if test ! -d lib then mkdir lib fi if test ! -d postnews then mkdir postnews fi cat > lib/routines.doc <<\!E!O!F! .. Run this file through nroff (no macro packages needed) .. To get page boundaries, pipe the output of nroff though pr. .hy .na .ll 72 .de p .sp .. .de h .in 0 .sp 2 .ne 4 .nr h +1 \\nh)\ \ \\$1 .p .. .de i .in +4 .fi .. .de o .sp .in -4 .nf .. .h "INTRODUCTION" This file describes the contents of the lib directory. .p The rlib library is intended to simplify the task of writing news reading programs. Previously, there was no specific support for writing news reading programs, and in order to take advantage of existing software, programmers had to dig the routines out of the netnews software themselves. This library attempt collects a number of routines, in some cases modified to make them more general or to simplify the caller interface, into a central location where all users can share them. It is hoped that this library will unlimately evolve into a collection of routines used not just by the news reading software but by all the netnews software. .p There are certain limitations to this library. Because this code was designed and selected for its usefulness for use with vnews, it may not always do things in ways appropriate for other programs. On the other hand, certain functions that might be useful were not included because they had too much vnews specific code in them. In particular, writers of news reading programs will probably want to copy the article selection routines out of vnews/artseq.c and modify them to work for their particular application. This does not attempt to provide complete documentation on all the routines; so you may have to consult the code for details. .p .h "BASIC INFORMATION" The library source resides in a directory called "lib". In general, you should set .br LIB = ../lib .br in your makefiles. That way, your makefiles will run unchanged if they are placed in a directory parallel to the lib directory. You should compile your programs with -I$(LIB) so that they can access header files in lib, and link with $(LIB)/rpathinit.o and $(LIB)/rlib.a. The file rpathinit.o contains the pathinit routine; and rlib.a is an archive containing all the rest of the routines. .p To use many of these routines you must provide an error exit routine called xerror; a typical version is: .nf xerror(msg, a1, a2, a3, a4) char *msg; { printf(msg, a1, a2, a3, a4); putchar('\\n'); exit(2); } .fi There is a global variable called bfr which is a character array of LBUFLEN (currently 1024) bytes. Various routines in the library use this for scratch space; you can use it as well. Be careful not to rely on the value of bfr if you call another routine that might modify it. The following library routines are guarenteed not to use bfr: afree, ainit, bcopy, bzero, ckmalloc, clrunread, findgroup, getaddr, getopt, g_num, hfgets, hfree, hinit, inunread, launder, lcase, makehimask, nextgrp, ngmatch, nstrip, prefix, prevgrp, rename, replyname, rmnf, savestr, scopyn, setunread, and titmat. For convenience, a declaration of bfr appears in libextern.h. .h "HEADER FILES" This section lists the various header files. In some cases, you will have to see the descriptions of the routines that use the files for more details. .i .o artfile.h .i This include defines for accessing the artfile. .o arthead.h .i This header file defines the arthead structure used to hold and in-core copy of an article header. .o config.h .i This file specifies the version of UNIX you are running under. (UNIX is a trademark of AT&T Bell Laboratories.) It defines index and rindex to be strchr and strrchr, if necessary. It also defines BSDREL and USGREL. The values of these for various versions of UNIX are: .nf VERSION USGREL BSDREL Version 6 6 6 System III 30 6 System V 50 6 System V rel 2 52 6 Version 7 6 7 4.1 BSD 6 41 4.2 BSD 6 42 .fi .o defs.h .i This file includes lots of news related defines. It includes the file newsdefs.h, which is generated by the setup program, and also has a few defines of it's own. Some of the useful defines are: .nf Name Default Description MAXGROUPS 300 The maximum number of newsgroups BUFLEN 128/256 The size of a general purpose char array LBUFLEN 1024 The size of a big buffer DATELEN 48 The maximum size of a date FPATHLEN 64 The maximum length of a file name NAMELEN 64 The maximum size of a message ID or address PATHLEN 512 The maximum size of a Path: entry .fi .o libextern.h .i Declares various global variables defined in the library. Bfr is declared here, as are the various variables set up by pathinit and getuser. .o newsrc.h .i Defines for the .newsrc accessing routines. .o ng.h .i Defines for accessing the newgroups file. .o roptions.h .i Defines for the roptions routine. .o stroff.h .i This defines one macro called stroff(element, structure). It returns the offset of the specified element into the given structure. .in -4 .p The rest of this file details the various routines available. .h PATHS To avoid the necessity of hard coding paths, machine names, and so forth in your program, these routines are provided. Declarations for all the variables set by these routines appear in libextern.h. .i .o pathinit() .i This routine fills in the following character arrays: .nf .in +4 SPOOL: The netnews spool directory. LIB: /usr/lib/news or equivelant. FULLSYSNAME: System name as known by neighbors. DOMAIN: Concatenated to FULLSYSNAME to form domain name. XINEWS: Path of inews program. MAILPARSER: Path of sendmail or recmail program. .in -4 .fi A number of other library routines assume that pathinit has been called. .o isadmin() .i Returns nonzero if user is the netnews administrator or the superuser. .o getpaths() pgetpaths() .i Sets username to the user's login name and userhome to the user's home directory. The latter version always goes to the /etc/passwd file and thus cannot be subverted by modifying the environment. .h "NEWSGROUPS" For convenience, each newsgroups is assigned a small integer which uniquely identifies it. These numbers will vary from machine to machine and therefore can only be used locally. The file /usr/lib/news/groupfile maintains this mapping. For reliability, a backup copy is kept in /usr/lib/news/groupfile.bak. .p To access this file, #include\ "ng.h" and use the following routines. .i .o gfopen() gfclose() .i These routines open and close the newsgroup file. The routine gfopen also sets the global variable maxng to the largest newsgroup number in use. .o ALL_GROUPS(g) { statement... } (struct ngrec g) .i This macro sets up a loop through all the newsgroups. The entries in the ngrec structure are .nf char g_name[MAXNGNAME]; /* newsgroup name */ short g_num; /* newsgroup number */ short g_flags; /* various flags */ .fi The only flag currently in use is G_MOD, which indicates a moderated or fa.all group. .h "ARTFILE" Artfile keeps track of all the articles in the system. To use these routines, #include "artfile.h". Artfile.h contains two typedefs. An ARTNO is the number of an article within a newsgroup. This is currently defined to be int, but will be changed to "long" when article numbers reach 32000. A DPTR is the address of an article record in artfile. The value of a DPTR is only valid within a given program; therefore if you want to pass the identity of an article to another program, you should pass the message-ID of the article. There is a special value DNULL used to indicate a null DPTR. There is one artrec structure for each article on the system. The artrec structure contains the following entries of interest: long a_subtime; /* when article was posted */ long a_rectime; /* when article was received */ long a_exptime; /* when article expires (0 if not specified) */ DPTR a_parent; /* article this is a followup to */ DPTR a_children; /* linked list of followups */ DPTR a_childchain; /* link for followup chain */ short a_flags; /* various flags */ char a_ngroups; /* number of newsgroups article posted to */ struct artgroup { short a_ngnum; /* newsgroup number */ short a_artno; /* article number */ DPTR a_ngchain; /* next article in this newsgroup */ } a_group[MAXNG]; /* list of groups article posted to */ char *a_ident; /* message id */ char *a_title; /* article subject line */ char *a_from; /* author of article (real name omitted) */ char *a_file; /* file containing article */ char a_nkwords; /* number of keywords on article */ char *a_kword[A_MAXKW]; /* keywords */ .fi A_flags&A_NOFILE will be true if this article does not appear in the spool directory. Currently, this can occur if a followup is received before the original article. In that case, a dummy entry will be made for the original article until it arrives. Later, this may also indicate that the article has been cancelled or expired. .p Currently, keywords are not stored in artfile. However, most of the code is in place so that this can be changed if keywords are needed. .i .o afopen() .i Open artfile. A corresponding close routine could be written if there is a need. .o ainit(a) struct artrec *a; afree(a) struct artrec *a; .i Ainit initializes and artrec structure and afree frees up the storage associated with it. Both of these routines are currently no-ops but that may change in the future. .o lookart(msgid, a) char *msgid; struct artrec *a; .i Get the record for the article. Returns the address of the record, or DNULL on failure. .o readrec(dp, a) DPTR dp; struct artrec *a; .i Read an article record given its address. .o BKWD_GROUP(ngnum, artno, dp, a) { statements... } .i This macro sets up a "for" loop to fetch all the articles in the newsgroup numbered ngnum. For each article, artno is set to the article number within the group, a is set to the article record, and dp is set to the address of the article record. The highest numbered records are produced first. This means you will normally have to sort the articles before you display them. On the other hand, this order has the advantage that you can stop scanning the newsgroup when you reach the lowest numbered article marked unread in the .newsrc file. .h ".NEWSRC PROCESSING ROUTINES" These routines maintain an in-core copy of the .newsrc file and the the groupfile. You should #include "newsrc.h" which defines the ngentry structure. (There is one such structure for each group.) .i .o openrc() .i Open the .newsrc file, creating it if necessary. A file pointer is returned. Getuser must be called before this routine is used. .o readinrc(fp) FILE *fp; .i Read in the .newsrc and groupfile files. fp is the file pointer returned by openrc, or NULL in which case only the groupfile is read. This routine should be called before any of the following routines are used. To use this routine, you must provide a routine called "wewant", which takes the name of a newsgroup, and returns true if the newsgroup should be appended to the .newsrc file. Wewant generally tests whether the user asked for the group in the -n option. .o writeoutrc() .i Write out an updated version of the .newsrc file. This routine is a no-op if readinrc was not called, or was called with a NULL argument .o nextgrp(ngp) struct ngentry *ngp; .i Returns the next group in the .newsrc file, or the first group if ngp is NULL. .o prevgrp(ngp) .i Returns the previous group in the .newsrc file. .o setupgrp(ngp, max) struct ngentry *ngp; ARTNO max; .i Make the specified group the current group. Max is the maximum article number apprearing in the group, which will be the first article number generated by the BKWD_GROUP macro. The global variable minartno is set to the smallest unread article and maxartno is set to max. .o isunread(artno) setunread(artno) clrunread(artno) .i These routines test, set, or clear the "unread article" indication for a given article. The group of the article is the group specified in the last call to setupgrp. .o findgroup(name) .i Return the address of the ngentry strucure for the group. .o numtong(num) .i Takes a newsgroup number and returns the address of the ngentry for the newsgroup. Currently this routine does not check its argument for validity. .o g_num(ngp) .i Return the number of the group. .h "ARTICLE HEADERS" The netnews code includes some routines for dealing with article headers, but they currently require about 5K to store a headers and still don't allocate enough space to store the "References:" line. These routines use dynamicly allocated memory. To use them, #include "arthead.h". .i .o hinit(hp) struct arthead *hp; hfree(hp) struct arthead *hp; .i These routines initialize and free the storage associated with an arthead structure. Hinit does not have to be called for static or global variables since they are initialize to zero automaticly. .o gethead(hp, fp) .i This routine reads in a news header. It returns fp on success and NULL on failure. .o hxchg(hp1, hp2) .i This routine exchanges the value of two arthead structures. There is no way to copy an arthead structure, but an exchange operation will serve for most purposes. .o hfgets(buf, buflen, fp) .i Reads a USENET header line. This routine is like fgets except that 1) it handles continuation lines, and 2) it always reads in the entire line, even if it doesn't fit. The part that doesn't fit is discarded. .h "DATE CONVERSION" .i .o cgtdate(datestr) .i This routine converts a date string to UNIX internal format. Because this routine is so big (a little over 10K), there is also a program called /usr/lib/news/cgtdate which invokes this routine on its argument and writes the converted value (in decimal) to the standard output. .o getadate(datestr) .i This routine converts a date in RFC 822 format to UNIX internal format. .h "MISCELLANEOUS NETNEWS ORIENTED ROUTINES" .i .o cancel(ofp, hp, notauthor) .i The article whose header has been read into hp is cancelled. If the notauthor flag is set, the article will be cancelled locally only rather than net-wide. Ofp is a file pointer that is used to write an error message on if the attempt to fork fails. .o dirname(group, buf) .i Generates the name of the directory containing the newsgroup in buf and returns buf. .o getaddr(name, result) char *name; char result[NAMELEN]; .i Given the contents of a "From:" line to the right of the colon, place the machine address in "result". (E. g. generate "user@x" from "user@x (Real Name)". .o launder(newsgroups) .i This routine should be called when generating followups. It does the net.general to net.followup conversion. .o makehimask(sublist, newsgroup) .i Unless the newsgroup is specificly asked for in the subscription list, append !newsgroup to the subscription list. Used to keep people from seeing groups like control unless they really want to. .o ngmatch(nglist, sublist) char *nglist, *sublist; .i Returns nonzero if one of the newsgroups in nglist is matched by an entry in the subscription list. Unlike the 2.10 netnews routine or the same name, neither argument needs a trailing comma. .o replyname(hp, buf) .i Generates the name of the person to send replies to this article to. .o roptions(argv, rcfp) .i This routines does the readnews option processing. Argv is the arguments to the program. Rcfp is refers to the .newsrc file; it is used to read the "options " line at the top of the .newsrc file. To access the options set by roptions, #include "roptions.h". .o rmnf(s) .i Remove any trailing " - (nf)" from the string. Returns nonzero if removed. .o titmat(titles, curtitle) .i See if curtitle contains one of the strings listed in titles. The global variable "titles" is set by the roptions routine. .o tomsgid(id) .i The argument should be a message ID or an article ID. If it appears to be the latter, it is converted to a message ID. .h "STRING AND MEMORY UTILITY ROUTINES" The remaining routines are not very netnews specific. .i .o bcopy(from, to, n) .i Copy n bytes. .o bzero(block, n) .i Clear n bytes of memory. .o ckmalloc(nbytes) .i Invokes malloc and calles xerror if the malloc fails. All the routines in rlib call ckmalloc instead of malloc. .o lcase(s) .i Convert the string to all lower case. .o nstrip(s) char *s; .i Strip off trailing newlines, tabs, and spaces. Returns nonzero if a newline was present. .o prefix(s, pfx) .i Return nonzero if pfx is a prefix of s. .o savestr(s) char *s; .i Return a copy of s in a block of memory obtained from ckmalloc. .o scopyn(from, to, n) .i Copy a character string, truncating the string if necessary for make it fit. "n" is the size of the destination. Unlike strncpy, this routine always terminates the result with a nul. .o sindex(s1, s2) .i Return a pointer to the first occurance of the string s2 within s1, or NULL if not found. .o strpbrk(s1, s2) .i Return a pointer to the first character of s1 that also occurs in s2, or NULL if no such character exists. .o strspn(s1, s2) strcspn(s1, s2) .i Return the length of the longest prefix of s1 sonsisting of characters in (for strspn), or not in (for strcspn), s2. .o strtok(s1, s2) .i The System III strtok routine. .h "OTHER UTILITY ROUTINES" .i .o ckfopen(file, mode) .i Calls fopen, and invokes xerror if the fopen fails. .o opendir(name) closedir(dirp) readdir(dirp) rewinddir(dirp) .i The Berkeley directory access routines. Opendir opens a directory and returns a (DIR *) pointer, or NULL on failure. Readdir reads the next directory entry and returns a ponter to a struct direct, or NULL on eof. Closedir closes a directory. Rewinddir goes back to the beginning of a directory and clears any buffered information. .o getopt(argc, argv, optlist) .i The System III command argument parsing routine. .o rename(from, to) .i Rename a file, deleting any existing file named "to". .h SYNOPSYS This section gives an alphabetical listing of all the routines in the library: .sp .nf void addrc(ngp) struct ngentry *ngp; void afopen() void afree(a) struct artrec *a; void ainit(a) struct artrec *a; void bcopy(from, to, n) char *from, *to; int n; char bfr[LBUFLEN]; void bzero(mem, n) char *mem; int n; int cancel(ofp, hp, notauthor) FILE *ofp; struct arthead *hp; int notauthor; time_t cgtdate(datestr) char *datestr; FILE *ckfopen(filename, mode) char *filename, *mode; char *ckmalloc(nbytes) int nbytes; void closedir(dirp) DIR *dirp; void clrunread(artno) ARTNO artno; char *dirname(group, buf) char *group, *buf; struct ngentry *findgroup(name) char *name; long getadate(datestr) char *datestr; char *getaddr(full, mach) char *full, mach[NAMELEN]; FILE *gethead(hp, fp) struct arthead *hp; FILE *fp; int getopt(argc, argv, optstr) int argc; char **argv; char *optstr; void getuser(); void gfclose(); void gfopen(); int g_num(ngp) struct ngentry *ngp; char *hfgets(buf, buflen, fp) char *buf; int buflen; FILE *fp; void hfree(hp) struct arthead *hp; void hinit(hp) struct arthead *hp; void hxchg(hp1, hp2) struct arthead *hp1, *hp2; char *index(str, c) char *str; char c; int isadmin(); int isre(title) char *title; int isunread(artno) ARTNO artno; void launder(newsgroups) char *newsgroups; void lcase(str) char *str; DPTR lookart(msgid, a) char *msgid; struct artrec *a; void makehimask(sublist, group) char *sublist, *group; struct ngentry *nextgrp(curgrp) struct ngentry *curgrp; void pathinit(); int ngmatch(nglist, sublist) char *nglist, *sublist; int nstrip(str) char *str; DIR *opendir(name) char *name; FILE *openrc() void pgetuser() int prefix(str, pfx) char *str, *pfx; struct ngentry *prevgrp(curgrp) struct ngentry *curgrp; struct direct *readdir(dirp) DIR *dirp; void readrec(dp, a) DPTR dp; struct artrec *a; void readinrc(rcfp) FILE *rcfp; int rename(from, to) char *from, *to; char *replyname(hp, buf) struct arthead *hp; char buf[PATHLEN]; void rewinddir(dirp) DIR *dirp; int rmnf(title) char *title; void roptions(argv, rcfp) char **argv; FILE *rcfp; char *savestr(str) char *str; void scopyn(from, to, tosize) char *from, *to; int tosize; void setunread(artno) ARTNO artno; void setupgrp(ngp, max) struct ngentry *ngp; ARTNO max; char *sindex(s1, s2) char *s1, *s2; char *strcspn(s1, s2) char *s1, *s2; char *strpbrk(s1, s2) char *s1, *s2; char *strspn(s1, s2) char *s1, *s2; char *strtok(s1, s2) char *s1, *s2; int titmat(titles, title) char **titles, *title; void tomsgid(id) char *id; void writeoutrc(); .fi !E!O!F! cat > lib/setup.doc <<\!E!O!F! .. Run this file through nroff (no macro packages needed) .. To get page boundaries, pipe the output of nroff though pr. .hy .na .ll 72 .de p .sp .. .de h .in 0 .sp 2 .ne 4 .nr h +1 \\nh)\ \ \\$1 .p .. .de i \f3\\$1\f1\\$2 .. .de b \f2\\$1\f1\\$2 .. .de n .sp .in 0 \\$1 .in 4 .. .ce Configuring the Netnews Software .sp 3 The setup program is used to configure the netnews software. To run it, simply type "sh setup". The setup program reads if file called "config", which you must create, and sets up the netnews library. The setup program attempts to provide sensible defaults, but you must never the less provide certain entries. .p Lines in the config file beginning with a "#" are considered to be comment lines and are ignored. Other lines should consist of a parameter name followed by a value. Certain parameters are boolean flags which should be set to "yes" or "no". If the name of a boolean flag is given without specifying a value, the flag is set to "yes" A sample config file appears below: .sp .nf newsusr news newsgrp news myorg BTL, Holmdel, NJ. mydomain .UUCP spool /tools/netnews/spool notify internet no .fi .p The first four lines are required entries which you must provide values for. .n newsusr This is the owner (user name) of .i inews . If you are a superuser, you should probably create a new user id (traditionally .b news ) and use this id. If you are not a superuser, you can use your own user id. If you are able to, you should create a mail alias .b usenet and have mail to this alias forwarded to you. This will make it easier for other sites to find the right person in the presence of changing jobs and out of date or nonexistent directory pages. .n newsgrp This is the group (name) to which .i inews belongs. The same considerations as NEWSUSR apply. .n myorg This should be set to the name of your organization. Please keep the name short, because it will be printed, along with the electronic address and full name of the author of each message. 40 characters is probably a good upper bound on the length. If the city and state or country of your organization are not obvious, please try to include them. If the organization name begins with a `/', it will be taken as the name of a file. The first line in that file will be used as the organization. This permits the same binary to be used on many different machines. A good file name would be `/usr/lib/news/organization'. For example, an organization might read ``Bell Labs, Murray Hill'', or ``U.C. Berkeley'' or ``MIT'' or ``Computer Corp. America, Cambridge, Mass''. .n mydomain When generating internet addresses, this domain will be appended to the local site name to form mailing address domains. For example, on system ucbvax with user root, if MYDOMAIN is set to ``.UUCP'', addresses generated will read ``root@ucbvax.UUCP''. If MYDOMAIN is ``.Berkeley.ARPA'', the address would be ``root@ucbvax.Berkeley.ARPA''. If your site is in more than one domain, use your primary domain. The domain always begins with a period, unless the local site name contains the domain; in this case MYDOMAIN should be the null string. .in 0 .p The following entries are not required for the setup program, but the defaults used by the setup program may not work for you. .n admin This is the login name of the USENET administrator for this machine. This may be different from newsusr. The default is the person running the setup program. .n internet If your system has a mailer that understands ARPA Internet syntax addresses (user@domain) turn this on, and replies will use the From or Reply-To headers. Otherwise, set it to no and replies will use the Path header. The default value for this parameter is "yes" because everyone was supposed to install an internet mailer back in January of 1984. .n sys This is the version of UNIX you are running under. (UNIX is a trademark of AT&T Bell Laboratories.) The following verions of UNIX are defined: .nf sys3 AT&T System III sys5 AT&T System V release 1 sys5r2 AT&T System V release 2 v7 AT&T Version 7 UNIX 4.1bsd Berkeley release 4.1 4.2bsd Berkeley release 4.2 .fi Hopefully, this list will be expanded in the future. For now, simply choose the one that is closest to your version. If you omit this paramter, setup will normally select the correct value. .n path This is the path search used by the setup program. The default is the value of $PATH. .in 0 .p The remaining parameters can be tuned as you see fit, but netnews should run OK if you just use the defaults. .n small True if you are running on a 16 bit machine such as a PDP-11. The default is yes if you are running on a PDP-11 under USG UNIX, and no otherwise. .n dftsub The default subscription list. If a user does not specify any list of newsgroups, this will be used. Popular choices are .b all and .b general,all.general . The default is .b all . .n admsub This newsgroup (or newsgroup list) will always be selected unless the user specifies a newsgroup list that doesn't include ADMSUB on the command line. That is, as long as the user doesn't use the .b -n flag to readnews on the command line, ADMSUB will always be selected. The default is .b general,all.announce . The intent of this parameter is to have certain newsgroups which users are required to subscribe to. .n umask Mask for .i umask(2) system call. Set to something like 022 for a secure system. Unsecure systems might want 002 or 000. This mask controls the mode of news files created by the software. Insecure modes would allow people to edit the files directly. .n dftexp The default number of days after which an article will expire. 2 weeks (14 days) is the default choice. .n tmail This is the version of the Berkeley .i Mail program that has the \-T option. If left undefined, the .b -M option to .i readnews will be disabled. .n page The default program for which articles will be piped to for paging. This can be disabled or changed by the environment variable PAGER. If you have it, the Berkeley .i more command should be used, since the + option allows the headers to be skipped. If not specified, setup will look around your system in an attempt to find a suitable program. .n dfteditor This is the full path name of the default editor to use during followups and replies. It should be set to the most popular text editor on your system. As distributed, .b vi is used. .n sendmail This is the name of a sendmail program that understands the .b -t option. .n mailer This is the name of the mail program that recmail will invoke. Unless you specify "internet no", this must be a mail program that understand internet addresses. The default is mail. .n home Some sites will want to run the same version of the object code on multiple computers. If home is defined, then the directories lib and spool are assumed to be relative to the login directory of the user home. .n compadmin Normally, the numeric user id of the netnews administrator (specified by admin) is compiled into the netnews programs. If compadmin is set to "yes", then the individual netnews program will search the password file to know the numeric user id of the netnews administrator. .n myname The name of your machine. If you don't specify this, the netnews programs will determine your system name either by using the uname or gethostname system calls or by scanning /usr/include/whoami.h. .n uname Set this if the uname system call is available locally, even though you are not a USG system. This defaults to "yes" if you are on a USG system. .n ghname Define this if the 4.2BSD gethostname system call is available. This defaults to "yes" if you are running 4.2 BSD. .n v7mail Define this if your system uses V7 mail conventions. The V7 mail convention is that a mailbox contains several messages concatenated, each message beginning with a line reading ``From user date'' and ending in a blank line. If this is defined, articles saved will have these lines added so that mail can be used to look at saved news. .n spool This directory contains subdirectories in which news articles will be stored. It is normally /usr/spool/news. .PP Briefly, for each newsgroup (say .b net.general ) there will be a subdirectory /usr/spool/news/net/general containing articles, whose filenames are sequential numbers, e.g. /usr/spool/news/net/general/1, etc. .PP Each article file is in a mail-compatible format. It begins with a number of header lines, followed by a blank line, followed by the body of the article. The format has deliberately been chosen to be compatible with the ARPANET standard for mail documented in RFC 822. .PP You should place news in an area of the disk with enough free space to hold news you intend to keep on line. The total volume of news in net.all currently runs about 3MB/week. If you expirenews after the default 2 weeks, you will need about 6MB of disk space (plus some extra as a safety margin and to allow for increased traffic in the future.) If you only receive some of the newsgroups, or expire news after a different interval, these figures can be adjusted accordingly. Other newsgroup classes do not add much to the volume; fa.all accounts for only about 80KB/week, and btl.all+bell.all are only about 450KB/week. .n lib This directory will contain various system files. It is normally /usr/lib/news. .n bin This is the directory in which .i inews , .i readnews , and .i checknews are to be installed. This is normally /usr/bin. If you decide to set BINDIR to a local binary directory, you should consider that the .b rnews command must be in a directory that can be found by .b uuxqt , which only searches /bin and /usr/bin unless you modify uuxqt. .n maxgroups The maximum number of newsgroups that the software will support. You may have to increase this as the network grows. .n "buflen, lbuflen, datelen, fpathlen, namelen, pathlen" See the description of defs.h in the file routines.doc for a description of these. Decreasing these values to save space should not be done lightly. !E!O!F! cat > lib/setupgrp.c <<\!E!O!F! #include <stdio.h> #include <ctype.h> #include "config.h" #include "defs.h" #include "newsrc.h" #include "artfile.h" char *savestr(), *ckmalloc(); /* * Set up the bit map, curng, ngsize, and groupdir for this newsgroup. * If no newsrc was read in then we don't bother with the bit map. */ char *bitmap; /* which articles have been read */ ARTNO minartno; /* first unread article */ ARTNO maxartno; /* last article */ setupgrp(ngp, max) struct ngentry *ngp; ARTNO max; { int mapsize = (max >> 3) + 1; if (curng != NULL) { updaterc(); free(bitmap); } curng = ngp; maxartno = max; bitmap = ckmalloc(mapsize); /* * Set up the bit map. * * The key to understanding this piece of code is that a bit is set iff * that article has NOT been read. Thus, we fill in the holes when * commas are found (e.g. 1-20,30-35 will result in filling in the 21-29 * hold), and so we assume the newsrc file is properly ordered, the way * we write it out. */ { register char *p, punct = ','; register ARTNO cur = 0; ARTNO next; bzero(bitmap, mapsize); /* check for first unread article */ p = ngp->ng_bits; if (p == NULL) p = ""; if (p[0] == '1' && p[1] == '-') { p += 2; cur = atoi(p); while (isdigit(*p)) p++; } minartno = cur + 1; /* process rest of bit string */ while (*p) { while (!isdigit(*p) && *p) p++; if (!*p) break; next = atoi(p); if (next > maxartno) /* "Can't happen" */ next = maxartno + 1; if (punct == ',') { while (++cur < next) { setunread(cur); } } cur = next; while (!ispunct(*p) && *p) p++; punct = *p; } while (++cur <= maxartno) setunread(cur); return 0; } } updaterc() { register int cur, next = 1; register char *ptr; extern int rcreadok; extern char bfr[]; if (!rcreadok || !curng) return; bfr[0] = bfr[1] = '\0'; for (;;) { ptr = &bfr[strlen(bfr)]; while (next <= maxartno && isunread(next)) next++; if (next > maxartno) break; cur = next; while (next <= maxartno && ! isunread(next)) next++; if (cur + 1 == next) sprintf(ptr, ",%d", cur); else sprintf(ptr, ",%d-%d", cur, next - 1); } if (curng->ng_bits != NULL) free(curng->ng_bits); curng->ng_bits = savestr(bfr + 1); /* the +1 skips the leading comma */ } !E!O!F! cat > lib/str.h <<\!E!O!F! /* string declarations */ char *index(), *rindex(), *sindex(), *strpbrk(); char *ckmalloc(), *savestr(), *nsavestr(); #define scopy(from, to) strcpy(to, from) #define equal(s1, s2) (strcmp(s1, s2) == 0) !E!O!F! cat > lib/strcspn.c <<\!E!O!F! /* * strcspn - find length of initial segment of s1 consisting entirely * of characters not from s2 */ int strcspn(s1, s2) char *s1; char *s2; { register char *scan1; register char *scan2; register int count; count = 0; for (scan1 = s1; *scan1 != '\0'; scan1++) { for (scan2 = s2; *scan2 != '\0';) /* ++ moved down. */ if (*scan1 == *scan2++) return(count); count++; } return(count); } !E!O!F! cat > lib/stroff.h <<\!E!O!F! #define stroff(member, str) ((char *)&((struct str *)0)->member - (char *)0) !E!O!F! cat > lib/strpbrk.c <<\!E!O!F! #include "config.h" #if USGREL < 30 /* * strpbrk - find first occurrence of any char from s2 in s1 * Written by Henry Spencer. */ #define NULL 0 char * /* found char, or NULL if none */ strpbrk(s1, s2) char *s1; char *s2; { register char *scan1; register char *scan2; for (scan1 = s1; *scan1 != '\0'; scan1++) { for (scan2 = s2; *scan2 != '\0';) /* ++ moved down. */ if (*scan1 == *scan2++) return(scan1); } return(NULL); } #endif !E!O!F! cat > lib/strpbrk.u3b <<\!E!O!F! .file "strpbrk.u3b" # think of this line as an offering to the gods # char *strpbrk(s1, s2) char *s1, *s2; # Finds first occurance in s1 of a character in s2. .text .globl strpbrk .align 4 strpbrk: save &2 # save r7 and r8 movw 0(%ap), %r0 # r0 = s1 movw 4(%ap), %r8 # r8 = s2 movw &0, %r2 # string termination character jmp L2 L1: # while (*s1 != '\0') { movw %r8, %r7 # get s2 locce %r7, %r1, %r2 # strchr(s2, *s1) je L4 # if found, return addw2 &1, %r0 # increment s1 L2: movb 0(%r0), %r1 # get *s1 jne L1 # loop if not at end of string movw &0, %r0 # set s1 to NULL L4: ret &2 # and return s1 !E!O!F! cat > lib/strspn.c <<\!E!O!F! /* * strspn - find length of initial segment of s1 consisting entirely * of characters from s2 */ int strspn(s1, s2) char *s1; char *s2; { register char *scan1; register char *scan2; register int count; count = 0; for (scan1 = s1; *scan1 != '\0'; scan1++) { for (scan2 = s2; *scan2 != '\0'; scan2++) if (*scan1 == *scan2) break; if (*scan2 == '\0') return(count); count++; } return(count); } !E!O!F! cat > lib/strtok.c <<\!E!O!F! /* * Get next token from string s1 (NULL on 2nd, 3rd, etc. calls), * where tokens are nonempty strings separated by runs of * chars from s2. Writes NULs into s1 to end tokens. s2 need not * remain constant from call to call. */ #define NULL 0 static char *scanpoint = NULL; char * /* NULL if no token left */ strtok(s1, s2) char *s1; register char *s2; { register char *scan; char *tok; register char *scan2; if (s1 == NULL && scanpoint == NULL) return(NULL); if (s1 != NULL) scan = s1; else scan = scanpoint; /* * Scan leading delimiters. */ for (; *scan != '\0'; scan++) { for (scan2 = s2; *scan2 != '\0'; scan2++) if (*scan == *scan2) break; if (*scan2 == '\0') break; } if (*scan == '\0') { scanpoint = NULL; return(NULL); } tok = scan; /* * Scan token. */ for (; *scan != '\0'; scan++) { for (scan2 = s2; *scan2 != '\0';) /* ++ moved down. */ if (*scan == *scan2++) { scanpoint = scan+1; *scan = '\0'; return(tok); } } /* * Reached end of string. */ scanpoint = NULL; return(tok); } !E!O!F! cat > lib/titmat.c <<\!E!O!F! /* * Match title. */ titmat(title, titlist) char *title; register char **titlist; { char *sindex(); while (*titlist) { if (sindex(title, *titlist)) return 1 ; titlist++ ; } return 0 ; } char * sindex(s1, s2) register char *s1 ; /* string being searched */ register char *s2 ; /* string being scanned for */ { if (*s2 == '\0') return s1 ; while (*s1) { if (*s1 == *s2 && prefix(s1, s2)) return s1 ; s1++ ; } return 0 ; } !E!O!F! cat > lib/tomsgid.c <<\!E!O!F! #include "config.h" #include "defs.h" /* * Convert an article id to a message id if it's not already a message id. */ tomsgid(id) char *id ; { char lbuf[NAMELEN]; register char *p ; char *index() ; if (id[0] != '<') { strcpy(lbuf, id); p = index(lbuf, '.'); if (p == 0) { return; } *p++ = '\0'; /* * It may seem strange that we hardwire ".UUCP" in * here instead of MYDOMAIN. However, we are trying * to guess what the domain was on the posting system, * not the local system. Since we don't really know * what the posting system does, we just go with the * majority - almost everyone will be a .UUCP if they * didn't fill in their Message-ID. */ sprintf(id, "<%s@%s%s>", p, lbuf, ".UUCP"); } } !E!O!F! cat > lib/vprintf.h <<\!E!O!F! /* * These defines allow you to define routines that call printf on their * arguments in a way that at least marks them as machine dependent. * Example: * * fatal(VPARGS) * VPDCL; * { * VFPRINTF(stderr, VPARGS); * exit(1); * } * * Later: use varargs.h. */ #define VPARGS msg, a1, a2, a3, a4 #define VPDCL char *msg; #define VPRINTF(args) printf(VPARGS) #define VFPRINTF(fp, args) fprintf(fp, VPARGS) #define VSPRINTF(s, args) sprintf(s, VPARGS) !E!O!F! cat > lib/write.c <<\!E!O!F! #include <stdio.h> #include "af.h" #include "libextern.h" long lseek(); /* * Write a record to the data base. We can't use stdio because fseek * doesn't work under 4.1 BSD. */ writerec(a, fd) struct artrec *a ; int fd ; { int i ; register char *p, *q ; char **pp ; bfr[0] = A_PREFIX ; bcopy((char *)a, bfr + 1, A_WRTLEN) ; bcopy((char *)a->a_group, bfr + 1 + A_WRTLEN, i = a->a_ngroups * sizeof(*a->a_group)) ; p = bfr + 1 + A_WRTLEN + i ; pp = &a->a_ident ; i = (a->a_flags & A_DUMMY)? 1 : 4 + a->a_nkwords ; while (--i >= 0) { for (q = *pp++ ; *p++ = *q++ ; ) ; } if (write(fd, bfr, p - bfr) != p - bfr) xerror("Write error in writerec") ; } writeptr(p, dp) DPTR p, dp ; { if (lseek(affd, (long)dp, 0) < 0) xerror("seek %ld failed, writeptr %ld", dp, p) ; if (write(affd, (char *)&p, sizeof p) != sizeof p) xerror("write failed, writeptr(%ld, %ld)", p, dp) ; } !E!O!F! cat > postnews/artlist.c <<\!E!O!F! /* * This routine generates a list of articles for postnews. */ #include <stdio.h> #include <sys/types.h> #include "config.h" #include "artfile.h" #include "ng.h" artlist(ngname, pattern) char *ngname, *pattern ; { static struct ngrec ng ; struct artrec a ; ARTNO artno ; DPTR dp ; static int first = 1 ; if (first || strcmp(ngname, ng.g_name) != 0) { gfopen() ; ALL_GROUPS(ng) { if (strcmp(ng.g_name, ngname) == 0) goto found ; } xerror("%s does not appear in groupfile", ngname) ; found: gfclose() ; } if (first) { afopen() ; first = 0 ; } fputs("NUMB AUTHOR TITLE\n", stdout) ; BKWD_GROUP(ng.g_num, artno, dp, a) { if (a.a_flags & A_DUMMY) continue ; if (sindex(a.a_title, pattern) || sindex(a.a_from, pattern)) { printf("%-5d %.16s\t", artno, a.a_from) ; if (strlen(a.a_from) < 10) putchar('\t') ; if (strlen(a.a_from) < 2) putchar('\t') ; printf("%.40s\n", a.a_title) ; } } } !E!O!F! cat > postnews/distlist <<\!E!O!F! # This file contains descriptions of the various distributions, and is # used to build the /usr/lib/news/distributions file which is used by # postnews. Unfortunately, this list is probably not complete. Please # mail any additions to ihnp4!hou3c!ka. local Local to this site unm University of New Mexico um University of Maryland wat Universtiy of Waterloo atl Atlanta ba SF Bay Area chi Chicago cmh Columbus, Ohio la Los Angeles ho AT&T Holmdel location ih AT&T Indian Hill location cb AT&T Columbus location mh AT&T Murrey Hill location dr AT&T IS Denver location ont Onterio ca California ga Georgia nj New Jersey ny New York oh Ohio or Oregon ne New England intel Intel tek Tektronix btl AT&T Bell Labs att AT&T bell Bell operating companies usa United States can Canada na North America uk United Kingdom eunet Europe world Everywhere on Usenet in the world (same as net) !E!O!F! cat > postnews/genmakefile <<\!E!O!F! LIB=../lib . $LIB/makedefs exec > makefile cat <<! # makefile 2.11-B 1/12/85 LIB=$LIB ! cat $LIB/makedefs cat <<\! POSTNEWS = postnews.o artlist.o $(LIB)/rpathinit.o $(LIB)/rlib.a POSTREPLY = postreply.o $(LIB)/rpathinit.o $(LIB)/rlib.a POSTNM = postnm1.o postnm2.o postnm3.o postnm4.o postnm5.o $(LIB)/rpathinit.o $(LIB)/rlib.a RECMAIL = recmail.o CFLAGS = $(DEBUG) -I$(LIB) DEBUG = -O all: makefile postnews postreply postnm distributions gparent.wm makefile: genmakefile $(LIB)/makedefs genmakefile @echo 'Makefile changed, so restart make.' @sh -c 'exit 22' install: all $(LIBDIR)/distributions $(LIBDIR)/moderators -/bin/mv $(BINDIR)/postnews $(BINDIR)/opostnews /bin/cp postnews postnm gparent $(BINDIR) /bin/cp postreply $(LIBDIR)/postreply postnews: $(POSTNEWS) $(CC) $(DEBUG) -o $@ $(POSTNEWS) postreply: $(POSTREPLY) $(CC) $(DEBUG) -o $@ $(POSTREPLY) postnm: $(POSTNM) $(CC) $(DEBUG) -o $@ $(POSTNM) recmail: $(RECMAIL) $(CC) $(DEBUG) -o $@ $(RECMAIL) distributions: distlist makedist > distributions gparent.wm: gparent.wm.c $(CC) gparent.wm.c a.out > gparent.wm rm a.out $(LIBDIR)/distributions: distributions -/bin/mv $(LIBDIR)/distributions $(LIBDIR)/odistributions /bin/cp distributions $(LIBDIR)/distributions $(LIBDIR)/moderators: /bin/cp moderators $@ postnews.o postreply.o recmail.o: $(FRC) postnm1.o postnm2.o postnm3.o postnm4.o postnm5.o: postnm.h $(FRC) FRC: ! !E!O!F! chmod +x postnews/genmakefile cat > postnews/gparent <<\!E!O!F! #!/bin/sh a=${1-${A?}} sed -e '1,/^$/d' -e 's/^/> /' $a !E!O!F! chmod +x postnews/gparent cat > postnews/gparent.ml <<\!E!O!F! ; This mlisp macro reads in the body of the article being followed up, ; preceding each line with a "> ". ; It is intended to be bound to ^X^Y. (defun (gparent (end-of-file) (save-excursion (set-mark) (insert-file (getenv "A")) (re-search-forward "^$") (next-line) (erase-region) (re-replace-string "^" "> ") ) ) ) !E!O!F! cat > postnews/gparent.wm.c <<\!E!O!F! /* * Since the gparent macro for Warren Montgomery's emacs * contains control characters, it cannot be distributed * directly over the net. This C program will write the * macro to the standard output. */ #define SIZE 95 char gparent[SIZE] = { 0030,0031,0034,0147,0160,0141,0162,0145,0156,0164, 0040,0055,0040,0151,0156,0163,0145,0162,0164,0040, 0142,0157,0144,0171,0040,0157,0146,0040,0157,0162, 0151,0147,0151,0156,0141,0154,0040,0141,0162,0164, 0151,0143,0154,0145,0012,0276,0000,0030,0074,0101, 0012,0305,0025,0030,0022,0030,0030,0000,0030,0074, 0136,0044,0012,0223,0016,0027,0030,0055,0033,0061, 0064,0000,0030,0074,0076,0040,0012,0030,0074,0136, 0012,0222,0122,0033,0062,0010,0030,0055,0033,0061, 0064,0030,0030,0032,0012 }; main() { int i ; for (i = 0 ; i < SIZE ; i++) putchar(gparent[i]); return 0; } !E!O!F! cat > postnews/letter <<\!E!O!F! To: uucp-news@cbosgd Subject: A new program: postnm Message-ID: <467517088@hou3c.UUCP> This program is not quite finished yet, but I thought I would let you know about it. NAME: Postnm - post news and/or mail SYNOPSYS: postnm -x [ file ] DESCRIPTION: Postnm reads and article from the file, or from the standard input if no filename is specified. If the article header contains a Newsgroup: line, the article is posted. If it contains To:, Cc:, or Bcc: lines, the article is mailed to the specified recipients. Postnm attempts to pass only valid articles to inews. Postnm cannot guarentee to pass only valid mail to the mail program because of the lack of standardization of mail under UNIX. Therefore, tries to accept a variety of mail formats and to pass them through to the mailer unchanged. The input to the program should look like a USENET article or a piece of RFC822 mail. Some headers supported by postnm are: To:, Cc:, and Bcc: These lines are scanned for address to be passed to the mail program. Commas between the addresses are optional. Any RFC 822 address should be accepted as long as it is formatted sensibly (no comments within the address, and no white space except within angle brackets or around the at sign). Some legal address lines are: To: "Kenneth Almquist" @ hou3c.UUCP (That's me) To: Kenneth Almquist <@cbosgd.UUCP: ka@hou3c.UUCP> The address is passed to the mailer uninterpreted except that comments and any enclosing angle brackets are deleted. Newsgroups:, Followup-To: Newsgroups on these lines are separated by white space and/or commas. From:, Reply-To: On posted news, these lines will be converted to the format: From: user@machine (Real Name) References: This line is passed through to news. If you don't include an In-reply-to: line, one will be generated from the References: line. Command: This specifies that the article is a reply or a followup. If "Command: reply" is specified, any Newsgroup: line will be ignored. If "Command: followup" is specified, any "To:" line will be ignored. This way, if you type a followup command and then decide that your reply really isn't of interest to the entire net, you can edit this line. Other headers are supported. In addition, any unsupported header is passed thorough unchanged if it does not appear to be a misspelling of a supported header. Although postnm will read from its standard input if no file is given, typing an article directly into postnm from the terminal is expressly frowned upon because that mode of operation makes it difficult to correct errors. Therefore, postnm will not save the article in dead.article if an error occurs. Kenneth Almquist !E!O!F! cat > postnews/makedist <<\!E!O!F! : This shell procedure creates the distributions file. . ../lib/makedefs dlist=`sed -e '/^#/d' -e 's/[^:]*://' -e 's/:.*//' -e 's/,/ /g' -e 's/ */ /g' $LIBDIR/sys | tr ' ' ' ' | sed -e '/^!/d' -e 's/\..*//' | sort | uniq` exec < distlist while read dist desc do case "$dist" in ""|\#*) ;; local|world) echo "$dist $desc" ;; *) ndlist= for x in $dlist do if test "$x" = "$dist" then echo "$dist $desc" else ndlist="$ndlist $x" fi done dlist="$ndlist" ;; esac done ndlist= for x in $dlist do case "$x" in fa|mod|net|ug|to|all) ;; *) grep "^$x " $LIBDIR/active > junk if test -s junk then : else ndlist="$ndlist $x" fi rm junk ;; esac done if test "$ndlist" != "" -a "$ndlist" != " " then echo "The following distributions are not known to me: $ndlist" >&2 echo "Please add descriptions of them to postnews/distlist." >&2 exit 1 fi exit 0 !E!O!F! chmod +x postnews/makedist cat > postnews/moderators <<\!E!O!F! net.announce announce@cbosgd.UUCP net.announce.newusers usenet@gatech.UUCP mod.map mark@cbosgd.UUCP mod.map.news map@cbosgd.UUCP mod.map.uucp uucpmap@cbosgd.UUCP mod.motss motss@bbncca.UUCP mod.movies movies@ecsvax.UUCP mod.music gregbo@hou2e.UUCP mod.newslists usenet@gatech.UUCP mod.singles singles@nsc.UUCP mod.sources sources@genrad.UUCP mod.std.c std-c@cbosgd.UUCP mod.std.mumps std-mumps@plus5.UUCP mod.unix unix@masscomp.UUCP fa.arms-d arms-d@ucbvax.UUCP fa.arpa-bboard arpa-bboard@ucbvax.UUCP fa.bitgraph INFO-BITGRAPH@MIT-MC.ARPA fa.human-nets human-nets@brl-bmd.UUCP fa.info-mac info-mac@uw-beaver.UUCP fa.info-vax info-vax@ucbvax.UUCP fa.laser-lovers laser-lovers@uw-beaver.UUCP fa.poli-sci poli-sci@ucbvax.UUCP fa.telecom telecom@brl-bmd.UUCP fa.raliroad railroad@ucbvax.UUCP !E!O!F! echo Part 4 of 7 extracted.