nick@nswitgould.cs.uts.oz (Nick Andrew) (12/07/89)
WARNING: Posting not for the faint of heart. This is a very messy implementation of News 2.11 for MINIX. I will undoubtedly get flamed for posting such mess; such is life. I've been using this software successfully with a news feed from ACSnet for over 6 months now, and it is high time Minix had some N_E_W_S software. Some installation notes (read & follow before typing make!) ... - I have been primarily using News to read, not post. The links into ACSnet were set up in an unusual way, and since I don't run UUPC on my Minix, I don't know what needs to be changed for UUCP. - You will have to make some directories: /usr/spool, /usr/spool/batch, /usr/spool/news, /usr/lib/news, /usr/local/bin. Make sure /usr/spool is on a filesystem with plenty of space free (depending on how many newsgroups you want to get). - Several programs use the "r+", "w+" type modes in fopen(). You'll need to have one of the recently posted Stdio packages for things to work. I just coded a quick one, and it is known in the Makefile as libcio.a (check for the -lcio parameter). - Some programs won't compile, for some reason or other. caesar.c for example. I guess you can safely ignore those; I did! The ones to worry about are inews, rnews, postnews, expire, and unbatch. - getdate.y required yacc. I used a real unix yacc to make getdate.c but have only included getdate.s (shar'ed as getdate.s.uu). - The original makefile did a lot of customisation work (running customize shell scripts before recompiling etc..). These have all been removed as they stood in the way of the port. What you see is what you get. - I haven't tried vnews at all; preferring to use vn. - You will have to set up various config files; active, newsgroups, sys, distributions, etc... The install manual should tell a lot about this. - unbatch has been heavily modified to do its work on a compressed news batch by decompressing to a temporary file, and then running inews on that file. Minix's memory limitations don't allow any other method. - This posting comes as 12 source postings (src directory), followed in a day or two by postings of the (essentially unmodified) manuals and user guides etc. My aim in making this posting is to allow the dedicated Minix hackers to create a real News for Minix. I have not the time nor the resources to spend further on News, and I feel that since the software is running fairly stable on my own system, it would benefit the rest of the net, despite the obvious work people will have to go through to get it running locally. Finally, good luck, and happy newsreading. Nick. "Zeta Microcomputer Software" ACSnet: nick@ultima.cs.uts.oz UUCP: ...!uunet!munnari!ultima.cs.uts.oz!nick Fidonet: Nick Andrew on 3:713/602 (Zeta) -- "Zeta Microcomputer Software" ACSnet: nick@ultima.cs.uts.oz UUCP: ...!uunet!munnari!ultima.cs.uts.oz!nick Fidonet: Nick Andrew on 3:713/602 (Zeta)
nick@ultima.cs.uts.oz (Nick Andrew) (12/07/89)
#! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of shell archive." # Contents: README Notes visual.c # Wrapped by nick@nswitgould on Thu Dec 7 22:39:35 1989 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'README' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'README'\" else echo shar: Extracting \"'README'\" \(2761 characters\) sed "s/^X//" >'README' <<'END_OF_FILE' XWARNING: Posting not for the faint of heart. X X This is a very messy implementation of News 2.11 for MINIX. I will Xundoubtedly get flamed for posting such mess; such is life. I've been Xusing this software successfully with a news feed from ACSnet for over 6 Xmonths now, and it is high time Minix had some N_E_W_S software. X XSome installation notes (read & follow before typing make!) ... X X- I have been primarily using News to read, not post. The links into XACSnet were set up in an unusual way, and since I don't run UUPC on my Minix, XI don't know what needs to be changed for UUCP. X X- You will have to make some directories: /usr/spool, /usr/spool/batch, X/usr/spool/news, /usr/lib/news, /usr/local/bin. Make sure /usr/spool is on Xa filesystem with plenty of space free (depending on how many newsgroups Xyou want to get). X X- Several programs use the "r+", "w+" type modes in fopen(). You'll Xneed to have one of the recently posted Stdio packages for things to work. XI just coded a quick one, and it is known in the Makefile as libcio.a (check Xfor the -lcio parameter). X X- Some programs won't compile, for some reason or other. caesar.c for Xexample. I guess you can safely ignore those; I did! The ones to worry Xabout are inews, rnews, postnews, expire, and unbatch. X X- getdate.y required yacc. I used a real unix yacc to make getdate.c Xbut have only included getdate.s (shar'ed as getdate.s.uu). X X- The original makefile did a lot of customisation work (running Xcustomize shell scripts before recompiling etc..). These have all been Xremoved as they stood in the way of the port. What you see is what you Xget. X X- I haven't tried vnews at all; preferring to use vn. X X- You will have to set up various config files; active, newsgroups, Xsys, distributions, etc... The install manual should tell a lot about this. X X- unbatch has been heavily modified to do its work on a compressed Xnews batch by decompressing to a temporary file, and then running inews on Xthat file. Minix's memory limitations don't allow any other method. X X- This posting comes as 12 source postings (src directory), followed Xin a day or two by postings of the (essentially unmodified) manuals and Xuser guides etc. X X X X XMy aim in making this posting is to allow the dedicated Minix hackers to Xcreate a real News for Minix. I have not the time nor the resources to Xspend further on News, and I feel that since the software is running Xfairly stable on my own system, it would benefit the rest of the net, Xdespite the obvious work people will have to go through to get it running Xlocally. X XFinally, good luck, and happy newsreading. Nick. X X "Zeta Microcomputer Software" XACSnet: nick@ultima.cs.uts.oz XUUCP: ...!uunet!munnari!ultima.cs.uts.oz!nick XFidonet: Nick Andrew on 3:713/602 (Zeta) END_OF_FILE if test 2761 -ne `wc -c <'README'`; then echo shar: \"'README'\" unpacked with wrong size! fi # end of 'README' fi if test -f 'Notes' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'Notes'\" else echo shar: Extracting \"'Notes'\" \(519 characters\) sed "s/^X//" >'Notes' <<'END_OF_FILE' XNick@ultima.cs.uts.oz's notes about News ... X Xinews -C fails (create new newsgroup), because it forks and executes X itself again. The fork fails. Perhaps an execl would have been X a better choice! (does execl get rid of the old process before X creating the new one?) X Xcompress works ... but it is only a 12-bit compress. It seems to be X compatible with the 1.4a compress (the braindead one) and the X previous, compatible compress. X Xbatch & unbatch work ... fine X Xrnews must be in bindir, while inews must be in libdir. END_OF_FILE if test 519 -ne `wc -c <'Notes'`; then echo shar: \"'Notes'\" unpacked with wrong size! fi # end of 'Notes' fi if test -f 'visual.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'visual.c'\" else echo shar: Extracting \"'visual.c'\" \(55369 characters\) sed "s/^X//" >'visual.c' <<'END_OF_FILE' X/* X * visual - visual news interface. X * Kenneth Almquist X */ X X#ifdef SCCSID Xstatic char *SccsId = "@(#)visual.c 1.36 3/21/87"; X#endif /* SCCSID */ X X#include "rparams.h" X#ifdef USG X#include <sys/ioctl.h> X#include <termio.h> X#include <fcntl.h> X#else /* !USG */ X#include <sgtty.h> X#endif /* !USG */ X X#include <errno.h> X#if defined(BSD4_2) || defined(BSD4_1C) X#include <sys/dir.h> X#else X#include "ndir.h" X#endif X#ifdef BSD4_2 X#ifndef sigmask X#define sigmask(m) (1<<((m)-1)) X#endif /* !sigmask */ X#endif /* BSD4_2 */ X#ifdef MYDB X#include "db.h" X#endif /* MYDB */ X Xextern int errno; X X#ifdef SIGTSTP X#include <setjmp.h> X#endif /* SIGTSTP */ X X#define ARTWLEN (ROWS-2)/* number of lines used to display article */ X#define even(cols) ((cols&1) ? cols + 1 : cols) X#ifdef STATTOP X#define PRLINE 0 /* prompter line */ X#define SPLINE 1 /* secondary prompt line */ X#define ARTWIN 2 /* first line of article window */ X#define SECPRLEN 81 /* length of secondary prompter */ X#else X#define PRLINE (ROWS-1)/* prompter line */ X#define SPLINE (ROWS-2)/* secondary prompt line */ X#define ARTWIN 0 /* first line of article window */ X#define SECPRLEN 100 /* length of secondary prompter */ X#endif X X#define PIPECHAR '|' /* indicate save command should pipe to program */ X#define CAGAIN ('e'&0x1F) /* Save-to-same-place indicator */ X#define META 0200 /* meta character bit (as in emacs) */ X/* print (display) flags */ X#define HDRONLY 0001 /* print header only */ X#define NOPRT 0002 /* don't print at all */ X#define NEWART 0004 /* force article display to be regenerated */ X#define HELPMSG 0010 /* display currently contains help message */ X/* prun flags */ X#define CWAIT 0001 /* type "continue?" and wait for return */ X#define BKGRND 0002 /* run process in the background */ X/* values of curflag */ X#define CURP1 1 /* cursor after prompt */ X#define CURP2 2 /* cursor after secondary prompt */ X#define CURHOME 3 /* cursor at home position */ X/* flags for vsave routine */ X#define SVHEAD 01 /* write out article header */ X#define OVWRITE 02 /* overwrite the file if it already exists */ X/* other files */ X X#define saveart oobit = bit;strcpy(ofilename1, filename);strcpy(ogroupdir, groupdir);hptr = h;h = hold;hold = hptr;ongsize = pngsize X#define NLINES(h, fp) (h->numlines[0] ? h->intnumlines : (h->intnumlines=linecnt(fp),sprintf(h->numlines, "%d", h->intnumlines), h->intnumlines)) X X/* terminal handler stuff */ Xextern int _junked; X#define clearok(xxx, flag) _junked = flag Xextern int COLS; Xextern int ROWS; Xextern int hasscroll; X XFILE *tmpfile(); Xchar *getmailname(); X#ifdef MYDB Xchar *findparent(); X#endif /* MYDB */ Xint onint(); Xint onstop(); Xint xxit(); X Xchar *Progname = "vnews"; /* for xerror */ X X/* variables shared between vnews routines */ Xstatic char linebuf[LBUFLEN]; /* temporary workspace */ Xstatic FILE *tfp; /* temporary file */ Xstatic char tfname[] = "/tmp/vnXXXXXX"; /* name of temp file */ Xstatic long artbody; /* offset of body into article */ Xstatic int quitflg; /* if set, then quit */ Xstatic int erased; /* current article has been erased */ Xstatic int artlines; /* # lines in article body */ Xstatic int artread; /* entire article has been read */ Xstatic int hdrstart; /* beginning of header */ Xstatic int hdrend; /* end of header */ Xstatic int lastlin; /* number of lines in tempfile */ Xstatic int tflinno = 0; /* next line in tempfile */ Xstatic int maxlinno; /* number of lines in file + folded */ Xstatic char secpr[SECPRLEN]; /* secondary prompt */ Xstatic char prompt[30]; /* prompter */ Xstatic short prflags; /* print flags (controls updscr) */ Xstatic short curflag; /* where to locate cursor */ Xstatic int dlinno; /* top line on screen */ Xstatic char timestr[20]; /* current time */ Xstatic int ismail; /* true if user has mail */ Xstatic char *mailf; /* user's mail file */ Xstatic int alflag; /* set if unprocessed alarm signal */ Xstatic int atend; /* set if at end of article */ Xstatic char cerase; /* erase character */ Xstatic char ckill; /* kill character */ Xstatic char cintr; /* interrupt character */ X#ifdef TIOCGLTC Xstatic char cwerase; /* word erase character */ X#endif /* TIOCGLTC */ Xshort ospeed; /* terminal speed NOT STATIC */ Xstatic int intflag; /* set if interrupt received */ X X#ifdef SIGTSTP Xstatic int reading; /* to keep stupid BSD from restarting reads */ Xjmp_buf intjmp, alrmjmp; X#endif /* SIGTSTP */ X X#ifdef MYDB Xstatic int hasdb; /* true if article data base exists */ X#endif /* MYDB */ X X#ifdef DIGPAGE Xstatic int endsuba; /* end of sub-article in digest */ X#endif X X#ifdef MYDEBUG XFILE *debugf; /* file to write debugging info on */ X#endif X Xchar *tft = "/tmp/folXXXXXX"; X X/* X * These were made static for u370 with its buggy cc. X * I judged it better to have one copy with no ifdefs than X * to conditionally compile them as automatic variables X * in readr (which they originally were). Performance X * considerations might warrant moving some of the simple X * things into register variables, but I don't know what X * breaks the u370 cc. X */ Xstatic char goodone[BUFLEN]; /* last decent article */ Xstatic char ogroupdir[BUFLEN]; /* last groupdir */ Xstatic char edcmdbuf[128]; Xstatic int rfq = 0; /* for last article */ Xstatic long ongsize; /* Previous ngsize */ Xstatic long pngsize; /* Printing ngsize */ Xstatic char *bptr; /* temp pointer. */ Xstatic char *tfilename; /* temporary file name */ Xstatic char ofilename1[BUFLEN]; /* previous file name */ Xstatic struct hbuf hbuf1, hbuf2; /* for minusing */ Xstatic struct hbuf *h = &hbuf1, /* current header */ X *hold = &hbuf2, /* previous header */ X *hptr; /* temporary */ Xstatic char *ptr1, *ptr2, *ptr3; /* for reply manipulation */ Xstatic int aabs = FALSE; /* TRUE if we asked absolutely */ Xstatic char *ed, tf[100]; Xstatic long oobit; /* last bit, really */ Xstatic int dgest = 0; Xstatic FILE *fp; /* current article to be printed*/ X Xreadr() X{ X X#ifdef MYDEBUG X debugf = fopen("DEBUG", "w"); X setbuf(debugf, (char *)NULL); X#endif X if (aflag) { X if (*datebuf) { X if ((atime = cgtdate(datebuf)) == -1) X xerror("Cannot parse date string"); X } else X atime = 0; X } X X if (SigTrap) X xxit(1); X (void) mktemp(tfname); X (void) close(creat(tfname,0666)); X if ((tfp = fopen(tfname, "w+")) == NULL) X xerror("Can't create temp file"); X (void) unlink(tfname); X mailf = getmailname(); X#ifdef MYDB X if (opendb() >= 0) { X hasdb = 1; X fputs("Using article data base\n", stderr); /*DEBUG*/ X getng(); X } X#endif X ttysave(); X (void) signal(SIGINT, onint); X (void) signal(SIGQUIT, xxit); X if (SigTrap) X xxit(1); X ttyraw(); X timer(); X X /* loop reading articles. */ X fp = NULL; X obit = -1; X nextng(); X quitflg = 0; X while (quitflg == 0) { X if (getnextart(FALSE)) X break; X (void) strcpy(goodone, filename); X if (SigTrap) X return; X vcmd(); X } X X if (!news) { X ttycooked(); X ospeed = 0; /* to convince xxit() not to clear screen */ X fprintf(stderr, "No news.\n"); X } X} X X/* X * Read and execute a command. X */ Xvcmd() { X register c; X char *p; X long count; X int countset; X X if (prflags & HDRONLY) X appfile(fp, lastlin + 1); X else X appfile(fp, dlinno + ARTWLEN + 1); X X#ifdef DIGPAGE X endsuba = findend(dlinno); X if (artlines > dlinno + ARTWLEN X || endsuba > 0 && endsuba < artlines X#else X if (artlines > dlinno + ARTWLEN X#endif X || (prflags & HDRONLY) && artlines > hdrend) { X atend = 0; X if (prflags&HDRONLY || maxlinno == 0) X (void) strcpy(prompt, "more? "); X else X#ifdef DIGPAGE X (void) sprintf(prompt, "more(%d%%)? ", X ((((endsuba > 0) ? X endsuba : (dlinno + ARTWLEN)) - X hdrend) * 100) / maxlinno); X#else /* !DIGPAGE */ X (void) sprintf(prompt, "more(%d%%)? ", X ((dlinno + ARTWLEN - hdrend) * 100) / maxlinno); X#endif /* !DIGPAGE */ X } else { X atend = 1; X (void) strcpy(prompt, "next? "); X if (!erased) X clear(bit); /* article read */ X } X curflag = CURP1; X p = prompt + strlen(prompt); X countset = 0; X count = 0; X /* X * Loop while accumulating a count, until an action character X * is entered. Also handle "meta" here. X * X * Count is the current count. Countset=0 means no count X * currently exists. Countset=1, count=0 is valid and means X * a count of 0 has been entered X */ X for (;;) { X c = vgetc(); X if (c == cerase || c == '\b' || c == '\177') { X if (countset == 0) X break; /* Use as action char */ X if (count < 10) X countset = 0; /* Erase only char of count */ X else X count /= 10L; /* Erase 1 char of count */ X } else { X#ifdef TIOCGLTC X if (c == ckill || c == cwerase) { X#else X if (c == ckill) { X#endif X if (countset == 0) X break; X countset = 0; X } else if (c < '0' || c > '9') X break; X else { X countset = 1; X count = (count * 10) + (c - '0'); X } X } X if (countset) { X (void) sprintf(p, "%ld", count); X } else { X *p = '\0'; X count = 0; X } X } X X if (c == '\033') { /* escape */ X (void) strcat(prompt, "M-"); X c = vgetc(); X if (c != cintr) X c |= META; X } X secpr[0] = '\0'; X if (countset == 0) X count = 1; X docmd(c, count, countset); X if (c != '?' && c != 'H') /* UGGH */ X prflags &=~ HELPMSG; X if (dlinno > hdrstart) X prflags &=~ HDRONLY; X} X X X/* X * Process one command, which has already been typed in. X */ Xdocmd(c, count, countset) Xint c; Xlong count; Xint countset; X{ X int i; X long nart, Hoffset; X char *findhist(); X X switch (c) { X X /* display list of articles in current group */ X case 'l': X case 'L': X botscreen(); X ttycooked(); X list_group(groupdir, countset ? count : 0, X (c == 'l') ? FALSE : TRUE, pngsize); X ttyraw(); X clearok(curscr, 1); X updscr(); X break; X X /* Show more of current article, or advance to next article */ X case '\n': X case ' ': X#ifdef DIGPAGE X case 'm': X#endif /* DIGPAGE */ X case '\06': /* Control-F for vi compat */ X prflags &=~ NOPRT; X if (atend) X goto next; X else if (prflags & HDRONLY) { X prflags &=~ HDRONLY; X if (hasscroll) X dlinno = hdrstart;} X#ifdef DIGPAGE X else if (endsuba > 0) X dlinno = endsuba; X else if (c == 'm') { X do { X if (lastlin >= maxlinno) X goto next; X else X appfile(fp, lastlin + 1); X } while(strncmp(linebuf, "------------------------", 24) X != 0); X dlinno = endsuba = lastlin; X } X#endif X else if ((appfile(fp, dlinno + 2 * ARTWLEN), artread) X && hasscroll && artlines - dlinno <= ARTWLEN + 2) X dlinno = artlines - ARTWLEN; X else X dlinno += ARTWLEN * count; X break; X X /* No. Go on to next article. */ X case '.': /* useful if you have a keypad */ Xnext: case 'n': X readmode = NEXT; X FCLOSE(fp); X clear(bit); X saveart; X nextbit(); X break; X X X /* Back up count pages */ X case '\b': X case '\177': X if (dlinno == 0) X goto backupone; X /* NO BREAK */ X case META|'v': X case '\002': /* Control-B */ X dlinno -= ARTWLEN * count; X if (dlinno < 0) X dlinno = 0; X break; X X /* forward half a page */ X case '\004': /* Control-D, as in vi */ X if (!atend) X dlinno += ARTWLEN/2 * count; X break; X X /* backward half a page */ X case '\025': /* Control-U */ X dlinno -= ARTWLEN/2 * count; X if (dlinno < 0) X dlinno = 0; X break; X X /* forward count lines */ X case '\016': /* Control-N */ X case '\005': /* Control-E */ X dlinno += count; X break; X X /* backwards count lines */ X case '\020': /* Control-P */ X case '\031': /* Control-Y */ X dlinno -= count; X if (dlinno < 0) X dlinno = 0; X break; X X /* Turn displaying of article back on */ X case 'd': X prflags &=~ NOPRT; X break; X X /* display header */ X case 'h': X dlinno = hdrstart; X prflags |= HDRONLY; X prflags &=~ NOPRT; X break; X X /* X * Unsubscribe to the newsgroup and go on to next group X */ X X case 'U': X case 'u': X strcat(prompt, "u"); X c = vgetc(); X if (c == 'g') { X obit = -1; X FCLOSE(fp); X zapng = TRUE; X saveart; X if (nextng()) { X if (actdirect == BACKWARD) X msg("Can't back up."); X else X quitflg = 1; /* probably unnecessary */ X } X } else { X if (c != cintr && c != ckill) X beep(); X msg("Illegal command"); X } X break; X X /* Print the current version of news */ X case 'v': X msg("News version: %s", news_version); X break; X X X /* Decrypt joke. Always does rot 13 */ X case 'D': X appfile(fp, 32767); X for (i = hdrend ; i < artlines ; i++) { X register char ch, *p; X tfget(linebuf, i); X for (p = linebuf ; (ch = *p) != '\0' ; p++) { X if (ch >= 'a' && ch <= 'z') X *p = (ch - 'a' + 13) % 26 + 'a'; X else if (ch >= 'A' && ch <= 'Z') X *p = (ch - 'A' + 13) % 26 + 'A'; X } X tfput(linebuf, i); X } X prflags |= NEWART; X prflags &=~ (HDRONLY|NOPRT); X break; X X /* write out the article someplace */ X /* w writes out without the header */ X /* | defaults to pipeing */ X { X static char savebuf[BUFLEN]; X int wflags; X X case PIPECHAR: X case 's': X case 'w': X /* We loop back to here each time user types ^U to prompt */ X do { X /* Prompt based on command char */ X msg( (c==PIPECHAR)? "|": "file: "); X curflag = CURP2; X while ((wflags = vgetc()) == ' '); X if (wflags == cintr) { X secpr[0] = '\0'; X break; X } X if (wflags != CAGAIN) { X if ((wflags & 0x1F) == wflags) { /* control char */ X pushback(wflags); X savebuf[0] = 0; X } else { X if (c == PIPECHAR) { X savebuf[0] = PIPECHAR; X savebuf[1] = wflags; X savebuf[2] = 0; X } else { X savebuf[0] = wflags; X savebuf[1] = 0; X } X } X } else { X /* don't let them pipe to a saved filename */ X if (c == PIPECHAR && savebuf[0] != PIPECHAR) { X savebuf[0] = PIPECHAR; X savebuf[1] = 0; X } X } X X wflags = prget( (savebuf[0] == PIPECHAR) ? "" : "file: ", X savebuf); X } while (wflags == 2); X if (wflags) break; /* Interrupted out */ X wflags = 0; X if (c == PIPECHAR) c = 's'; X if (c == 's') X wflags |= SVHEAD; X if (count != 1) X wflags |= OVWRITE; X bptr = savebuf; X while( *bptr == ' ') X bptr++; /* strip leading spaces */ X X if (*bptr != PIPECHAR && *bptr != '/') { X char hetyped[BUFLEN]; X char *boxptr; X (void) strcpy(hetyped, bptr); X if (hetyped[0] == '~' && hetyped[1] == '/') { X strcpy(hetyped, bptr+2); X strcpy(bptr, userhome); X } else if (boxptr = getenv("NEWSBOX")) { X if (index(boxptr, '%')) { X struct stat stbf; X sprintf(bptr, boxptr, groupdir); X if (stat(bptr,&stbf) < 0) { X if (mkdir(bptr, 0777) < 0) { X msg("Cannot create directory %s", bptr); X break; X } X } else if ((stbf.st_mode&S_IFMT) != S_IFDIR) { X msg("%s not a directory", bptr); X break; X } X } else X strcpy(bptr, boxptr); X } else X bptr[0] = '\0'; X X if (bptr[0]) X (void) strcat(bptr, "/"); X if (hetyped[0] != '\0') X (void) strcat(bptr, hetyped); X else X (void) strcat(bptr, "Articles"); X } X X /* handle ~/ for pipes */ X if (*bptr == PIPECHAR) { X char fullname[BUFLEN]; X bptr++; /* skip PIPECHAR */ X while( *bptr == ' ') X bptr++; /* strip leading spaces */ X if (bptr[0] == '~' && bptr[1] == '/') { X strcpy(fullname,userhome); X strcat(fullname,bptr+2); X } else X strcpy(fullname,bptr); X /* we know PIPECHAR is in *savebuf */ X strcpy(savebuf+1,fullname); X bptr = savebuf; X } X X vsave(bptr, wflags); X break; X } X X /* back up */ X case '-': Xcaseminus: X aabs = TRUE; X if (!*ofilename1) { X msg("Can't back up."); X break; X } X FCLOSE(fp); X hptr = h; X h = hold; X hold = hptr; X (void) strcpy(bfr, filename); X (void) strcpy(filename, ofilename1); X (void) strcpy(ofilename1, bfr); X obit = bit; X if (strcmp(groupdir, ogroupdir)) { X (void) strcpy(bfr, groupdir); X selectng(ogroupdir, FALSE, FALSE); X (void) strcpy(groupdir, ogroupdir); X (void) strcpy(ogroupdir, bfr); X ngrp = 1; X back(); X } X bit = oobit; X oobit = obit; X obit = -1; X getnextart(TRUE); X break; X X /* skip forwards */ X case '+': X case '=': Xcaseplus: if (count == 0) X break; X saveart; X last = bit; X for (i = 0; i < count; i++) { X nextbit(); X if ((bit > pngsize) || (rflag && bit < 1)) X break; X } X FCLOSE(fp); X obit = -1; X break; X X /* exit - time updated to that of most recently read article */ X case 'q': X quitflg = 1; X break; X X case 'x': X xxit(0); X break; X X /* cancel the article. */ X case 'c': X strcpy(prompt, "cancel [n]? "); X if (vgetc() != 'y') { X msg("Article not cancelled"); X break; X } X cancel_command(); X break; X X /* escape to shell */ X case '!': { X register char *p; X int flags; X X p = linebuf; X *p = 0; X if (prget("!", p)) X break; X flags = CWAIT; X if (*p == '\0') { X (void) strcpy(linebuf, SHELL); X flags = 0; X } X while (*p) p++; X while (p > linebuf && p[-1] == ' ') X p--; X if (*--p == '&') { X *p = '\0'; X flags = BKGRND; X } else if (*p == PIPECHAR) { X *p = '\0'; X (void) sprintf(bfr, "(%s)%cmail '%s'", linebuf, PIPECHAR, username); X (void) strcpy(linebuf, bfr); X flags |= BKGRND; X } else { X prflags |= NOPRT; X } X shcmd(linebuf, flags); X break; X } X X /* mail reply */ X case 'r': X reply(FALSE); X break; X X case 'R': X reply(TRUE); X break; X X case META|'r': X direct_reply(); X break; X X /* next newsgroup */ X case 'N': X FCLOSE(fp); X if (next_ng_command()) X quitflg = 1; X break; X X /* mark the rest of the articles in this group as read */ X case 'K': X saveart; X while (bit <= ngsize && bit >= minartno) { X clear(bit); X nextbit(); X } X FCLOSE(fp); X break; X X /* Print the full header */ X case 'H': X if (fp == NULL) { X msg("No current article"); X break; X } X move(ARTWIN, 0); X Hoffset = ftell(fp); X (void) fseek(fp, 0L, 0); X for (i = 0; i < ARTWLEN; i++) { X if (fgets(linebuf, COLS, fp) == NULL) X break; X if (linebuf[0] == '\n') X break; X linebuf[COLS] = '\0'; X addstr(linebuf); X } X (void) fseek(fp, Hoffset, 0); X for(; i < ARTWLEN; i++) X addstr(linebuf); X prflags |= HELPMSG|NEWART; X break; X case 'b': /* backup 1 article */ Xbackupone: X count = bit - 1; X /* NO BREAK */ X X case 'A': /* specific number */ X if (count > pngsize) { X msg("not that many articles"); X break; X } X readmode = SPEC; X aabs = TRUE; X bit = count; X obit = -1; X FCLOSE(fp); X break; X X /* display parent article */ X case 'p': X#ifdef MYDB X if (hasdb && (ptr3 = findparent(h->ident, &nart)) != NULL) { X msg("parent: %s/%ld", ptr3, nart); /*DEBUG*/ X updscr(); /*DEBUG*/ X goto selectart; X } X#endif X if (h->followid[0] == '\0') { X msg("no references line"); X break; X } X ptr1 = h->followid + strlen(h->followid); X do { X ptr2 = ptr1; X if (*ptr2 == '\0') X ptr1 = rindex(h->followid, ' '); X else { X *ptr2 = '\0'; X ptr1 = rindex(h->followid, ' '); X *ptr2 = ' '; X } X } while (ptr1 != NULL && --count > 0); X if (ptr1 == NULL) X ptr1 = h->followid; X else ++ptr1; X (void) strncpy(linebuf, ptr1, ptr2 - ptr1); X linebuf[ptr2 - ptr1] = '\0'; X msg("%s", linebuf); X curflag = CURP2; X updscr(); /* may take this out later */ X goto searchid; X /* specific message ID. */ X case '<': X /* could improve this */ X linebuf[0] = '<'; linebuf[1] = 0; X if (prget("", linebuf)) { X secpr[0] = 0; X break; X } Xsearchid: secpr[0] = '\0'; X if (index(linebuf, '@') == NULL && index(linebuf, '>') == NULL) { X ptr1 = linebuf; X if (*ptr1 == '<') X ptr1++; X ptr2 = index(ptr1, '.'); X if (ptr2 != NULL) { X *ptr2++ = '\0'; X (void) sprintf(bfr, "<%s@%s.UUCP>", ptr2, ptr1); X (void) strcpy(linebuf, bfr); X } X } X if (index(linebuf, '>') == NULL) X (void) strcat(linebuf, ">"); X X ptr1 = findhist(linebuf); X if (ptr1 == NULL) { X msg("%s not found", linebuf); X break; X } X ptr2 = index(ptr1, '\t'); X ptr3 = index(++ptr2, '\t'); X ptr2 = index(++ptr3, ' '); X if (ptr2) X *ptr2 = '\0'; X ptr2 = index(ptr3, '/'); X if (!ptr2) { X if (strcmp(ptr3, "cancelled") == 0) X msg("%s has been cancelled", linebuf); X else X msg("%s has expired", linebuf); X break; X } X *ptr2++ = '\0'; X (void) sscanf(ptr2, "%ld", &nart); X X /* X * Go to a given article. Ptr3 specifies the newsgroup X * and nart specifies the article number. X */ X#ifdef MYDB Xselectart: X#endif /* MYDB */ X aabs = TRUE; X FCLOSE(fp); X saveart; X (void) strcpy(ogroupdir, ptr3); X if (strcmp(groupdir, ogroupdir)) { X (void) strcpy(bfr, groupdir); X selectng(ogroupdir, TRUE, PERHAPS); X (void) strcpy(groupdir, ogroupdir); X (void) strcpy(ogroupdir, bfr); X ngrp = 1; X back(); X } X bit = nart; X oobit = obit; X obit = -1; X getnextart(TRUE); X if (bit != nart || strcmp(groupdir, ptr3) != 0) { X msg("can't read %s/%ld", ptr3, nart); X goto caseminus; X } X rfq = 0; X break; X X /* follow-up article */ X case 'f': X if (strcmp(h->followto, "poster") == 0) { X reply(FALSE); X break; X } X (void) sprintf(bfr, "%s/%s %s", BIN, "postnews", goodone); X shcmd(bfr, CWAIT); X break; X X /* erase - pretend we haven't seen this article. */ X case 'e': X erased = 1; X set(bit); X goto caseplus; /* skip this article for now */ X X case '#': X msg("Article %ld of %ld", rfq ? oobit : bit, pngsize); X break; X X /* error */ X case '?': X { X FILE *helpf; X (void) sprintf(linebuf, "%s/vnews.help", LIB); X if ((helpf = fopen(linebuf, "r")) == NULL) { X msg("Can't open help file"); X break; X } X move(ARTWIN, 0); X while (fgets(linebuf, LBUFLEN, helpf) != NULL) X addstr(linebuf); X (void) fclose(helpf); X prflags |= HELPMSG|NEWART; X } X break; X X default: X if (c != ckill && c != cintr && c != cerase) X#ifdef TIOCGLTC X if (c != cwerase) X#endif X { X beep(); X msg("Illegal command"); X } X break; X } X} X Xcancel_command() X{ X register char *poster, *r; X int notauthor; X char *senderof(); X X poster = senderof(&h); X /* only compare up to '.' or ' ' */ X r = index(poster,'.'); X if (r == NULL) X r = index(poster,' '); X if (r != NULL) X *r = '\0'; X tfilename = filename; X notauthor = strcmp(username, poster); X if (uid != ROOTID && uid && notauthor) { X msg("Can't cancel what you didn't write."); X return; X } X if (!cancel(stderr, h, notauthor)) { X clear(bit); X saveart; X nextbit(); X obit = -1; X fp = NULL; X } X FCLOSE(fp); X} X/* X * Generate replies X */ X Xreply(include) X int include; X{ X char *arg[4]; X register FILE *rfp; X char subj[132]; X register char *p; X char *replyname(); X struct stat statb; X time_t creatm; X X /* Put the user in the editor to create the body of the reply. */ X ed = getenv("EDITOR"); X if (ed == NULL || *ed == '\0') X ed = DFTEDITOR; X if (ed == NULL) { X msg("You don't have an editor"); X return; X } X X arg[0] = "/bin/sh"; X arg[1] = "-c"; X X (void) strcpy(tf, tft); X (void) mktemp(tf); X (void) close(creat(tf,0600)); X if ((rfp = fopen(tf, "w")) == NULL) { X msg("Can't create %s", tf) ; X return; X } X (void) strcpy(subj, h->title); X if (!prefix(subj, "Re:")){ X (void) strcpy(bfr, subj); X (void) sprintf(subj, "Re: %s", bfr); X } X X p = replyname(h); X fprintf(rfp, "To: %s\n", p); X fprintf(rfp, "Subject: %s\n", subj); X fprintf(rfp, "In-reply-to: your article %s\n", h->ident); X#ifdef INTERNET X fprintf(rfp, "News-Path: %s\n", h->path); X#endif /* INTERNET */ X (void) sprintf(rcbuf, "%s -t < %s; rm -f %s", MAILPARSER, tf, tf); X putc('\n', rfp); X if (include) { X FILE *of; X char buf[BUFSIZ]; X X of = xart_open(goodone, "r"); X while (fgets(buf, sizeof buf, of) != NULL) X if (buf[0] == '\n') X break; X while (fgets(buf, sizeof buf, of) != NULL) X fprintf(rfp, "> %s", buf); X fclose(of); X putc('\n', rfp); X } X fflush(rfp); X (void) fstat(fileno(rfp), &statb); X creatm = statb.st_mtime; X (void) fclose(rfp); X X (void) sprintf(edcmdbuf, "exec %s %s", ed, tf); X arg[2] = edcmdbuf; X arg[3] = NULL; X if (prun(arg, 0) != 0) { X msg("Couldn't run editor"); X (void) unlink(tf); X return; X } X X if (access(tf, 4) || stat(tf, &statb)) { X msg("No input file - mail not sent"); X (void) unlink(tf); X return; X } X if (statb.st_mtime == creatm || statb.st_size < 5) { X msg("File unchanged - no message posted"); X (void) unlink(tf); X return; X } X X arg[2] = rcbuf; X arg[3] = NULL; X prun(arg, BKGRND); X prflags |= NOPRT; X} X Xdirect_reply() X{ X register char *p; X register char *q; X char *arg[4]; X char address[PATHLEN]; X extern char *replyname(); X extern char *getenv(); X X arg[0] = "/bin/sh"; X arg[1] = "-c"; X p = replyname(h); X q = address; X while (*p != '\0') { X if (index("\"\\$", *p) != 0) X *q++ = '\\'; X *q++ = *p++; X } X *q++ = '\0'; X if ((MAILER = getenv("MAILER")) == NULL) X MAILER = "mail"; X sprintf(rcbuf, MAILER, hptr->title); X sprintf(bfr, "%s %s", rcbuf, address); X arg[2] = bfr; X arg[3] = NULL; X if (prun(arg, 0) != 0) { X msg("Couldn't run mailer"); X return; X } X prflags |= NOPRT; X} X Xnext_ng_command() X{ X set(bit); X obit = -1; X linebuf[0] = 0; X if (prget("group? ", linebuf)) X return FALSE; X bptr = linebuf; X if (!*bptr || *bptr == '-') { X if (*bptr) X actdirect = BACKWARD; X saveart; X if (nextng()) { X if (actdirect == BACKWARD) X msg("Can't back up."); X else X return TRUE; X } X return FALSE; X } X while (isspace(*bptr)) X bptr++; X if (!validng(bptr)) { X msg("No such group."); X return FALSE; X } X saveart; X back(); X selectng(bptr, TRUE, TRUE); X return FALSE; X} X X/* X * Find the next article we want to consider, if we're done with X * the last one, and show the header. X */ Xgetnextart(minus) Xint minus; X{ X int noaccess; X register DIR *dirp; X register struct direct *dir; X long nextnum, tnum; X long atol(); X X noaccess = 0; X if (minus) X goto nextart2; /* Kludge for "-" command. */ X X if (bit == obit) /* Return if still on same article as last time */ X return 0; X Xnextart: X if (news) { X curflag = CURHOME; X _amove(0, 0); X vflush(); X } X dgest = 0; X X /* If done with this newsgroup, find the next one. */ X while (ngsize <= 0 || (!rflag && ((long) bit > ngsize)) || (rflag && bit < minartno)) { X if (nextng()) { X if (actdirect == BACKWARD) { X msg("Can't back up."); X actdirect = FORWARD; X continue; X } X else /* if (rfq++ || pflag || cflag) */ X return 1; X } X if (rflag) X bit = ngsize + 1; X else X bit = -1; X noaccess = 2; X } X X /* speed things up by not searching for article -1 */ X if (bit < 0) { X bit = minartno - 1; X nextbit(); X aabs = FALSE; X goto nextart; X } X Xnextart2: X if (rcreadok) X rcreadok = 2; /* have seen >= 1 article */ X (void) sprintf(filename, "%s/%ld", dirname(groupdir), bit); X if (rfq && goodone[0]) /* ??? */ X strcpy(filename, goodone); X if (SigTrap == SIGHUP) X return 1; X /* Decide if we want to show this article. */ X if ((fp = art_open(filename, "r")) == NULL) { X /* since there can be holes in legal article numbers, */ X /* we wait till we hit 5 consecutive bad articles */ X /* before we haul off and scan the directory */ X if (++noaccess < 5) X goto badart; X noaccess = 0; X dirp = opendir(dirname(groupdir)); X if (dirp == NULL) { X if (errno != EACCES) X msg("Can't open %s", dirname(groupdir)); X goto nextart; X } X nextnum = rflag ? minartno - 1 : ngsize + 1; X while ((dir = readdir(dirp)) != NULL) { X if (!dir->d_ino) X continue; X tnum = atol(dir->d_name); X if (tnum <= 0) X continue; X if (rflag ? (tnum > nextnum && tnum < bit) X : (tnum < nextnum && tnum > bit)) X nextnum = tnum; X } X closedir(dirp); X if (rflag ? (nextnum >= bit) : (nextnum <= bit)) X goto badart; X do { X clear(bit); X nextbit(); X } while (rflag ? (nextnum < bit) : (nextnum > bit)); X obit = -1; X aabs = FALSE; X goto nextart; X } else X noaccess = 0; X X if (hread(h, fp, TRUE) == NULL || (!rfq && !aselect(h, aabs))) { Xbadart: X FCLOSE(fp); X clear(bit); X obit = -1; X nextbit(); X aabs = FALSE; X goto nextart; X } X aabs = FALSE; X actdirect = FORWARD; X news = TRUE; X artbody = ftell(fp); X fmthdr(); X artlines = lastlin; X artread = 0; X prflags |= NEWART; X prflags &=~ NOPRT; X if (! cflag && hdrend < ARTWLEN && !cflag) X prflags |= HDRONLY; X dlinno = 0; X maxlinno = NLINES(h, fp); X erased = 0; X X obit = bit; X return 0; X} X X/* X * Print out whatever the appropriate header is X */ Xfmthdr() { X char *briefdate(); X static FILE *ngfd = NULL; X static int triedopen = 0; X char pbuf[BUFLEN], *printbuffer = groupdir; X X lastlin = 0; X if (ngrp) { X pngsize = ngsize; X ngrp--; X if (!hflag) { X if (!triedopen) { X (void) sprintf(pbuf,"%s/newsgroups", LIB); X ngfd = fopen(pbuf, "r"); X triedopen++; X } X if (ngfd != NULL) { X register char *p; X char ibuf[BUFLEN]; X rewind(ngfd); X while (fgets(ibuf, BUFLEN, ngfd) != NULL) { X p = index(ibuf, '\t'); X if (p) X *p++ = '\0'; X if (strcmp(ibuf, groupdir) == 0) { X register char *q; X q = rindex(p, '\t'); X if (q) { X p = q; X *p++ = '\0'; X } X if (p) { X q = index(p, '\n'); X if (q) X *q = '\0'; X if (*--q == '.') X *q = '\0'; X (void) sprintf(pbuf,"%s (%s)", X groupdir, p); X printbuffer = pbuf; X } X break; X } X } X } X (void) sprintf(linebuf, "Newsgroup %s", printbuffer); X tfappend(linebuf); X } X } X hdrstart = lastlin; X if (!hflag) { X (void) sprintf(linebuf, "Article %s %s", X h->ident, briefdate(h->subdate)); X tfappend(linebuf); X } X xtabs(h); X vhprint(h, pflag ? 1 : 0); X (void) sprintf(linebuf, "(%d lines)", NLINES(h, fp)); tfappend(linebuf); X tfappend(""); X hdrend = lastlin; X} X X/* X * Grow tabs into spaces in header fields, 'cause the rest of this X * lax program drops turds all over tabs (so it does with \b's, but ..) X */ Xxtabs(p) Xregister struct hbuf *p; X{ X xtabf(p->from, sizeof p->from); X xtabf(p->path, sizeof p->path); X xtabf(p->nbuf, sizeof p->nbuf); X xtabf(p->title, sizeof p->title); X xtabf(p->ident, sizeof p->ident); X xtabf(p->replyto, sizeof p->replyto); X xtabf(p->followid, sizeof p->followid); X xtabf(p->subdate, sizeof p->subdate); X xtabf(p->expdate, sizeof p->expdate); X xtabf(p->ctlmsg, sizeof p->ctlmsg); X xtabf(p->sender, sizeof p->sender); X xtabf(p->followto, sizeof p->followto); X xtabf(p->distribution, sizeof p->distribution); X xtabf(p->organization, sizeof p->organization); X xtabf(p->numlines, sizeof p->numlines); X xtabf(p->keywords, sizeof p->keywords); X xtabf(p->summary, sizeof p->summary); X xtabf(p->approved, sizeof p->approved); X xtabf(p->nf_id, sizeof p->nf_id); X xtabf(p->nf_from, sizeof p->nf_from); X#ifdef DOXREFS X xtabf(p->xref, sizeof p->xref); X#endif /* DOXREFS */ X} X Xxtabf(s, size) Xchar *s; Xint size; X{ X register char *p, *str; X register c, i; X char buf[LBUFLEN]; X X str = s; X if (index(str, '\t') == NULL) X return; X i = 0; X for (p = buf; c = *str++; i++) { X if (c == '\t') { X *p++ = ' '; X if ((i & 7) != 7) X str--; X } else if (c == '\n') { X i = -1; X *p++ = c; X } else X *p++ = c; X } X *p = '\0'; X strncpy(s, buf, size - 1); X} X X/* X * Print the file header to the temp file. X */ Xvhprint(hp, verbose) Xregister struct hbuf *hp; Xint verbose; X{ X register char *p1, *p2; X char fname[BUFLEN]; X char *tailpath(); X X fname[0] = '\0'; /* init name holder */ X X p1 = index(hp->from, '('); /* Find the sender's full name. */ X if (p1 == NULL && hp->path[0]) X p1 = index(hp->path, '('); X if (p1 != NULL) { X (void) strcpy(fname, p1+1); X p2 = index(fname, ')'); X if (p2 != NULL) X *p2 = '\0'; X } X X (void) sprintf(linebuf, "Subject: %s", hp->title); X tfappend(linebuf); X if (!hflag && hp->summary[0]) X (void) sprintf(linebuf, "Summary: %s", hp->summary), tfappend(linebuf); X if (!hflag && hp->keywords[0]) X (void) sprintf(linebuf, "Keywords: %s", hp->keywords), tfappend(linebuf); X if (verbose) { X (void) sprintf(linebuf, "From: %s", hp->from); tfappend(linebuf); X (void) sprintf(linebuf, "Path: %s", hp->path); tfappend(linebuf); X if (hp->organization[0]) { X (void) sprintf(linebuf, "Organization: %s", hp->organization); X tfappend(linebuf); X } X } X else { X if (p1 != NULL) X *--p1 = '\0'; /* bump over the '(' */ X#ifdef INTERNET X /* X * Prefer Path line if it's in internet format, or if we don't X * understand internet format here, or if there is no reply-to. X */ X (void) sprintf(linebuf, "From: %s", hp->from); X#else X (void) sprintf(linebuf, "Path: %s", tailpath(hp)); X#endif X if (fname[0] || (hp->organization[0] && !hflag)) { X (void) strcat(linebuf, " ("); X if (fname[0] == '\0') { X (void) strcpy(fname, hp->from); X p2 = index(fname,'@'); X if (p2) X *p2 = '\0'; X } X (void) strcat(linebuf, fname); X if (hp->organization[0] && !hflag) { X (void) strcat(linebuf, " @ "); X (void) strcat(linebuf, hp->organization); X } X (void) strcat(linebuf, ")"); X } X tfappend(linebuf); X if (p1 != NULL) X *p1 = ' '; X if (hp->ctlmsg[0]) { X (void) sprintf(linebuf, "Control: %s", hp->ctlmsg); X tfappend(linebuf); X } X } X X if (verbose) { X (void) sprintf(linebuf, "Newsgroups: %s", hp->nbuf); tfappend(linebuf); X (void) sprintf(linebuf, "Date: %s", hp->subdate); tfappend(linebuf); X if (hp->sender[0]) { X (void) sprintf(linebuf, "Sender: %s", hp->sender); X tfappend(linebuf); X } X if (hp->replyto[0]) { X (void) sprintf(linebuf, "Reply-To: %s", hp->replyto); X tfappend(linebuf); X } X if (hp->followto[0]) { X (void) sprintf(linebuf, "Followup-To: %s", hp->followto); X tfappend(linebuf); X } X } X else if (strcmp(hp->nbuf, groupdir) != 0) { X (void) sprintf(linebuf, "Newsgroups: %s", hp->nbuf); X tfappend(linebuf); X timer(); X } X} X X#ifdef MYDB X Xchar * Xfindparent(id, num) Xchar *id; Xlong *num; X{ X struct artrec a; X char idbuf[BUFSIZE]; X char *ngname(); X X strcpy(idbuf, id); X lcase(idbuf); X X if (lookart(id, &a) == DNULL) X return NULL; X if (a.parent == DNULL) X return NULL; X readrec(a.parent, &a); X *num = a.groups[0].artno; X return ngname(a.groups[0].newsgroup); X} X X#endif X X X/* X * Append file to temp file, handling control characters, folding lines, etc. X * We don't grow the temp file to more than nlines so that a user won't have X * to wait for 20 seconds to read in a monster file from net.sources. X * What we really want is coroutines--any year now. X */ X X#define ULINE 0200 Xstatic char *maxcol; X Xappfile(iop, nlines) Xregister FILE *iop; X{ X register int c; X register char *icol; /* &linebuf[0] <= icol <= maxcol */ X X if (artread || artlines >= nlines || iop == NULL) X return; X maxcol = linebuf; X icol = linebuf; X while ((c = getc(iop)) != EOF) { X switch (c) { X case ' ': X if (icol == maxcol && icol < linebuf + LBUFLEN - 1) { X *icol++ = ' '; X maxcol = icol; X } else { X if (*icol == '_') X *icol++ = ULINE | ' '; X else X icol++; X } X break; X case '\t': X icol = (icol - linebuf &~ 07) + 8 + linebuf; X growline(icol); X break; X case '\b': X if (icol > linebuf) --icol; X break; X case '\n': X outline(); X if (artlines >= nlines) X return; X icol = linebuf; X break; X case '\r': X icol = linebuf; X break; X case '\f': X outline(); outline(); outline(); X if (artlines >= nlines) X return; X icol = linebuf; X break; X default: X if (c < ' ' || c > '~') X break; X else if (icol >= linebuf + LBUFLEN - 1) X icol++; X else if (icol == maxcol) { X *icol++ = c; X maxcol = icol; } X else if (c == '_') X *icol++ |= ULINE; X else if (*icol == '_') X *icol++ = (c | ULINE); X else *icol++ = c; X break; X } X } X if (maxcol != linebuf) /* file not terminated with newline */ X outline(); X artread++; X} X Xgrowline(col) Xchar *col; X{ X while (maxcol < col && maxcol < linebuf + LBUFLEN - 1) X *maxcol++ = ' '; X} X Xoutline() X{ X *maxcol = '\0'; X if (strncmp(linebuf, ">From ", 6) == 0) { X register char *p; X for (p = linebuf ; (*p = p[1]) != '\0' ; p++); X } X tfappend(linebuf); X if (maxcol > linebuf) X artlines = lastlin; X maxcol = linebuf; X} X X X/* X * Prompt the user and get a line. X * "prompter" is the prompt. "buf" contains a string which X * will be used as the initial user response (which may be edited X * by the user with backspace, ^U, etc). The resulting line is X * returned in "buf". The result of prget() is: X * 0 if the line was terminated by NL or CR X * 1 if it was terminated by the interrupt character. X * 2 if it was terminated by erasing all the characters, including X * one or more that were prompted initially in "buf". (If "buf" X * was empty, this will never occur.) X */ Xint Xprget(prompter, buf) Xchar *prompter, *buf; X{ X register char *p, *q, *r; X register char c; X char lastc; X char hadprompt = buf[0]; X X curflag = CURP2; X r = buf + strlen(buf); X lastc = '\0'; X for (;;) { X p = secpr; X for (q = prompter ; *q ; q++) X *p++ = *q; X for (q = buf ; *q ; q++) { X if (p < &secpr[SECPRLEN-1] && *q >= ' ' && *q <= '~') X *p++ = *q; X } X *p = '\0'; X c = vgetc(); X if (c == '\n' || c == '\r' || c == cintr) { X break; X } X if (c == cerase || c == '\b' || c == '\177') { X if (lastc == '\\') X r[-1] = c; X else if (r > buf) X r--; X } else if (c == ckill) { X if (lastc == '\\') X r[-1] = c; X else X r = buf; X#ifdef TIOCGLTC X } else if (c == cwerase) { X if (lastc == '\\') X r[-1] = c; X else { X while (r > buf && (r[-1] == ' ' || r[-1] == '\t')) X r--; X while (r > buf && r[-1] != ' ' && r[-1] != '\t') X r--; X } X#endif X } else { X *r++ = c; X } X lastc = c; X *r = '\0'; X if ((r == buf) && hadprompt) X return 2; X } X curflag = CURHOME; X secpr[0] = '\0'; X return (c == cintr); X} X X X X/* X * Execute a shell command. X */ X Xshcmd(cmd, flags) Xchar *cmd; X{ X char *arg[4]; X X arg[0] = SHELL, arg[1] = "-c", arg[2] = cmd, arg[3] = NULL; X return prun(arg, flags); X} X X Xprun(args, flags) Xchar **args; X{ X int pid; X int i; X int (*savequit)(); X char *env[100], **envp, **oenvp; X char a[BUFLEN + 2]; X extern char **environ; X int pstatus, retval; X X if (!(flags & BKGRND)) { X botscreen(); X ttycooked(); X#ifdef SIGTSTP X (void) signal(SIGTSTP, SIG_DFL); X (void) signal(SIGTTIN, SIG_DFL); X (void) signal(SIGTTOU, SIG_DFL); X#endif X } X#if defined(BSD4_2) && !defined(sun) X while ((pid = vfork()) == -1) X#else /* !BSD4_2 */ X /* 4.1 BSD (at least) can't handle this vfork with -ljobs */ X while ((pid = fork()) == -1) X#endif /* !BSD4_2 */ X sleep(1); /* must not clear alarm */ X if (pid == 0) { X for (i = 3 ; i < 20 ; i++) X close(i); X if (flags & BKGRND) { X (void) signal(SIGINT, SIG_IGN); X (void) signal(SIGQUIT, SIG_IGN); X#ifdef SIGTSTP X (void) signal(SIGTSTP, SIG_IGN); X (void) signal(SIGTTIN, SIG_IGN); X (void) signal(SIGTTOU, SIG_IGN); X#endif X (void) close(0); X (void) close(1); X (void) open("/dev/null", 2); X (void) dup(0); X } X /* set $A */ X (void) sprintf(a, "A=%s", filename); X oenvp = environ; X env[0] = a; X for (envp = env + 1 ; *oenvp != NULL && envp < env + 98 ; oenvp++) X if ((*oenvp)[0] != 'A' || (*oenvp)[1] != '=') X *envp++ = *oenvp; X *envp = NULL; X X (void) umask(savmask); X execve(args[0], args, env); X perror(args[0]); X exit(20); X } X if (!(flags & BKGRND)) { X savequit = signal(SIGQUIT, SIG_IGN); X while ((i = wait(&pstatus)) != pid && (i != -1 || errno == EINTR)) X ; X if (i == -1) X retval = 1; X else X retval = pstatus; X if (flags & CWAIT) { X fprintf(stderr, "[Hit return to continue]"); X while ((errno = 0, i = getchar()) != '\n' X && (i != EOF || errno == EINTR)); X } X (void) signal(SIGQUIT, savequit); X ttyraw(); X clearok(curscr, 1); X#ifdef SIGTSTP X (void) signal(SIGTSTP, onstop); X (void) signal(SIGTTIN, onstop); X (void) signal(SIGTTOU, onstop); X#endif X return retval; X } else X return 0; X} X X#ifdef DIGPAGE X X X/* X * Find end of current subarticle in digest. X */ X Xfindend(l) X{ X register int i, n; X register char *p; X X for (i = l ; i < l + ARTWLEN && i < lastlin ; i++) { X tfget(linebuf, i); X for (p = linebuf ; *p == '-' ; p++) X ; X n = (int)p - (int)linebuf; X if ( (n > 23 && n < 33) || (n > 65 && n < 79)) { X tfget(linebuf, ++i); X if (linebuf[0] == '\0') X return i + 1; X } X } X return 0; X} X X#endif X X X/*** Routines for handling temporary file ***/ X X/* X * Append to temp file. X * Long lines are folded. X */ X Xtfappend(tline) Xregister char *tline; X{ X register char *nxtlin; X X do { X nxtlin = index(tline, '\n'); X if (nxtlin) X *nxtlin++ = '\0'; X X while (strlen(tline) > COLS) { X tfput(tline, lastlin++); X tline += COLS; X maxlinno++; X } X tfput(tline, lastlin++); X } while ((tline = nxtlin) != NULL); X} X X Xtfput(tline, linno) Xchar *tline; X{ X register char *p; X register FILE *rtfp; /* try to make it a little faster */ X register int i; X X p = tline, i = even(COLS); X tfseek(linno, 1); X rtfp = tfp; X while (--i >= 0) { X if (*p) X putc(*p++, rtfp); X else X putc('\0', rtfp); X } X tflinno++; X} X X Xtfget(tline, linno) Xchar *tline; X{ X tfseek(linno, 0); X fread(tline, even(COLS), 1, tfp); X tline[COLS] = '\0'; X tflinno++; X} X X Xtfseek(linno, wrflag) X{ X static int lastwrflag = 1; X X if (linno != tflinno || wrflag != lastwrflag) { X (void) fseek(tfp, (long)linno * even(COLS), 0); X tflinno = linno; X lastwrflag = wrflag; X } X} X X/* VARARGS1 */ Xmsg(s, a1, a2, a3, a4) Xchar *s; Xlong a1, a2, a3, a4; X{ X (void) sprintf(secpr, s, a1, a2, a3, a4); X} X X X/* X * Update the display. X * The display is entirely controlled by this routine, X * which means that this routine may get pretty snarled. X */ X Xstatic int savelinno = -1; /* dlinno on last call to updscr */ Xstatic int savepr; /* prflags on last call */ X#ifdef TIOCGWINSZ Xstatic int UPDATING = 0, WINCH = 0; X X/* X * called by winch() from virtterm.c -- resets state information back X * to start-up state and forces a full redraw of the screen. The X * current article is rewound to the beginning because it's would X * be very difficult to get the screen to return to the exact point X * in the file that the user left off (I know, I tried). X */ Xwinch_upd() X{ X if(UPDATING) /* concurrency. wow! */ X WINCH++; X else if((WINCH == 0) && (savelinno >= 0)) { X int saveflag = curflag; X X /* reread the article */ X FCLOSE(fp); X obit = -1; X getnextart(FALSE); X appfile(fp, dlinno + ARTWLEN + 1); X X /* fix up the screen */ X curflag = saveflag; X strcpy(prompt,"more? "); X clearok(curscr, 1); X updscr(); X } X} X#endif /* TIOCGWINSZ */ X X Xupdscr() X{ X int count; X int i; X X#ifdef TIOCGWINSZ X UPDATING++; X#endif /* TIOCGWINSZ */ X if (checkin()) X return; X if ((prflags & HELPMSG) == 0 X && (dlinno != savelinno || savepr != prflags) X && quitflg == 0) { X if (dlinno != savelinno) X prflags &=~ NOPRT; X count = ARTWLEN; X if (prflags & NOPRT) X count = 0; X if ((prflags & HDRONLY) && count > hdrend) X count = hdrend - dlinno; X#ifdef DIGPAGE X if (endsuba > 0 && count > endsuba - dlinno) X count = endsuba - dlinno; X#endif X if ((prflags & NEWART) == 0) X ushift(ARTWIN, ARTWIN+ARTWLEN-1, dlinno - savelinno); X if (count > lastlin - dlinno) X count = lastlin - dlinno; X for (i = ARTWIN ; i < ARTWIN + ARTWLEN ; i++) X clrline(i); X for (i = 0 ; i < count ; i++) { X tfget(linebuf, dlinno + i); X mvaddstr(ARTWIN + i, 0, linebuf); X } X prflags &=~ NEWART; X savepr = prflags; X savelinno = dlinno; X } X clrline(SPLINE), clrline(PRLINE); X#ifdef STATTOP X mvaddstr(PRLINE, 0, prompt); X#else X if (strlen(secpr) <= COLS) X mvaddstr(PRLINE, 0, prompt); X#endif X mvaddstr(PRLINE, 59, timestr); X mvaddstr(PRLINE, 17, groupdir); X addch(' '); addnum(bit); addch('/'); addnum(pngsize); addch(' '); X if (ismail) X mvaddstr(PRLINE, 75, ismail > 1? "MAIL" : "mail"); X mvaddstr(SPLINE, 0, secpr); X if (curflag == CURP1) X move(PRLINE, strlen(prompt)); X else if (curflag == CURHOME) X move(0, 0); X refresh(); X#ifdef TIOCGWINSZ X UPDATING=0; X if (WINCH) { /* window changed while updating screen */ X WINCH = 0; X winch_upd(); X } X#endif /* TIOCGWINSZ */ X} X Xaddnum(n) Xregister long n; X{ X if (n >= 10) X addnum(n / 10); X addch((char)(n % 10 + '0')); X} X X/* X * Called on alarm signal. X * Simply sets flag, signal processed later. X */ X Xonalarm() X{ X#ifdef SIGTSTP X int dojump = reading; X X reading = FALSE; X alflag++; X if (dojump) X longjmp(alrmjmp, 1); X#else /* !SIGTSTP */ X alflag++; X#endif X} X X/* X * Process alarm signal (or start clock) X */ Xtimer() X{ X time_t tod; X int hour; X int i; X struct tm *t; X struct stat statb; X struct tm *localtime(); X static char months[] = "JanFebMarAprMayJunJulAugSepOctNovDec"; X static long oldmsize = 1000000L; X static int rccount = 10; X static time_t lastismail = 0; X X alflag = 0; X (void) signal(SIGALRM, onalarm); X (void) time(&tod); X t = localtime(&tod); X i = 60 - t->tm_sec; X (void) alarm(i > 30? 30 : i); /* reset alarm */ X hour = t->tm_hour % 12; X if (hour == 0) hour = 12; X (void) sprintf(timestr, "%.3s %d %d:%02d", X months + 3 * t->tm_mon, t->tm_mday, hour, t->tm_min); X if (mailf == NULL || stat(mailf, &statb) < 0) { X statb.st_size = 0; X } X if (statb.st_size > oldmsize) { X ismail = 2; X beep(); X } else { X if (statb.st_size == 0) X ismail = 0; X /* force MAIL for at least 30 seconds */ X else if (ismail > 1 && (lastismail+30) < tod) X ismail = 1; X } X oldmsize = statb.st_size; X lastismail = tod; X if (uflag && !xflag && --rccount < 0) { X writeoutrc(); X if (secpr[0] == '\0') X (void) strcpy(secpr, ".newsrc updated"); X rccount = 10; X } X} X Xchar * Xgetmailname() X{ X static char mailname[32]; X register char *p; X X if( (p = getenv("MAIL")) != NULL) X return p; X#ifndef MMDF X if (username[0] == '\0' || strlen(username) > 15) X return NULL; X#ifdef USG X (void) sprintf(mailname, "/usr/mail/%s", username); X#else /* !USG */ X (void) sprintf(mailname, "/usr/spool/mail/%s", username); X#endif /* !USG */ X#else /* MMDF */ X (void) sprintf(mailname, "%s/mailbox", userhome); X#endif /* MMDF */ X return mailname; X} X X X X/*** Terminal I/O ***/ X X#define INBUFSIZ 8 X Xchar inbuf[INBUFSIZ]; /* input buffer */ Xchar outbuf[BUFSIZ]; /* output buffer */ Xint innleft = 0; /* # of chars in input buffer */ Xint outnleft = BUFSIZ; /* room left in output buffer */ Xchar *innext; /* next input character */ Xchar *outnext = outbuf; /* next space in output buffer */ X#ifdef USG Xint oflags; /* fcntl flags (for nodelay read) */ X#endif X X/* X * Input a character X */ X Xvgetc() X{ X register c; X#if defined(BSD4_2) || defined(BSD4_1C) X int readfds, exceptfds; X#endif X Xrecurse: X if (--innleft >= 0) { X c = *innext++; X } else { X if (alflag) X timer(); X updscr(); /* update the display */ X for (;;) { X if (innleft > 0 || alflag) X goto recurse; X intflag = 0; X#ifdef USG X if (oflags & O_NDELAY) { X oflags &=~ O_NDELAY; X fcntl(0, F_SETFL, oflags); X } X#endif X#ifdef SIGTSTP X if (setjmp(alrmjmp)) X continue; X if (setjmp(intjmp)) X return cintr; X reading = TRUE; X#endif /* SIGTSTP */ X#if defined(BSD4_2) || defined(BSD4_1C) X /* Use a select because it can be interrupted. */ X readfds = 1; exceptfds = 1; X select(1, &readfds, (int *)0, &exceptfds, (int *)0); X if (!(readfds & 1)) X break; X#endif X innleft = read(0, inbuf, INBUFSIZ); X#ifdef SIGTSTP X reading = FALSE; X#endif /* SIGTSTP */ X if (innleft > 0) X break; X if (innleft == 0) { X quitflg++; X return cintr; X } X if (errno != EINTR) X abort(); /* "Can't happen" */ X if (intflag) { X intflag--; X return cintr; X } X } X innext = inbuf + 1; X innleft--; X c = inbuf[0]; X } X#ifndef USG X#ifndef CBREAK X c &= 0177; X if (c == '\034') /* FS character */ X xxit(0); X#endif X#endif X if (c == '\f') { X clearok(curscr, 1); X prflags &=~ NOPRT; X goto recurse; X } X if (c == '\r') X c = '\n'; X return c; X} X X X/* X * Push a character back onto the input stream. X */ X Xpushback(c) X{ X if (innext <= inbuf) X abort(); X *--innext = c; X innleft++; X} X X/* X * Check for terminal input X */ X Xcheckin() X{ X#ifdef FIONREAD X int count; X#endif X#ifdef STATTOP X if (innleft > 0) X#else X if (innleft > 0 || alflag) X#endif X return 1; X#if defined(USG) || defined(FIONREAD) X if (ospeed >= B9600) X return 0; X vflush(); X if (ospeed <= B300) X ttyowait(); X#ifdef USG X if ((oflags & O_NDELAY) == 0) { X oflags |= O_NDELAY; X (void) fcntl(0, F_SETFL, oflags); X } X if ((innleft = read(0, inbuf, INBUFSIZ)) > 0) { X innext = inbuf; X return 1; X } X#endif X#ifdef FIONREAD X count = 0; /* in case FIONREAD fails */ X (void) ioctl(0, FIONREAD, (char *)&count); X if (count) X return 1; X#endif X#endif X return 0; X} X X X X/* X * flush terminal input queue. X */ X Xclearin() X{ X#ifdef USG X (void) ioctl(0, TCFLSH, (char *)0); X#else X#ifdef TIOCFLUSH X (void) ioctl(0, TIOCFLUSH, (char *)0); X#else X struct sgttyb tty; X (void) ioctl(0, TIOCGETP, &tty); X (void) ioctl(0, TIOCSETP, &tty); X#endif X#endif X innleft = 0; X} X Xvputc(c) X{ X if (--outnleft < 0) { X vflush(); X outnleft--; X } X *outnext++ = c; X} X X/* X * Flush the output buffer X */ X Xvflush() X{ X register char *p; X register int i; X#ifdef BSD4_2 X int mask; X#else X unsigned oalarm; X#endif X X#ifdef BSD4_2 X mask = sigblock(1 << (SIGALRM-1)); X#else X oalarm = alarm(0); X#endif X for (p = outbuf ; p < outnext ; p += i) { X if ((i = write(1, p, outnext - p)) < 0) { X if (errno != EINTR) X abort(); /* "Can't happen" */ X i = 0; X } X } X outnleft = BUFSIZ; X outnext = outbuf; X#ifdef BSD4_2 X sigsetmask(mask); X#else X (void) alarm(oalarm); X#endif X} X X/*** terminal modes ***/ X X#ifdef USG Xstatic struct termio oldtty, newtty; X X/* X * Save tty modes X */ X Xttysave() X{ X if (ioctl(1, TCGETA, &oldtty) < 0) X xerror("Can't get tty modes"); X newtty = oldtty; X newtty.c_iflag &=~ (INLCR|IGNCR|ICRNL); X newtty.c_oflag &=~ (OPOST); X newtty.c_lflag &=~ (ICANON|ECHO|ECHOE|ECHOK|ECHONL); X newtty.c_lflag |= (NOFLSH); X newtty.c_cc[VMIN] = 1; X newtty.c_cc[VTIME] = 0; X cerase = oldtty.c_cc[VERASE]; X ckill = oldtty.c_cc[VKILL]; X cintr = oldtty.c_cc[VINTR]; X ospeed = oldtty.c_cflag & CBAUD; X initterm(); X} X X X/* X * Set tty modes for visual processing X */ X Xttyraw() X{ X while (ioctl(1, TCSETAF, &newtty) < 0 && errno == EINTR) X ; X rawterm(); X} X Xttyowait() X{ /* wait for output queue to drain */ X while (ioctl(1, TCSETAW, &newtty) < 0 && errno == EINTR) X ; X} X X/* X * Restore tty modes X */ X Xttycooked() X{ X cookedterm(); X vflush(); X while (ioctl(1, TCSETAF, &oldtty) < 0 && errno == EINTR) X ; X oflags &=~ O_NDELAY; X (void) fcntl(0, F_SETFL, oflags) ; X} X X#else X Xstatic struct sgttyb oldtty, newtty; X#ifdef TIOCGLTC Xstatic struct ltchars oldltchars, newltchars; X#endif X X/* X * Save tty modes X */ X Xttysave() X{ X#ifdef CBREAK X struct tchars tchars; /* special characters, including interrupt */ X#endif X#ifdef SIGTSTP X int getpgrp(); X#if defined(BSD4_2) || defined(BSD4_1C) X int tpgrp; X#else /* BSD4_1 */ X short tpgrp; X#endif /* BSD4_1 */ X Xretry: X#ifdef BSD4_2 X (void) sigblock(sigmask(SIGTSTP)|sigmask(SIGTTIN)|sigmask(SIGTTOU)); X#else /* !BSD4_2 */ X (void) signal(SIGTSTP, SIG_HOLD); X (void) signal(SIGTTIN, SIG_HOLD); X (void) signal(SIGTTOU, SIG_HOLD); X#endif /* !BSD4_2 */ X if (ioctl(2, TIOCGPGRP, (char *)&tpgrp) < 0) X goto nottty; X if (tpgrp != getpgrp(0)) { /* not in foreground */ X (void) signal(SIGTTOU, SIG_DFL); X#ifdef BSD4_2 X (void) sigsetmask(sigblock(0) & ~sigmask(SIGTTOU)); X#endif /* BSD4_2 */ X (void) kill(0, SIGTTOU); X /* job stops here waiting for SIGCONT */ X goto retry; X } X (void) signal(SIGTTIN, SIG_DFL); X (void) signal(SIGTTOU, SIG_DFL); X (void) signal(SIGTSTP, SIG_DFL); X#ifdef BSD4_2 X (void) sigsetmask(sigblock(0) & ~(sigmask(SIGTSTP)|sigmask(SIGTTIN)|sigmask(SIGTTOU))); X#endif /* BSD4_2 */ X#endif /* SIGTSTP */ X if (ioctl(1, TIOCGETP, (char *)&oldtty) < 0) Xnottty: xerror("Can't get tty modes"); X newtty = oldtty; X newtty.sg_flags &=~ (CRMOD|ECHO|XTABS); X#ifdef CBREAK X newtty.sg_flags |= CBREAK; X ioctl(1, TIOCGETC, (char *)&tchars); X cintr = tchars.t_intrc; X#else /* !CBREAK */ X newtty.sg_flags |= RAW; X cintr = '\0177'; /* forcibly this on V6 systems */ X#endif /* !CBREAK */ X cerase = oldtty.sg_erase; X ckill = oldtty.sg_kill; X ospeed = oldtty.sg_ospeed; X#ifdef TIOCGLTC X if (ioctl(1, TIOCGLTC, (char *)&oldltchars) >= 0) { X newltchars = oldltchars; X newltchars.t_dsuspc = -1; X cwerase = oldltchars.t_werasc; X } X#endif X initterm(); X#ifdef SIGTSTP X (void) signal(SIGTTIN, onstop); X (void) signal(SIGTTOU, onstop); X (void) signal(SIGTSTP, onstop); X#endif /* SIGTSTP */ X} X X X/* X * Set tty modes for visual processing X */ X Xttyraw() X{ X while (ioctl(1, TIOCSETN, (char *)&newtty) < 0 && errno == EINTR) X ; X#ifdef TIOCGLTC X if (newltchars.t_dsuspc == '\377') X while (ioctl(1, TIOCSLTC, (char *)&newltchars) < 0 && errno == EINTR) X ; X#endif X rawterm(); X} X Xttyowait() X{ /* wait for output queue to drain */ X#ifdef TIOCDRAIN /* This ioctl is a local mod on linus */ X (void) ioctl(1, TIOCDRAIN, (char *)0); X#endif X} X X X/* X * Restore tty modes X */ X Xttycooked() X{ X cookedterm(); X vflush(); X while (ioctl(1, TIOCSETN, (char *)&oldtty) < 0 && errno == EINTR) X ; X#ifdef TIOCGLTC X if (newltchars.t_dsuspc == '\377') X while (ioctl(1, TIOCSLTC, (char *)&oldltchars) < 0 && errno == EINTR) X ; X#endif X} X X#endif X X X X/*** signal handlers ***/ X Xonint() { X#ifdef SIGTSTP X int dojump = reading; X X reading = FALSE; X#endif /* SIGTSTP */ X if (!news) { X ttycooked(); X xxit(1); X } X (void) signal(SIGINT, onint); X clearin(); /* flush input queue */ X#ifdef SIGTSTP X if (dojump) X longjmp(intjmp, 1); X#endif /* SIGTSTP */ X intflag++; X} X X#ifdef SIGTSTP Xonstop(signo) Xint signo; X{ X /* restore old terminal state */ X botscreen(); X vflush(); X ttycooked(); X (void) signal(signo, SIG_DFL); X#ifdef BSD4_2 X (void) sigblock(sigmask(SIGALRM)|sigmask(SIGINT)); X (void) sigsetmask(sigblock(0) & ~sigmask(signo)); X#else /* BSD4_1 */ X (void) alarm(0); X#endif /* BSD4_1 */ X (void) kill(0, signo); /* stop here until continued */ X X (void) signal(signo, onstop); X /* restore our special terminal state */ X ttyraw(); X#ifdef TIOCGWINSZ X winch(); /* get current window size and redraw screen */ X#else /* !TIOCGWINSZ */ X clearok(curscr, 1); X updscr(); X#endif /* !TIOCGWINSZ */ X#ifdef BSD4_2 X (void) sigsetmask(sigblock(0) & ~(sigmask(SIGALRM)|sigmask(SIGINT))); X#else /* BSD4_1 */ X timer(); X#endif /* BSD4_1 */ X} X#endif X X/*** stolen from rfuncs2.c and modified ***/ X Xvsave(to, flags) Xregister char *to; X{ X register FILE *ufp; X int isprogram = 0; X int isnew = 1; X long saveoff; X char temp[20]; X char *fname; X char prog[BUFLEN + 24]; X int err; X X saveoff = ftell(fp); X (void) fseek(fp, artbody, 0); X fname = to; X if (*to == PIPECHAR) { X if (strlen(to) > BUFLEN) { X msg("Command name too long"); X goto out; X } X flags |= OVWRITE; X (void) strcpy(temp, "/tmp/vnXXXXXX"); X (void) mktemp(temp); X fname = temp; X _amove(ROWS - 1, 0); X vflush(); X } X if ((flags & OVWRITE) == 0) { X ufp = fopen(fname, "r"); X if (ufp != NULL) { X (void) fclose(ufp); X isnew = 0; X } X } X (void) umask(savmask); X X if (*to == PIPECHAR) X isprogram++; X if ((ufp = fopen(fname, (flags & OVWRITE) == 0? "a" : "w")) == NULL) { X msg("Cannot open %s", fname); X goto out; X } X /* X * V7MAIL code is here to conform to V7 mail format. X * If you need a different format to be able to X * use your local mail command (such as four ^A's X * on the end of articles) substitute it here. X */ X if (flags & SVHEAD) { X#ifdef MMDF X if (!isprogram) X fprintf(ufp, "\001\001\001\001\n"); X#endif /* MMDF */ X#ifdef V7MAIL X h->subtime = cgtdate(h->subdate); X fprintf(ufp, "From %s %s", replyname(h), ctime(&h->subtime)); X#endif X hprint(h, ufp, 2); X#ifdef V7MAIL X tprint(fp, ufp, TRUE); X putc('\n', ufp); /* force blank line at end (ugh) */ X#else X tprint(fp, ufp, FALSE); X#endif X } else { X tprint(fp, ufp, FALSE); X } X X err = ferror(ufp); X X fclose(ufp); X if (isprogram) { X if (err) X msg("error in writing temp file, maybe disk full?"); X else { X (void) sprintf(prog, "(%s)<%s", to + 1, fname); X shcmd(prog, CWAIT); X prflags |= NOPRT; X } X } else { X msg("%sfile: %s %s", X err? "ERROR WHILE WRITING ": "", X to, X (flags&OVWRITE)? "written": X isnew ? "created" : "appended"); X } X X /* If we got an error, screen may be messed. E.g. 4.2BSD X * writes "disk full" messages to the user's tty. X */ X if (err) { X clearok(curscr, 1); X updscr(); X } X Xout: X if (isprogram) { X (void) unlink(fname); X } X (void) umask(N_UMASK); X (void) fseek(fp, saveoff, 0); X} X Xxxit(status) Xint status; X{ X (void) unlink(infile); X (void) unlink(outfile); X#ifdef SORTACTIVE X if (strncmp(ACTIVE,"/tmp/", 5) == 0) X (void) unlink(ACTIVE); X#endif /* SORTACTIVE */ X if (ospeed) { /* is == 0, we haven't been in raw mode yet */ X botscreen(); X vflush(); X ttycooked(); X } X exit(status); X} END_OF_FILE if test 55369 -ne `wc -c <'visual.c'`; then echo shar: \"'visual.c'\" unpacked with wrong size! fi # end of 'visual.c' fi echo shar: End of shell archive. exit 0 -- "Zeta Microcomputer Software" ACSnet: nick@ultima.cs.uts.oz UUCP: ...!uunet!munnari!ultima.cs.uts.oz!nick Fidonet: Nick Andrew on 3:713/602 (Zeta)
nick@ultima.cs.uts.oz (Nick Andrew) (12/07/89)
#! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of shell archive." # Contents: compress.c # Wrapped by nick@ultima on Thu Dec 7 22:48:42 1989 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'compress.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'compress.c'\" else echo shar: Extracting \"'compress.c'\" \(35496 characters\) sed "s/^X//" >'compress.c' <<'END_OF_FILE' X#ifdef SCCSID Xstatic char *SccsId = "@(#)compress.c 1.13 12/16/86"; X#endif /* SCCSID */ Xstatic char rcs_ident[] = "Based on compress.c,v 4.0 85/07/30 12:50:00 joe Release"; X X/* X * Compress - data compression program X */ X#define min(a,b) ((a>b) ? b : a) X X/* X * machine variants which require cc -Dmachine: pdp11, z8000, pcxt X */ X X/* X * Set USERMEM to the maximum amount of physical user memory available X * in bytes. USERMEM is used to determine the maximum BITS that can be used X * for compression. X * X * SACREDMEM is the amount of physical memory saved for others; compress X * will hog the rest. X */ X#ifndef SACREDMEM X#define SACREDMEM 0 X#endif X X#ifndef USERMEM X# define USERMEM 450000 /* default user memory */ X#endif X X#ifdef interdata /* (Perkin-Elmer) */ X#define SIGNED_COMPARE_SLOW /* signed compare is slower than unsigned */ X#endif X X#ifdef pdp11 X# define BITS 12 /* max bits/code for 16-bit machine */ X# define NO_UCHAR /* also if "unsigned char" functions as signed char */ X# undef USERMEM X#endif /* pdp11 */ /* don't forget to compile with -i */ X X#ifdef z8000 X# define BITS 12 X# undef vax /* weird preprocessor */ X# undef USERMEM X#endif /* z8000 */ X X#ifdef pcxt X# define BITS 12 X# undef USERMEM X#endif /* pcxt */ X X#ifdef MINIX X/* Minixy things to at least make it compile */ X# define BITS 12 X# undef USERMEM X#endif /* pcxt */ X X#ifdef USERMEM X# if USERMEM >= (433484+SACREDMEM) X# define PBITS 16 X# else X# if USERMEM >= (229600+SACREDMEM) X# define PBITS 15 X# else X# if USERMEM >= (127536+SACREDMEM) X# define PBITS 14 X# else X# if USERMEM >= (73464+SACREDMEM) X# define PBITS 13 X# else X# define PBITS 12 X# endif X# endif X# endif X# endif X# undef USERMEM X#endif /* USERMEM */ X X#ifdef PBITS /* Preferred BITS for this memory size */ X# ifndef BITS X# define BITS PBITS X# endif BITS X#endif /* PBITS */ X X#if BITS == 16 X# define HSIZE 69001 /* 95% occupancy */ X#endif X#if BITS == 15 X# define HSIZE 35023 /* 94% occupancy */ X#endif X#if BITS == 14 X# define HSIZE 18013 /* 91% occupancy */ X#endif X#if BITS == 13 X# define HSIZE 9001 /* 91% occupancy */ X#endif X#if BITS <= 12 X# define HSIZE 5003 /* 80% occupancy */ X#endif X X#ifdef M_XENIX /* Stupid compiler can't handle arrays with */ X# if BITS == 16 /* more than 65535 bytes - so we fake it */ X# define XENIX_16 X# else X# if BITS > 13 /* Code only handles BITS = 12, 13, or 16 */ X# define BITS 13 X# endif X# endif X#endif X X/* X * a code_int must be able to hold 2**BITS values of type int, and also -1 X */ X#if BITS > 15 Xtypedef long int code_int; X#else Xtypedef int code_int; X#endif X X#ifdef SIGNED_COMPARE_SLOW Xtypedef unsigned long int count_int; Xtypedef unsigned short int count_short; X#else Xtypedef long int count_int; X#endif X X#ifdef NO_UCHAR X typedef char char_type; X#else X typedef unsigned char char_type; X#endif /* UCHAR */ Xchar_type magic_header[] = { "\037\235" }; /* 1F 9D */ X X/* Defines for third byte of header */ X#define BIT_MASK 0x1f X#define BLOCK_MASK 0x80 X/* Masks 0x40 and 0x20 are free. I think 0x20 should mean that there is X a fourth header byte (for expansion). X*/ X#define INIT_BITS 9 /* initial number of bits/code */ X X/* X * compress.c - File compression ala IEEE Computer, June 1984. X * X * Authors: Spencer W. Thomas (decvax!harpo!utah-cs!utah-gr!thomas) X * Jim McKie (decvax!mcvax!jim) X * Steve Davies (decvax!vax135!petsd!peora!srd) X * Ken Turkowski (decvax!decwrl!turtlevax!ken) X * James A. Woods (decvax!ihnp4!ames!jaw) X * Joe Orost (decvax!vax135!petsd!joe) X * X */ X X#include <stdio.h> X#include <ctype.h> X#include <signal.h> X#include <sys/types.h> X#include <sys/stat.h> X X#define ARGVAL() (*++(*argv) || (--argc && *++argv)) X Xint n_bits; /* number of bits/code */ Xint maxbits = BITS; /* user settable max # bits/code */ Xcode_int maxcode; /* maximum code, given n_bits */ Xcode_int maxmaxcode = 1L << BITS; /* should NEVER generate this code */ X#ifdef COMPATIBLE /* But wrong! */ X# define MAXCODE(n_bits) (1 << (n_bits) - 1) X#else X# define MAXCODE(n_bits) ((1 << (n_bits)) - 1) X#endif /* COMPATIBLE */ X X#ifdef XENIX_16 Xcount_int htab0[8192]; Xcount_int htab1[8192]; Xcount_int htab2[8192]; Xcount_int htab3[8192]; Xcount_int htab4[8192]; Xcount_int htab5[8192]; Xcount_int htab6[8192]; Xcount_int htab7[8192]; Xcount_int htab8[HSIZE-65536]; Xcount_int * htab[9] = { X htab0, htab1, htab2, htab3, htab4, htab5, htab6, htab7, htab8 }; X X#define htabof(i) (htab[(i) >> 13][(i) & 0x1fff]) Xunsigned short code0tab[16384]; Xunsigned short code1tab[16384]; Xunsigned short code2tab[16384]; Xunsigned short code3tab[16384]; Xunsigned short code4tab[16384]; Xunsigned short * codetab[5] = { X code0tab, code1tab, code2tab, code3tab, code4tab }; X X#define codetabof(i) (codetab[(i) >> 14][(i) & 0x3fff]) X X#else /* Normal machine */ X# ifdef sel X/* support gould base register problems */ X/*NOBASE*/ Xcount_int htab [HSIZE]; Xunsigned short codetab [HSIZE]; X/*NOBASE*/ X# else /* !gould */ Xcount_int htab [HSIZE]; Xunsigned short codetab [HSIZE]; X# endif /* !gould */ X#define htabof(i) htab[i] X#define codetabof(i) codetab[i] X#endif /* !XENIX_16 */ Xcode_int hsize = HSIZE; /* for dynamic table sizing */ Xcount_int fsize; X X/* X * To save much memory, we overlay the table used by compress() with those X * used by decompress(). The tab_prefix table is the same size and type X * as the codetab. The tab_suffix table needs 2**BITS characters. We X * get this from the beginning of htab. The output stack uses the rest X * of htab, and contains characters. There is plenty of room for any X * possible stack (stack used to be 8000 characters). X */ X X#define tab_prefixof(i) codetabof(i) X#ifdef XENIX_16 X# define tab_suffixof(i) ((char_type *)htab[(i)>>15])[(i) & 0x7fff] X# define de_stack ((char_type *)(htab2)) X#else /* Normal machine */ X# define tab_suffixof(i) ((char_type *)(htab))[i] X# define de_stack ((char_type *)&tab_suffixof(1<<BITS)) X#endif /* XENIX_16 */ X Xcode_int free_ent = 0; /* first unused entry */ Xint exit_stat = 0; X Xcode_int getcode(); X XUsage() { X#ifdef DEBUG Xfprintf(stderr,"Usage: compress [-dDVfc] [-b maxbits] [file ...]\n"); X} Xint debug = 0; X#else Xfprintf(stderr,"Usage: compress [-dfvcV] [-b maxbits] [file ...]\n"); X} X#endif /* DEBUG */ Xint nomagic = 0; /* Use a 3-byte magic number header, unless old file */ Xint zcat_flg = 0; /* Write output on stdout, suppress messages */ Xint quiet = 1; /* don't tell me about compression */ X X/* X * block compression parameters -- after all codes are used up, X * and compression rate changes, start over. X */ Xint block_compress = BLOCK_MASK; Xint clear_flg = 0; Xlong int ratio = 0; X#define CHECK_GAP 10000 /* ratio check interval */ Xcount_int checkpoint = CHECK_GAP; X/* X * the next two codes should not be changed lightly, as they must not X * lie within the contiguous general code space. X */ X#define FIRST 257 /* first free entry */ X#define CLEAR 256 /* table clear output code */ X Xint force = 0; Xchar ofname [100]; X#ifdef DEBUG Xint verbose = 0; X#endif /* DEBUG */ Xint (*bgnd_flag)(); X Xint do_decomp = 0; X X/***************************************************************** X * TAG( main ) X * X * Algorithm from "A Technique for High Performance Data Compression", X * Terry A. Welch, IEEE Computer Vol 17, No 6 (June 1984), pp 8-19. X * X * Usage: compress [-dfvc] [-b bits] [file ...] X * Inputs: X * -d: If given, decompression is done instead. X * X * -c: Write output on stdout, don't remove original. X * X * -b: Parameter limits the max number of bits/code. X * X * -f: Forces output file to be generated, even if one already X * exists, and even if no space is saved by compressing. X * If -f is not used, the user will be prompted if stdin is X * a tty, otherwise, the output file will not be overwritten. X * X * -v: Write compression statistics X * X * file ...: Files to be compressed. If none specified, stdin X * is used. X * Outputs: X * file.Z: Compressed form of file with same mode, owner, and utimes X * or stdout (if stdin used as input) X * X * Assumptions: X * When filenames are given, replaces with the compressed version X * (.Z suffix) only if the file decreases in size. X * Algorithm: X * Modified Lempel-Ziv method (LZW). Basically finds common X * substrings and replaces them with a variable size code. This is X * deterministic, and can be done on the fly. Thus, the decompression X * procedure needs no input table, but tracks the way the table was built. X */ X Xmain( argc, argv ) Xregister int argc; char **argv; X{ X int overwrite = 0; /* Do not overwrite unless given -f flag */ X char tempname[100]; X char **filelist, **fileptr; X char *cp, *rindex(), *malloc(); X struct stat statbuf; X extern onintr(), oops(); X X X if ( (bgnd_flag = signal ( SIGINT, SIG_IGN )) != SIG_IGN ) { X signal ( SIGINT, onintr ); X signal ( SIGSEGV, oops ); X } X X#ifdef COMPATIBLE X nomagic = 1; /* Original didn't have a magic number */ X#endif /* COMPATIBLE */ X X filelist = fileptr = (char **)(malloc(argc * sizeof(*argv))); X *filelist = NULL; X X if((cp = rindex(argv[0], '/')) != 0) { X cp++; X } else { X cp = argv[0]; X } X if(strcmp(cp, "uncompress") == 0) { X do_decomp = 1; X } else if(strcmp(cp, "zcat") == 0) { X do_decomp = 1; X zcat_flg = 1; X } X X#ifdef BSD4_2 X /* 4.2BSD dependent - take it out if not */ X setlinebuf( stderr ); X#endif /* BSD4_2 */ X X /* Argument Processing X * All flags are optional. X * -D => debug X * -V => print Version; debug verbose X * -d => do_decomp X * -v => unquiet X * -f => force overwrite of output file X * -n => no header: useful to uncompress old files X * -b maxbits => maxbits. If -b is specified, then maxbits MUST be X * given also. X * -c => cat all output to stdout X * -C => generate output compatible with compress 2.0. X * if a string is left, must be an input filename. X */ X for (argc--, argv++; argc > 0; argc--, argv++) { X if (**argv == '-') { /* A flag argument */ X while (*++(*argv)) { /* Process all flags in this arg */ X switch (**argv) { X#ifdef DEBUG X case 'D': X debug = 1; X break; X case 'V': X verbose = 1; X version(); X break; X#else X case 'V': X version(); X break; X#endif /* DEBUG */ X case 'v': X quiet = 0; X break; X case 'd': X do_decomp = 1; X break; X case 'f': X case 'F': X overwrite = 1; X force = 1; X break; X case 'n': X nomagic = 1; X break; X case 'C': X block_compress = 0; X break; X case 'b': X if (!ARGVAL()) { X fprintf(stderr, "Missing maxbits\n"); X Usage(); X exit(1); X } X maxbits = atoi(*argv); X goto nextarg; X case 'c': X zcat_flg = 1; X break; X case 'q': X quiet = 1; X break; X default: X fprintf(stderr, "Unknown flag: '%c'; ", **argv); X Usage(); X exit(1); X } X } X } X else { /* Input file name */ X *fileptr++ = *argv; /* Build input file list */ X *fileptr = NULL; X /* process nextarg; */ X } X nextarg: continue; X } X X if(maxbits < INIT_BITS) maxbits = INIT_BITS; X if (maxbits > BITS) maxbits = BITS; X maxmaxcode = 1L << maxbits; X X if (*filelist != NULL) { X for (fileptr = filelist; *fileptr; fileptr++) { X exit_stat = 0; X if (do_decomp != 0) { /* DECOMPRESSION */ X /* Check for .Z suffix */ X if (strcmp(*fileptr + strlen(*fileptr) - 2, ".Z") != 0) { X /* No .Z: tack one on */ X strcpy(tempname, *fileptr); X strcat(tempname, ".Z"); X *fileptr = tempname; X } X /* Open input file */ X if ((freopen(*fileptr, "r", stdin)) == NULL) { X perror(*fileptr); continue; X } X /* Check the magic number */ X if (nomagic == 0) { X if ((getchar() != (magic_header[0] & 0xFF)) X || (getchar() != (magic_header[1] & 0xFF))) { X fprintf(stderr, "%s: not in compressed format\n", X *fileptr); X continue; X } X maxbits = getchar(); /* set -b from file */ X block_compress = maxbits & BLOCK_MASK; X maxbits &= BIT_MASK; X maxmaxcode = 1L << maxbits; X if(maxbits > BITS) { X fprintf(stderr, X "%s: compressed with %d bits, can only handle %d bits\n", X *fileptr, maxbits, BITS); X continue; X } X } X /* Generate output filename */ X strcpy(ofname, *fileptr); X ofname[strlen(*fileptr) - 2] = '\0'; /* Strip off .Z */ X } else { /* COMPRESSION */ X if (strcmp(*fileptr + strlen(*fileptr) - 2, ".Z") == 0) { X fprintf(stderr, "%s: already has .Z suffix -- no change\n", X *fileptr); X continue; X } X /* Open input file */ X if ((freopen(*fileptr, "r", stdin)) == NULL) { X perror(*fileptr); continue; X } X stat ( *fileptr, &statbuf ); X fsize = (long) statbuf.st_size; X /* X * tune hash table size for small files -- ad hoc, X * but the sizes match earlier #defines, which X * serve as upper bounds on the number of output codes. X */ X hsize = HSIZE; X if ( fsize < (1 << 12) ) X hsize = min ( 5003, HSIZE ); X else if ( fsize < (1 << 13) ) X hsize = min ( 9001, HSIZE ); X else if ( fsize < (1 << 14) ) X hsize = min ( 18013, HSIZE ); X else if ( fsize < (1 << 15) ) X hsize = min ( 35023, HSIZE ); X else if ( fsize < 47000 ) X hsize = min ( 50021, HSIZE ); X X /* Generate output filename */ X strcpy(ofname, *fileptr); X#ifndef BSD4_2 /* Short filenames */ X if ((cp=rindex(ofname,'/')) != NULL) cp++; X else cp = ofname; X if (strlen(cp) > 12) { X fprintf(stderr,"%s: filename too long to tack on .Z\n",cp); X continue; X } X#endif /* BSD4_2 Long filenames allowed */ X strcat(ofname, ".Z"); X } X /* Check for overwrite of existing file */ X if (overwrite == 0 && zcat_flg == 0) { X if (stat(ofname, &statbuf) == 0) { X char response[2]; X response[0] = 'n'; X fprintf(stderr, "%s already exists;", ofname); X if (foreground()) { X fprintf(stderr, " do you wish to overwrite %s (y or n)? ", X ofname); X fflush(stderr); X read(2, response, 2); X while (response[1] != '\n') { X if (read(2, response+1, 1) < 0) { /* Ack! */ X perror("stderr"); break; X } X } X } X if (response[0] != 'y') { X fprintf(stderr, "\tnot overwritten\n"); X continue; X } X } X } X if(zcat_flg == 0) { /* Open output file */ X if (freopen(ofname, "w", stdout) == NULL) { X perror(ofname); X continue; X } X if(!quiet) X fprintf(stderr, "%s: ", *fileptr); X } X X /* Actually do the compression/decompression */ X if (do_decomp == 0) compress(); X#ifndef DEBUG X else decompress(); X#else X else if (debug == 0) decompress(); X else printcodes(); X if (verbose) dump_tab(); X#endif /* DEBUG */ X if(zcat_flg == 0) { X copystat(*fileptr, ofname); /* Copy stats */ X if((exit_stat == 1) || (!quiet)) X putc('\n', stderr); X } X } X } else { /* Standard input */ X if (do_decomp == 0) { X compress(); X#ifdef DEBUG X if(verbose) dump_tab(); X#endif /* DEBUG */ X if(!quiet) X putc('\n', stderr); X } else { X /* Check the magic number */ X if (nomagic == 0) { X if ((getchar()!=(magic_header[0] & 0xFF)) X || (getchar()!=(magic_header[1] & 0xFF))) { X fprintf(stderr, "stdin: not in compressed format\n"); X exit(1); X } X maxbits = getchar(); /* set -b from file */ X block_compress = maxbits & BLOCK_MASK; X maxbits &= BIT_MASK; X maxmaxcode = 1L << maxbits; X fsize = 100000; /* assume stdin large for USERMEM */ X if(maxbits > BITS) { X fprintf(stderr, X "stdin: compressed with %d bits, can only handle %d bits\n", X maxbits, BITS); X exit(1); X } X } X#ifndef DEBUG X decompress(); X#else X if (debug == 0) decompress(); X else printcodes(); X if (verbose) dump_tab(); X#endif /* DEBUG */ X } X } X exit(exit_stat); X} X Xstatic int offset; Xlong int in_count = 1; /* length of input */ Xlong int bytes_out; /* length of compressed output */ Xlong int out_count = 0; /* # of codes output (for debugging) */ X X/* X * compress stdin to stdout X * X * Algorithm: use open addressing double hashing (no chaining) on the X * prefix code / next character combination. We do a variant of Knuth's X * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime X * secondary probe. Here, the modular division first probe is gives way X * to a faster exclusive-or manipulation. Also do block compression with X * an adaptive reset, whereby the code table is cleared when the compression X * ratio decreases, but after the table fills. The variable-length output X * codes are re-sized at this point, and a special CLEAR code is generated X * for the decompressor. Late addition: construct the table according to X * file size for noticeable speed improvement on small files. Please direct X * questions about this implementation to ames!jaw. X */ X Xcompress() { X register long fcode; X register code_int i = 0; X register int c; X register code_int ent; X#ifdef XENIX_16 X register code_int disp; X#else /* Normal machine */ X register int disp; X#endif X register code_int hsize_reg; X register int hshift; X X#ifndef COMPATIBLE X if (nomagic == 0) { X putchar(magic_header[0]); putchar(magic_header[1]); X putchar((char)(maxbits | block_compress)); X if(ferror(stdout)) X writeerr(); X } X#endif /* COMPATIBLE */ X X offset = 0; X bytes_out = 3; /* includes 3-byte header mojo */ X out_count = 0; X clear_flg = 0; X ratio = 0; X in_count = 1; X checkpoint = CHECK_GAP; X maxcode = MAXCODE(n_bits = INIT_BITS); X free_ent = ((block_compress) ? FIRST : 256 ); X X ent = getchar (); X X hshift = 0; X for ( fcode = (long) hsize; fcode < 65536L; fcode *= 2L ) X hshift++; X hshift = 8 - hshift; /* set hash code range bound */ X X hsize_reg = hsize; X cl_hash( (count_int) hsize_reg); /* clear hash table */ X X#ifdef SIGNED_COMPARE_SLOW X while ( (c = getchar()) != (unsigned) EOF ) { X#else X while ( (c = getchar()) != EOF ) { X#endif X in_count++; X fcode = (long) (((long) c << maxbits) + ent); X i = (((long)c << hshift) ^ ent); /* xor hashing */ X X if ( htabof (i) == fcode ) { X ent = codetabof (i); X continue; X } else if ( (long)htabof (i) < 0 ) /* empty slot */ X goto nomatch; X disp = hsize_reg - i; /* secondary hash (after G. Knott) */ X if ( i == 0 ) X disp = 1; Xprobe: X if ( (i -= disp) < 0 ) X i += hsize_reg; X X if ( htabof (i) == fcode ) { X ent = codetabof (i); X continue; X } X if ( (long)htabof (i) > 0 ) X goto probe; Xnomatch: X output ( (code_int) ent ); X out_count++; X ent = c; X#ifdef SIGNED_COMPARE_SLOW X if ( (unsigned) free_ent < (unsigned) maxmaxcode) { X#else X if ( free_ent < maxmaxcode ) { X#endif X codetabof (i) = free_ent++; /* code -> hashtable */ X htabof (i) = fcode; X } X else if ( (count_int)in_count >= checkpoint && block_compress ) X cl_block (); X } X /* X * Put out the final code. X */ X output( (code_int)ent ); X out_count++; X output( (code_int)-1 ); X X /* X * Print out stats on stderr X */ X if(zcat_flg == 0 && !quiet) { X#ifdef DEBUG X fprintf( stderr, X "%ld chars in, %ld codes (%ld bytes) out, compression factor: ", X in_count, out_count, bytes_out ); X prratio( stderr, in_count, bytes_out ); X fprintf( stderr, "\n"); X fprintf( stderr, "\tCompression as in compact: " ); X prratio( stderr, in_count-bytes_out, in_count ); X fprintf( stderr, "\n"); X fprintf( stderr, "\tLargest code (of last block) was %d (%d bits)\n", X free_ent - 1, n_bits ); X#else /* !DEBUG */ X fprintf( stderr, "Compression: " ); X prratio( stderr, in_count-bytes_out, in_count ); X#endif /* DEBUG */ X } X if(bytes_out > in_count) /* exit(2) if no savings */ X exit_stat = 2; X return; X} X X/***************************************************************** X * TAG( output ) X * X * Output the given code. X * Inputs: X * code: A n_bits-bit integer. If == -1, then EOF. This assumes X * that n_bits =< (long)wordsize - 1. X * Outputs: X * Outputs code to the file. X * Assumptions: X * Chars are 8 bits long. X * Algorithm: X * Maintain a BITS character long buffer (so that 8 codes will X * fit in it exactly). Use the VAX insv instruction to insert each X * code in turn. When the buffer fills up empty it and start over. X */ X Xstatic char buf[BITS]; X X#ifndef vax Xchar_type lmask[9] = {0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00}; Xchar_type rmask[9] = {0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff}; X#endif /* vax */ X Xoutput( code ) Xcode_int code; X{ X#ifdef DEBUG X static int col = 0; X#endif /* DEBUG */ X X /* X * On the VAX, it is important to have the register declarations X * in exactly the order given, or the asm will break. X */ X register int r_off = offset, bits= n_bits; X register char * bp = buf; X X#ifdef DEBUG X if ( verbose ) X fprintf( stderr, "%5d%c", code, X (col+=6) >= 74 ? (col = 0, '\n') : ' ' ); X#endif /* DEBUG */ X if ( code >= 0 ) { X#ifdef vax X /* VAX DEPENDENT!! Implementation on other machines is below. X * X * Translation: Insert BITS bits from the argument starting at X * offset bits from the beginning of buf. X */ X 0; /* Work around for pcc -O bug with asm and if stmt */ X asm( "insv 4(ap),r11,r10,(r9)" ); X#else /* not a vax */ X/* X * byte/bit numbering on the VAX is simulated by the following code X */ X /* X * Get to the first byte. X */ X bp += (r_off >> 3); X r_off &= 7; X /* X * Since code is always >= 8 bits, only need to mask the first X * hunk on the left. X */ X *bp = (*bp & rmask[r_off]) | (code << r_off) & lmask[r_off]; X bp++; X bits -= (8 - r_off); X code >>= 8 - r_off; X /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */ X if ( bits >= 8 ) { X *bp++ = code; X code >>= 8; X bits -= 8; X } X /* Last bits. */ X if(bits) X *bp = code; X#endif /* vax */ X offset += n_bits; X if ( offset == (n_bits << 3) ) { X bp = buf; X bits = n_bits; X bytes_out += bits; X do X putchar(*bp++); X while(--bits); X offset = 0; X } X X /* X * If the next entry is going to be too big for the code size, X * then increase it, if possible. X */ X if ( free_ent > maxcode || (clear_flg > 0)) X { X /* X * Write the whole buffer, because the input side won't X * discover the size increase until after it has read it. X */ X if ( offset > 0 ) { X if( fwrite( buf, 1, n_bits, stdout ) != n_bits) X writeerr(); X bytes_out += n_bits; X } X offset = 0; X X if ( clear_flg ) { X maxcode = MAXCODE (n_bits = INIT_BITS); X clear_flg = 0; X } X else { X n_bits++; X if ( n_bits == maxbits ) X maxcode = maxmaxcode; X else X maxcode = MAXCODE(n_bits); X } X#ifdef DEBUG X if ( debug ) { X fprintf( stderr, "\nChange to %d bits\n", n_bits ); X col = 0; X } X#endif /* DEBUG */ X } X } else { X /* X * At EOF, write the rest of the buffer. X */ X if ( offset > 0 ) X fwrite( buf, 1, (offset + 7) / 8, stdout ); X bytes_out += (offset + 7) / 8; X offset = 0; X fflush( stdout ); X#ifdef DEBUG X if ( verbose ) X fprintf( stderr, "\n" ); X#endif /* DEBUG */ X if( ferror( stdout ) ) X writeerr(); X } X} X X/* X * Decompress stdin to stdout. This routine adapts to the codes in the X * file building the "string" table on-the-fly; requiring no table to X * be stored in the compressed file. The tables used herein are shared X * with those of the compress() routine. See the definitions above. X */ X Xdecompress() { X register char_type *stackp; X register int finchar; X register code_int code, oldcode, incode; X X /* X * As above, initialize the first 256 entries in the table. X */ X maxcode = MAXCODE(n_bits = INIT_BITS); X for ( code = 255; code >= 0; code-- ) { X tab_prefixof(code) = 0; X tab_suffixof(code) = (char_type)code; X } X free_ent = ((block_compress) ? FIRST : 256 ); X X finchar = oldcode = getcode(); X if(oldcode == -1) /* EOF already? */ X return; /* Get out of here */ X putchar( (char)finchar ); /* first code must be 8 bits = char */ X if(ferror(stdout)) /* Crash if can't write */ X writeerr(); X stackp = de_stack; X X while ( (code = getcode()) > -1 ) { X X if ( (code == CLEAR) && block_compress ) { X for ( code = 255; code >= 0; code-- ) X tab_prefixof(code) = 0; X clear_flg = 1; X free_ent = FIRST - 1; X if ( (code = getcode ()) == -1 ) /* O, untimely death! */ X break; X } X incode = code; X /* X * Special case for KwKwK string. X */ X if ( code >= free_ent ) { X *stackp++ = finchar; X code = oldcode; X } X X /* X * Generate output characters in reverse order X */ X#ifdef SIGNED_COMPARE_SLOW X while ( ((unsigned long)code) >= ((unsigned long)256) ) { X#else X while ( code >= 256 ) { X#endif X *stackp++ = tab_suffixof(code); X code = tab_prefixof(code); X } X *stackp++ = finchar = tab_suffixof(code); X X /* X * And put them out in forward order X */ X do X putchar ( *--stackp ); X while ( stackp > de_stack ); X X /* X * Generate the new entry. X */ X if ( (code=free_ent) < maxmaxcode ) { X tab_prefixof(code) = (unsigned short)oldcode; X tab_suffixof(code) = finchar; X free_ent = code+1; X } X /* X * Remember previous code. X */ X oldcode = incode; X } X fflush( stdout ); X if(ferror(stdout)) X writeerr(); X} X X/***************************************************************** X * TAG( getcode ) X * X * Read one code from the standard input. If EOF, return -1. X * Inputs: X * stdin X * Outputs: X * code or -1 is returned. X */ X Xcode_int Xgetcode() { X /* X * On the VAX, it is important to have the register declarations X * in exactly the order given, or the asm will break. X */ X register code_int code; X static int offset = 0, size = 0; X static char_type buf[BITS]; X register int r_off, bits; X register char_type *bp = buf; X X if ( clear_flg > 0 || offset >= size || free_ent > maxcode ) { X /* X * If the next entry will be too big for the current code X * size, then we must increase the size. This implies reading X * a new buffer full, too. X */ X if ( free_ent > maxcode ) { X n_bits++; X if ( n_bits == maxbits ) X maxcode = maxmaxcode; /* won't get any bigger now */ X else X maxcode = MAXCODE(n_bits); X } X if ( clear_flg > 0) { X maxcode = MAXCODE (n_bits = INIT_BITS); X clear_flg = 0; X } X size = fread( buf, 1, n_bits, stdin ); X if ( size <= 0 ) X return -1; /* end of file */ X offset = 0; X /* Round size down to integral number of codes */ X size = (size << 3) - (n_bits - 1); X } X r_off = offset; X bits = n_bits; X#ifdef vax X asm( "extzv r10,r9,(r8),r11" ); X#else /* not a vax */ X /* X * Get to the first byte. X */ X bp += (r_off >> 3); X r_off &= 7; X /* Get first part (low order bits) */ X#ifdef NO_UCHAR X code = ((*bp++ >> r_off) & rmask[8 - r_off]) & 0xff; X#else X code = (*bp++ >> r_off); X#endif /* NO_UCHAR */ X bits -= (8 - r_off); X r_off = 8 - r_off; /* now, offset into code word */ X /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */ X if ( bits >= 8 ) { X#ifdef NO_UCHAR X code |= (*bp++ & 0xff) << r_off; X#else X code |= *bp++ << r_off; X#endif /* NO_UCHAR */ X r_off += 8; X bits -= 8; X } X /* high order bits. */ X code |= (*bp & rmask[bits]) << r_off; X#endif /* vax */ X offset += n_bits; X X return code; X} X Xchar * Xrindex(s, c) /* For those who don't have it in libc.a */ Xregister char *s, c; X{ X char *p; X for (p = NULL; *s; s++) X if (*s == c) X p = s; X return(p); X} X X#ifdef DEBUG Xprintcodes() X{ X /* X * Just print out codes from input file. For debugging. X */ X code_int code; X int col = 0, bits; X X bits = n_bits = INIT_BITS; X maxcode = MAXCODE(n_bits); X free_ent = ((block_compress) ? FIRST : 256 ); X while ( ( code = getcode() ) >= 0 ) { X if ( (code == CLEAR) && block_compress ) { X free_ent = FIRST - 1; X clear_flg = 1; X } X else if ( free_ent < maxmaxcode ) X free_ent++; X if ( bits != n_bits ) { X fprintf(stderr, "\nChange to %d bits\n", n_bits ); X bits = n_bits; X col = 0; X } X fprintf(stderr, "%5d%c", code, (col+=6) >= 74 ? (col = 0, '\n') : ' ' ); X } X putc( '\n', stderr ); X exit( 0 ); X} X X#ifdef XENIX_16 Xcode_int stab1[8192] ; Xcode_int stab2[8192] ; Xcode_int stab3[8192] ; Xcode_int stab4[8192] ; Xcode_int stab5[8192] ; Xcode_int stab6[8192] ; Xcode_int stab7[8192] ; Xcode_int stab8[8192] ; Xcode_int * sorttab[8] = {stab1, stab2, stab3, stab4, stab5, stab6, stab7, X stab8 } ; X#define stabof(i) (sorttab[(i) >> 13][(i) & 0x1fff]) X#else Xcode_int sorttab[SSIZE]; /* sorted pointers into htab */ X#define stabof(i) (sorttab[i]) X#endif X Xdump_tab() /* dump string table */ X{ X register int i, first; X register ent; X#define STACK_SIZE 15000 X int stack_top = STACK_SIZE; X register c; X unsigned mbshift ; X X if(do_decomp == 0) { /* compressing */ X register int flag = 1; X X for(i=0; i<hsize; i++) { /* build sort pointers */ X if((long)htabof(i) >= 0) { X stabof(codetabof(i)) = i; X } X } X first = block_compress ? FIRST : 256; X for(i = first; i < free_ent; i++) { X fprintf(stderr, "%5d: \"", i); X de_stack[--stack_top] = '\n'; X de_stack[--stack_top] = '"'; X stack_top = in_stack((htabof(stabof(i))>>maxbits)&0xff, X stack_top); X/* for(ent=htabof(stabof(i)) & ((1<<maxbits)-1); */ X mbshift = ((1 << maxbits) - 1) ; X ent = htabof(stabof(i)) & mbshift ; X for(; X ent > 256; X /* ent=htabof(stabof(ent)) & ((1<<maxbits)-1)) { */ X ent=htabof(stabof(ent)) & mbshift) { X stack_top = in_stack(htabof(stabof(ent)) >> maxbits, X stack_top); X } X stack_top = in_stack(ent, stack_top); X fwrite( &de_stack[stack_top], 1, STACK_SIZE-stack_top, stderr); X stack_top = STACK_SIZE; X } X } else if(!debug) { /* decompressing */ X X for ( i = 0; i < free_ent; i++ ) { X ent = i; X c = tab_suffixof(ent); X if ( isascii(c) && isprint(c) ) X fprintf( stderr, "%5d: %5d/'%c' \"", X ent, tab_prefixof(ent), c ); X else X fprintf( stderr, "%5d: %5d/\\%03o \"", X ent, tab_prefixof(ent), c ); X de_stack[--stack_top] = '\n'; X de_stack[--stack_top] = '"'; X for ( ; ent != NULL; X ent = (ent >= FIRST ? tab_prefixof(ent) : NULL) ) { X stack_top = in_stack(tab_suffixof(ent), stack_top); X } X fwrite( &de_stack[stack_top], 1, STACK_SIZE - stack_top, stderr ); X stack_top = STACK_SIZE; X } X } X} X Xint Xin_stack(c, stack_top) X register c, stack_top; X{ X if ( (isascii(c) && isprint(c) && c != '\\') || c == ' ' ) { X de_stack[--stack_top] = c; X } else { X switch( c ) { X case '\n': de_stack[--stack_top] = 'n'; break; X case '\t': de_stack[--stack_top] = 't'; break; X case '\b': de_stack[--stack_top] = 'b'; break; X case '\f': de_stack[--stack_top] = 'f'; break; X case '\r': de_stack[--stack_top] = 'r'; break; X case '\\': de_stack[--stack_top] = '\\'; break; X default: X de_stack[--stack_top] = '0' + c % 8; X de_stack[--stack_top] = '0' + (c / 8) % 8; X de_stack[--stack_top] = '0' + c / 64; X break; X } X de_stack[--stack_top] = '\\'; X } X return stack_top; X} X#endif /* DEBUG */ X Xwriteerr() X{ X perror ( ofname ); X unlink ( ofname ); X exit ( 1 ); X} X Xcopystat(ifname, ofname) Xchar *ifname, *ofname; X{ X struct stat statbuf; X int mode; X time_t timep[2]; X X fclose(stdout); X if (stat(ifname, &statbuf)) { /* Get stat on input file */ X perror(ifname); X return; X } X if ((statbuf.st_mode & S_IFMT/*0170000*/) != S_IFREG/*0100000*/) { X if(quiet) X fprintf(stderr, "%s: ", ifname); X fprintf(stderr, " -- not a regular file: unchanged"); X exit_stat = 1; X } else if (statbuf.st_nlink > 1) { X if(quiet) X fprintf(stderr, "%s: ", ifname); X fprintf(stderr, " -- has %d other links: unchanged", X statbuf.st_nlink - 1); X exit_stat = 1; X } else if (exit_stat == 2 && (!force)) { /* No compression: remove file.Z */ X if(!quiet) X fprintf(stderr, " -- file unchanged"); X } else { /* ***** Successful Compression ***** */ X exit_stat = 0; X mode = statbuf.st_mode & 07777; X if (chmod(ofname, mode)) /* Copy modes */ X perror(ofname); X chown(ofname, statbuf.st_uid, statbuf.st_gid); /* Copy ownership */ X timep[0] = statbuf.st_atime; X timep[1] = statbuf.st_mtime; X utime(ofname, timep); /* Update last accessed and modified times */ X if (unlink(ifname)) /* Remove input file */ X perror(ifname); X if(!quiet) X fprintf(stderr, " -- replaced with %s", ofname); X return; /* Successful return */ X } X X /* Unsuccessful return -- one of the tests failed */ X if (unlink(ofname)) X perror(ofname); X} X/* X * This routine returns 1 if we are running in the foreground and stderr X * is a tty. X */ Xforeground() X{ X if(bgnd_flag) { /* background? */ X return(0); X } else { /* foreground */ X if(isatty(2)) { /* and stderr is a tty */ X return(1); X } else { X return(0); X } X } X} X Xonintr ( ) X{ X unlink ( ofname ); X exit ( 1 ); X} X Xoops ( ) /* wild pointer -- assume bad input */ X{ X if ( do_decomp == 1 ) X fprintf ( stderr, "uncompress: corrupt input\n" ); X unlink ( ofname ); X exit ( 1 ); X} X Xcl_block () /* table clear for block compress */ X{ X register long int rat; X X checkpoint = in_count + CHECK_GAP; X#ifdef DEBUG X if ( debug ) { X fprintf ( stderr, "count: %ld, ratio: ", in_count ); X prratio ( stderr, in_count, bytes_out ); X fprintf ( stderr, "\n"); X } X#endif /* DEBUG */ X X if(in_count > 0x007fffff) { /* shift will overflow */ X rat = bytes_out >> 8; X if(rat == 0) { /* Don't divide by zero */ X rat = 0x7fffffff; X } else { X rat = in_count / rat; X } X } else { X rat = (in_count << 8) / bytes_out; /* 8 fractional bits */ X } X if ( rat > ratio ) { X ratio = rat; X } else { X ratio = 0; X#ifdef DEBUG X if(verbose) X dump_tab(); /* dump string table */ X#endif X cl_hash ( (count_int) hsize ); X free_ent = FIRST; X clear_flg = 1; X output ( (code_int) CLEAR ); X#ifdef DEBUG X if(debug) X fprintf ( stderr, "clear\n" ); X#endif /* DEBUG */ X } X} X Xcl_hash(hsize) /* reset code table */ X register count_int hsize; X{ X#ifndef XENIX_16 /* Normal machine */ X register count_int *htab_p = htab+hsize; X#else X register j; X register long k = hsize; X register count_int *htab_p; X#endif X register long i; X register long m1 = -1; X X#ifdef XENIX_16 X for(j=0; j<=8 && k>=0; j++,k-=8192) { X i = 8192; X if(k < 8192) { X i = k; X } X htab_p = &(htab[j][i]); X i -= 16; X if(i > 0) { X#else X i = hsize - 16; X#endif X do { /* might use Sys V memset(3) here */ X *(htab_p-16) = m1; X *(htab_p-15) = m1; X *(htab_p-14) = m1; X *(htab_p-13) = m1; X *(htab_p-12) = m1; X *(htab_p-11) = m1; X *(htab_p-10) = m1; X *(htab_p-9) = m1; X *(htab_p-8) = m1; X *(htab_p-7) = m1; X *(htab_p-6) = m1; X *(htab_p-5) = m1; X *(htab_p-4) = m1; X *(htab_p-3) = m1; X *(htab_p-2) = m1; X *(htab_p-1) = m1; X htab_p -= 16; X } while ((i -= 16) >= 0); X#ifdef XENIX_16 X } X } X#endif X for ( i += 16; i > 0; i-- ) X *--htab_p = m1; X} X Xprratio(stream, num, den) XFILE *stream; Xlong int num, den; X{ X register int q; /* Doesn't need to be long */ X X if(num > 214748L) { /* 2147483647/10000 */ X q = num / (den / 10000L); X } else { X q = 10000L * num / den; /* Long calculations, though */ X } X if (q < 0) { X putc('-', stream); X q = -q; X } X fprintf(stream, "%d.%02d%%", q / 100, q % 100); X} X Xversion() X{ X fprintf(stderr, "%s\n", rcs_ident); X fprintf(stderr, "Options: "); X#ifdef vax X fprintf(stderr, "vax, "); X#endif X#ifdef NO_UCHAR X fprintf(stderr, "NO_UCHAR, "); X#endif X#ifdef SIGNED_COMPARE_SLOW X fprintf(stderr, "SIGNED_COMPARE_SLOW, "); X#endif X#ifdef XENIX_16 X fprintf(stderr, "XENIX_16, "); X#endif X#ifdef COMPATIBLE X fprintf(stderr, "COMPATIBLE, "); X#endif X#ifdef DEBUG X fprintf(stderr, "DEBUG, "); X#endif X#ifdef BSD4_2 X fprintf(stderr, "BSD4_2, "); X#endif X fprintf(stderr, "BITS = %d\n", BITS); X} END_OF_FILE if test 35496 -ne `wc -c <'compress.c'`; then echo shar: \"'compress.c'\" unpacked with wrong size! fi # end of 'compress.c' fi echo shar: End of shell archive. exit 0 -- "Zeta Microcomputer Software" ACSnet: nick@ultima.cs.uts.oz UUCP: ...!uunet!munnari!ultima.cs.uts.oz!nick Fidonet: Nick Andrew on 3:713/602 (Zeta)
nick@ultima.cs.uts.oz (Nick Andrew) (12/07/89)
#! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of shell archive." # Contents: inews.c # Wrapped by nick@ultima on Thu Dec 7 22:48:48 1989 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'inews.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'inews.c'\" else echo shar: Extracting \"'inews.c'\" \(34390 characters\) sed "s/^X//" >'inews.c' <<'END_OF_FILE' X/* X * This software is Copyright (c) 1986 by Rick Adams. X * X * Permission is hereby granted to copy, reproduce, redistribute or X * otherwise use this software as long as: there is no monetary X * profit gained specifically from the use or reproduction or this X * software, it is not sold, rented, traded or otherwise marketed, and X * this copyright notice is included prominently in any copy X * made. X * X * The author make no claims as to the fitness or correctness of X * this software for any use whatsoever, and it is provided as is. X * Any use of this software is at the user's own risk. X * X * inews - insert, receive, and transmit news articles. X * X */ X X#ifdef SCCSID Xstatic char *SccsId = "@(#)inews.c 2.80 4/10/87"; X#endif /* SCCSID */ X X#include "iparams.h" X X# ifdef LOCKF X# include <unistd.h> X# include <fcntl.h> X X# ifdef F_RDLCK Xstruct flock news_lock; X# endif /* F_RDLCK */ X# endif /* LOCKF */ X X#ifdef BSD4_2 X# include <sys/dir.h> X# include <sys/file.h> X#else /* !BSD4_2 */ X# include "ndir.h" X# if defined(USG) && !defined(LOCKF) X# include <fcntl.h> X# endif /* USG */ X#endif /* !BSD4_2 */ X/* local defines for inews */ X X#define OPTION 0 /* pick up an option string */ X#define STRING 1 /* pick up a string of arguments */ X X#define UNKNOWN 0001 /* possible modes for news program */ X#define UNPROC 0002 /* Unprocessed input */ X#define PROC 0004 /* Processed input */ X#define CONTROL 0010 /* Control Message */ X#define CREATENG 0020 /* Create a new newsgroup */ X X#define DONT_SPOOL 0 X#define DO_SPOOL 1 X#define EXPIRE_RUNNING 2 Xint spool_news = DONT_SPOOL; X Xextern char histline[]; Xchar forgedname[NAMELEN]; /* A user specified -f option. */ X/* Fake sys line in case they forget their own system */ Xstruct srec dummy_srec = { "MEMEME", "", "all", "", "" }; X Xchar *Progname = "inews"; /* used by xerror to identify failing program */ X Xstruct { /* options table. */ X char optlet; /* option character. */ X char filchar; /* if to pickup string, fill character. */ X int flag; /* TRUE if have seen this opt. */ X int oldmode; /* OR of legal input modes. */ X int newmode; /* output mode. */ X char *buf; /* string buffer */ X} *optpt, options[] = { /* Xoptlet filchar flag oldmode newmode buf */ X't', ' ', FALSE, UNPROC, UNKNOWN, header.title, X'n', NGDELIM, FALSE, UNPROC, UNKNOWN, header.nbuf, X'd', '\0', FALSE, UNPROC, UNKNOWN, header.distribution, X'e', ' ', FALSE, UNPROC, UNKNOWN, header.expdate, X'p', '\0', FALSE, UNKNOWN|PROC, PROC, filename, X'f', '\0', FALSE, UNPROC, UNKNOWN, forgedname, X'F', ' ', FALSE, UNPROC, UNKNOWN, header.followid, X'c', ' ', FALSE, UNKNOWN,UNKNOWN, header.ctlmsg, X'C', ' ', FALSE, UNKNOWN,CREATENG, header.ctlmsg, X#define hflag options[9].flag X'h', '\0', FALSE, UNPROC, UNKNOWN, filename, X#define oflag options[10].flag X'o', '\0', FALSE, UNPROC, UNKNOWN, header.organization, X#define Mflag options[11].flag X'M', '\0', FALSE, UNPROC, UNKNOWN, filename, X'a', '\0', FALSE, UNPROC, UNKNOWN, header.approved, X'U', '\0', FALSE, PROC, PROC, filename, X#define Sflag options[14].flag X'S', '\0', FALSE, UNKNOWN|PROC, UNPROC, filename, X'x', '\0', FALSE, UNPROC, UNKNOWN, not_here, X'r', '\0', FALSE, UNPROC, UNKNOWN, header.replyto, X'\0', '\0', 0, 0, 0, (char *)NULL X}; X XFILE *mailhdr(); Xextern int errno; X Xstruct timeb Now; X X/* X * Authors: X * Matt Glickman glickman@ucbarpa.Berkeley.ARPA X * Mark Horton mark@cbosgd.UUCP X * Stephen Daniels swd@mcnc.UUCP X * Tom Truscott trt@duke.UUCP X * Rick Adams rick@seismo.CSS.GOV X * IHCC version adapted by: X * Larry Marek larry@ihuxf.UUCP X */ Xmain(argc, argv) Xint argc; Xregister char **argv; X{ X int state; /* which type of argument to pick up */ X int tlen, len; /* temps for string processing routine */ X register char *ptr; /* pointer to rest of buffer */ X int filchar; /* fill character (state = STRING) */ X char *user = NULL, *home = NULL; /* environment temps */ X struct passwd *pw; /* struct for pw lookup */ X struct group *gp; /* struct for group lookup */ X register int i; X FILE *mfd; /* mail file file-descriptor */ X X /* uuxqt doesn't close all it's files */ X for (i = 3; !close(i); i++) X ; X /* set up defaults and initialize. */ X mode = UNKNOWN; X infp = stdin; X pathinit(); X savmask = umask(N_UMASK); /* set up mask */ X ptr = rindex(*argv, '/'); X if (!ptr) X ptr = *argv - 1; X actfp = xfopen(ACTIVE, "r+"); X#ifdef LOCKF X# ifdef F_RDLCK X news_lock.l_type = F_RDLCK; X if (fcntl(fileno(actfp), F_SETLK, &news_lock) < 0) { X# else /* !F_RDLCK */ X if (lockf(fileno(actfp), F_TLOCK, 0) < 0) { X# endif /* !F_RDLCK */ X if (errno != EAGAIN && errno != EACCES) X#else /* !LOCKF */ X#ifdef BSD4_2 X if (flock(fileno(actfp), LOCK_SH|LOCK_NB) < 0) { X if (errno != EWOULDBLOCK) X#else /* !BSD4_2 */ X sprintf(bfr, "%s.lock", ACTIVE); X if (LINK(ACTIVE, bfr) < 0) { X if (errno != EEXIST) X#endif /* V7 */ X#endif /* !BSD4_2 */ X xerror("Can't lock %s: %s", ACTIVE, errmsg(errno)); X spool_news = EXPIRE_RUNNING; X } else { X#ifdef SPOOLNEWS X if (argc > 1 && !strcmp(*(argv+1), "-S")) { X argc--; X argv++; X Sflag = 1; X } else X spool_news = DO_SPOOL; X X#endif /* SPOOLNEWS */ X } X if (spool_news != EXPIRE_RUNNING) { X /* only unlock if we locked */ X#ifdef LOCKF X (void) lockf(fileno(actfp), F_ULOCK, 0); X#else /* !LOCKF */ X#ifdef BSD4_2 X (void) flock(fileno(actfp), LOCK_UN); X#else /* !BSD4_2 */ X (void) UNLINK(bfr); X#endif /* V7 */ X#endif /* !BSD4_2 */ X } else { /* expire is running */ X if (argc > 1 && !strcmp(*(argv+1), "-S")) X exit(42); /* inform rnews -U by exit status */ X } X if (argc > 1 && !strcmp(*(argv+1), "-U")) { X /* can't unspool while things are locked */ X if (spool_news == EXPIRE_RUNNING) X xxit(0); X dounspool(); X /* NOT REACHED */ X } X X if (!strncmp(ptr+1, "rnews", 5)) { X mode = PROC; X if (spool_news != DONT_SPOOL) { X dospool((char *)NULL, FALSE); X /* NOT REACHED */ X } X#ifdef NICENESS X if (nice(0) < NICENESS) X (void) nice(NICENESS); X#endif /* NICENESS */ X } else { X /* it's not rnews, so it must be inews */ X if (argc < 2) X goto usage; X#ifndef SPOOLINEWS X if (spool_news == DO_SPOOL) X spool_news = DONT_SPOOL; X#endif /* SPOOLINEWS */ X } X X state = OPTION; X header.title[0] = header.nbuf[0] = filename[0] = '\0'; X X /* check for existence of special files */ X#ifdef DBM X chkfile(ARTFILE); X#else X chkdir(ARTFILE); X#endif /* DBM */ X chkfile(ACTIVE); X SigTrap = FALSE; /* true if a signal has been caught */ X if (mode != PROC) { X (void) signal(SIGHUP, onsig); X (void) signal(SIGINT, onsig); X } X uid = getuid(); X gid = getgid(); X duid = geteuid(); X dgid = getegid(); X (void) ftime(&Now); X if (uid == 0 && duid == 0) { X /* X * Must go through with this kludge since X * some systems do not honor the setuid bit X * when root invokes a setuid program. X */ X if ((pw = getpwnam(NEWSUSR)) == NULL) X xerror("Cannot get NEWSU pw entry"); X X duid = pw->pw_uid; X if ((gp = getgrnam(NEWSGRP)) == NULL) X xerror("Cannot get NEWSG gr entry"); X dgid = gp->gr_gid; X (void) setgid(dgid); X (void) setuid(duid); X } X X /* X * IHCC forces the use of 'getuser()' to prevent forgery of articles X * by just changing $LOGNAME X */ X#ifndef IHCC X if (isatty(fileno(stderr))) { X if ((user = getenv("USER")) == NULL) X user = getenv("LOGNAME"); X if ((home = getenv("HOME")) == NULL) X home = getenv("LOGDIR"); X } X#endif /* !IHCC */ X if (user == NULL || home == NULL) X getuser(); X else { X if (username == NULL || username[0] == 0) { X username = AllocCpy(user); X } X userhome = AllocCpy(home); X } X getuser(); X X /* loop once per arg. */ X X ++argv; /* skip first arg, which is prog name. */ X X while (--argc) { X if (state == OPTION) { X if (**argv != '-') { X xerror("Bad option string \"%s\"", *argv); X } X while (*++*argv != '\0') { X for (optpt = options; optpt->optlet != '\0'; ++optpt) { X if (optpt->optlet == **argv) X goto found; X } X /* unknown option letter */ Xusage: X fprintf(stderr, "usage: inews -t title"); X fprintf(stderr, " [ -n newsgroups ]"); X fprintf(stderr, " [ -e expiration date ]\n"); X fprintf(stderr, "\t[ -f sender]\n\n"); X xxit(1); X X found:; X if (optpt->flag == TRUE || (mode != UNKNOWN && X (mode&optpt->oldmode) == 0)) { X xerror("Bad %c option", **argv); X } X if (mode == UNKNOWN) X mode = optpt->newmode; X filchar = optpt->filchar; X optpt->flag = TRUE; X state = STRING; X ptr = optpt->buf; X len = BUFLEN; X } X X argv++; /* done with this option arg. */ X X } else { X X /* X * Pick up a piece of a string and put it into X * the appropriate buffer. X */ X if (**argv == '-') { X state = OPTION; X argc++; /* uncount this arg. */ X continue; X } X X if ((tlen = strlen(*argv)) >= len) X xerror("Argument string too long"); X (void) strcpy(ptr, *argv++); X ptr += tlen; X if (*(ptr-1) != filchar) X *ptr++ = filchar; X len -= tlen + 1; X *ptr = '\0'; X } X } X X /* X * ALL of the command line has now been processed. (!) X */ X X if (*filename) { X infp = freopen(filename, "r", stdin); X if (infp == NULL) X xerror("freopen(%s): %s", filename, errmsg(errno)); X } else X infp = stdin; X X tty = isatty(fileno(infp)); X X if (mode == CREATENG) X createng(); X X if (header.ctlmsg[0] != '\0' && header.title[0] == '\0') X (void) strcpy(header.title, header.ctlmsg); X X if (*header.nbuf) { X lcase(header.nbuf); X ptr = index(header.nbuf, '\0'); X if (ptr[-1] == NGDELIM) X *--ptr = '\0'; X } X (void) nstrip(header.title); X (void) nstrip(header.expdate); X (void) nstrip(header.followid); X if (mode != PROC) { X if (hflag) { X header.path[0] = '\0'; X (void) hread(&header, infp, FALSE); X /* there are certain fields we won't let him specify. */ X if (header.from[0]) { X (void) fixfrom(header.from); X if (Sflag && !Mflag && !header.approved[0] & X !header.sender[0]) { X register char *p; X strcpy(bfr, header.from); X p = strpbrk(bfr, "@ !"); X if (p) X *p = '\0'; X if ((pw = getpwnam(bfr)) != NULL) { X uid = pw->pw_uid; X gid = pw->pw_gid; X username = AllocCpy(bfr); X } X } else { X (void) strcpy(forgedname, header.from); X header.from[0] = '\0'; X } X } X if (!header.approved[0]) X Mflag = FALSE; X header.sender[0] = '\0'; X if (header.subdate[0] && cgtdate(header.subdate) < 0) X header.subdate[0] = '\0'; X } X X if (header.ident[0] == '\0') X getident(&header); X X if (forgedname[0]) { X register char *p1; X if (Mflag) X sprintf(header.path, "%s!%s", X PATHSYSNAME, username); X else if (!header.path[0]) { X (void) strcpy(header.path, forgedname); X X if ((p1 = strpbrk(header.path, "@ (<")) != NULL) X *p1 = '\0'; X } X if (!Mflag && !strpbrk(forgedname, "@ (<")) X (void) sprintf(header.from,"%s@%s", X forgedname, FROMSYSNAME); X else X (void) strncpy(header.from, forgedname, BUFLEN); X X (void) sprintf(header.sender, "%s@%s", X username, FROMSYSNAME); X } else { X gensender(&header, username); X } X#ifdef MYORG X if (header.organization[0] == '\0' && !Mflag && X header.sender[0] == '\0') { X strncpy(header.organization, MYORG, BUFLEN); X if (strncmp(header.organization, "Frobozz", 7) == 0) X header.organization[0] = '\0'; X if (ptr = getenv("ORGANIZATION")) X strncpy(header.organization, ptr, BUFLEN); X /* X * Note that the organization can also be turned off by X * setting it to the null string, either in MYORG or X * $ORGANIZATION in the environment. X */ X if (header.organization[0] == '/') { X mfd = fopen(header.organization, "r"); X if (mfd) { X (void) fgets(header.organization, sizeof header.organization, mfd); X (void) fclose(mfd); X } else { X header.organization[0] = '\0'; X logerr("Couldn't open %s", X header.organization); X } X ptr = index(header.organization, '\n'); X if (ptr) X *ptr = '\0'; X } X } X#endif /* MYORG */ X } X X /* Authorize newsgroups. */ X if (mode == PROC) { X checkbatch(); X (void) signal(SIGHUP, SIG_IGN); X (void) signal(SIGINT, SIG_IGN); X (void) signal(SIGQUIT, SIG_IGN); X header.ident[0] = '\0'; X if (hread(&header, infp, TRUE) == NULL) X xerror("%s: Inbound news is garbled", filename); X input(); X } X /* always check history */ X X if (history(&header)) { X log("Duplicate article %s rejected. Path: %s", X header.ident, header.path); X xxit(0); X } X X /* Easy way to make control messages, since all.all.ctl is unblessed */ X if (mode != PROC && prefix(header.title, "cmsg ") && header.ctlmsg[0] == 0) X (void) strcpy(header.ctlmsg, &header.title[5]); X is_ctl = mode != CREATENG && X (ngmatch(header.nbuf, "all.all.ctl,") || header.ctlmsg[0]); X#ifdef DEBUG X fprintf(stderr,"is_ctl set to %d\n", is_ctl); X#endif X X if (mode != CREATENG) { X if (!*header.title) X error("No title, ng %s from %s", header.nbuf, X header.from); X if (!*header.nbuf) X (void) strcpy(header.nbuf, DFLTNG); X } X X if (mode <= UNPROC) { X#ifdef FASCIST X if (uid && uid != ROOTID && fascist(user, header.nbuf)) X xerror("User %s is not authorized to post to newsgroup %s", X user, header.nbuf); X#endif /* FASCIST */ X ctlcheck(); X } X X if (mode == CREATENG) X createng(); X X /* Determine input. */ X if (mode != PROC) X input(); X if (header.intnumlines == 0 && !is_ctl) X error("%s rejected: no text lines", header.ident); X X dates(&header); X X /* Do the actual insertion. */ X insert(); X /* NOTREACHED */ X} X X/* check for existence of file */ Xstatic chkfile(f) Xchar *f; X{ X FILE *mfd; /* mail file file-descriptor */ X char cbuf[BUFLEN]; /* command buffer */ X X if (rwaccess(f)) X return; /* everything is ok */ X mfd = mailhdr((struct hbuf *)NULL, X exists(f) ? "Unwritable files!" : "Missing files!"); X if (mfd == NULL) X return; X putc('\n', mfd); X fprintf(mfd, "System: %s\n\nThere was a problem with %s!!\n", X LOCALSYSNAME, f); X (void) sprintf(cbuf, "touch %s;chmod 666 %s", f, f); X (void) system(cbuf); X if (rwaccess(f)) X fprintf(mfd, "The problem has been taken care of.\n"); X else X fprintf(mfd, "Corrective action failed - check suid bits.\n"); X (void) mclose(mfd); X} X X#ifndef DBM X/* check for existence of directory */ Xstatic chkdir(d) Xchar *d; X{ X FILE *mfd; /* mail file file-descriptor */ X char dir[BUFLEN]; /* holds directory name */ X X sprintf(dir, "%s.d", d); X if (eaccess(dir, 07) == 0) X return; /* everything is ok */ X mfd = mailhdr((struct hbuf *)NULL, X exists(dir) ? "Unwritable directories" : "Missing directories"); X if (mfd == NULL) X return; X putc('\n', mfd); X fprintf(mfd, "System: %s\n\nThere was a problem with %s!\n", X LOCALSYSNAME, dir); X (void) mkdir(dir, 0775); X if (eaccess(dir, 07) == 0) X fprintf(mfd, "The problem has been taken care of.\n"); X else X fprintf(mfd, "Corrective action failed - check suid bits.\n"); X (void) mclose(mfd); X} X X/* X * This version of access checks against effective uid and effective gid X */ Xeaccess(name, mode) Xregister char *name; Xregister int mode; X{ X struct stat statb; X int euserid = geteuid(); X int egroupid = getegid(); X X if (stat(name, &statb) == 0) { X if (euserid == 0) { X if ((statb.st_mode&S_IFMT) != S_IFREG || mode != 1) X return 0; X /* root needs execute permission for someone */ X mode = (S_IEXEC|(S_IEXEC>>3)|(S_IEXEC>>6)); X } X else if (euserid == statb.st_uid) X mode <<= 6; X else if (egroupid == statb.st_gid) X mode <<= 3; X#ifdef BSD4_2 X /* in BSD4_2 you can be in several groups */ X else { X int groups[NGROUPS]; X register int n; X n = getgroups(NGROUPS,groups); X while(--n >= 0) { X if(groups[n] == statb.st_gid) { X mode <<= 3; X break; X } X } X } X#endif /* BSD4_2 */ X X if (statb.st_mode & mode) X return 0; X } X return -1; X} X#endif /* DBM */ X Xdospool(batchcmd, dolhwrite) Xchar *batchcmd; Xint dolhwrite; X{ X register int c; X register FILE *sp; X register struct tm *tp; X time_t t; X char buf[BUFLEN], sfile[BUFLEN]; X extern struct tm *gmtime(); X X (void) sprintf(sfile, "%s/.spXXXXXX", SPOOL); X sp = xfopen(mktemp(sfile), "w"); X if (batchcmd != NULL) { X if (not_here[0] != '\0') X fprintf(sp, "%s -x %s\n", batchcmd, not_here); X else X fprintf(sp, "%s\n", batchcmd); X } else X if (not_here[0] != '\0') X fprintf(sp, "#! inews -x %s -p\n", not_here); X if (dolhwrite) X lhwrite(&header, sp); X while ((c = getc(infp)) != EOF) X putc(c, sp); X fclose(sp); X X (void) time(&t); X tp = gmtime(&t); X /* This file name "has to" be unique (right?) */ X#ifdef USG X (void) sprintf(buf, "%s/.rnews/%2.2d%2.2d%2.2d%2.2d%2.2d%x", X#else X#ifdef VMS X /* Eunice doesn't like dots in directory names */ X (void) sprintf(buf, "%s/+rnews/%02d%02d%02d%02d%02d%x", X#else /* V7 */ X (void) sprintf(buf, "%s/.rnews/%02d%02d%02d%02d%02d%x", X#endif /* V7 */ X#endif /* VMS */ X SPOOL, X tp->tm_year, tp->tm_mon+1, tp->tm_mday, X tp->tm_hour, tp->tm_min, getpid()); X if (LINK(sfile, buf) < 0) { X char dbuf[BUFLEN]; X#ifdef VMS X sprintf(dbuf, "%s/+rnews", SPOOL); X#else /* !VMS */ X sprintf(dbuf, "%s/.rnews", SPOOL); X#endif /* !VMS */ X if (mkdir(dbuf, 0777&~N_UMASK) < 0) X xerror("Cannot mkdir %s: %s", dbuf, errmsg(errno)); X if (LINK(sfile, buf) < 0) X xerror("Cannot link(%s,%s): %s", sfile, buf, X errmsg(errno)); X } X (void) UNLINK(sfile); X xxit(0); X /* NOTREACHED */ X} X X/* X * Create a newsgroup X */ Xcreateng() X{ X register char *cp; X X /* X * Only certain users are allowed to create newsgroups X */ X if (uid != ROOTID && uid != duid && uid) { X logerr("Please contact one of the local netnews people"); X xerror("to create group \"%s\" for you", header.ctlmsg); X } X if (header.distribution[0] == '\0') X#ifdef ORGDISTRIB X strcpy(header.distribution, ORGDISTRIB); X#else /* !ORGDISTRIB */ X strcpy(header.distribution, "local"); X#endif /* !ORGDISTRIB */ X X (void) strcpy(header.nbuf, header.ctlmsg); X if ((cp=index(header.nbuf, ' ')) != NULL) X *cp = '\0'; X X if (header.approved[0] == '\0') X (void) sprintf(header.approved, "%s@%s", X username, FROMSYSNAME); X (void) sprintf(bfr, "%s/inews -n %s.ctl -c newgroup %s -d %s -a \"%s\"", X LIB, header.nbuf, header.ctlmsg, header.distribution, X header.approved); X if (tty) { X printf("Please type in a paragraph describing the new newsgroup.\n"); X printf("End with control D as usual.\n"); X } X printf("%s\n", bfr); X (void) fflush(stdout); X (void) system(bfr); X exit(0); X /*NOTREACHED*/ X} X Xchar firstbufname[BUFLEN]; X/* X * Link ARTICLE into dir for ngname and update active file. X */ Xlong Xlocalize(ngname) Xchar *ngname; X{ X char afline[BUFLEN]; X long ngsize; X long fpos; X int e; X char *cp; X X lock(); X (void) rewind(actfp); clearerr(actfp); X X for(;;) { X fpos = ftell(actfp); X if (fgets(afline, sizeof afline, actfp) == NULL) { X unlock(); X logerr("Can't find \"%s\" in active file", ngname); X return FALSE; /* No such newsgroup locally */ X } X if (prefix(afline, ngname)) { X (void) sscanf(afline, "%s %ld", bfr, &ngsize); X if (strcmp(bfr, ngname) == 0) { X if (ngsize < 0 || ngsize > 99998) { X logerr("found bad ngsize %ld ng %s, setting to 1", ngsize, bfr); X ngsize = 1; X } X break; X } X } X } X for (;;) { X cp = dirname(ngname); X X (void) sprintf(bfr, "%s/%ld", cp, ngsize+1); X#ifdef VMS X /* X * The effect of this code is to store the article in the first X * newsgroup's directory and to put symbolic links elsewhere. X * If this is the first group, firstbufname is not yet filled X * in. It should be portable to other link-less systems. X * epimass!jbuck X */ X if (firstbufname[0]) { X if (vmslink(firstbufname, bfr) == 0) X break; X } else if (rename(ARTICLE, bfr) == 0) X break; X#else /* !VMS */ X if (link(ARTICLE, bfr) == 0) X break; X#endif /* !VMS */ X if (!exists(cp)) X mknewsg(cp, ngname); X#ifdef VMS X if (firstbufname[0]) { X if (vmslink(firstbufname, bfr) == 0) X break; X } else if (rename(ARTICLE, bfr) == 0) X break; X#else /* !VMS */ X if (link(ARTICLE, bfr) == 0) X break; X#endif /* !VMS */ X e = errno; /* keep log from clobbering it */ X log("Cannot install article as %s: %s", bfr, errmsg(errno)); X if (e != EEXIST) { X logerr("Link into %s failed (%s); check dir permissions.", X bfr, errmsg(e)); X unlock(); X return FALSE; X } X ngsize++; X } X X /* X * This works around a bug in the 4.1bsd stdio X * on fseeks to non even offsets in r+w files X */ X if (fpos&1) X (void) rewind(actfp); X X (void) fseek(actfp, fpos, 0); X /* X * Has to be same size as old because of %05d. X * This will overflow with 99999 articles. X */ X fprintf(actfp, "%s %05ld", ngname, ngsize+1); X#if defined(USG) || defined(MG1) X /* X * U G L Y K L U D G E X * This utter piece of tripe is the only way I know of to get X * around the fact that ATT BROKE standard IO in System 5.2. X * Basically, you can't open a file for "r+" and then try and X * write to it. This works on all "real" USGUnix systems, It will X * probably break on some obscure look alike that doesnt use the X * real ATT stdio.h X * Don't blame me, blame ATT. stdio should have already done the X * following line for us, but it doesn't X * also broken in WCW MG-1 42nix 2.0 X */ X actfp->_flag |= _IOWRT; X#endif /* USG */ X (void) fflush(actfp); X if (ferror(actfp)) X xerror("Active file write failed"); X unlock(); X if (firstbufname[0] == '\0') X (void) strcpy(firstbufname, bfr); X (void) sprintf(bfr, "%s/%ld ", ngname, ngsize+1); X addhist(bfr); X return ngsize+1; X} X X/* X * Localize for each newsgroup and broadcast. X */ Xinsert() X{ X register char *ptr; X register FILE *tfp; X register int c; X struct srec srec; /* struct for sys file lookup */ X struct tm *tm, *gmtime(); X int is_invalid = FALSE; X int exitcode = 0; X long now; X#ifdef DOXREFS X register char *nextref = header.xref; X#endif /* DOXREFS */ X X /* Clean up Newsgroups: line */ X if (!is_ctl && mode != CREATENG) X is_invalid = ngfcheck(mode == PROC); X X (void) time(&now); X tm = gmtime(&now); X if (header.expdate[0]) X addhist(" "); X#ifdef USG X sprintf(bfr,"%2.2d/%2.2d/%d %2.2d:%2.2d\t", X#else /* !USG */ X sprintf(bfr,"%02d/%02d/%d %02d:%02d\t", X#endif /* !USG */ X tm->tm_mon+1, tm->tm_mday, tm->tm_year,tm->tm_hour, tm->tm_min); X addhist(bfr); X log("%s %s ng %s subj '%s' from %s", spool_news != DONT_SPOOL X ? "queued" : (mode==PROC ? "received" : "posted"), X header.ident, header.nbuf, header.title, header.from); X X /* Write article to temp file. */ X tfp = xfopen(mktemp(ARTICLE), "w"); X X if (is_invalid) { X logerr("No valid newsgroups found, moved to junk"); X if (localize("junk")) X savehist(histline); X exitcode = 1; X goto writeout; X } X X#ifdef ZAPNOTES X if (strncmp(header.title, "Re: Orphaned Response", 21) == 0) { X logerr("Orphaned Response, moved to junk"); X if (localize("junk")) X savehist(histline); X exitcode = 1; X goto writeout; X } X#endif /* ZAPNOTES */ X X if (time((time_t *)0) > (cgtdate(header.subdate) + HISTEXP) ){ X logerr("Article too old, moved to junk"); X if (localize("junk")) X savehist(histline); X exitcode = 1; X goto writeout; X } X X if (is_mod[0] != '\0' /* one of the groups is moderated */ X && header.approved[0] == '\0') { /* and unapproved */ X struct hbuf mhdr; X FILE *mfd, *mhopen(); X register char *p; X char modadd[BUFLEN], *replyname(); X#ifdef DONTFOWARD X if(mode == PROC) { X logerr("Unapproved article in moderated group %s", X is_mod); X if (localize("junk")) X savehist(histline); X goto writeout; X } X#endif /* DONTFORWARD */ X fprintf(stderr,"%s is moderated and may not be posted to", X is_mod); X fprintf(stderr," directly.\nYour article is being mailed to"); X fprintf(stderr," the moderator who will post it for you.\n"); X /* Let's find a path to the backbone */ X sprintf(bfr, "%s/mailpaths", LIB); X mfd = xfopen(bfr, "r"); X do { X if (fscanf(mfd, "%s %s", bfr, modadd) != 2) X xerror("Can't find backbone in %s/mailpaths", X LIB); X } while (strcmp(bfr, "backbone") != 0 && !ngmatch(is_mod, bfr)); X (void) fclose(mfd); X /* fake a header for mailhdr */ X mhdr.from[0] = '\0'; X mhdr.replyto[0] = '\0'; X p = is_mod; X while (*++p) X if (*p == '.') X *p = '-'; X sprintf(mhdr.path, modadd, is_mod); X mfd = mhopen(&mhdr); X if (mfd == NULL) X xerror("Can't send mail to %s", mhdr.path); X fprintf(mfd, "To: %s\n", replyname(mhdr.path)); X lhwrite(&header, mfd); X putc('\n', mfd); X while ((c = getc(infp)) != EOF) X putc(c, mfd); X mclose(mfd); X log("Article mailed to %s", mhdr.path); X xxit(0); X } X X if (mode != PROC && spool_news != DONT_SPOOL) { X if (spool_news != EXPIRE_RUNNING X && ngmatch(header.nbuf,"to.all.ctl")) X spool_news = DONT_SPOOL; X if (spool_news != DONT_SPOOL) { X fprintf(stderr, X "Your article has been spooled for later processing.\n"); X dospool("#! inews -S -h", TRUE); X /* NOT REACHED */ X } X } X X if (is_ctl) { X exitcode = control(&header); X if (localize("control") && exitcode != 0) X savehist(histline); X } else { X if (s_find(&srec, LOCALPATHSYSNAME) == FALSE) { X logerr("Cannot find my name '%s' in %s", X LOCALPATHSYSNAME, SUBFILE); X srec = dummy_srec; X } X#ifdef DOXREFS X (void) strncpy(nextref, PATHSYSNAME, BUFLEN); X#endif /* DOXREFS */ X for (ptr = nbuf; *ptr;) { X if (ngmatch(ptr,srec.s_nbuf) || index(ptr,'.') == NULL){ X#ifdef DOXREFS X while (*nextref++) X ; X (void) sprintf(--nextref, " %s:%ld", ptr, localize(ptr)); X#else /* !DOXREFS */ X (void) localize(ptr); X#endif /* !DOXREFS */ X } X while (*ptr++) X ; X } X if (firstbufname[0] == '\0') { X logerr("Newsgroups in active, but not sys"); X (void) localize("junk"); X } X } X#ifdef DOXREFS X if (index(header.nbuf, NGDELIM) == NULL) X header.xref[0] = '\0'; X#endif /* DOXREFS */ X Xwriteout: X /* Part 1 of kludge to get around article truncation problem */ X if ( (c=getc(infp)) != EOF) { X ungetc(c, infp); X if (c == ' ' || c == '\t') { X header.intnumlines++; X (void) sprintf(header.numlines, "%d", X header.intnumlines); X } X } X /* End of part 1 */ X if (header.expdate[0] != '\0' && mode != PROC) { X /* Make sure it's fully qualified */ X long t = cgtdate(header.expdate); X strcpy(header.expdate, arpadate(&t)); X } X X lhwrite(&header, tfp); X if ((c = getc(infp)) != EOF) { X /* Part 2 of kludge to get around article truncation problem */ X if (c == ' ' || c == '\t' ) X putc('\n', tfp); X /* End of part 2 */ X ungetc(c, infp); X while (fgets(bfr, BUFLEN, infp) != NULL) X fputs(bfr, tfp); X if (bfr[strlen(bfr)-1] != '\n') X putc('\n',tfp); X } X if (ferror(tfp)) X xerror("Write failed for temp file"); X (void) fclose(tfp); X (void) fclose(infp); X if(exitcode == 0) { X /* article has passed all the checks, so work in background */ X if (mode != PROC) { X int pid; X if ((pid=fork()) < 0) X xerror("Can't fork"); X else if (pid > 0) X _exit(0); X } X#ifdef SIGTTOU X (void) signal(SIGTTOU, SIG_IGN); X#endif /* SIGTTOU */ X savehist(histline); X broadcast(mode==PROC); X } X xxit((mode == PROC && filename[0] == '\0') ? 0 : X (exitcode < 0 ? 0 : exitcode)); X} X Xinput() X{ X register char *cp; X register int c; X register int empty = TRUE; X FILE *tmpfp; X int consec_newlines = 0; X int linecount = 0; X int linserted = 0; X X tmpfp = xfopen(mktemp(INFILE), "w"); X while (!SigTrap && fgets(bfr, BUFLEN, infp) != NULL) { X if (mode == PROC) { /* zap trailing empty lines */ X#ifdef ZAPNOTES X if (empty && bfr[0] == '#' && bfr[2] == ':' X && header.nf_id[0] == '\0' X && header.nf_from[0] == '\0' ) { X (void) strcpy(header.nf_id, bfr); X (void) nstrip(header.nf_id); X (void) fgets(bfr, BUFLEN, infp); X (void) strcpy(header.nf_from, bfr); X (void) nstrip(header.nf_from); X (void) fgets(bfr, BUFLEN, infp); X X if (header.numlines[0]) { X header.intnumlines -= 2; X (void) sprintf(header.numlines, "%d", header.intnumlines); X } X X /* Strip trailing " - (nf)" */ X if ((cp = rindex(header.title, '-')) != NULL X && !strcmp(--cp, " - (nf)")) X *cp = '\0'; X log("Stripped notes header on %s", header.ident); X continue; X } X#endif /* ZAPNOTES */ X if (bfr[0] == '\n' || X /* Bandage for older versions of inews */ X bfr[1] == '\n' && !isascii(bfr[0])) { X consec_newlines++; /* count it, in case */ X continue; /* but don't write it*/ X } X /* foo! a non-empty line. write out all saved lines. */ X while (consec_newlines > 0) { X putc('\n', tmpfp); X consec_newlines--; X linecount++; X } X } X if (mode != PROC && tty && strcmp(bfr, ".\n") == 0) X break; X for (cp = bfr; c = toascii(*cp); cp++) { X if (isprint(c) || isspace(c) || c == '\b') X putc(c, tmpfp); X if (c == '\n') X linecount++; X } X if (bfr[0] == '>') X linserted++; X if (bfr[0] == '<') /* kludge to allow diff's to be posted */ X linserted--; X empty = FALSE; X } X if (*filename) X (void) fclose(infp); X if (mode != PROC && X linecount > LNCNT && linserted > (linecount-linserted)) X error("Article rejected: %s included more text than new text", X username); X X if (mode != PROC && !is_ctl && header.sender[0] == '\0' && !Sflag) { X int siglines = 0; X char sbuf[BUFLEN]; X (void) sprintf(bfr, "%s/%s", userhome, ".signature"); X if (access(bfr, 4) == 0) { X if ((infp = fopen(bfr, "r")) == NULL) { X (void) fprintf(stderr, X "inews: \"%s\" left off (must be readable by \"inews\" owner)\n", bfr); X goto finish; X } X X while (fgets(sbuf, sizeof sbuf, infp) != NULL) X if (++siglines > 4) X break; X if (siglines > 4) X fprintf(stderr,".signature not included (> 4 lines)\n"); X else { X rewind(infp); X fprintf(tmpfp, "-- \n"); /* To separate */ X linecount++; X while ((c = getc(infp)) != EOF) { X putc(c, tmpfp); X if (c == '\n') X linecount++; X } X } X (void) fclose(infp); X } X } X Xfinish: X if (ferror(tmpfp)) X xerror("write failed to temp file"); X (void) fclose(tmpfp); X if (SigTrap) { X if (tty) X fprintf(stderr, "Interrupt\n"); X if (tty && !empty) X fwait(fsubr(newssave, (char *) NULL, (char *) NULL)); X if (!tty) X log("Blown away by an interrupt %d", SigTrap); X xxit(1); X } X if (tty) X fprintf(stderr, "EOT\n"); X fflush(stdout); X infp = fopen(INFILE, "r"); X if (header.numlines[0]) { X /* X * Check line count if there's already one attached to X * the article. Could make this a fatal error - X * throwing it away if it got chopped, in hopes that X * another copy will come in later with a correct X * line count. But that seems a bit much for now. X */ X if (linecount != header.intnumlines) { X if (linecount == 0) X error("%s rejected. linecount expected %d, got 0", header.ident, header.intnumlines); X if (linecount > header.intnumlines || X linecount+consec_newlines < header.intnumlines) X log("linecount expected %d, got %d", header.intnumlines, linecount+consec_newlines); X } X /* adjust count for blank lines we stripped off */ X if (consec_newlines) { X header.intnumlines -= consec_newlines; X if (header.intnumlines < 0 ) X header.intnumlines = 0; /* paranoia */ X (void) sprintf(header.numlines, "%d", header.intnumlines); X } X X } else { X /* Attach a line count to the article. */ X header.intnumlines = linecount; X (void) sprintf(header.numlines, "%d", linecount); X } X} X X/* X * Make the directory for a new newsgroup. ngname should be the X * full pathname of the directory. Do the other stuff too. X * The various games with setuid and chown are to try to make sure X * the directory is owned by NEWSUSR and NEWSGRP, which is tough to X * do if you aren't root. This will work on a UCB system (which allows X * setuid(geteuid()) or a USG system (which allows you to give away files X * you own with chown), otherwise you have to change your kernel to allow X * one of these things or run with your dirs 777 so that it doesn't matter X * who owns them. X */ Xmknewsg(fulldir, ngname) Xchar *fulldir; Xchar *ngname; X{ X if (ngname == NULL || !isalpha(ngname[0])) X xerror("Tried to make illegal newsgroup %s", ngname); X X /* Create the directory */ X mkparents(fulldir); X X if (mkdir(fulldir, 0777) < 0) X xerror("Cannot mkdir %s: %s", fulldir, errmsg(errno)); X X log("make newsgroup %s in dir %s", ngname, fulldir); X} X X/* X * If any parent directories of this dir don't exist, create them. X */ Xmkparents(dname) Xchar *dname; X{ X char buf[200]; X register char *p; X X (void) strcpy(buf, dname); X p = rindex(buf, '/'); X if (p) X *p = '\0'; X if (exists(buf)) X return; X mkparents(buf); X if (mkdir(buf, 0777) < 0) X xerror("Can not mkdir %s: %s", buf, errmsg(errno)); X} X Xcancel() X{ X register FILE *fp; X X log("cancel article %s", filename); X fp = fopen(filename, "r"); X if (fp == NULL) { X log("article %s not found", filename); X return; X } X if (hread(&header, fp, TRUE) == NULL) X error("Article is garbled."); X (void) fclose(fp); X (void) unlink(filename); X} X Xdounspool() X{ X register DIR *dirp; X register struct direct *dir; X register int foundsome; X int pid, status, ret; X char spbuf[BUFLEN]; X#ifdef LOCKF X FILE* LockFd; X#endif /* LOCKF */ X#ifdef VMS X sprintf(spbuf, "%s/+rnews", SPOOL); X#else /* !VMS */ X sprintf(spbuf, "%s/.rnews", SPOOL); X#endif /* !VMS */ X X if (chdir(spbuf) < 0) X xerror("chdir(%s):%s", spbuf, errmsg(errno)); X X dirp = opendir("."); X if (dirp == NULL) /* Boy are things screwed up */ X xerror("opendir can't open .:%s", errmsg(errno)); X#ifdef LOCKF X LockFd = xfopen(SEQFILE, "r+w"); X if (lockf(fileno(LockFd), F_TLOCK, 0) < 0) { X if (errno != EAGAIN && errno != EACCES) X#else /* !LOCKF */ X#ifdef BSD4_2 X if (flock(dirp->dd_fd, LOCK_EX|LOCK_NB) < 0) { X if (errno != EWOULDBLOCK) X#else /* V7 */ X strcat(spbuf, ".lock"); X sprintf(bfr, "%s.tmp", spbuf); X (void) close(creat(bfr, 0666)); X ret = LINK(bfr, spbuf); X status = errno; X (void) UNLINK(bfr); X errno = status; X if (ret < 0) { X if (errno != EEXIST) X#endif /* V7 */ X#endif /* !LOCKF */ X xerror("Can't lock %s: %s", spbuf, errmsg(errno)); X xxit(3); /* another rnews -U is running */ X } X X do { X foundsome = 0; X X while ((dir=readdir(dirp)) != NULL) { X if (dir->d_name[0] == '.') X continue; X if ((pid=vfork()) == -1) X xerror("Can't fork: %s", errmsg(errno)); X if (pid == 0) { X#ifdef IHCC X char bufr[BUFSIZ]; X sprintf(bufr, "%s/%s", logdir(HOME), RNEWS); X execl(bufr, "rnews", "-S", "-p", dir->d_name, X (char *) NULL); X#else /* !IHCC */ X execl(RNEWS, "rnews", "-S", "-p", dir->d_name, X (char *) NULL); X#endif /* !IHCC */ X _exit(1); X } X X while ((ret=wait(&status)) != pid && ret != -1) X /* continue */; X X if (((status>>8)&0177) == 42) { X /* expire has started up, shutdown rnews -U */ X break; X } X X if (status != 0) { X sprintf(bfr, "../%s", dir->d_name); X (void) LINK(dir->d_name, bfr); X logerr("rnews failed, status %d. Batch saved in %s/%s", X status, SPOOL, dir->d_name); X } X (void) unlink(dir->d_name); X foundsome++; X } X rewinddir(dirp); X } while (foundsome); /* keep rereading the directory until it's empty */ X (void) UNLINK(spbuf); X X xxit(0); X} END_OF_FILE if test 34390 -ne `wc -c <'inews.c'`; then echo shar: \"'inews.c'\" unpacked with wrong size! fi # end of 'inews.c' fi echo shar: End of shell archive. exit 0 -- "Zeta Microcomputer Software" ACSnet: nick@ultima.cs.uts.oz UUCP: ...!uunet!munnari!ultima.cs.uts.oz!nick Fidonet: Nick Andrew on 3:713/602 (Zeta)
nick@ultima.cs.uts.oz (Nick Andrew) (12/07/89)
#! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of shell archive." # Contents: ifuncs.c expire.c # Wrapped by nick@nswitgould on Thu Dec 7 22:39:55 1989 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'ifuncs.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'ifuncs.c'\" else echo shar: Extracting \"'ifuncs.c'\" \(32337 characters\) sed "s/^X//" >'ifuncs.c' <<'END_OF_FILE' X/* X * This software is Copyright (c) 1986 by Rick Adams. X * X * Permission is hereby granted to copy, reproduce, redistribute or X * otherwise use this software as long as: there is no monetary X * profit gained specifically from the use or reproduction or this X * software, it is not sold, rented, traded or otherwise marketed, and X * this copyright notice is included prominently in any copy X * made. X * X * The author make no claims as to the fitness or correctness of X * this software for any use whatsoever, and it is provided as is. X * Any use of this software is at the user's own risk. X * X * ifuncs - functions used by inews. X */ X X#ifdef SCCSID Xstatic char *SccsId = "@(#)ifuncs.c 2.65 4/10/87"; X#endif /* SCCSID */ X X#include "iparams.h" X X/*LINTLIBRARY*/ X X/* X * Transmit this article to all interested systems. X */ X X#ifdef u370 Xstatic struct srec srec; X#endif /* u370 */ X Xstatic struct hbuf h, hh; X X#ifdef MULTICAST X#define MAXMCAST 20 X#define MAXMCS 10 X Xstruct multicast { X char mc_name[SBUFLEN]; /* "multi-cast" name */ X short mc_syscnt; X char mc_tosys[MAXMCAST][SBUFLEN]; X} mcast[MAXMCS]; X Xstatic int mccount; X#endif /* MULTICAST */ X Xlong lseek(); X X#ifndef DBM Xchar *histfile(); X#endif /* !DBM */ X X#ifdef VMS X/* X * For VMS/Eunice there are no links: article was moved to firstbufname X * before broadcast is reached. So we read it from there. X */ Xextern char firstbufname[]; X#endif X Xbroadcast(is_rnews) Xint is_rnews; X{ X register char *hptr; X register char *sptr; X register FILE *fp; X#ifndef u370 X struct srec srec; X#endif X char sentbuf[LBUFLEN]; X int nsent = 0; X char *sentsys; X#ifdef GENERICPATH X int len; X#endif /* GENERICPATH */ X X /* h is a local copy of the header we can scribble on */ X#ifdef VMS X fp = xfopen (firstbufname, "r"); X#else X fp = xfopen(ARTICLE, "r"); X#endif X if (hread(&h, fp, TRUE) == NULL) X xerror("Cannot reread article"); X (void) fclose(fp); X X (void) strcpy(sentbuf, h.ident); X (void) strcat(sentbuf, " sent to "); X sentsys = index(sentbuf, '\0'); X nsent = 0; X /* break path into list of systems. */ X hptr = h.path; X#ifdef GENERICPATH X if (!is_rnews && X strncmp(PATHSYSNAME, h.path, (len = strlen(PATHSYSNAME))) == 0 X && index(NETCHRS, h.path[len])) X (void) strcpy(h.path, &(h.path[len+1])); X#endif /* GENERICPATH */ X sptr = hptr = h.path; X while ((hptr=strpbrk(hptr, NETCHRS)) != NULL) { X *hptr++ = '\0'; X sptr = hptr; X } X *sptr = '\0'; X X#ifdef MULTICAST X mccount = 0; X#endif /* MULTICAST */ X X /* loop once per system. */ X s_openr(); X while (s_read(&srec)) { X char *dist = h.distribution; X if (strncmp(srec.s_name, LOCALPATHSYSNAME, SNLN) == 0) X continue; X if (sptr = srec.s_nosend) { X while (*sptr) { X while (*sptr && *sptr != ',') X sptr++; X if (*sptr == ',') X *sptr++ = '\0'; X } X *++sptr = '\0'; X } X hptr = h.path; X while (*hptr != '\0') { X if (strncmp(srec.s_name, hptr, SNLN) == 0) X goto contin; X if (sptr = srec.s_nosend) { X while (*sptr != '\0') { X if (strncmp(sptr, hptr, SNLN) == 0) X goto contin; X while (*sptr++) X ; X } X } X while (*hptr++ != '\0') X ; X } X if (!ngmatch(h.nbuf, srec.s_nbuf)) X continue; X if (*dist == '\0') X dist = "world"; X if (!ngmatch(dist, srec.s_nbuf) && !ngmatch(srec.s_nbuf, dist)) X continue; X X if (nsent) { X hptr = sentsys; X while ((sptr = index(hptr, ',')) != NULL) { X *sptr = '\0'; X if (strcmp(hptr, srec.s_name) == 0) { X *sptr = ','; X goto contin; X } X *sptr++ = ','; X for (hptr = sptr; isspace(*hptr); hptr++) X ; X } X if (strcmp(hptr, srec.s_name) == 0) X continue; X } X /* now we've found a system to send this article to */ X#ifdef MULTICAST X if (index(srec.s_flags, 'M')) { X /* do a "multi-cast" transmit */ X register struct multicast *m; X X if (strlen(srec.s_name) >= SBUFLEN || X strlen(srec.s_xmit) >= SBUFLEN) X xerror("system name too long for multicast"); X for (m = mcast; m < &mcast[mccount]; m++) X if (strcmp(srec.s_xmit, m->mc_name) == 0) X break; X if (m >= &mcast[MAXMCS]) X xerror("Too many multicasts"); X if (m == &mcast[mccount]) { X mccount++; X m->mc_syscnt = 0; X strcpy(m->mc_name, srec.s_xmit); X } X if (m->mc_syscnt >= MAXMCAST) X xerror("Too many systems for multicast"); X strcpy(m->mc_tosys[m->mc_syscnt++], srec.s_name); X } else { X register struct multicast *m; X register char **yptr; X char *sysptrs[MAXMCAST]; X int mc; X X mc = 0; X for (m = mcast; m < &mcast[mccount]; m++) X if (strcmp(m->mc_name, srec.s_name) == 0) { X yptr = sysptrs; X while (mc < m->mc_syscnt) X *yptr++ = m->mc_tosys[mc++]; X break; X } X#ifdef VMS X if (!transmit(&srec, xfopen(firstbufname,"r"), X#else /* !VMS */ X if (!transmit(&srec, xfopen(ARTICLE,"r"), X#endif /* !VMS */ X (strncmp(h.nbuf, "to.", 3) != 0), X sysptrs, mc)) X continue; X } X#else /* !MULTICAST */ X#ifdef VMS X if (!transmit(&srec, xfopen(firstbufname, "r"), X#else /* !VMS */ X if (!transmit(&srec, xfopen(ARTICLE, "r"), X#endif /* !VMS */ X (strncmp(h.nbuf, "to.", 3) != 0), X (char **) NULL, FALSE)) X continue; X#endif /* !MULTICAST */ X if (nsent) X (void) strcat(sentbuf, ", "); X (void) strcat(sentbuf, srec.s_name); X nsent++; X contin:; X } X if (nsent) X log(sentbuf); X s_close(); X} X X/* X * Transmit file to system. X */ X#define PROC 0004 X#ifndef MULTICAST X/* ARGSUSED */ X#endif /* !MULTICAST */ Xtransmit(sp, ifp, maynotify, sysnames, mc) Xregister struct srec *sp; Xregister FILE *ifp; Xint maynotify; Xchar **sysnames; Xint mc; X{ X register FILE *ofp; X register int c; X register char *ptr; X char TRANS[BUFLEN]; X char *argv[20]; X register int pid; X extern char firstbufname[]; X X/* A: afmt: the other machine runs an A news, so we xmit in A format */ X int afmt = (index(sp->s_flags, 'A') != NULL); X/* B: use B format (this is the default - don't use this letter elsewise). */ X/* F: append name to file */ X int appfile = (index(sp->s_flags, 'F') != NULL); X/* L: local: don't send the article unless it was generated locally */ X int local = ((ptr = index(sp->s_flags, 'L')) != NULL); X/* H: interpolate history line into command, use existing file */ X int history = (index(sp->s_flags, 'H') != NULL); X/* m: moderated: only send if group is moderated */ X int sendifmoderated = (index(sp->s_flags, 'm') != NULL); X/* u: unmoderated: only send if group is unmoderated */ X int sendifunmoderated = (index(sp->s_flags, 'u') != NULL); X/* M: multi-cast: this is taken care of above, but don't reuse flag */ X#ifdef MULTICAST X/* O: multi-cast only, don't send article if not multicast hosts */ X int multisend = (index(sp->s_flags, 'O') != NULL); X#endif /* MULTICAST */ X/* N: notify: don't send the article, just tell him we have it */ X int notify = maynotify && (index(sp->s_flags, 'N') != NULL); X/* S: noshell: don't fork a shell to execute the xmit command */ X int noshell = (index(sp->s_flags, 'S') != NULL); X/* U: useexist: use the -c option to uux to use the existing copy */ X int useexist = (index(sp->s_flags, 'U') != NULL); X/* I: append messageid to file. implies F flag */ X int appmsgid = maynotify && (index(sp->s_flags, 'I') != NULL); X X if (notify) X appfile = appmsgid = FALSE; X X if (local && mode == PROC) { X local = 0; X while (isdigit(*++ptr)) X local = local * 10 + *ptr - '0'; X for (ptr = h.path; *ptr != '\0' && local >= 0; local--) X while (*ptr++ != '\0') X ; X if (local < 0) { X (void) fclose(ifp); X return FALSE; X } X } X X /* X ** Do not transmit to system specified in -x flag. X */ X if (not_here[0] && strcmp(not_here, sp->s_name) == 0) { X (void) fclose(ifp); X return FALSE; X } X X#ifdef DEBUG X printf("Transmitting to '%s'\n", sp->s_name); X#endif /* DEBUG */ X X#ifdef MULTICAST X if (multisend && mc == 0) { X (void) fclose(ifp); X return FALSE; X } X#endif /* MULTICAST */ X X if ((sendifmoderated && is_mod[0] == '\0') || X (sendifunmoderated && is_mod[0] != '\0')) { X fclose(ifp); X return FALSE; X } X X if (appmsgid || (!appfile && !useexist && !history)) { X if (!hread(&hh, ifp, TRUE)) { X logerr("Bad header, not transmitting %s re %s to %s", X hh.ident, hh.title, sp->s_name); X (void) fclose(ifp); X return FALSE; X } X if (hh.nbuf[0] == '\0') { X fprintf(stderr, "Article not subscribed to by %s\n", sp->s_name); X (void) fclose(ifp); X return FALSE; X } X (void) sprintf(TRANS, "%s/trXXXXXX", SPOOL); X } X X if (notify) { X char oldid[50]; X (void) sprintf(hh.title, "ihave %s %s", hh.ident, PATHSYSNAME); X (void) strcpy(hh.ctlmsg, hh.title); X (void) strcpy(hh.numlines, "0"); X (void) sprintf(hh.nbuf, "to.%s.ctl", sp->s_name); X (void) strcpy(oldid, hh.ident); X getident(&hh); X log("tell %s about %s, notif. id %s", X sp->s_name, oldid, hh.ident); X } X X if (appfile || appmsgid) { X if (firstbufname[0] == '\0') { X extern char histline[]; X localize("junk"); X savehist(histline); X xerror("No file name to xmit from"); X } X if (sp->s_xmit[0] == '\0') X sprintf(sp->s_xmit, "%s/%s%s", BATCHDIR, sp->s_name, X appmsgid ? ".ihave" : ""); X#ifdef IHCC X (void) sprintf(TRANS, "%s/%s/%s", logdir(HOME), BATCHDIR, sp->s_xmit); X ofp = fopen(TRANS, "a"); X#else /* !IHCC */ X ofp = fopen(sp->s_xmit, "a"); X#endif /* !IHCC */ X if (ofp == NULL) X xerror("Cannot append to %s", sp->s_xmit); X fprintf(ofp, "%s", appmsgid ? hh.ident : firstbufname); X#ifdef MULTICAST X while (--mc >= 0) X fprintf(ofp, " %s", *sysnames++); X#endif /* !MULTICAST */ X putc('\n', ofp); X (void) fclose(ofp); X (void) fclose(ifp); X return TRUE; X } X else if (useexist) { X if (firstbufname[0] == '\0') X xerror("No file name to xmit from"); X if (*sp->s_xmit == '\0') X#ifdef UXMIT X (void) sprintf(bfr, UXMIT, sp->s_name, firstbufname); X#else X xerror("UXMIT not defined for U flag"); X#endif X else X#ifdef MULTICAST X makeargs(bfr, sp->s_xmit, firstbufname, sysnames, mc); X#else X (void) sprintf(bfr, sp->s_xmit, firstbufname); X#endif X (void) fclose(ifp); X } else if (history) { X extern char histline[]; X X if (*sp->s_xmit == '\0') X xerror("no xmit command with H flag"); X#ifdef MULTICAST X makeargs(bfr, sp->s_xmit, histline, sysnames, mc); X#else X (void) sprintf(bfr, sp->s_xmit, histline); X#endif X } else { X ofp = xfopen(mktemp(TRANS), "w"); X if (afmt) { X#ifdef OLD X fprintf(ofp, "A%s\n%s\n%s!%s\n%s\n%s\n", oident(hh.ident), hh.nbuf, PATHSYSNAME, X hh.path, hh.subdate, hh.title); X#else /* !OLD */ X logerr("Must have OLD defined to use A flag for xmit"); X return FALSE; X#endif /* !OLD */ X } else X hwrite(&hh, ofp); X if (!notify) X while ((c = getc(ifp)) != EOF) X putc(c, ofp); X if (ferror(ofp)) X xerror("write failed on transmit"); X (void) fclose(ifp); X (void) fclose(ofp); X if (*sp->s_xmit == '\0') X (void) sprintf(bfr, DFTXMIT, sp->s_name, TRANS); X else X#ifdef MULTICAST X makeargs(bfr, sp->s_xmit, TRANS, sysnames, mc); X#else /* !MULTICAST */ X (void) sprintf(bfr, sp->s_xmit, TRANS); X#endif /* !MULTICAST */ X } X X /* At this point, the command to be executed is in bfr. */ X if (noshell) { X if (pid = vfork()) X fwait(pid); X else { X (void) close(0); X (void) open(TRANS, 0); X ptr = bfr; X for (pid = 0; pid < 19; pid++) { X while (isspace(*ptr)) X *ptr++ = 0; X argv[pid] = ptr; X while (!isspace(*++ptr) && *ptr) X ; X if (!*ptr) X break; X } X argv[++pid] = 0; X (void) setgid(gid); X (void) setuid(uid); X execvp(argv[0], argv); X xerror("Can't execv %s", argv[0]); X } X } else { X if (!history && sp->s_xmit[0] && !index(bfr, '<')) { X char newcmd[LBUFLEN]; X X (void) sprintf(newcmd, "(%s) <%s", bfr, X useexist ? firstbufname : TRANS); X system(newcmd); X } else X system(bfr); X } X if (!appfile && !useexist && !history) X (void) unlink(TRANS); X (void) fclose(ifp); X return TRUE; X} X X#ifdef MULTICAST Xmakeargs(buf, cmd, arg2, sysargs, sac) Xchar *buf; Xchar *cmd; Xchar *arg2; Xregister char **sysargs; Xint sac; X{ X register char *p = cmd; X register char *q; X register ac = 0; X register char *b = buf; X X q = p; X do { X if (q = index(q, ' ')) X *q = '\0'; X if (index(p, '%')) { X switch (++ac) { X case 1: X while (--sac >= 0) { X sprintf(b, p, *sysargs++); X b = index(b, '\0'); X } X break; X case 2: X sprintf(b, p, arg2); X b = index(b, '\0'); X break; X default: X if (q) X *q = ' '; X xerror("badly formed command: %s", cmd); X } X } else { X strcpy(b, p); X b = index(b, '\0'); X } X if (q) { X *q = ' '; X p = q; X while (isspace(*q)) X q++; X } X } while (q != NULL); X} X#endif /* MULTICAST */ X Xtypedef struct { X char *dptr; X int dsize; X} datum; X X/* X * Return TRUE if we have seen this file before, else FALSE. X */ Xhistory(hp) Xstruct hbuf *hp; X{ X#ifdef DBM X datum lhs, rhs; X datum fetch(); X#else /* !DBM */ X register FILE *hfp; X register char *p; X#endif /* !DBM */ X char lcident[BUFLEN]; X extern char histline[]; X X#ifdef DEBUG X fprintf(stderr,"history(%s)\n", hp->ident); X#endif /* DEBUG */ X /* X * Make the article ID case insensitive. X */ X (void) strcpy(lcident, hp->ident); X lcase(lcident); X X idlock(lcident); X#ifdef DBM X initdbm(ARTFILE); X lhs.dptr = lcident; X lhs.dsize = strlen(lhs.dptr) + 1; X rhs = fetch(lhs); X if (rhs.dptr) { X idunlock(); X return(TRUE); X } X#else /* !DBM */ X hfp = xfopen(histfile(lcident), "r"); X while (fgets(bfr, BUFLEN, hfp) != NULL) { X p = index(bfr, '\t'); X if (p == NULL) X p = index(bfr, '\n'); X if (p != NULL) /* can happen if nulls in file */ X *p = 0; X lcase(bfr); X X if (strcmp(bfr, lcident) == 0) { X (void) fclose(hfp); X idunlock(); X#ifdef DEBUG X fprintf(stderr,"history returns true\n"); X#endif /* DEBUG */ X return TRUE; X } X } X (void) fclose(hfp); X#endif /* !DBM */ X histline[0] = '\0'; X addhist(hp->ident); X addhist("\t"); X#ifdef DEBUG X fprintf(stderr,"history returns false\n"); X#endif X return FALSE; X} X Xchar histline[PATHLEN]; X Xaddhist(msg) Xchar *msg; X{ X (void) strcat(histline, msg); X} X Xsavehist(hline) Xchar *hline; X{ X register FILE *hfp; X register char *p; X#ifdef DBM X long fpos; X#endif /* !DBM */ X X#ifndef DBM X if (strcmp((p = histfile(hline)), ARTFILE) != 0) { X /* If the history subfile is accessible */ X if ((hfp = xfopen(p, "a")) != NULL ) { /* If we can append */ X fprintf(hfp, "%s\n", hline); /* Append */ X (void) fclose(hfp); X } else X logerr("Unable to append to %s: %s", p, errmsg(errno)); X } else X#endif /* !DBM */ X { X hfp = xfopen(ARTFILE, "a"); X (void) fseek(hfp, 0L, 2); /* Unisoft 5.1 doesn't seek to EOF on 'a' */ X#ifdef DBM X fpos = ftell(hfp); X#endif /* !DBM */ X fprintf(hfp, "%s\n", hline); X (void) fclose(hfp); X } X#ifdef DBM X { X datum lhs, rhs; X /* We assume that history has already been called, calling dbminit. */ X p = index(hline, '\t'); X if (p) X *p = 0; X lcase(hline); X lhs.dptr = hline; X lhs.dsize = strlen(lhs.dptr) + 1; X rhs.dptr = (char *)&fpos; X rhs.dsize = sizeof fpos; X store(lhs, rhs); X } X#endif /* DBM */ X idunlock(); X} X X/* X * Save partial news. X */ X/* ARGSUSED */ Xnewssave(fd, dummy) XFILE *fd; Xchar *dummy; X{ X register FILE *tofd, *fromfd; X char sfname[BUFLEN]; X register int c; X time_t tim; X X if (fd == NULL) X fromfd = xfopen(INFILE, "r"); X else X fromfd = fd; X (void) umask(savmask); X (void) setgid(gid); X (void) setuid(uid); X X (void) sprintf(sfname, "%s/%s", userhome, PARTIAL); X if ((tofd = fopen(sfname, "a")) == NULL) X xerror("Cannot save partial news in %s", sfname); X (void) time(&tim); X fprintf(tofd, "----- News saved at %s\n", arpadate(&tim)); X while ((c = getc(fromfd)) != EOF) X putc(c, tofd); X (void) fclose(fromfd); X (void) fclose(tofd); X printf("News saved in %s\n", sfname); X xxit(1); X} X X/* X * Handle dates in header. X */ X Xdates(hp) Xstruct hbuf *hp; X{ X time_t edt; X X if (*hp->subdate) { X if (cgtdate(hp->subdate) < 0) { X error("Cannot parse submittal date '%s'", hp->subdate); X } X } else { X (void) time(&edt); X (void) strcpy(hp->subdate, arpadate(&edt)); X } X} X X#define LOCKSIZE 128 Xchar lockname[LOCKSIZE]; X Xidlock(str) Xchar *str; X{ X register int i; X register char *cp, *scp; X char tempname[LOCKSIZE]; X time_t now; X struct stat sbuf; X extern int errno; X#ifdef VMS X int fd; X/* The name here is because of the peculiar properties of version numbers X * in Eunice. We eliminate any troublesome characters also. X */ X (void) sprintf(lockname, "/tmp/%.10s.l.1", str); X for (cp = lockname; *cp; cp++) X if (*cp == '/' || *cp == '[' || *cp == ']') *cp = '.'; X while ((fd = creat(lockname, 0444)) < 0) { X#else /* !VMS */ X (void) strcpy(tempname, "/tmp/LTMP.XXXXXX"); X (void) mktemp(tempname); X (void) strcpy(lockname, "/tmp/L"); X i = strlen(lockname); X cp = &lockname[i]; X scp = str - 1; X while (i++ < LOCKSIZE && *++scp != '\0') X if (*scp == '/') /* slash screws up the open */ X *cp++ = '.'; X else X *cp++ = *scp; X *cp = '\0'; X#ifdef FOURTEENMAX X lockname[5 /* /tmp/ */ + 14] = '\0'; X#endif X i = creat(tempname, 0666); X if (i < 0) X xerror("Cannot creat %s: errno %d", tempname, errno); X (void) close(i); X while (link(tempname, lockname)) { X#endif /* !VMS */ X (void) time(&now); X if (stat(lockname, &sbuf) < 0) X xerror("Directory permission problem in /tmp"); X X if (sbuf.st_mtime + 10*60 < now) { X (void) unlink(lockname); X logerr("Article %s locked up", str); X break; X } X log("waiting on lock for %s", lockname); X sleep((unsigned)60); X } X#ifdef VMS X (void) close(fd); X#endif X (void) unlink(tempname); X} X Xidunlock() X{ X (void) unlink(lockname); X} X X/* X * Put a unique name into header.ident. X */ Xgetident(hp) Xstruct hbuf *hp; X{ X long seqn; X register FILE *fp; X extern char *mydomain(); X X lock(); X fp = xfopen(SEQFILE, "r"); X (void) fgets(bfr, BUFLEN, fp); X (void) fclose(fp); X seqn = atol(bfr) + 1; X/* X * For Eunice, this breaks if SEQFILE is not in Unix format. X */ X fp = xfopen(SEQFILE, "r+w"); X fprintf(fp, "%ld\n", seqn); X (void) fclose(fp); X unlock(); X (void) sprintf(hp->ident, "<%ld@%s>", seqn, LOCALSYSNAME); X} X X/* X * Check that header.nbuf contains only valid newsgroup names; X * exit with error if not valid. X */ Xngfcheck(isproc) X{ X register FILE * f; X register char * cp; X register int i, j; X register int ngcount, okcount, havealiased; X register int pass; X char * ngs[sizeof header.nbuf / 2]; X char uses[sizeof header.nbuf / 2]; X char tbuf[sizeof header.nbuf]; X char abuf[BUFLEN]; X X havealiased = ngcount = 0; X is_mod[0] = '\0'; X /* X ** Split header.nbuf into constituent newsgroups. X ** Zap "local" newsgroups of articles from remote sites. X */ X cp = tbuf; X (void) strcpy(cp, header.nbuf); X for ( ; ; ) { X while (*cp == NGDELIM || *cp == ' ') X ++cp; X if (*cp == '\0') X break; X ngs[ngcount] = cp; X do { X ++cp; X } while (*cp != '\0' && *cp != NGDELIM && *cp != ' '); X if (*cp != '\0') X *cp++ = '\0'; X /* X ** Check for local only distribution on incoming X ** newsgroups. This might occur if someone posted to X ** general,net.unix X */ X if (isproc && index(ngs[ngcount], '.') == NULL && X index(header.nbuf, '.') != NULL) { X logerr("Local group %s removed", X ngs[ngcount]); X continue; X } X uses[ngcount] = 1; /* it should go in "Newsgroups" line */ X ++ngcount; X } X /* X ** Check groups against active file. X */ Xrecheck: X okcount = 0; X rewind(actfp); clearerr(actfp); X while (okcount < ngcount && fgets(bfr, BUFLEN, actfp) == bfr) { X if ((cp = index(bfr, ' ')) == NULL) X continue; /* strange line in input! */ X /* newsgroup 12345 12345 X */ X /* cp + 01234567890123 */ X if (!isproc && cp[13] == 'n') X continue; /* can't post to this group! */ X *cp = '\0'; X for (i = 0; i < ngcount; ++i) X if (uses[i] >= 1 && strcmp(bfr, ngs[i]) == 0) { X uses[i] = 2; /* it should be localized too */ X if (cp[13] == 'm') X strcpy(is_mod, bfr); X ++okcount; X } X } X#ifdef ALWAYSALIAS X okcount = 0; X#endif /* ALWAYSALIAS */ X /* X ** Handle groups absent from active file. X */ X if (havealiased == 0 && okcount < ngcount) { X /* X ** See if remaining groups are in our alias list. X */ X f = xfopen(ALIASES, "r"); X while (okcount < ngcount && fscanf(f, "%s %s", abuf, bfr) == 2) X for (i = 0; i < ngcount; ++i) { X#ifndef ALWAYSALIAS X if (uses[i] == 2) X continue; X#endif /* ALWAYSALIAS */ X if (strcmp(ngs[i], abuf) != 0) X continue; X if (isproc) X cp = "Aliased newsgroup %s to %s"; X else X cp = "Please change %s to %s"; X logerr(cp, abuf, bfr); X ngs[i] = AllocCpy(bfr); X uses[i] = 2; X ++havealiased; X ++okcount; X } X (void) fclose(f); X for (i = 0; i < ngcount; ++i) { X if (uses[i] == 2) X continue; X if (isproc) X log("Unknown newsgroup %s not localized", X ngs[i]); X else X logerr("Unknown newsgroup %s", ngs[i]); X#ifdef ALWAYSALIAS X ++okcount; /* so we know to exit below */ X } X if (!isproc && okcount > 0) X#else /* !ALWAYSALIAS */ X } X if (!isproc) X#endif /* !ALWAYSALIAS */ X newssave(infp, (char *) NULL); X /* X * Unfortunately, if you alias an unmoderated group to a X * moderated group, you must recheck the active file to see X * if the new group is moderated. Rude but necessary. X */ X if (havealiased) X goto recheck; X } X /* X ** Zap duplicates. X */ X for (i = 0; i < ngcount - 1; ++i) { X if (uses[i] == 0) X continue; X for (j = i + 1; j < ngcount; ++j) { X if (uses[j] == 0) X continue; X if (strcmp(ngs[i], ngs[j]) != 0) X continue; X logerr("Duplicate %s removed", ngs[j]); X if (uses[i] < uses[j]) X uses[i] = uses[j]; X uses[j] = 0; X } X } X for (pass = 1; pass <= 2; ++pass) { X register int avail; X X if (pass == 1) { X /* X ** Rewrite header.nbuf. X */ X cp = header.nbuf; X avail = sizeof header.nbuf; X } else { X /* X ** Fill in nbuf. X */ X cp = nbuf; X avail = sizeof nbuf; X } X for (i = 0; i < ngcount; ++i) { X if (uses[i] < pass) X continue; X j = strlen(ngs[i]); X if (j + 2 > avail) { X logerr("Redone Newsgroups too long"); X break; X } X (void) strcpy(cp, ngs[i]); X cp += j; X *cp++ = (pass == 1) ? NGDELIM : '\0'; X avail -= (j + 1); X } X if (pass == 1) { X if (cp == header.nbuf) X *cp = '\0'; X else *(cp - 1) = '\0'; X } else *cp = '\0'; X } X /* X ** Free aliases. X */ X for (i = 0; i < ngcount; ++i) X if (ngs[i] < tbuf || ngs[i] > &tbuf[sizeof tbuf - 1]) X free(ngs[i]); X return nbuf[0] == '\0'; X} X X/* X * Figure out who posted the article (which is locally entered). X * The results are placed in the header structure hp. X */ Xgensender(hp, logname) Xstruct hbuf *hp; Xchar *logname; X{ X register char *fn, *p; X char buf[BUFLEN]; X char *fullname(), *getenv(); X int fd, n; X extern char *mydomain(); X X if ((fn = getenv("NAME")) == NULL) { X (void) sprintf(buf, "%s/%s", userhome, ".name"); X if ((fd = open(buf, 0)) >= 0) { X n = read(fd, buf, sizeof buf); X (void) close(fd); X if (n > 0 && buf[0] >= 'A') { X for (p = fn = buf; *p; p++) X if (*p < ' ') X *p = '\0'; X } X } X } X X if (fn == NULL) X fn = fullname(logname); X X (void) sprintf(hp->path, "%s", logname); X (void) sprintf(hp->from, "%s@%s (%s)", logname, FROMSYSNAME, fn); X} X X/* X * Trap interrupts. X */ Xonsig(n) Xint n; X{ X static int numsigs = 0; X /* X * Most UNIX systems reset caught signals to SIG_DFL. X * This bad design requires that the trap be set again here. X * Unfortunately, if the signal recurs before the trap is set, X * the program will die, possibly leaving the lock in place. X */ X if (++numsigs > 100) { X xerror("inews ran away looping on signal %d", n); X } X (void) signal(n, onsig); X SigTrap = n; X} X X/* X * If the stdin begins with "#" the input is some kind of batch. if X * the first line is: X * #!cunbatch X * or X * #!c7unbatch X * then fork off a pipe to do the either a X * "compress -d" X * or a X * "decode | compress -d" X * and check their output for more batch headers. They probably X * contain a batch format that looks like this: X * #! rnews 1234 X * article with 1234 chars X * #! rnews 4321 X * article with 4321 chars X * If so, then for each article, copy the indicated number of chars into X * a temp file, fork a copy of ourselves, make its input the temp file, X * and allow the copy to process the article. This avoids an exec of X * rnews for each article. X */ X Xcheckbatch() X{ X int c; X char *cp; X X setbuf(infp, (char *)NULL); X while ((c = getc(infp)) == '#') { X /* some kind of batch, investigate further */ X int i; X char cmd[BUFLEN]; X cmd[0] = c; X fgets(cmd + 1, BUFLEN, infp); X if (strncmp(cmd, "#! cunbatch", 11) == 0) { X (void) sprintf(cmd, "%s/compress", LIB); X input_pipe(cmd, "compress", "-d", (char *) 0); X continue; /* look for the #! rnews */ X } else if (strncmp(cmd, "#! c7unbatch", 12) == 0) { X (void) sprintf(cmd, "%s/decode | %s/compress -d", X LIB, LIB); X input_pipe("/bin/sh", "news-unpack", "-c", cmd); X continue; /* look for the #! rnews */ X } else if (strncmp(cmd, "#! rnews ", 9) == 0 || X strncmp(cmd, "! rnews ", 8) == 0) { X /* instead of execing unbatch do it ourselves */ X register int fd, rc, wc; X int piped[2]; X register long size, asize; X char *filename; X int pid, wpid, exstat; X#define CPBFSZ 8192 X char buf[CPBFSZ]; X X filename = 0; X do { X while (strncmp(cmd, "#! rnews ", 9)) { X fprintf(stderr, "out of sync, skipping %s\n", cmd); X if (fgets(cmd, BUFLEN, infp) == NULL) X exit(0); X } X asize = atol(cmd + 9); X if (asize <= 0) X xerror("checkbatch: bad batch count %ld", asize); X fd = -1; X size = asize; X do { X if (size > CPBFSZ) X rc = CPBFSZ; X else X rc = size; X rc = fread(buf, 1, rc, infp); X if (rc <= 0) X break; X if (fd < 0) { X if (rc == asize) X break; /* fits in buffer */ X if (!filename) X filename = mktemp("/tmp/unbnewsXXXXXX"); X if ((fd = creat(filename, 0666)) < 0) { X fprintf(stderr, "rnews: creat of \"%s\" failed", X filename); X perror(" "); X exit(1); X } X } X wc = write(fd, buf, rc); /* write to temp file */ X if (wc != rc) { X fprintf(stderr, "write of %d to \"%s\" returned %d", X rc, filename, wc); X perror(" "); X exit(1); X } X size -= rc; X } while (size > 0); X if (fd >= 0) X (void) close(fd); X X /* X * If we got a truncated batch, don't process X * the last article; it will probably be X * received again. X */ X if ((rc < asize) && (size > 0)) X break; X X /* X * This differs from the old unbatcher in X * that we don't exec rnews, mainly because X * we ARE rnews. Instead we fork off a copy X * of ourselves for each article and allow it X * to process. X */ X if (rc == asize) { X /* X * article fits in buffer, use a pipe X * instead of a temporary file. X */ X if (pipe(piped) != 0) X xerror("checkbatch: pipe() failed"); X } X while ((pid = fork()) == -1) { X fprintf(stderr, "fork failed, waiting...\r\n"); X sleep(60); X } X if (pid == 0) { X if (rc == asize) { X /* article fits in buffer X * make the output of the X * pipe for STDIN X */ X (void) fclose(infp); X /* redundant but why not */ X (void) close(0); X if ((i = dup(piped[0])) != 0) X xerror("dup() returned %d, should be 0", i); X (void) close(piped[0]); X (void) close(piped[1]); X infp = fdopen(0, "r"); X } else /* supstitute temp file as X * input */ X freopen(filename, "r", infp); X return; /* from checkbatch as if X * normal article */ X } X /* parent of fork */ X if (rc == asize) { X /* article fits in buffer */ X wc = write(piped[1], buf, rc); X if (wc != rc) { X fprintf(stderr, "write of %d to pipe returned %d", X rc, wc); X perror("rnews: write"); X exit(1); X } X (void) close(piped[0]); X (void) close(piped[1]); X } X while ((wpid = wait(&exstat)) >= 0 && wpid != pid); X } while (fgets(cmd, BUFLEN, infp) != NULL); X (void) unlink(filename); X exit(0);/* all done */ X X } else { X docmd(cmd); X xxit(0); X } X } /* while a batch */ X cp = malloc((unsigned)BUFSIZ); X if (cp != NULL) X setbuf(infp, cp); X if (c != EOF) X (void) ungetc(c, infp); X clearerr(infp); X} X X/* X * The input requires some processing so fork and exec the indicated command X * with its output piped to our input. X */ Xstatic Xinput_pipe(cmd, arg0, arg1, arg2) Xchar *cmd, *arg0, *arg1, *arg2; X{ X int i, pid; X int piped[2]; X X if (pipe(piped) != 0) { X perror("checkbatch: pipe() failed"); X exit(1); X } X fflush(stdout); X while ((pid = vfork()) == -1) { X perror("checkbatch: fork failed, waiting"); X sleep(60); X } X if (pid == 0) { /* child process */ X /* X * setup a pipe such that the exec'ed process will read our X * input file and write to the pipe X */ X (void) close(1); X if ((i = dup(piped[1])) != 1) X xerror("dup() returned %d, should be 1", i); X (void) close(piped[0]); X (void) close(piped[1]); X execl(cmd, arg0, arg1, arg2, (char *) 0); X perror("checkbatch"); X xerror("Unable to exec %s to unpack news.", cmd); X } else { /* parent process */ X /* make the output of the pipe for STDIN */ X (void) fclose(infp); X (void) close(0); X if ((i = dup(piped[0])) != 0) X xerror("dup() returned %d, should be 0", i); X (void) close(piped[0]); X (void) close(piped[1]); X /* X * there should be a way to clear any buffered input and just X * replace file descriptor 0 but I can't find a portable way. X */ X infp = fdopen(0, "r"); X } X} X X#define MAXARGS 32 X Xdocmd(p) Xregister char *p; X{ X char *args[MAXARGS]; X register char **ap = args; X char path[BUFSIZ]; X char *rindex(), *cp; X X while (*p && !isspace(*p)) /* skip leading #! crud */ X p++; X X while (isspace(*p)) X p++; X X while (*p != '\0') { X *ap++ = p; X if (ap >= &args[MAXARGS]) { X logerr("inews: unbatch: Too many args to %s", args[0]); X exit(2); X } X while (*p && !isspace(*p)) X p++; X if (*p) X *p++ = '\0'; X while (isspace(*p)) X p++; X } X *ap = (char *)0; X X if (ap == args) { X logerr("inews: unbatch: no command to execute"); X exit(2); X } X X /* strip off any leading pathname in case someone gets tricky */ X cp = rindex(args[0], '/'); X if (cp++ == NULL) X cp = args[0]; X X# ifdef HOME X sprintf(path, "%s/%s/%s", logdir(HOME), LIBDIR, cp); X# else /* !HOME */ X sprintf(path, "%s/%s", LIBDIR, cp); X# endif /* HOME */ X X /* X * "path" is absolute, no searching is needed, we use X * 'execvp' solely so that sh scripts will be handled X */ X (void) execvp(path, args); X perror(path); X xxit(2); X} X X/* X * Exit and cleanup. X */ Xxxit(status) Xint status; X{ X (void) unlink(INFILE); X (void) unlink(ARTICLE); X while (lockcount > 0) X unlock(); X idunlock(); X exit(status); X} X Xrwaccess(fname) Xchar *fname; X{ X int fd; X X fd = open(fname, 2); X if (fd < 0) X return 0; X (void) close(fd); X return 1; X} X Xexists(fname) Xchar *fname; X{ X int fd; X X fd = open(fname, 0); X if (fd < 0) X return 0; X (void) close(fd); X return 1; X} X Xint lockcount = 0; /* no. of times we've called lock */ X X#ifdef VMS X X#define SUBLOCK "/tmp/netnews.lck.1" X X/* X * Newsystem locking. X * These routines are different for VMS because we can not X * effectively simulate links, and VMS supports multiple X * version numbers of files X */ Xlock() X{ X register int i; X register int fd; X X if (lockcount++ == 0) { X i = DEADTIME; X while ((fd = creat(SUBLOCK, 0444)) < 0) { X if (--i < 0) { X (void) unlink(SUBLOCK); X logerr("News system locked up"); X } X if (i < -3) X xerror("Unable to unlock news system"); X sleep((unsigned)1); X } X (void) close(fd); X } X} X Xunlock() X{ X if (--lockcount == 0) X (void) unlink(SUBLOCK); X} X X#else /* !VMS */ X X/* X * Newsystem locking. X */ X X#if defined(BSD4_2) || defined(LOCKF) X#ifdef LOCKF X#include <unistd.h> X#else /* !LOCKF */ X#include <sys/file.h> X#endif /* !LOCKF */ Xstatic int LockFd = -1; Xlock() X{ X LockFd = open(SUBFILE, 2); X if (LockFd < 0) X logerr("Can't open(\"%s\",2) to lock", SUBFILE); X /* This will sleep until the other program releases the lock */ X /* We may need to alarm out of this, but I don't think so */ X#ifdef LOCKF X if (lockf(LockFd, F_LOCK, 0) < 0) X#else X if (flock(LockFd, LOCK_EX) < 0) X#endif X xerror("Can't get lock on %s: %s", SUBFILE, errmsg(errno)); X} X Xunlock() X{ X (void) close(LockFd); X} X#else /* !BSD4_2 */ Xlock() X{ X register int i; X extern int errno; X X if (lockcount++ == 0) { X i = DEADTIME; X while (link(SUBFILE, LOCKFILE)) { X if (errno != EEXIST) X break; X if (--i < 0) X xerror("News system locked up"); X sleep((unsigned)1); X } X } X} X Xunlock() X{ X if (--lockcount == 0) X (void) unlink(LOCKFILE); X} X#endif /* !BSD4_2 */ X#endif /* !VMS */ X X/* VARARGS1 */ Xerror(message, arg1, arg2, arg3) Xchar *message; Xlong arg1, arg2, arg3; X{ X char buffer[LBUFLEN]; X X fflush(stdout); X (void) sprintf(buffer, message, arg1, arg2, arg3); X logerr(buffer); X xxit(mode == PROC ? 0 : 1); X} END_OF_FILE if test 32337 -ne `wc -c <'ifuncs.c'`; then echo shar: \"'ifuncs.c'\" unpacked with wrong size! fi # end of 'ifuncs.c' fi if test -f 'expire.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'expire.c'\" else echo shar: Extracting \"'expire.c'\" \(28180 characters\) sed "s/^X//" >'expire.c' <<'END_OF_FILE' X/* X * This software is Copyright (c) 1986 by Rick Adams. X * X * Permission is hereby granted to copy, reproduce, redistribute or X * otherwise use this software as long as: there is no monetary X * profit gained specifically from the use or reproduction or this X * software, it is not sold, rented, traded or otherwise marketed, and X * this copyright notice is included prominently in any copy X * made. X * X * The author make no claims as to the fitness or correctness of X * this software for any use whatsoever, and it is provided as is. X * Any use of this software is at the user's own risk. X * X * expire - expire daemon runs around and nails all articles that X * have expired. X */ X X#ifdef SCCSID Xstatic char *SccsId = "@(#)expire.c 2.53 4/6/87"; X#endif /* SCCSID */ X X#include "params.h" X#include <errno.h> X#if defined(BSD4_2) || defined(BSD4_1C) X# include <sys/dir.h> X# include <sys/file.h> X#else X# include "ndir.h" X#endif X X#ifdef LOCKF X#include <unistd.h> X#endif /* LOCKF */ X Xchar *Progname = "expire"; /* used by xerror to identify failing program */ X X/* Number of array entries to allocate at a time. */ X#define SPACE_INCREMENT 1000 X Xstruct expdata { X char *e_name; X long e_min, e_max; X time_t e_droptime, e_expiretime; X char e_ignorexp; X char e_doarchive; X char e_doexpire; X}; X Xextern int errno; Xchar NARTFILE[BUFLEN], OARTFILE[BUFLEN]; Xchar PAGFILE[BUFLEN], DIRFILE[BUFLEN]; Xchar NACTIVE[BUFLEN], OACTIVE[BUFLEN]; Xchar recdate[BUFLEN]; Xlong rectime, exptime; Xextern char *OLDNEWS; Xint verbose = 0; /* output trace information */ Xint ignorexp = 0; /* ignore Expire: lines */ Xint doarchive = 0; /* archive articles in SPOOL/oldnews */ Xint nohistory = 0; /* ignore history file */ Xint dorebuild = 0; /* rebuild history file */ Xint dorbldhistory = 0; /* rebuild history.d directory */ Xint usepost = 0; /* use posting date to expire */ Xint frflag = 0; /* expire specific user */ Xint doupdateactive = 0; /* update ACTIVE file */ Xchar baduser[BUFLEN]; Xextern char filename[], nbuf[]; X Xstruct timeb Now; X X/* X * This code uses realloc to get more of the multhist array. X */ Xstruct multhist { X char *mh_ident; X char *mh_file; X} *multhist; Xunsigned int mh_size; Xchar *calloc(); Xchar *realloc(); Xstruct tm *gmtime(); X X#ifdef DBM Xtypedef struct { X char *dptr; X int dsize; X} datum; X#else XFILE *nexthistfile(); X#endif /* !DBM */ X Xlong expincr; Xlong dropincr; Xlong atol(); Xtime_t cgtdate(), time(); XFILE *popen(); Xstruct passwd *pw; Xstruct group *gp; Xchar arpat[LBUFLEN]; Xint arpatlen = 0; Xchar ngpat[LBUFLEN]; Xint ngpatlen = 0; Xchar afline[BUFLEN]; Xchar grpsleft[BUFLEN]; Xstruct hbuf h; Xint ExpireLock; Xint rmlock(); Xtime_t today; X Xmain(argc, argv) Xint argc; Xchar **argv; X{ X pathinit(); X (void) umask(N_UMASK); X username = NEWSUSR; X X /* X * Try to run as NEWSUSR/NEWSGRP X */ X if ((pw = getpwnam(NEWSUSR)) == NULL) X xerror("Cannot get NEWSUSR pw entry"); X X uid = pw->pw_uid; X if ((gp = getgrnam(NEWSGRP)) == NULL) X xerror("Cannot get NEWSGRP gr entry"); X gid = gp->gr_gid; X (void) setgid(gid); X (void) setuid(uid); X X if (signal(SIGHUP, SIG_IGN) != SIG_IGN) X signal(SIGHUP, rmlock); X if (signal(SIGINT, SIG_IGN) != SIG_IGN) X signal(SIGINT, rmlock); X expincr = DFLTEXP; X dropincr = HISTEXP; X ngpat[0] = ','; X arpat[0] = ','; X while (argc > 1) { X switch (argv[1][1]) { X case 'v': X if (isdigit(argv[1][2])) X verbose = argv[1][2] - '0'; X else if (argc > 2 && argv[2][0] != '-') { X X argv++; X argc--; X verbose = atoi(argv[1]); X } else X verbose = 1; X if (verbose < 3) X setbuf(stdout, (char *)NULL); X break; X case 'e': /* Use this as default expiration time */ X if (argc > 2 && argv[2][0] != '-') { X argv++; X argc--; X expincr = atol(argv[1]) * DAYS; X } else if (isdigit(argv[1][2])) X expincr = atol(&argv[1][2]) * DAYS; X break; X case 'E': /* Use this as default forget time */ X if (argc > 2 && argv[2][0] != '-') { X argv++; X argc--; X dropincr = atol(argv[1]) * DAYS; X } else if (isdigit(argv[1][2])) X dropincr = atol(&argv[1][2]) * DAYS; X break; X case 'I': /* Ignore any existing expiration date */ X ignorexp = 2; X break; X case 'i': /* Ignore any existing expiration date */ X ignorexp = 1; X break; X case 'n': X if (argc > 2) { X argv++; X argc--; X while (argc > 1 && argv[1][0] != '-') { X int argvlen; X argvlen = strlen(argv[1]); X if (ngpatlen + argvlen + 2 > sizeof (ngpat)) { X xerror("Too many groups specified for -n\n"); X } X if (ngpat[ngpatlen] == '\0') { X ngpat[ngpatlen++] = ','; X ngpat[ngpatlen] = '\0'; X } X strcpy(&ngpat[ngpatlen], argv[1]); X ngpatlen += argvlen; X argv++; X argc--; X } X argv--; X argc++; X } X break; X case 'a': /* archive expired articles */ X if (access(OLDNEWS,0) < 0){ X perror(OLDNEWS); X xerror("No archiving possible\n"); X } X doarchive++; X if (argc > 2) { X argv++; X argc--; X while (argc > 1 && argv[1][0] != '-') { X int argvlen; X argvlen = strlen(argv[1]); X if (arpatlen + argvlen + 2 > sizeof (arpat)) { X xerror("Too many groups specified for -a\n"); X } X if (arpat[arpatlen] == '\0') { X arpat[arpatlen++] = ','; X arpat[arpatlen] = '\0'; X } X strcpy(&arpat[arpatlen], argv[1]); X arpatlen += argvlen; X argv++; X argc--; X } X argv--; X argc++; X } X break; X case 'h': /* ignore history */ X nohistory++; X break; X case 'r': /* rebuild history file */ X dorebuild++; X nohistory++; X break; X case 'R': /* just rebuild the dbm files */ X#ifdef DBM X rebuilddbm(); X xxit(0); X#else /* !DBM */ X fprintf(stderr, "You have not compiled expire with DBM, so -R is meaningless\n"); X xxit(1); X#endif /* !DBM */ X X case 'p': /* use posting date to expire */ X usepost++; X break; X case 'f': /* expire messages from baduser */ X frflag++; X if (argc > 2) { X strcpy(baduser, argv[2]); X argv++; X argc--; X } X break; X case 'u': /* update the active file from 2.10.1 fmt */ X doupdateactive++; X break; X case 'H': /* convert to history.d format */ X dorbldhistory++; X break; X default: X printf("Usage: expire [ -v [level] ] [-e days ] [-i] [-a] [-r] [-h] [-p] [-u] [-f username] [-n newsgroups] [-H]\n"); X xxit(1); X } X argc--; X argv++; X } X if (dorbldhistory) { X#ifndef DBM X rebuildhistorydir(); X#endif /* !DBM */ X exit(0); X } X if (dropincr < expincr) { X dropincr = HISTEXP; X fprintf(stderr, "History expiration time < article expiration time. Default used.\n"); X } X if (ngpat[0] == ',') X (void) strcpy(ngpat, "all,"); X if (arpat[0] == ',') X (void) strcpy(arpat, "all,"); X (void) ftime(&Now); X today = Now.time; X if (chdir(SPOOL)) X xerror("Cannot chdir %s", SPOOL); X X if (verbose) { X printf("expire: nohistory %d, rebuild %d, doarchive %d\n", X nohistory, dorebuild, doarchive); X printf("newsgroups: %s\n",ngpat); X if (doarchive) X printf("archiving: %s\n",arpat); X } X X#ifdef DBM X (void) sprintf(OARTFILE, "%s/%s", LIB, "ohistory"); X#endif /* DBM */ X (void) sprintf(NARTFILE, "%s/%s", LIB, "nhistory"); X X (void) sprintf(OACTIVE, "%s/%s", LIB, "oactive"); X (void) sprintf(NACTIVE, "%s/%s", LIB, "nactive"); X X if (!doupdateactive) { X expire(); X#ifndef DBM X rebuildhistorydir(); X#endif X } X X updateactive(); X rmlock(); X X /* X * Now read in any saved news. X */ X#ifdef PROFILING X monitor((int(*)())0,(int(*)())0,0,0,0); X#endif /* PROFILING */ X#ifdef IHCC X /*afline happens to be available - (we're getting out anyway)*/ X sprintf(afline, "%s/%s", logdir(HOME), RNEWS); X execl(afline, "rnews", "-U", (char *)NULL); X#else /* ! IHCC */ X execl(RNEWS, "rnews", "-U", (char *)NULL); X#endif /* ! IHCC */ X perror(RNEWS); X xxit(1); X /* NOTREACHED */ X} X Xexpire() X{ X register char *p1, *p2, *p3; X register time_t newtime; X register FILE *fp = NULL; X FILE *ohfd, *nhfd; X int i; X char fn[BUFLEN]; X DIR *ngdirp = NULL; X static struct direct *ngdir; X X#ifdef DBM X if (!dorebuild) { X (void) sprintf(PAGFILE, "%s/%s", LIB, "nhistory.pag"); X (void) sprintf(DIRFILE, "%s/%s", LIB, "nhistory.dir"); X (void) close(creat(PAGFILE, 0666)); X (void) close(creat(DIRFILE, 0666)); X initdbm(NARTFILE); X } X#endif X X if (nohistory) { X ohfd = xfopen(ACTIVE, "r"); X if (dorebuild) { X /* Allocate initial space for multiple newsgroup (for X an article) array */ X multhist = (struct multhist *)calloc (SPACE_INCREMENT, X sizeof (struct multhist)); X mh_size = SPACE_INCREMENT; X X (void) sprintf(afline, "exec sort -t\t +1.6 -2 +1 >%s", NARTFILE); X printf("%s\n",afline); X if ((nhfd = popen(afline, "w")) == NULL) X xerror("Cannot exec %s", afline); X } else X nhfd = xfopen("/dev/null", "w"); X } else { X#ifdef DBM X ohfd = xfopen(ARTFILE, "r"); X#else X ohfd = nexthistfile((FILE *)NULL); X#endif /* DBM */ X nhfd = xfopen(NARTFILE, "w"); X } X X dolock(); X X for(i=0;i<NUNREC;i++) X h.unrec[i] = NULL; X X while (TRUE) { X fp = NULL; X if (nohistory) { X recdate[0] = '\0'; X do { X if (ngdir == NULL) { X if ( ngdirp != NULL ) X closedir(ngdirp); X if (fgets(afline, BUFLEN, ohfd) == NULL) X goto out; X (void) strcpy(nbuf, afline); X p1 = index(nbuf, ' '); X if (p1 == NULL) X p1 = index(nbuf, '\n'); X if (p1 != NULL) X *p1 = NULL; X if (!ngmatch(nbuf, ngpat)) X continue; X X /* Change a group name from X a.b.c to a/b/c */ X for (p1=nbuf; *p1; p1++) X if (*p1 == '.') X *p1 = '/'; X X if ((ngdirp = opendir(nbuf)) == NULL) X continue; X X } X ngdir = readdir(ngdirp); X /* Continue looking if not an article. */ X } while (ngdir == NULL || !islegal(fn,nbuf,ngdir->d_name)); X X p2 = fn; X if (verbose > 2) X printf("article: %s\n", fn); X strcpy(filename, dirname(fn)); X fp = access(filename, 04) ? NULL : art_open(filename, "r"); X } else { X char dc; X#ifdef DBM X if (fgets(afline, BUFLEN, ohfd) == NULL) X break; X#else X if (fgets(afline, BUFLEN, ohfd) == NULL) X if (!(ohfd = nexthistfile(ohfd))) X break; X else X continue; X#endif /* DBM */ X if (verbose > 2) X printf("article: %s", afline); X p1 = index(afline, '\t'); X if (!p1) X continue; X *p1 = '\0'; X (void) strcpy(h.ident, afline); X *p1 = '\t'; X p2 = index(p1 + 1, '\t'); X if (!p2) X continue; X *p2 = '\0'; X (void) strcpy(recdate, p1+1); X rectime = cgtdate(recdate); X *p2++ = '\t'; X (void) strcpy(nbuf, p2); X p3 = index(nbuf, '/'); X if (p3) { X register char *p4; X X p4 = index(p3, '\n'); X if (p4) { X while (p4[-1] == ' ') X p4--; X *p4 = '\0'; X } X X /* X * convert list of newsgroups from X * ng1/num ng2/num ... X * to X * ng1,ng2,... X */ X p4 = p3; X do { X *p3++ = NGDELIM; X while (*p4 != '\0' && *p4 != ' ') X p4++; X if (*p4++ == '\0') { X *--p3 = '\0'; X break; X } X while (*p3 = *p4++) { X if (*p3 == '/') X break; X else X p3++; X } X } while (*p3); X } else { X /* X * Nothing after the 2nd tab. This happens X * when there is no message left in the spool X * directory, only the memory of it in the X * history file. (That is, it got cancelled X * or expired.) Use date in the history file X * to decide if we should keep the memory. X */ X grpsleft[0] = '\0'; X goto checkdate; X } X if (!ngmatch(nbuf, ngpat) || X ((rectime+expincr > today) && !dorebuild && X !frflag && !usepost && recdate[0] != ' ')) X goto keephist; X if (!dorebuild && !frflag && !usepost && X recdate[0] != ' ') { X grpsleft[0] = '\0'; X goto nailit; /* just expire it */ X } X X /* X * Look for the file--possibly several times, X * if it was posted to several news groups. X */ X dc = ' '; X p3 = p2; X while (dc != '\n') { X p1 = index(p3, ' '); X if (p1) { X dc = ' '; X *p1 = '\0'; X } else { X p1 = index(p3, '\n'); X if (p1 && p1 > p3) { X dc = '\n'; X *p1 = '\0'; X } else { X fp = NULL; X break; X } X } X strcpy(filename, dirname(p3)); X if (access(filename, 4) == 0 && X ((fp=art_open(filename, "r")) != NULL)) X break; X p3 = p1 + 1; X } X if (p1) X *p1 = dc; X } X X if (fp == NULL) { X /* X * this probably means that the article has been X * cancelled. Lets assume that, and make an X * entry in the history file to that effect. X */ X if (verbose) X perror(filename); X strcpy(p2, "cancelled\n"); X grpsleft[0] = '\0'; X goto checkdate; X } X for(i=0; i<NUNREC; i++) X if (h.unrec[i] != NULL) { X free(h.unrec[i]); X h.unrec[i] = NULL; X } else X break; X if (!hread(&h, fp, TRUE)) { X printf("Garbled article %s.\n", filename); X (void) fclose(fp); X /* X * Usually means disk ran out of space. X * Drop this article from our history file X * completely, so we have a chance of picking X * it up again from another feed .. X */ X goto nailit; X } X if (nohistory) { X if (recdate[0] == '\0') { X struct stat statb; X if (fstat(fileno(fp), &statb) < 0) X rectime = cgtdate(h.subdate); X else X rectime = statb.st_mtime; X } else X rectime = cgtdate(recdate); X } X if (dorebuild) { X register char *cp, *lastslash; X register struct multhist *mhp; X X /* X * Format of filename until now was /SPOOL/a/b/c/4 X * and this code changes it to a.b.c/4 (the correct X * kind of entry in the history file.) X * X * This cannot be a strcpy because the addresses X * overlap and some machines cannot handle that. X */ X p1 = filename; X cp = p1 + strlen(SPOOL); X while (*++cp) { X if (*cp == '/') { X lastslash = p1; X *p1++ = '.'; X } else X *p1++ = *cp; X } X *p1 = '\0'; X *lastslash = '/'; X X if ((cp = index(h.nbuf, NGDELIM)) == NULL) { X struct tm *tm; Xsaveit: X tm = gmtime(&rectime); X if (fprintf(nhfd, X#ifdef USG X "%s\t%s%2.2d/%2.2d/%d %2.2d:%2.2d\t%s\n", X#else /* !USG */ X "%s\t%s%02d/%02d/%d %02d:%02d\t%s\n", X#endif /* !USG */ X h.ident, h.expdate[0] ? " " : "", X tm->tm_mon+1, tm->tm_mday, tm->tm_year, X tm->tm_hour, tm->tm_min, filename) X == EOF) X xerror("History write failed"); X (void) fclose(fp); X continue; X } X for (mhp = multhist; mhp < multhist+mh_size && mhp->mh_ident != NULL; mhp++) { X if (mhp->mh_file == NULL) X continue; X if (strcmp(mhp->mh_ident, h.ident)) X continue; X (void) strcat(filename, " "); X (void) strcat(filename, mhp->mh_file); X free(mhp->mh_file); X mhp->mh_file = NULL; X /* X * if we have all the links, write to hist now X */ X if (chrcnt(filename, ' ') == chrcnt(cp,NGDELIM)) X goto saveit; X break; X } X X /* X * Here is where we realloc the multhist space rather X * than the old way of static allocation. It is X * really trivial. We just clear out the space X * in case it was reused. The old static array was X * guaranteed to be cleared since it was cleared when X * the process started. X */ X if (mhp >= multhist + mh_size) { X multhist = (struct multhist *) X realloc ((char *)multhist, X sizeof (struct multhist) * X (SPACE_INCREMENT + mh_size)); X if (multhist == NULL) X xerror("Too many articles with multiple newsgroups"); X for (mhp = multhist + mh_size; X mhp < multhist+mh_size+SPACE_INCREMENT; X mhp++) { X mhp->mh_ident = NULL; X mhp->mh_file = NULL; X } X mhp = multhist + mh_size; X mh_size += SPACE_INCREMENT; X } X X if (mhp->mh_ident == NULL) { X mhp->mh_ident = malloc(strlen(h.ident)+1); X (void) strcpy(mhp->mh_ident, h.ident); X } X cp = malloc(strlen(filename) + 1); X if (cp == NULL) X xerror("Out of memory"); X (void) strcpy(cp, filename); X mhp->mh_file = cp; X (void) fclose(fp); X continue; X } X X (void) fclose(fp); X X if (h.expdate[0]) { X Now.time = rectime; X exptime = cgtdate(h.expdate); X } X newtime = (usepost ? cgtdate(h.subdate) : rectime) + expincr; X if (!h.expdate[0] || ignorexp == 2 || X (ignorexp == 1 && newtime < exptime)) X exptime = newtime; X if (frflag ? strcmp(baduser,h.from)==0 : today >= exptime) { Xnailit: X#ifdef DEBUG X printf("cancel %s\n", filename); X#else /* !DEBUG */ X printf("cancel %s\n", filename); X if (verbose) X printf("cancel %s\n", h.ident); X ulall(p2, &h); X (void) sprintf(p2, "%s\n", grpsleft); X if (verbose > 2 && grpsleft[0]) X printf("Some good in %s\n", h.ident); X#endif /* !DEBUG */ X } else { X if (verbose > 2) X printf("Good article %s\n", h.ident); X grpsleft[0] = '!'; X } X Xcheckdate: X if (grpsleft[0] == '\0' && today >= rectime + dropincr) { X if (verbose > 3) X printf("Drop history of %s - %s\n", X h.ident, recdate); X } else { X#ifdef DBM X long hpos; X#endif /* DBM */ Xkeephist: X#ifdef DBM X hpos = ftell(nhfd); X#endif /* DBM */ X X if (verbose > 3) X printf("Retain history of %s - %s\n", X h.ident, recdate); X if (fputs(afline, nhfd) == EOF) X xerror("history write failed"); X#ifdef DBM X if (!dorebuild) X remember(h.ident, hpos); X#endif /* DBM */ X } X } Xout: X if (dorebuild) { X register struct multhist *mhp; X struct tm *tm; X for (mhp = multhist; mhp < multhist+mh_size && mhp->mh_ident != NULL; mhp++) X if (mhp->mh_file != NULL) { X if (verbose) X printf("Article: %s [%s] Cannot find all links\n", mhp->mh_ident, mhp->mh_file); X (void) sprintf(filename,"%s/%s",SPOOL,mhp->mh_file); X for (p1 = filename; *p1 != ' ' && *p1 != '\0'; p1++) X if (*p1 == '.') X *p1 = '/'; X *p1 = '\0'; X if ((fp = art_open(filename, "r")) == NULL) { X if (verbose) X printf("Can't open %s.\n", filename); X continue; X } X if (!hread(&h, fp, TRUE)) { X printf("Garbled article %s.\n", filename); X (void) fclose(fp); X continue; X } else { X struct stat statb; X if (fstat(fileno(fp), &statb) < 0) X rectime = cgtdate(h.subdate); X else X rectime = statb.st_mtime; X } X tm = gmtime(&rectime); X if ( fprintf(nhfd, X#ifdef USG X "%s\t%s%2.2d/%2.2d/%d %2.2d:%2.2d\t%s\n", X#else /* !USG */ X "%s\t%s%02d/%02d/%d %02d:%02d\t%s\n", X#endif /* !USG */ X h.ident, h.expdate[0] ? " " : "", X tm->tm_mon+1, tm->tm_mday, tm->tm_year, X tm->tm_hour, tm->tm_min, mhp->mh_file) X == EOF ) X xerror("History write failed"); X (void) fclose(fp); X continue; X } X (void) pclose(nhfd); X free ((char *)multhist); X } else X if (fclose(nhfd)) X xerror("History write failed, %s", errmsg(errno)); X X if (dorebuild || !nohistory) { X#ifndef DBM X (void) rename(ARTFILE, OARTFILE); X#endif /* !DBM */ X (void) rename(NARTFILE, ARTFILE); X#ifdef DBM X if (dorebuild) X rebuilddbm( ); X else { X char tempname[BUFLEN]; X (void) sprintf(tempname,"%s.pag", ARTFILE); X (void) strcat(NARTFILE, ".pag"); X (void) rename(NARTFILE, tempname); X (void) sprintf(tempname,"%s.dir", ARTFILE); X (void) strcpy(rindex(NARTFILE, '.'), ".dir"); X (void) rename(NARTFILE, tempname); X } X#endif X } X} X X#if defined(BSD4_2) || defined(LOCKF) Xstatic int LockFd = -1; X#endif X Xdolock() X{ X /* set up exclusive locking so inews does not run while expire does */ X#if defined(BSD4_2) || defined(LOCKF) X LockFd = open(ACTIVE, 2); X# ifdef LOCKF X if (lockf(LockFd, F_LOCK, 0) < 0) X# else /* BSD4_2 */ X if (flock(LockFd, LOCK_EX) < 0) X# endif /* BSD4_2 */ X xerror("Can't get lock for expire: %s", errmsg(errno)); X#else /* !BSD4_2 && !LOCKF */ X int i = 0; X sprintf(afline,"%s.lock", ACTIVE); X while (LINK(ACTIVE, afline) < 0 && errno == EEXIST) { X if (i++ > 5) X xerror("Can't get lock for expire"); X sleep(i*2); X } X#endif /* !BSD4_2 && !LOCKF */ X} X Xrmlock() X{ X#if defined(BSD4_2) || defined(LOCKF) X close(LockFd); X#else X sprintf(bfr, "%s.lock", ACTIVE); X (void) UNLINK(bfr); X#endif /* !BSD4_2 */ X} X Xupdateactive() X{ X register char *p1; X FILE *ohfd, *nhfd; X DIR *ngdirp = NULL; X static struct direct *ngdir; X X if (verbose) X printf("updating active file %s\n", ACTIVE); X ohfd = xfopen(ACTIVE, "r"); X nhfd = xfopen(NACTIVE, "w"); X do { X long n; X long maxart, minart; X char cansub; X int gdsize, hassubs; X struct stat stbuf; X X if (fgets(afline, BUFLEN, ohfd) == NULL) X continue; X if (sscanf(afline,"%s %ld %ld %*c%c",nbuf,&maxart, &minart, X &cansub) < 4) X xerror("Active file corrupt"); X if (verbose > 3) X printf("looking at group %s\n", nbuf); X if (!ngmatch(nbuf, ngpat)) { X if (fputs(afline, nhfd) == EOF) X xerror("active file write failed"); X continue; X } X minart = 99999L; X /* Change a group name from a.b.c to a/b/c */ X for (p1=nbuf; *p1; p1++) X if (*p1 == '.') X *p1 = '/'; X X hassubs = stat(nbuf, &stbuf) != 0 || stbuf.st_nlink != 2; X gdsize = strlen(nbuf); X if ((ngdirp = opendir(nbuf)) != NULL) { X while (ngdir = readdir(ngdirp)) { X nbuf[gdsize] = '/'; X (void) strcpy(&nbuf[gdsize+1], ngdir->d_name); X /* We have to do a stat because of micro.6809 */ X if (hassubs && (stat(nbuf, &stbuf) < 0 || X !(stbuf.st_mode&S_IFREG)) ) X continue; X n = atol(ngdir->d_name); X if (n > 0 && n < minart) X minart = n; X if (n > 0 && n > maxart) X maxart = n; X } X closedir(ngdirp); X } X afline[gdsize] = '\0'; X if (minart > maxart) X minart = maxart; X#ifdef USG X if (verbose > 4) X printf("\tmaxart = %5.5ld, minart = %5.5ld\n", X maxart, minart); X if (fprintf(nhfd,"%s %5.5ld %5.5ld %c\n", afline, maxart, X minart, cansub) == EOF) X xerror("Active file write failed"); X#else X if (verbose > 4) X printf("\tmaxart = %05ld, minart = %05ld\n", X maxart, minart); X if (fprintf(nhfd,"%s %05ld %05ld %c\n", afline, maxart, X minart, cansub) == EOF) X xerror("Active file write failed"); X#endif /* !USG */ X } while (!feof(ohfd)); X if (fclose(nhfd)) X xerror("Active file write failed, %s", errmsg(errno)); X (void) fclose(ohfd); /* this might unlock inews as a side effect */ X X (void) rename(ACTIVE, OACTIVE); X (void) rename(NACTIVE, ACTIVE); X} X X/* Unlink (using unwound tail recursion) all the articles in 'artlist'. */ Xulall(artlist, hp) Xchar *artlist; Xstruct hbuf *hp; X{ X register char *p, *q; X int last = 0; X char newname[BUFLEN]; X time_t timep[2]; X char *fn; X X grpsleft[0] = '\0'; X do { X if (verbose > 2) X printf("ulall '%s', '%s'\n", artlist, hp->subdate); X if (nohistory) { X last = 1; X } else { X while (*artlist == ' ' || *artlist == '\n' || *artlist == ',') X artlist++; X if (*artlist == '\0') X return; X p = index(artlist, ' '); X if (p == NULL) { X last = 1; X p = index(artlist, '\n'); X } X if (p == NULL) { X last = 1; X fn = dirname(artlist); X if (UNLINK(fn) < 0 && errno != ENOENT) X perror(fn); X return; X } X if (p) X *p = 0; X } X strcpy(newname, artlist); X q = index(newname,'/'); X if (q) { X *q++ = NGDELIM; X *q = '\0'; X } else { X q = index(newname, '\0'); X if (q == artlist) /* null -> the end */ X return; X /* should be impossible to get here */ X } X fn = dirname(artlist); X if (ngmatch(newname, ngpat)) { X if (doarchive){ X if (ngmatch(newname, arpat)) { X q = fn + strlen(SPOOL) + 1; X (void) sprintf(newname, "%s/%s", OLDNEWS, q); X if (verbose) X printf("link %s to %s\n", fn, newname); X if (LINK(fn, newname) == -1) { X if (mkparents(newname) == 0) X if (LINK(fn, newname) == -1) X fcopy(fn, newname); X } X timep[0] = timep[1] = cgtdate(hp->subdate); X (void) utime(newname, timep); X } X } X if (verbose) X printf("unlink %s\n", fn); X if (UNLINK(fn) < 0 && errno != ENOENT) X perror(fn); X } else { X if (verbose > 3) X printf("retain %s (%s)\n", hp->ident, fn); X strcat(grpsleft, artlist); X strcat(grpsleft, " "); X } X artlist = p + 1; X } while (!last); X} X Xfcopy(fn, newname) Xchar *fn, *newname; X{ X int f1, f2; X int r; X char buf[BUFSIZ]; X f1 = open(fn, 0); X if (f1 < 0) X return -1; X f2 = open(newname, 1); X if (f2 < 0) { X if (errno == ENOENT) { X f2 = creat(newname,0644); X if (f2 < 0) { X close(f1); X return -1; X } X } else { X close(f1); X return -1; X } X } X while((r=read(f1, buf, BUFSIZ)) > 0) X write(f2, buf, r); X (void) close(f1); X (void) close(f2); X return 0; X} X X/* X * Count instances of c in s X */ Xchrcnt(s, c) Xregister char *s; Xregister c; X{ X register n = 0; X register cc; X X while (cc = *s++) X if (cc == c) X n++; X return n; X} X X/* X * If any parent directories of this dir don't exist, create them. X */ Xmkparents(fullname) Xchar *fullname; X{ X char buf[200]; X register char *p; X int rc; X X (void) strcpy(buf, fullname); X p = rindex(buf, '/'); X if (p) X *p = '\0'; X if (access(buf, 0) == 0) X return 0; X mkparents(buf); X if ((rc = mkdir(buf, 0755)) < 0) X perror("mkdir failed"); X if (verbose) X printf("mkdir %s, rc %d\n", buf, rc); X X return rc; X} X X/* Make sure this file is a legal article. */ Xislegal(fullname, path, name) Xregister char *fullname; Xregister char *path; Xregister char *name; X{ X struct stat buffer; X X (void) sprintf(fullname, "%s/%s", path, name); X X /* make sure the article is numeric. */ X while (*name != '\0') X if (!isascii(*name) || !isdigit(*name)) X return 0; X else X name++; X X /* Now make sure we don't have a group like net.micro.432, X * which is numeric but not a regular file -- i.e., check X * for being a regular file. X */ X if ((stat(fullname, &buffer) == 0) && X ((buffer.st_mode & S_IFMT) == S_IFREG)) { X /* Now that we found a legal group in a/b/c/4 X notation, switch it to a.b.c/4 notation. */ X for (name = fullname; name != NULL && *name != '\0'; name++) X if (*name == '/' && name != rindex (name, '/')) X *name = '.'; X X return 1; X } X return 0; X} X X#ifdef DBM X/* X * This is taken mostly intact from ../cvt/cvt.hist.c and is used at the X * end by the options that make a new history file. X * Routine to convert history file to dbm file. The old 3 field X * history file is still kept there, because we need it for expire X * and for a human readable copy. But we keep a dbm hashed copy X * around by message ID so we can answer the yes/no question "have X * we already seen this message". The content is the ftell offset X * into the real history file when we get the article - you can't X * really do much with this because the file gets compacted. X */ X XFILE *fd; X Xchar namebuf[BUFSIZ]; Xchar lb[BUFSIZ]; X Xrebuilddbm() X{ X register char *p; X long fpos; X X (void) sprintf(namebuf, "%s.dir", ARTFILE); X (void) close(creat(namebuf, 0666)); X (void) sprintf(namebuf, "%s.pag", ARTFILE); X (void) close(creat(namebuf, 0666)); X (void) sprintf(namebuf, "%s", ARTFILE); X X fd = fopen(namebuf, "r"); X if (fd == NULL) { X perror(namebuf); X xxit(2); X } X X initdbm(namebuf); X while (fpos=ftell(fd), fgets(lb, BUFSIZ, fd) != NULL) { X p = index(lb, '\t'); X if (p) X *p = 0; X remember(lb, fpos); X } X} X Xremember(article, fileoff) Xregister char *article; Xlong fileoff; X{ X datum lhs, rhs; X X lcase(article); X lhs.dptr = article; X lhs.dsize = strlen(article) + 1; X rhs.dptr = (char *) &fileoff; X rhs.dsize = sizeof fileoff; X X if (verbose > 5) X printf("remember: %s @ %ld\n", article, fileoff); X if (store(lhs, rhs) < 0) X xerror("dbm store failed"); X} X#else X/* X * Open the next history subdirectory file X */ X XFILE *nexthistfile(ofp) XFILE *ofp; X{ X static int histfilecounter = -1; X X if (ofp) X fclose(ofp); X do { X if (++histfilecounter > 9) X return NULL; X sprintf(bfr, "%s.d/%d", ARTFILE, histfilecounter); X if (verbose > 3) X printf("reading history file %s\n", bfr); X ofp = xfopen(bfr, "r"); X } while (ofp == NULL); X return ofp; X} X X/* X * Rebuild the history subdirectory from LIBDIR/history X */ Xrebuildhistorydir() X{ X char fn[BUFLEN], ofn[BUFLEN]; X register int i; X FILE *subfd[10], *ohfd; X X /* rebuild history subfiles */ X (void) sprintf(fn, "%s.od", ARTFILE); X if (access(fn,0) != 0) X (void) mkdir(fn, 0755); X (void) sprintf(fn, "%s.d", ARTFILE); X if (verbose) X printf("Rebuilding history subfile directory %s.\n", fn); X if (access(fn,0) != 0) X (void) mkdir(fn, 0755); X for (i = 0; i < 10; i++) { X (void) sprintf(fn, "%s.d/%c", ARTFILE, i + '0'); X (void) sprintf(ofn, "%s.od/%c", ARTFILE, i + '0'); X (void) rename(fn, ofn); X close(creat(fn, 0644)); X subfd[i] = xfopen(fn, "w+"); X } X ohfd = xfopen(ARTFILE, "r"); X while (fgets(fn, BUFLEN, ohfd) != NULL) { X i = findhfdigit(fn) - '0'; X fputs(fn, subfd[i]); X } X (void) fclose(ohfd); X for (i = 0; i < 10; i++) X if (ferror(subfd[i]) || fclose(subfd[i])) X xerror("History subfile write"); X (void) UNLINK(ARTFILE); X} X#endif /* !DBM */ X Xxxit(i) X{ X rmlock(); X exit(i); X} END_OF_FILE if test 28180 -ne `wc -c <'expire.c'`; then echo shar: \"'expire.c'\" unpacked with wrong size! fi # end of 'expire.c' fi echo shar: End of shell archive. exit 0 -- "Zeta Microcomputer Software" ACSnet: nick@ultima.cs.uts.oz UUCP: ...!uunet!munnari!ultima.cs.uts.oz!nick Fidonet: Nick Andrew on 3:713/602 (Zeta)
nick@ultima.cs.uts.oz (Nick Andrew) (12/07/89)
#! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of shell archive." # Contents: postnews.c getdate.s.uu # Wrapped by nick@nswitgould on Thu Dec 7 22:40:11 1989 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'postnews.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'postnews.c'\" else echo shar: Extracting \"'postnews.c'\" \(26497 characters\) sed "s/^X//" >'postnews.c' <<'END_OF_FILE' X/* X * This software is Copyright (c) 1986 by Rick Adams. X * X * Permission is hereby granted to copy, reproduce, redistribute or X * otherwise use this software as long as: there is no monetary X * profit gained specifically from the use or reproduction or this X * software, it is not sold, rented, traded or otherwise marketed, and X * this copyright notice is included prominently in any copy X * made. X * X * The author make no claims as to the fitness or correctness of X * this software for any use whatsoever, and it is provided as is. X * Any use of this software is at the user's own risk. X * X * Postnews: post a news message to Usenet. This C version replaces a shell X * script, and does more intelligent prompting and filtering than possible X * in a shell script. X */ X#ifdef SCCSID Xstatic char *SccsId = "@(#)postnews.c 1.31 3/21/87"; X#endif /* SCCSID */ X X#include "params.h" X X#define APPEND 1 X#define REPLACE 2 X Xextern char *MAILPARSER; X Xchar tempfname[50]; /* file name used for making article */ Xchar original[BUFLEN]; /* file name of original, used in followup */ Xchar homedir[BUFLEN]; /* HOME environment setting */ Xchar user[SBUFLEN]; /* user name */ Xchar ccname[BUFLEN]; /* file name for article copy */ X X/* article header information */ Xchar subject[BUFLEN]; Xchar distribution[BUFLEN]; Xchar references[BUFLEN]; Xchar newsgroups[BUFLEN]; Xchar isfrom[BUFLEN]; Xchar msgid[BUFLEN]; Xchar keywords[BUFLEN]; Xchar summary[BUFLEN]; X Xchar ngsep[] = { NGDELIM, '\0' }; /* == "," */ X Xchar *Progname = "postnews"; /* for xerror */ X Xtime_t fmodtime; Xchar pobuf[BUFLEN]; X X#define MAXDISTR 16 Xstruct distr { X char abbr[24]; X char descr[128]; X} distr[MAXDISTR]; X Xchar def_distr[24] = ""; /* default distribution */ XFILE *xfopen(); X Xmain(argc, argv) Xchar *argv[]; X{ X register int c; X X init(); X X if (argc == 2) { X if (!prefix(argv[1], SPOOL)) X xerror("Can only followup to articles in %s", SPOOL); X followup(argv[1]); X (void) strcpy(original, argv[1]); X } else X if (askyes("Is this message in response to some other message? ","no")) { X char ng[BUFLEN], num[BUFLEN]; X long i, j, lastnum; X register char *p; X int fd, dir; X char canpost; X X getpr("In what newsgroup was the article posted? ",ng); X if (!valid_ng(ng, &i, &j, &canpost)) X if (canpost == 'i' ) X byebye("There is no such newsgroup."); X else if (canpost == 'n') X byebye("You are not allowed to post to that group."); X X printf("Valid article numbers are from %ld to %ld\n", j, i); X lastnum = i + 1; X dir = -1; X X for(;;) { X getpr("\nWhat was the article number? ", num); X switch(num[0]) { X case '+': X dir = 1; X sprintf(num, "%ld", lastnum + 1); X break; X case '-': X dir = -1; X /* no break */ X case '\0': X sprintf(num, "%ld", lastnum + dir); X break; X } X (void) sprintf(original, "%s/%s", SPOOL, ng); X for (p=original+strlen(SPOOL)+1; *p ;++p) X if (*p == '.') X *p = '/'; X (void) strcat(original, "/"); X (void) strcat(original, num); X X if ((fd=open(original,0)) >= 0) { X (void) close(fd); X printf("\narticle %s\n", original); X if (article_line(original, "From: ", pobuf)) X printf("%s\n", pobuf); X if (article_line(original, "Subject: ", pobuf)) X printf("%s\n", pobuf); X if (askyes("Is this the one you want? ", "n")) X break; X } else X printf("I can't find that article.\n"); X lastnum = atol(num); X } X X followup(original); X } else { X do { X getpr("Subject: ", subject); X if (*subject == '?') { Xprintf("People read the subject line to learn what your article is about.\n"); Xprintf("You want it to do the same job as a newspaper headline.\n"); Xprintf("So type in something both brief and descriptive.\n"); X *subject = '\0'; X } X } while (*subject == '\0'); X getpr("Keywords: ", keywords); X X while (!get_newsgroup()) X ; X get_distribution((char *)0); X } X X if (pre_checks()) X exit(1); X X prep_article(); X c = 'e'; X for (;;) { X if (c == 'e') { X edit_article(); X post_checks(); X } X do { X do { X getpr("\nWhat now? [send, edit, list, quit, write, append] ", pobuf); X c = pobuf[0]; X } while (c == '\0'); X if (isupper(c)) X c = tolower(c); X if (c == 'q') { X (void) UNLINK(tempfname); X exit(1); X } X if (c == 'l') { X char *pager = getenv("PAGER"); X char lbuf[BUFLEN]; X if (pager == NULL || *pager == '\0') { X#ifdef PAGE X# ifdef IHCC X (void) sprintf(lbuf,"%s/bin/%s", logdir(HOME), PAGE); X# else /* !IHCC */ X (void) strcpy(lbuf, PAGE); X# endif /* !IHCC */ X pager = lbuf; X#else /* !PAGE */ X pager = "cat"; X#endif /* !PAGE */ X } X sprintf(pobuf, "exec %s %s", pager, tempfname); X (void) system(pobuf); X } X if (c == 'w' || c == 'a') { X register int ifd, ofd, nbytes; X char iobuf[BUFSIZ]; X char fname[BUFLEN]; X getpr("Filename? ", fname); X if (fname[0] == '\0') X continue; X ofd = (c == 'w') ? creat(fname, 0666) X : open(fname, 2); X if (ofd < 0) X perror(fname); X else { X if (c == 'a') X (void) lseek(ofd, 0L, 2); X ifd = open(tempfname, 0); X if (ifd < 0) X xerror("Can't reopen %s\n", tempfname); X while ((nbytes = read(ifd, iobuf, BUFSIZ)) > 0 ) X write(ofd, iobuf, nbytes); X close(ofd); X close(ifd); X } X } X } while (!index("eps", c)); X if (c != 'e') X post_article(); /* will exit if posted successfully */ X }; X} X X/* X * Find out the topic of interest. X */ Xget_newsgroup() X{ X int n; X long i; X char canpost; X static int first = 1; X X printf("Newsgroups (enter one at a time, end with a blank line):\n"); X if (first) { X printf("\nThe most relevant newsgroup should be the first, you should\n"); X printf("add others only if your article really MUST be read by people\n"); X printf("who choose not to read the appropriate group for your article.\n"); X printf("But DO use multiple newsgroups rather than posting many times.\n\n"); X first = 0; X } X printf("For a list of newsgroups, type ?\n"); X n = 0; X newsgroups[0] = '\0'; X X for(;;) { X getpr("> ", pobuf); X if (pobuf[0] == '\0') X if (n == 0) X return FALSE; X else X return TRUE; X if (pobuf[0] == '?'){ X char *pager = getenv("PAGER"); X char lbuf[BUFLEN]; X if (pager == NULL) { X#ifdef PAGE X# ifdef IHCC X (void) sprintf(lbuf,"%s/bin/%s", logdir(HOME), PAGE); X# else /* !IHCC */ X (void) strcpy(lbuf, PAGE); X# endif /* !IHCC */ X pager = lbuf; X#else /* !PAGE */ X pager = "cat"; X#endif /* !PAGE */ X } X printf("These are the currently active groups:\n"); X (void) fflush(stdout); X sprintf(pobuf, "exec %s %s/newsgroups", pager, LIB); X (void) system(pobuf); X continue; X } X if (valid_ng(pobuf, &i, &i, &canpost)) { X if (n++ != 0) X (void) strcat(newsgroups, ngsep); X (void) strcat(newsgroups, pobuf); X } else { X if (canpost == 'n') X printf("You are not allowed to post to %s\n", X pobuf); X else if (canpost == 'i') X printf("%s is not a valid newsgroup.\n", pobuf); X } X } X} X X/* X * Find out how widely the author wants the message distributed. X */ Xget_distribution(deflt) X char *deflt; X{ X register int i; X register char *r; X char def[BUFLEN]; X char *lastgroup; X X lastgroup = newsgroups; X (void) strcpy(def, newsgroups); X r = index(def, NGDELIM); X if (r) X *r = '\0'; X r = index(def, '.'); X if (r) { X *r = '\0'; X if (strcmp(def, "net") == 0) X (void) strcpy(def, "world"); X } else { X distribution[0] = '\0'; X return; X } X X if (strcmp(def, "to") == 0) { X /* X * This only works if "to.xx" is the first (or only) X * newsgroup, but it usually is .. X * Perhaps we should make the distribution be "to.xxx" ?? X */ X distribution[0] = '\0'; X return; /* He's probably testing something */ X } X if (deflt != (char *)0) X (void) strcpy(def, deflt); X if (ngmatch("misc.test", newsgroups)) X (void) strcpy(def, "local"); X for (i=0; distr[i].abbr[0]; i++) { X if (strcmp(distr[i].abbr, def) == 0) X break; X } X if (distr[i].abbr[0] == '\0') X strcpy(def, def_distr); X for(;;) { X do { X (void) sprintf(pobuf, "Distribution (default='%s', '?' for help) : ", def); X getpr(pobuf, distribution); X if (distribution[0] == '\0') { X if (strcmp(def, "*None*") == 0) X printf("You must enter a distribution, '?' for help.\n"); X (void) strcpy(distribution, def); X } X } while (strcmp(distribution, "*None*") == 0); X X /* Did the user ask for help? */ X if (distribution[0] == '?') { X printf("How widely should your article be distributed?\n\n"); X for (i=0; distr[i].abbr[0]; i++) X printf("%s\t%s\n", distr[i].abbr, distr[i].descr); X printf("\nEnter the word that specifies the distribution that you require.\n"); X continue; X } X X /* Check that it's a proper distribution */ X for (i=0; distr[i].abbr[0]; i++) { X if (strncmp(distr[i].abbr, distribution, sizeof(distr[0].abbr)) == 0) { X return; X } X } X if (strcmp(distribution, def) != 0) X printf("Type ? for help.\n"); X else { X int once = TRUE; X X do { X r = lastgroup; X while (r = index(r, NGDELIM)) X if (!prefix(++r, def)) X break; X if (r == NULL) { X /* X * no newsgroups are distribution X * names, and user simply will X * not type a valid distribution, X * assume that the default is OK. X */ X distribution[0] = '\0'; X return; X } X lastgroup = r; X if (once) X printf("Sorry, '%s' is an unknown distribution. Type ? for help.\n", def); X once = FALSE; X strcpy(def, r); X r = index(def, NGDELIM); X if (r) X *r = '\0'; X r = index(def, '.'); X } while (r == NULL); X *r = '\0'; X if (strcmp(def, "net") == 0) X strcpy(def, "world"); X } X } X} X X/* X * Do sanity checks before the author types in the message. X */ Xpre_checks() X{ X if (recording(newsgroups)) X return 1; X return 0; X} X X/* X * Set up the temp file with headers. X */ Xprep_article() X{ X FILE *tf, *of; X struct stat stbuf; X X (void) strcpy(tempfname, "/tmp/postXXXXXX"); X (void) mktemp(tempfname); X X /* insert a header */ X tf = xfopen(tempfname, "w"); X fprintf(tf, "Subject: %s\n", subject); X fprintf(tf, "Newsgroups: %s\n", newsgroups); X if (distribution[0] != '\0' && strcmp(distribution, "world")) X fprintf(tf, "Distribution: %s\n", distribution); X X if (keywords[0] != '\0') X fprintf(tf, "Keywords: %s\n", keywords); X if (summary[0] != '\0') X fprintf(tf, "Summary: %s\n", summary); X X if (references[0] != '\0') { X fprintf(tf, "References: %s\n\n", references); X X if (askyes("Do you want to include a copy of the article? ", "no")){ X of = xfopen(original, "r"); X while (fgets(pobuf, BUFSIZ, of) != NULL) X if (pobuf[0] == '\n') /* skip headers */ X break; X fprintf(tf, "In article %s, %s writes:\n", msgid, isfrom); X while (fgets(pobuf, BUFSIZ, of) != NULL) X fprintf(tf, "> %s", pobuf); X (void) fclose(of); X printf("OK, but please edit it to suppress unnecessary verbiage, signatures, etc.\n"); X (void) fflush(stdout); X } X } X X fprintf(tf, "\n\n"); X (void) fflush(tf); X (void) fstat(fileno(tf), &stbuf); X fmodtime = stbuf.st_mtime; X (void) fclose(tf); X} X Xedit_article() X{ X register char *p; X char *editor; X char *endflag = ""; X char *getenv(); X X /* edit the file */ X editor = getenv("EDITOR"); X if (editor == NULL) X editor = DFTEDITOR; X X p = editor + strlen(editor) - 2; X if (strcmp(p, "vi") == 0) X endflag = "+"; X X (void) sprintf(pobuf, "A=%s;export A;exec %s %s %s", X original, editor, endflag, tempfname); X X (void) system(pobuf); X} X X/* X * Do sanity checks after the author has typed in the message. X */ Xpost_checks() X{ X char group[BUFLEN]; X register char *c, *p; X struct stat stbuf; X X if (stat(tempfname, &stbuf) < 0) { X printf("File deleted - no message posted.\n"); X (void) UNLINK(tempfname); X exit(1); X } X if (stbuf.st_size < 5) { X printf("File too small (<5 characters) - no message posted.\n"); X (void) UNLINK(tempfname); X exit(1); X } X X if (stbuf.st_mtime == fmodtime) { X printf("File not modified - no message posted.\n"); X (void) UNLINK(tempfname); X exit(1); X } X X /* X * Is this the right number? Most of the headers are yet to be added X */ X if (stbuf.st_size > 64000) { X printf("\nYour message will probably be truncated when it\n"); X printf("passes through a notesfile site, since it is\n"); X printf("greater than 64000 characters.\n\n"); X if (!askyes("Do you still want to post it? ","")) { X sprintf(ccname, "%s/dead.article", homedir); X save_article(); X (void) UNLINK(tempfname); X exit(1); X } X } X X /* X * get the newsgroups from the edited article, in X * case they were altered in the editor X */ X if (!article_line(tempfname, "Newsgroups: ", group)) { X nogroups: X printf("Not sending to any newsgroups - no message posted\n"); X sprintf(ccname, "%s/dead.article", homedir); X save_article(); X (void) UNLINK(tempfname); X exit(1); X } X c = &group[11]; X while (*c == ' ' || *c == '\t') X c++; X if (*c == '\0') X goto nogroups; X for (p = newsgroups; *c; c++) /* copy to newsgroups, w/o blanks */ X if (*c != ' ' && *c != '\t') X *p++ = *c; X *p = '\0'; X X /* Sanity checks for certain newsgroups */ X if (ngmatch(newsgroups, "all.wanted") && ngmatch(distribution,"world,na,usa,att,btl,eunet,aus")) { X printf("Is your message something that might go in your local\n"); X printf("newspaper, for example a used car ad, or an apartment\n"); X printf("for rent? "); X if (askyes("","")) { X printf("It's pointless to distribute your article widely, since\n"); X printf("people more than a hundred miles away won't be interested.\n"); X printf("Please use a more restricted distribution.\n"); X get_distribution("*None*"); X modify_article(tempfname, "Distribution: ", distribution,REPLACE); X } X } X X if (ngmatch(newsgroups, "rec.humor,!rec.humor.d")) { X if (askyes("Could this be offensive to anyone? ","")) { X getpr("Whom might it offend? ", group); X (void) sprintf(pobuf," - offensive to %s (rot 13)",group); X modify_article(tempfname, "Subject: ", pobuf, APPEND); X encode(tempfname); X } X } X X if (ngmatch(newsgroups, "comp.sources.all,!comp.sources.wanted")) { X if (!article_line(tempfname, "Subject: ", group)) { X nosubj: X printf("There seems to be no subject for this article.\n"); X getpr("Subject: ", subject); X modify_article(tempfname, "Subject: ", subject, REPLACE); X } else { X c = &group[8]; X while (*c == ' ' || *c == '\t') X c++; X if (*c == '\0') X goto nosubj; X strcpy(subject, c); X } X if (ngmatch(newsgroups, "all.wanted") || iswanted(subject)) { X printf("Requests for sources should not be posted to any of\n"); X printf("the comp.sources newsgroups, please post such requests\n"); X printf("to comp.sources.wanted only. Please reenter the newsgroups.\n\n"); X while (!get_newsgroup()) X ; X modify_article(tempfname, "Newsgroups: ", newsgroups, REPLACE); X } X if (ngmatch(newsgroups, "comp.sources.all")) { X if (!ngmatch(newsgroups, "comp.sources.wanted") && X stbuf.st_size < (4*1024)) { X printf("Your article seems rather small to be a source distribution.\n"); X if (!askyes("Are you certain that this is really source? ", "")) { X X while (!get_newsgroup()) X ; X modify_article(tempfname, "Newsgroups: ", newsgroups, REPLACE); X } X } X if (index(newsgroups, NGDELIM)) { X printf("Sources should be posted to one newsgroup only.\n"); X printf("Please pick the most appropriate group for your article.\n\n"); X while (!get_newsgroup()) X ; X modify_article(tempfname, "Newsgroups: ", newsgroups, REPLACE); X } X } X } X} X Xiswanted(str) Xregister char *str; X{ X while (*str == ' ') X str++; X X if (prefix(str, "Re:")) X return (FALSE); X X if (isin(str, " wanted ") || isin(str, " can any") || X isin(str, " need ") || isin(str, " please ") || isin(str, " help ") X || isin(str, " looking ") || index(str, '?')) X return (TRUE); X X return (FALSE); X} X Xisin(str, words) Xregister char *str, *words; X{ X register char *p; X register sc, wc; X X p = words; X while (sc = *str++) { X if ((wc = *p++) == '\0') X return (TRUE); X if (wc == ' ') { X if (index(".,!?-; \t\n", sc)) X continue; X } else { X if (isupper(wc)) X wc = tolower(wc); X if (isupper(sc)) X sc = tolower(sc); X if (wc == sc) X continue; X } X str -= p - words - 1; X p = words; X } X if (*p == '\0') X return (TRUE); X return (FALSE); X} X X/* X * Save a copy of the article in the users NEWSARCHIVE directory. X */ Xsave_article() X{ X FILE *in, *out; X int c; X time_t timenow, time(); X char *today, *ctime(); X struct stat stbuf; X char filename[BUFLEN]; X X if (stat(ccname, &stbuf) == 0 && (stbuf.st_mode&S_IFMT) == S_IFDIR) { X /* X * It would be much nicer here to write articles X * in MH format (numbered files, in rfc822 format) X * X * one day .. X */ X (void) sprintf(filename, "%s/author_copy", ccname); X (void) strcpy(ccname, filename); X } X in = xfopen(tempfname, "r"); X out = xfopen(ccname, "a"); X timenow = time((time_t)0); X today = ctime(&timenow); X fprintf(out,"From postnews %s",today); X while ((c=getc(in)) != EOF) X putc(c, out); X putc('\n', out); X (void) fclose(in); X (void) fclose(out); X} X X/* X * Post the article to the net. X */ Xpost_article() X{ X int status; X X printf("Posting article...\n"); X fflush(stdout); X (void) sprintf(pobuf, "exec %s/%s -h < %s", LIB, "inews", tempfname); X status = system(pobuf); X X if (status) { X printf("Article not posted - exit status %d\n", status); X return; X } else X printf("Article posted successfully.\n"); X X if (ccname[0]) { X printf("A copy has been saved in %s\n", ccname); X save_article(); X } X X (void) UNLINK(tempfname); X exit(0); X} X X/* X * Initialization. X */ Xinit() X{ X FILE *fd; X register char *p; X int i; X char *getenv(); X struct passwd *pw; X X references[0] = '\0'; X distribution[0] = '\0'; X X uid = getuid(); X pw = getpwuid(uid); X if (pw == NULL) { X fprintf(stderr,"You're not in /etc/passwd\n"); X exit(1); X } X p = getenv("HOME"); X if (p == NULL) { X p = getenv("LOGDIR"); X if (p == NULL) X p = pw->pw_dir; X } X (void) strncpy(user, pw->pw_name, SBUFLEN); X (void) strcpy(homedir, p); X X p = getenv("NEWSARCHIVE"); X if (p != NULL) { X if (*p == '\0') X sprintf(ccname, "%s/author_copy", homedir); X else X strcpy(ccname, p); X } X X pathinit(); X (void) sprintf(pobuf, "%s/%s", LIB, "distributions"); X fd = xfopen(pobuf, "r"); X for (i=0; i < MAXDISTR; i++) { X if (fscanf(fd, "%s %[^\n]", distr[i].abbr, distr[i].descr) X != 2) X break; X if (strcmp(distr[i].abbr, "default") == 0) X strcpy(def_distr, distr[i--].descr); X } X (void) fclose(fd); X distr[i].abbr[0] = '\0'; X if (def_distr[0] == '\0') X strcpy(def_distr, "world"); /* maybe "local" is better? */ X} X X/* X * Get a yes or no answer to a question. A default may be used. X */ Xaskyes(msg, def) Xchar *msg, *def; X{ X for(;;) { X printf("%s", msg); X pobuf[0] = 0; X (void) gets(pobuf); X switch(pobuf[0]) { X case 'y': X case 'Y': X return TRUE; X case 'n': X case 'N': X return FALSE; X case '\0': X switch(*def) { X case 'y': X case 'Y': X return TRUE; X case 'n': X case 'N': X return FALSE; X } X default: X printf("Please answer yes or no.\n"); X } X } X} X X/* X * Get a character string into pobuf, using prompt msg. X */ Xgetpr(msg, bptr) Xchar *msg, *bptr; X{ X static int numeof = 0; X printf("%s", msg); X (void) gets(bptr); X (void) nstrip(bptr); X if (feof(stdin)) { X if (numeof++ > 3) { X fprintf(stderr,"Too many EOFs\n"); X exit(1); X } X clearerr(stdin); X } X} X Xbyebye(mesg) Xchar *mesg; X{ X printf("%s\n", mesg); X exit(1); X} X X/* X * make a modification to the header of an article X * X * fname -- name of article X * field -- header field to modify X * line -- modification line X * how -- APPEND or REPLACE X * X * example: X * modify_article("/tmp/article" , "Subject:" , "new subject" , REPLACE); X * X * X */ Xmodify_article(fname, field, line, how) Xchar *fname, *field, *line; X{ X FILE *fpart, *fptmp; X char *temp2fname = "/tmp/postXXXXXX"; X char lbfr[BUFLEN]; X register found = FALSE; X X mktemp(temp2fname); X X fptmp = xfopen(temp2fname, "w"); X fpart = xfopen(fname, "r"); X X while (fgets(lbfr, BUFLEN, fpart) != NULL) { X if (prefix(lbfr, field)) { X found = TRUE; X (void) nstrip(lbfr); X if (how == APPEND) { X /* append to current field */ X (void) strcat(lbfr, line); X (void) strcat(lbfr, "\n"); X } else X /* replace current field */ X (void) sprintf(lbfr, "%s%s\n", field, line); X } X (void) fputs(lbfr, fptmp); X } X X fclose(fpart); X fclose(fptmp); X X fptmp = xfopen(temp2fname, "r"); X fpart = xfopen(fname, "w"); X X if (!found) X fprintf(fpart, "%s%s\n", field, line); X while (fgets(pobuf,BUFLEN,fptmp) != NULL) X (void) fputs(pobuf, fpart); X X (void) fclose(fpart); X (void) fclose(fptmp); X (void) UNLINK(temp2fname); X} X X X/* verify that newsgroup exists, and get number of entries */ Xvalid_ng(ng, maxart, minart, canpost) Xchar *ng; Xlong *maxart, *minart; Xchar *canpost; X{ X char ng_check[BUFLEN], ng_read[BUFLEN]; X FILE *fp; X X fp = xfopen(ACTIVE, "r"); X while (fgets(ng_read, BUFLEN, fp) != NULL) { X switch (sscanf(ng_read, "%s %ld %ld %c", ng_check, maxart, minart, canpost)) { X case 2: X *minart = 1; X /* fall through */ X case 3: X *canpost = 'y'; X /* fall through */ X case 4: X break; X X default: X printf("Active file (%s) corrupted. ", ACTIVE); X byebye("Seek help!"); X } X X if (strcmp(ng_check, ng) == 0) { X (void) fclose(fp); X if (*canpost != 'n') { X#ifdef FASCIST X if (uid && uid != ROOTID && fascist(user, ng)) { X *canpost = 'n'; X return FALSE; X } X#endif /* FASCIST */ X return TRUE; X } else X return FALSE; X } X } X *canpost = 'i'; X *maxart = 0; X *minart = 0; X (void) fclose(fp); X return FALSE; X} X X/* get the line specified by field from an article */ Xarticle_line(article, field, line) Xchar *article, *field, *line; X{ X FILE *fp; X char *c; X X fp = xfopen(article,"r"); X while ((c=fgets(line,BUFLEN,fp)) != NULL && !prefix(line, field)) X if (line[0] == '\n') { X c = NULL; X break; X } X (void) fclose(fp); X if (c != NULL) { X (void) nstrip(line); X return TRUE; X } else { X line[0] = '\0'; X return FALSE; X } X} X X/* get the header information for a followup article */ Xfollowup(baseart) Xregister char *baseart; X{ X register char *p; X X /* subject */ X if (article_line(baseart, "Subject: ", pobuf)) { X p = pobuf+9; X for ( ; ; ) { X while (*p == ' ' || *p == '\t') X ++p; X if ((*p != 'r' && *p != 'R') || X (p[1] != 'e' && p[1] != 'E') || X (p[2] != ':' && p[2] != ' ')) X break; X p += 3; X } X (void) sprintf(subject, "Re: %s", p); X } else { X if (article_line(baseart, "From: ", pobuf)) X (void) sprintf(subject, "Re: orphan response from %s", pobuf); X else X (void) strcpy(subject, "Re: orphan response"); X } X X /* newsgroup */ X if (article_line(baseart, "Newsgroups: ", pobuf)) X (void) strcpy(newsgroups, pobuf+12); X if (ngmatch(newsgroups, "misc.jobs")) { X printf("misc.jobs is for the direct posting of job announcements and requests.\n"); X printf("it is not for discussion. You followup has been directed to misc.misc\n"); X (void) strcpy(newsgroups,"misc.misc"); X } X X /* distribution */ X if (article_line(baseart, "Distribution: ", pobuf)) X (void) strcpy(distribution, pobuf+14); X X /* references */ X if (article_line(baseart, "References: ", pobuf)) { X register char *rcp; X (void) strcpy(references, pobuf+12); X (void) strcat(references, " "); X /* keep the number of references to a reasonable number */ X rcp = rindex(references, ' '); /* Can not fail */ X while ((int)(rcp - references) > 70) { X while (*--rcp != ' ') X ; X rcp[1] = '\0'; X } X } X if (article_line(baseart, "Message-ID: ", pobuf)) { X (void) strcat(references, pobuf+12); X (void) strcpy(msgid, pobuf+12); X } X X if (article_line(baseart, "From: ", pobuf)) X (void) strcpy(isfrom, pobuf+6); X X if (article_line(baseart, "Keywords: ", pobuf)) X (void) strcpy(keywords, pobuf+10); X X if (article_line(baseart, "Followup-To: ", pobuf)) { X (void) strcpy(newsgroups, pobuf+13); X if (strcmp(newsgroups, "poster") == 0) X byebye("Mail followups directly to poster."); X } X X get_summary(); X} X Xget_summary() X{ X register char *p; X register i; X X printf("Please enter a short summary of your contribution to the discussion\n"); X printf("Just one or two lines ... (end with a blank line)\n"); X p = summary; X for (i = 0; i < 3; i++) { /* 3 * 80 < 256, should be safe .. */ X getpr(">\t", p); X if (*p == '\0') X break; X p = index(p, '\0'); X (void) strcpy(p, "\n\t "); X p += 3; X } X if (p > summary) X p[-3] = '\0'; X} X Xencode(article) Xchar *article; X{ X FILE *fpart, *fphead, *fpcoded; X char *headerfile = "/tmp/pheadXXXXXX"; X char *codedfile = "/tmp/pcodeXXXXXX"; X X (void) mktemp(headerfile); X (void) mktemp(codedfile); X X fpart = xfopen(article, "r"); X X /* place article header in "headerfile" file */ X fphead = xfopen(headerfile, "w"); X while (fgets(pobuf, BUFLEN, fpart) != NULL) { X (void) fputs(pobuf, fphead); X if (pobuf[0] == '\n') X break; X } X (void) fclose(fphead); X X /* place article body in "codedfile" file */ X fpcoded = xfopen(codedfile, "w"); X while (fgets(pobuf, BUFLEN, fpart) != NULL) X (void) fputs(pobuf, fpcoded); X (void) fclose(fpcoded); X (void) fclose(fpart); X X /* encode body and put back together with header */ X (void) rename(headerfile, article); X X (void) sprintf(pobuf,"exec %s/%s 13 < %s >> %s\n", LIB, "caesar", codedfile, article); X printf("Encoding article -- please stand by\n"); X (void) fflush(stdout); X if (system(pobuf)) { X printf("encoding failed"); X exit(2); X } X (void) UNLINK(codedfile); X} X X X/* X * Print a recorded message warning the poor luser what he is doing X * and demand that he understands it before proceeding. Only do X * this for newsgroups listed in LIBDIR/recording. X */ Xrecording(ngrps) Xchar *ngrps; X{ X char recbuf[BUFLEN]; X FILE *fd; X char nglist[BUFLEN], fname[BUFLEN]; X int c, n, yes, retval = 0; X X (void) sprintf(recbuf, "%s/%s", LIB, "recording"); X fd = fopen(recbuf, "r"); X if (fd == NULL) X return 0; X while ((fgets(recbuf, sizeof recbuf, fd)) != NULL) { X (void) sscanf(recbuf, "%s %s", nglist, fname); X if (ngmatch(ngrps, nglist)) { X (void) fclose(fd); X if (fname[0] == '/') X (void) strcpy(recbuf, fname); X else X (void) sprintf(recbuf, "%s/%s", LIB, fname); X fd = fopen(recbuf, "r"); X if (fd == NULL) X return 0; X while ((c = getc(fd)) != EOF) X putc(c, stderr); X fprintf(stderr, "Do you understand this? Hit <return> to proceed, <BREAK> to abort: "); X n = read(2, recbuf, 100); X c = recbuf[0]; X yes = (c=='y' || c=='Y' || c=='\n' || c=='\n' || c==0); X if (n <= 0 || !yes) X retval = -1; X } X } X return retval; X} X Xxxit(i) X{ X exit(i); X} X X#if !defined(BSD4_2) && !defined(BSD4_1C) Xrename(from,to) Xregister char *from, *to; X{ X (void) unlink(to); X if (link(from, to) < 0) X return -1; X X (void) unlink(from); X return 0; X} X#endif /* !BSD4_2 && ! BSD4_1C */ END_OF_FILE if test 26497 -ne `wc -c <'postnews.c'`; then echo shar: \"'postnews.c'\" unpacked with wrong size! fi # end of 'postnews.c' fi if test -f 'getdate.s.uu' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'getdate.s.uu'\" else echo shar: Extracting \"'getdate.s.uu'\" \(26072 characters\) sed "s/^X//" >'getdate.s.uu' <<'END_OF_FILE' Xbegin 644 getdate.s XMK@I?;61A>7,Z"L(S,0JX"L(S,0K",S *PC,Q"L(S, K",S$*PC,Q"L(S, K" XM,S$*PC,P"LE?9&%T96-O;G8*PC,Q"H8*7V1A=&5C;VYV.@J#"H(*U_(L(S$P XM"L'O"L'P"L#IU IO<B#I\ IJ9V4@23 P,3,*]/ *E0K-Z2,Q,# *:F=E($DP XM,#$V"L3I(S$Y,# *O0K XS0*P.3P"F-W9 II\'8@[0IO<B#G[@K923 P,3D* XMP.,Q,# *P.3P"F-W9 II\'8@[0IO<B#G[@K923 P,4$*P.,T,# *P.3P"F-W XM9 II\'8@[0IO<B#G[@K923 P,3D*23 P,4$Z"H\*@ K,23 P,4,*23 P,3DZ XM"H<*@ I),# Q0SH*P^T*Q.,R. K 7VUD87ES*S(L[0K-Z2,Q.3<P"FIL($DP XM,#%$"LWI(S$Y.3D*:F<@23 P,40*S<7V"FIL92!),# Q1 K-Q2PC,3(*:F<@ XM23 P,40*S<[V"FIL92!),# Q1 KSQ0J2"G-A;"#B,0K Y%]M9&%Y<\<*S<XL XMZPIJ;&4@23 P,44*23 P,40Z"L#A+3$*@ K X38U-3,U"H *F@I),# Q13H* XMP.3."O/K"F-W9 K V"SK"L#0+.X*R^CO"DDP,#$Q.#H*S<4L[PIJ;&4@23 P XM,3$U"L#E[PIS86P@XC$*P.1?;61A>7/'"F-W9 K$Y-@*861C(.?0"L#8+.L* XMP- L[@K<[PJ:. I),# Q,34Z"FUO=B!S:2PC,3DW, I),# Q,4,Z"LWI[PIJ XM;&4@23 P,3$Y"L#C- K Y.\*8W=D"FGP=B#M"H<*;W(@Y^X*V3%F"MSK"C$Z XM"L3A,S8U"F-W9 K$Y-@*861C(.?0"L#8+.L*P- L[@K<[PJ:0PI),# Q,3DZ XM"K0P.#8T"L#G(S$*P= *P=@*TRYM;&DT"L#8+.L*P- L[@K Y#'4"F-W9 K! XMT K!V J<"H *P.$V, K+Y^X*TRYM;&DT"L/M"HD*Q.;K"F%D8R#E[@K V"SM XM"L#0+.P*P3'."L$QQ0K!,3(H\2D*P3$P*/$I"M-?=&EM96-O;G8*Q/(L(S@* XMK K QBSN"LW&]@IJ9V4@23 P,3%%"L#A+3$*@ K X38U-3,U"H *F@I),# Q XM,44Z"J,*P.;&"L38+.L*861C(- L[0K-,C H\2DL(S$*L3 *S3(P*/$I+",S XM"ME),# Q,C$*V^38"H *TU]L;V-A;'1I;64*B0J["LTQ-L?V"K$Q"DDP,#$R XM,#H*Q-@L(S8Q.3,V"F%D8R#0+",M,0I),# Q,C$Z"L'0"L'8"I\*C0K#[@K, XM+F1S@0K)7V1A>6-O;G8*7V1A>6-O;G8Z"H,*@@K7\BPC-@K![PK!\ K Z<4* XMP.0X*&)P*0IM;W8@8W@L,3 H\2D*P- LZPK SRSM"MODT J "M-?;&]C86QT XM:6UE"HD*P.CK"L#DS@K7Y#$R*.\I"L3A-PK XS<*8W=D"FGP=B#M"L#D[@IC XM=V0*N0K!T J<"H *M# X-C0*P.<C,0K3+FUL:30*P^T*B0K$YNL*861C(.7N XM"L#0+.T*P,\L[ JY"L'0"F]R(.GP"FIG($DP,#(S"L'P"LQ),# R- I),# R XM,SH*P.3P"O/K"H *23 P,C0Z"HT*8W=D"IP*@ J/-#DW-@K YR,Y"M,N;6QI XM- K#[0J)"L3FZPIA9&,@Y>X*P- L[0K SRSL"L$Q,"CQ*0K!U JY"L'0"M-? XM9&%Y;&-O<G(*Q/(L(S@*S"YD<X$*R5]T:6UE8V]N=@I?=&EM96-O;G8Z"H,* XM@@K![PK Z,4*P? *P.G4"JX*7S$Z"L)),# S,3D*PC,*PC$*PDDP,#-!"L(R XM"L)),# S1@K",C0*PDDP,#,Q- J&"LW.]@IJ;"!),# S,@K-SBPC-3D*:F<@ XM23 P,S(*;W(@Z? *:FP@23 P,S(*S>DC-3D*:FQE($DP,#,S"DDP,#,R.@K XMX2TQ"H *P.$V-34S-0J "LQ),# S,0I),# S,SH*P3$P*/$I"LQ),# S. I) XM,# S03H*;W(@Z.\*:FQE($DP,#-""LWH(S$R"FIL92!),# S0PI),# S0CH* XM;6]V(&%X+",M,0J "L#A-C4U,S4*@ K,23 P,S$*23 P,T,Z"L#C,3(*P.3O XM"F-W9 II\'8@[0K Y.X*8W=D"IP*@ K X38P"LOG[@K3+FUL:30*G J "L#D XMS@IC=V0*P^T*B0K$YNL*861C(.7N"L#A-C *R^?N"J8*P>T*TRYM;&DT"IP* XM@ K Y/ *8W=D"L/M"HD*Q.;K"F%D8R#E[@JF"L'M"LQ),# S,0I),# S1CH* XM;W(@Z.\*:FQE($DP,#,Q, K-Z",Q,@IJ;&4@23 P,S$Q"DDP,#,Q,#H*P.$M XM,0J "L#A-C4U,S4*@ K,23 P,S$*23 P,S$Q.@K XS$R"L#D[PIC=V0*:?!V XM(.T*Q.<C,3(*P.3N"F-W9 J<"H *P.$V, K+Y^X*TRYM;&DT"IP*@ K Y,X* XM8W=D"L/M"HD*Q.;K"F%D8R#E[@K X38P"LOG[@JF"L'M"M,N;6QI- J<"H * XMP.3P"F-W9 K#[0J)"L3FZPIA9&,@Y>X*I@K![0K,23 P,S$*23 P,S$T.@IO XM<B#H[PIJ;"!),# S,34*S>@C,C,*:FQE($DP,#,Q-@I),# S,34Z"L#A+3$* XM@ K X38U-3,U"H *S$DP,#,Q"DDP,#,Q-CH*P.3O"F-W9 J<"H *P.$V, K+ XMY^X*TRYM;&DT"IP*@ K Y,X*8W=D"L/M"HD*Q.9A> IA9&,@8G@L9'@*P.$V XM, K+Y^X*I@K![0K3+FUL:30*G J "L#D\ IC=V0*P^T*B0K$YNL*861C(.7N XM"J8*P>T*S$DP,#,Q"DDP,#,Q.3H*P.$M,0J "L#A-C4U,S4*@ K,23 P,S$* XM23 P,S@Z"L#B7S$*C0K,+F-S8C(*23 P,S$Z"HT*P^X*S"YD<X$*R5]M;VYT XM:&%D9 I?;6]N=&AA9&0Z"H,*@@K7\BPC-@K![PK!\ K Y#$P*/$I"F]R(.34 XM"ME),# T,PJ'"H *@ K,23 P-#$*23 P-#,Z"MODQ0J "M-?;&]C86QT:6UE XM"HD*P.CK"H\R"FUU;" Q,"CO*0K$Y#@H[RD*8W=D"L3DU IA9&,@YS$P*/$I XM"L#IZPK XS$R"L#D\ IC=V0*:?!V(.T*P- LZPK Y/ *8W=D"FGP=B#M"MSN XM"L#I[@J3"H@*P.$S"H *P5]O=7)Z;VYE"K0T"H *P2CO*0K!,BCO*0K!-"CO XM*0K!T K!-BCO*0K!\ K37V1A=&5C;VYV"L3R+",Q. J<"H *TU]D87EL8V]R XM<@K$\BPC. J<"H *23 P-#$Z"HT*P^X*S"YD<X$*R5]D87EL8V]R<@I?9&%Y XM;&-O<G(Z"H,*@@J "H *P>\*P? *V^34"H *TU]L;V-A;'1I;64*B0IM;W8@ XM8G@L87@*;6]V(.0TQPK<ZPJ=- IC=V0*:?!V(.T*P.GN"MODQ0J "M-?;&]C XM86QT:6UE"HD*NPK Y#3'"MSK"ITT"F-W9 II\'8@[0K Z.X*P.3P"M?D[PIC XM=V0*G J "L#A,S8P, K+Y^X*TRYM;&DT"L#FQ0JO"M?FU IS8F(@Y3$P*/$I XM"L3FZPIA9&,@Y>X*P.3M"L#G[ K,+F1S@0K)7WEY;&5X"E]Y>6QE>#H*@PJ" XM"M?R+",R. K![PK!\ I),# V-SH*P.5?;'!T<@J,"HL*NPK*86PL7U]C='EP XM95\K,<<*BPIT97-T8B!A;"PC. IJ92!),# V-@K<7VQP='(*S$DP,#8W"DDP XM,#8V.@K Y5]L<'1R"HP*RBTS*/$I+&%L"HL*NPK*86PL7U]C='EP95\K,<<* XMBPIT97-T8B!A;"PC- K923 P-CD*8VUP8B M,RCQ*2PC-#4*:F4@23 P-CD* XM8VUP8B M,RCQ*2PC-#,*V4DP,#9!"DDP,#8Y.@IC;7!B("TS*/$I+",T-0IJ XM92!),# V10IC;7!B("TS*/$I+",T,PK923 P-D8*23 P-D4Z"F-M<&(@+3,H XM\2DL(S0U"ME),# V,3,*P,8L(RTQ"LQ),# V,30*23 P-C$S.@K QBPC,0I) XM,# V,30Z"MQ?;'!T<@K Y5]L<'1R"HP*BPJ["LIA;"Q?7V-T>7!E7RLQQPJ+ XM"G1E<W1B(&%L+",T"ME),# V,3 *TU]Y>6QE> J "LQ),# V,0I),# V1CH* XMP,8L(S$*23 P-C$P.@K 7WEY;'9A;/8*23 P-C$Y.@IM;W8@8G@L7VQP='(* XMW%]L<'1R"HP*RBTS*/$I+&%L"HL*NPK*86PL7U]C='EP95\K,<<*BPIT97-T XM8B!A;"PC- IJ92!),# V,3@*RF%L+"TS*/$I"HL*@ J/, IM=6P@7WEY;'9A XM; K#[0K$YNL*U^,T. K 7WEY;'9A;"SM"LQ),# V,3D*23 P-C$X.@K Y%]Y XM>6QV86P*;75L(,8*P%]Y>6QV86PLZPKS7VQP='(*M#8Q"H *S$DP,#8Q"DDP XM,#9!.@K*86PL+3,H\2D*BPJ["LIA;"Q?7V-T>7!E7RLQQPJ+"G1E<W1B(&%L XM+",S"FIE($DP,#8Q0PK;Y"TRS@K Z.L*23 P-C%&.@K Y5]L<'1R"MQ?;'!T XM<@J,"LHM,RCQ*2QA; J+"KL*RF%L+%]?8W1Y<&5?*S''"HL*=&5S=&(@86PL XM(S,*V4DP,#8R, IC;7!B("TS*/$I+",T-@K923 P-C%%"DDP,#8R,#H*RF%L XM+"TS*/$I"LHH[RDL86P*W.\*S$DP,#8Q1@I),# V,44Z"LHH[RGV"O-?;'!T XM<@K;Y"TRS@J "M-?;&]O:W5P"HD*@ K,23 P-C$*23 P-C%#.@IC;7!B("TS XM*/$I+",T, K923 P-C(S"LOI\ I),# V,C<Z"L#E7VQP='(*W%]L<'1R"HP* XMRBTS*/$I+&%L"F-M<&(@+3,H\2GV"ME),# V,CD*RF%L+"TS*/$I"HL*@ K, XM23 P-C$*23 P-C(Y.@IC;7!B("TS*/$I+",T, K923 P-C)#"MSP"LQ),# V XM,C8*23 P-C)#.@IC;7!B("TS*/$I+",T,0K923 P-C(V"O/P"DDP,#8R-CH* XM;W(@Z? *:F<@23 P-C(W"LQ),# V-PI),# V,C,Z"L!B>"Q?;'!T<@II;F,@ XM7VQP='(*C J+"H *23 P-C$Z"HT*S"YD<X$*R5]M9'1A8@JN"E]M9'1A8CH* XMPE\R"L(R-3@*PC$*PE\S"L(R-3@*PC(*PE\T"L(R-3@*PC,*PE\U"L(R-3@* XMPC0*PE\V"L(R-3@*PC4*PE\W"L(R-3@*PC8*PE\X"L(R-3@*PC<*PE\Y"L(R XM-3@*PC@*PE\Q, K",C4X"L(Y"L)?,3$*PC(U. K".0K"7S$R"L(R-3@*PC$P XM"L)?,3,*PC(U. K",3$*PE\Q- K",C4X"L(Q,@K"7S$U"L(R-3D*N K"7S$V XM"L(R-3D*PC$*PE\Q-PK",C4Y"L(R"L)?,3@*PC(U.0K",@K"7S$Y"L(R-3D* XMPC,*PE\R, K",C4Y"L(S"L)?,C$*PC(U.0K"- K"7S(R"L(R-3D*PC0*PE\R XM,PK",C4Y"L(T"L)?,C0*PC(U.0K"-0K"7S(U"L(R-3D*PC8*N JX"LE?;7IT XM86(*N I?;7IT86(Z"L)?,C8*PC(V, K",0K"7S(W"L(R-C *PC$*PE\R. K" XM,C8P"L(R"L)?,CD*PC(V, K",@K"7S,P"L(R-C4*PC(Q, K"7S,Q"L(R-C4* XMPC(Q, K"7S,R"L(R-C4*PC(T, K"7S,S"BYW;W)D(#(V-0HN=V]R9" R-# * XMPE\S- K",C8V"L(R-# *PE\S-0K",C8V"L(R-# *PE\S-@K",C8U"L(S,# * XMPE\S-PK",C8U"L(S,# *PE\S. K",C8V"L(S,# *PE\S.0K",C8V"L(S,# * XMPE\T, K",C8U"L(S-C *PE\T,0K",C8U"L(S-C *PE\T,@K",C8V"L(S-C * XMPE\T,PK",C8V"L(S-C *PE\T- K",C8U"L(T,C *PE\T-0K",C8U"L(T,C * XMPE\T-@K",C8V"L(T,C *PE\T-PK",C8V"L(T,C *PE\T. K",C8U"L(T.# * XMPE\T.0K",C8U"L(T.# *PE\U, K",C8V"L(T.# *PE\U,0K",C8V"L(T.# * XMPE\U,@K",C8U"L(U-# *PE\U,PK",C8U"L(U-# *PE\U- K",C8V"L(U-# * XMPE\U-0K",C8V"L(U-# *PE\U-@K",C8U"L(V,# *PE\U-PK",C8U"L(V,# * XMPE\U. K",C8V"L(V,# *PE\U.0K",C8V"L(V,# *PE\V, K",C8U"K@*PE\V XM,0K",C8U"K@*PE\V,@K",C8V"K@*PE\V,PK",C8V"K@*PE\V- K",C8U"K@* XMPE\V-0K",C8U"K@*PE\V-@K",C8V"K@*PE\V-PK",C8V"K@*+G=O<F0@7S8X XM"BYW;W)D(#(V-0K"+38P"L)?-CD*PC(V-0K"+38P"L)?-S *PC(V-@K"+38P XM"L)?-S$*PC(V-@K"+38P"L)?-S(*PC(V-0K"+3$R, K"7S<S"L(R-C4*PBTQ XM,C *PE\W- K",C8V"L(M,3(P"L)?-S4*PC(V-@K"+3$R, K"7S<V"L(R-C4* XMPBTU-# *PE\W-PK",C8U"L(M-30P"L)?-S@*PC(V-0K"+38P, K"7S<Y"L(R XM-C4*PBTV,# *PE\X, K",C8V"L(M-C P"L)?.#$*PC(V-@K"+38P, K"7S@R XM"L(R-C4*PBTU-S *PE\X,PK",C8U"L(M-3<P"L)?.#0*PC(V-@K"+34W, K" XM7S@U"L(R-C8*PBTU-S *PE\X-@K",C8U"L(M-#@P"L)?.#<*PC(V-0K"+30X XM, JX"K@*R5]U;FET=&(*N I?=6YI='1B.@K"7S@X"L(R-C,*PC$R"L)?.#D* XMPC(V,PK",0K"7SDP"L(R-C(*PC(P,38P"L)?.3$*PC(V,@K",3 P.# *PE\Y XM,@K",C8R"L(Q-#0P"L)?.3,*PC(V,@K"-C *PE\Y- K",C8R"L(Q"L)?.34* XMPC(V,@K",0K"7SDV"L(R-C0*PC$*PE\Y-PK",C8T"L(Q"K@*N K)7V]T:&5R XM=&(*N I?;W1H97)T8CH*PE\Y. K",C8R"BYW;W)D(#$T-# *PE\Y.0K",C8R XM"L(M,30T, K"7S$P, K",C8R"K@*PE\Q,#$*PC(V,@JX"L)?,3 R"L(R-C$* XMPBTQ"L)?,3 S"L(R-C(*N K"7S$P- K",C8Q"L(R"L)?,3 U"L(R-C$*PC$* XMPE\Q,#8*PC(V,0K",PK"7S$P-PK",C8Q"L(T"L)?,3 X"L(R-C$*PC4*PE\Q XM,#D*PC(V,0K"-@K"7S$Q, K",C8Q"L(W"L)?,3$Q"L(R-C$*PC@*PE\Q,3(* XMPC(V,0K".0K"7S$Q,PK",C8Q"L(Q, K"7S$Q- K",C8Q"L(Q,0K"7S$Q-0K" XM,C8Q"L(Q,@K"7S$Q-@K",C8W"L(Q"K@*N K)7VUI;'IO;F4*N I?;6EL>F]N XM93H*PE\Q,3<*PC(V-0K"-C *PE\Q,3@*PC(V-0K",3(P"L)?,3$Y"L(R-C4* XMPC$X, K"7S$R, K",C8U"L(R-# *PE\Q,C$*PC(V-0K",S P"L)?,3(R"L(R XM-C4*PC,V, K"7S$R,PK",C8U"L(T,C *PE\Q,C0*PC(V-0K"-#@P"L)?,3(U XM"L(R-C4*PC4T, K"7S$R-@K",C8U"L(V,# *PE\Q,C<*PC(V-0K"-C8P"L)? XM,3(X"L(R-C4*PC<R, K"7S$R.0K",C8U"L(M-C *PE\Q,S *PC(V-0K"+3$R XM, HN=V]R9"!?,3,Q"L(R-C4*PBTQ.# *PE\Q,S(*PC(V-0K"+3(T, K"7S$S XM,PK",C8U"L(M,S P"L)?,3,T"L(R-C4*PBTS-C *PE\Q,S4*PC(V-0K"+30R XM, K"7S$S-@K",C8U"L(M-#@P"L)?,3,W"L(R-C4*PBTU-# *PE\Q,S@*PC(V XM-0K"+38P, K"7S$S.0K",C8U"L(M-C8P"L)?,30P"L(R-C4*PBTW,C *PE\Q XM-#$*PC(V-0JX"K@*N K)7VQO;VMU< JX"H8*7VQO;VMU<#H*@PJ""M?R+",Q XM,S8*P>\*P? *B K;Y"TQ,M0*@ K37W-T<F-P>0J)"HD*V^0M,3+4"L M,3,P XM*/$I+.L*H@KSZPK Z>L*23 P-S,Z"MSP"F-M<&(@*/ I]@IJ92!),# W,@K* XM86PL*/ I"HL*NPK*86PL7U]C='EP95\K,<<*BPIT97-T8B!A;"PC,0IJ92!) XM,# W-@K*86PL*/ I"HL*@ K37W1O;&]W97(*B0J "LQ),# W-PI),# W-CH* XMRF%L+"CP*0J+"H *23 P-S<Z"L#E+3$S,"CQ*0J-"KH*W"TQ,S H\2D*S$DP XM,#<S"DDP,#<R.@K Y2TQ,S H\2D*RL?V"MOD+3$RU J "M-?<W1R;&5N"HD* XMS>$S"ME),# W.0K +3$SSBPC,0K,23 P-T$*23 P-SDZ"MOD+3$RU J "M-? XM<W1R;&5N"HD*8VUP(&%X+",T"ME),# W0PIC;7!B("TQ,C4H\2DL(S0V"ME) XM,# W0PK +3$SSBPC,0K*+3$R-2CQ*?8*S$DP,#=!"DDP,#=#.@K +3$SSO8* XM23 P-T$Z"L#H(U]M9'1A8@I),# W,3(Z"LTH[RGV"FIE($DP,#=&"MOD+3$R XMU K Z>L*P.0H[RD*P"TQ,S H\2DLZPI),# W,38Z"L#E+3$S,"CQ*0K<+3$S XM,"CQ*0J,"HL*P.7P"MSP"H *C J+"L/M"LWFZPK923 P-S$P"LTM,3/.]@IJ XM92!),# W,3@*P.4H[RD*Q.(S"LTM,3,P*/$I+.P*V4DP,#<Q. K YC0H[RD* XMP%]Y>6QV86PL[0K!,BCO*0K,23 P-S$*23 P-S$X.@K Y2TQ,S H\2D*8VUP XM8B M,<?V"ME),# W,38*P.8T*.\I"L!?>7EL=F%L+.T*P3(H[RD*S$DP,#<Q XM"DDP,#<Q,#H*Q.@C-@K,23 P-S$R"DDP,#=&.@K Z"-?;7IT86(*23 P-S(Q XM.@K-*.\I]@IJ92!),# W,44*V^0M,3+4"H *P2CO*0K37W-T<F-M< J)"HD* XMF0K923 P-S%&"L#F-"CO*0K 7WEY;'9A;"SM"L$R*.\I"LQ),# W,0I),# W XM,48Z"L3H(S8*S$DP,#<R,0I),# W,44Z"L#H(U]M>G1A8@I),# W,C@Z"LTH XM[RGV"FIE($DP,#<R-0K;Y"TQ,M0*@ K!*.\I"M-?<W1R8VUP"HD*B0J9"ME) XM,# W,C8*P.8T*.\I"L!?>7EL=F%L+.T*P3(H[RD*S$DP,#<Q"DDP,#<R-CH* XMQ.@C-@K,23 P-S(X"DDP,#<R-3H*;6]V('-I+"-?=6YI='1B"DDP,#<R1CH* XMS2CO*?8*:F4@23 P-S)#"MOD+3$RU J "L$H[RD*TU]S=')C;7 *B0J)"ID* XMV4DP,#<R1 K YC0H[RD*P%]Y>6QV86PL[0K!,BCO*0K,23 P-S$*23 P-S)$ XM.@K$Z",V"LQ),# W,D8*23 P-S)#.@K;Y"TQ,M0*@ J "M-?<W1R;&5N"HD* XM\^L*B0K$Y>L*8VUP8B#'+",Q,34*V4DP,#<S- J'"H *V^0M,3+4"H *@ K3 XM7W-T<FQE;@J)"O/K"HD*Q.7K"HT*N@I),# W,S0Z"L#H(U]U;FET=&(*23 P XM-S,Y.@K-*.\I]@IJ92!),# W,S8*V^0M,3+4"H *P2CO*0K37W-T<F-M< J) XM"HD*F0K923 P-S,W"L#F-"CO*0K 7WEY;'9A;"SM"L$R*.\I"LQ),# W,0I) XM,# W,S<Z"L3H(S8*S$DP,#<S.0I),# W,S8Z"L#H(U]O=&AE<G1B"DDP,#<T XM,#H*S2CO*?8*:F4@23 P-S-$"MOD+3$RU J "L$H[RD*TU]S=')C;7 *B0J) XM"ID*V4DP,#<S10K YC0H[RD*P%]Y>6QV86PL[0K!,BCO*0K,23 P-S$*23 P XM-S-%.@K$Z",V"LQ),# W-# *23 P-S-$.@K;Y"TQ,M0*@ K37W-T<FQE;@J) XM"LWA,0K923 P-S0U"LIA;"PM,3+4"HL*NPK*86PL7U]C='EP95\K,<<*BPIT XM97-T8B!A;"PC,PIJ92!),# W-#4*P.@C7VUI;'IO;F4*23 P-S1".@K-*.\I XM]@IJ92!),# W-#4*V^0M,3+4"H *P2CO*0K37W-T<F-M< J)"HD*F0K923 P XM-S0Y"L#F-"CO*0K 7WEY;'9A;"SM"L$R*.\I"LQ),# W,0I),# W-#DZ"L3H XM(S8*S$DP,#<T0@I),# W-#4Z"K0U-PJ "DDP,#<Q.@J-"LPN9'.!"LE?9V5T XM9&%T90I?9V5T9&%T93H*@PJ""M?R+",R,@K![PK!\ K YL4*P%]L<'1R+.T* XMS<[V"ME),# X,PK;Y"TQQ0K SBSK"MOD+3'%"H *TU]F=&EM90J)"DDP,#@S XM.@J3"M-?;&]C86QT:6UE"HD*P.CK"L#F,3 H[RD*P%]Y96%R+.T*P.0X*.\I XM"MSK"L!?;6]N=&@LZPK YC8H[RD*P%]D87DL[0K 7W)E;'-E8_8*P%]R96QS XM96,K,O8*P%]R96QM;VYT:/8*P%]R96QM;VYT:"LR]@K 7W)E;&9L86?V"L#F XM7W)E;&9L86<*P%]D87EF;&%G+.T*P%]D871E9FQA9RSM"L!?>F]N969L86<L XM[0K 7W1I;65F;&%G+.T*KPK YC;'"L!?;W5R>F]N92SM"L!?9&%Y;&EG:'0L XM(S,*P%]S<_8*P.9?<W,*P%]M;2SM"L!?:&@L[0K 7VUE<FED+",R- K37WEY XM<&%R<V4*P.GK"F]R(.GP"FIE($DP,#@V"L#A+3$*@ K X38U-3,U"H *S$DP XM,#@Q"DDP,#@V.@K-7W1I;65F;&%G+",Q"FIL92!),# X.0K<\ I),# X.3H* XMS5]Z;VYE9FQA9RPC,0IJ;&4@23 P.$,*:6YC(/ *23 P.$,Z"LU?9&%T969L XM86<L(S$*:FQE($DP,#A&"MSP"DDP,#A&.@K-7V1A>69L86<L(S$*:FQE($DP XM,#@Q,@K<\ I),# X,3(Z"F]R(.GP"FIE($DP,#@Q-0K X2TQ"H *P.$V-34S XM-0J "LQ),# X,0I),# X,34Z"LU?9&%T969L86?V"ME),# X,3<*S5]T:6UE XM9FQA9_8*V4DP,#@Q-PK-7V1A>69L86?V"FIE($DP,#@Q. I),# X,3<Z"L%? XM9&%Y;&EG:'0*P5]O=7)Z;VYE"L%?;65R:60*P5]S<PK!7VUM"L%?:&@*P5]Y XM96%R"L%?9&%Y"L%?;6]N=&@*TU]D871E8V]N=@K$\BPC,3@*P"TQU"SK"L M XM,<XL[@K-+3'.]@IJ9V4@23 P.#$Y"L#A+3$*@ K X38U-3,U"H *S$DP,#@Q XM"DDP,#@Q.#H*KPJK"L#F,L<*P"TQU"SK"L M,<XL[0K-7W)E;&9L86?V"ME) XM,# X,3D*P.$V, IM=6P@,BCO*0K$Y"CO*0IC=V0*P2TQS@K!+3'4"IP*@ K XMY#0H[RD*8W=D"IP*@ K X3,V,# *R^?N"M,N;6QI- K#[0J)"L3FZPIA9&,@ XMY>X*C0K#[@K7Y.T*<V)B(.?L"L M,=0LZPK +3'.+.X*23 P.#$Y.@K YE]R XM96QS96,*P.=?<F5L<V5C*S(*Q"TQU"SM"F%D8R M,<XL[@K!+3'."L$M,=0* XMP5]R96QM;VYT:"LR"L%?<F5L;6]N=&@*P2TQS@K!+3'4"M-?;6]N=&AA9&0* XM861D('-P+",X"G!O<"#M"HD*Q.;K"F%D8R#E[@K +3'4+.T*P"TQSBSL"LU? XM9&%Y9FQA9_8*:F4@23 P.#(S"LU?9&%T969L86?V"ME),# X,C,*P2TQS@K! XM+3'4"L%?9&%Y<F5Q"L%?9&%Y;W)D"M-?9&%Y8V]N=@K$\BPC. K +3(R*/$I XM+.L*P"TR,"CQ*2SN"L#D+3(R*/$I"L#F+3(P*/$I"L0M,=0LZPIA9&,@+3'. XM+.T*23 P.#(S.@K!+3'."L$M,=0*23 P.#$Z"HT*P^X*S"YD<X$*R5]Y>65R XM<F]R"E]Y>65R<F]R.@J#"H(*S"YC@0K)7WEY97AC80JN"E]Y>65X8V$Z"L(M XM,0K",0JX"L(M,0K"+3(*R5]Y>6%C= JX"E]Y>6%C=#H*PC$R"L(Q,PK",C$* XMPCD*PC$T"L(Q-0K",38*PC$P"L(Q,0K",S0*PC$W"L(S.0K"-# *PC$Y"L(S XM. K",S<*PC,V"L(S, K",CD*PC(X"L(R-@K",S4*PC,Q"L(R-PK". K"-PK" XM-@K"-0K"- K",PK",@K",0JX"K@*N JX"K@*N JX"K@*N JX"K@*N JX"K@* XMN JX"K@*N JX"K@*N JX"K@*N JX"K@*N JX"BYW;W)D(# *+G=O<F0@, JX XM"K@*N JX"K@*N JX"K@*N JX"K@*N JX"K@*N JX"K@*N JX"K@*N JX"K@* XMN JX"K@*N JX"K@*N JX"K@*N JX"K@*N JX"K@*N JX"K@*N JX"K@*N JX XM"K@*N JX"K@*N JX"K@*N JX"K@*N JX"K@*N JX"K@*N JX"K@*N JX"K@* XMN JX"K@*N JX"K@*N JX"K@*N JX"K@*N JX"K@*N JX"K@*N JX"K@*N JX XM"K@*N JX"K@*N JX"K@*N JX"K@*N JX"K@*N JX"K@*N JX"K@*N JX"K@* XMN JX"K@*N JX"K@*N JX"K@*N JX"K@*N HN=V]R9" P"BYW;W)D(# *N JX XM"K@*N JX"K@*N JX"K@*N JX"K@*N JX"K@*N JX"K@*N JX"K@*PC,R"L(S XM,PK",C(*PC(P"L(Q. JX"L(R,PK",C0*R5]Y>7!A8W0*PC(U"E]Y>7!A8W0Z XM"L(M,3 P, K"+3(U. K"+3$P,# *PBTQ,# P"L(M,3 P, K"+3$P,# *PBTQ XM,# P"L(M,C4W"L(M,3 P, K"+30U"L(M,3 P, K"+3$P,# *PBTR-#$*PBTR XM,0K"+3$P,# *PBTQ,# P"L(M,3 P, K"+3$P,# *PBTQ,# P"L(M,C0R"L(M XM,3 P, K"+3(T,PK"+3(T- K"+3$P,# *PBTQ,# P"L(M,3 P, K"+3(R"L(M XM,3 P, K"+30Y"L(M,C8*PBTQ,# P"L(M,C0U"L(M,3 P, K"+3$P,# *PBTR XM-#8*PBTR-#<*PBTQ,# P"L(M,C0Y"L(M,3 P, K"+3$P,# *R5]Y>7!G;PK" XM+3$P,# *7WEY<&=O.@JX"L(S,0K",S *PC(Y"L(R. K",C<*PC(V"L(R-0K) XM7WEY<C$*PC(T"E]Y>7(Q.@JX"L(Q"L(Q"L(R"L(R"L(R"L(R"L(R"L(R"L(X XM"L(S"L(S"L(S"L(S"L(S"L(S"L(S"L(T"BYW;W)D(#0*+G=O<F0@-@K"-@K" XM-@K"-0K"-0K"-0K"-0K"-0K"-0K"-PK"-PK"-PK"-PK"-PK"-PK)7WEY<C(* XMPC<*7WEY<C(Z"K@*N K",@K",0K",0K",0K",0K",0K",0K",0K",@K",PK" XM- K"- K"-0K"-@K"-@K",0K",0K",0K",@K",@K",PK"-0K",@K"- K",@K" XM,PK",@K",@K",@K",0K",0K",0K)7WEY8VAK"L(R"E]Y>6-H:SH*PBTQ,# P XM"L(M,0K"+3(*PBTS"L(M- K"+34*PBTV"L(M-PK"+3@*PC(V,0K",C8U"L(R XM-C8*PC(U. K",C4Y"L(R-C(*PC(V,PK",C8T"L(R-C<*PC(V, K"-3@*PC(U XM.0K"-#<*PC(U. K",C8R"L(R-C,*PC(V- K",C8Q"L(T- K",C8Q"L(R-C$* XMPC(V,0K"-#0*PC(V, K",C8Q"L(U. K"-#<*PC(V,0K",C8Q"L(R-C$*PC(V XM, K)7WEY9&5F"L(R-C$*7WEY9&5F.@K",0K"+3(*PC(*PC,*PC0*PC4*PC8* XMPC<*PC@*PCD*PC$W"L(Q. JX"L(Q.0K",S$*PC,R"L(S,PK",S0*+G=O<F0@ XM,3 *N K",C$*N K",C8*PC(X"L(R.0K",S *PC(T"L(R, K",3$*PC(R"L(R XM-PJX"L(Q,@K",3,*N JX"L(R-0K",30*PC(S"L(Q-0K)7WEY8VAA<@K",38* XM7WEY8VAA<CH*R5]Y>6YE<G)S"L(M,0I?>7EN97)R<SH*R5]Y>65R<F9L86<* XMN I?>7EE<G)F;&%G.@K)7WEY<&%R<V4*N J&"E]Y>7!A<G-E.@J#"H(*U_(L XM(S,Q-@K![PK!\ JN"E\Q-#0Z"L)),#!!,S,*N K",PK"23 P03,W"L)),#!! XM,T$*PDDP,$$S00K"23 P030T"E\Q-#4Z"L)),#!!,@K",PK",S$*PDDP,$$T XM10K"23 P031&"L)),#!!-3 *PDDP,$$U,0K"23 P034R"L)),#!!,@K"23 P XM034S"L)),#!!-3D*PDDP,$$U00K"23 P035""L)),#!!-4,*PDDP,$$U1 K" XM23 P035%"L)),#!!-48*PDDP,$$V, K"23 P038Q"L)),#!!-C(*PDDP,$$V XM,PK"23 P038T"L)),#!!-C4*PDDP,$$V-@K"23 P038W"L)),#!!-C@*PDDP XM,$$V.0K"23 P039!"L)),#!!-D(*PDDP,$$V0PK"23 P039$"L)),#!!-D4* XMPDDP,$$V1@K"23 P03<P"L)),#!!-S$*A@K +3,PU/8*P%]Y>6-H87(L(RTQ XM"L!?>7EN97)R<_8*P%]Y>65R<F9L86?V"MOD+3,P,BCQ*0IM;W8@+3,Q,"AB XM<"DLZPK +3,QQ2PC7WEY=BTR"DDP,$$R.@K$+3,Q,"CQ*2PC,@K;Y# H\2D* XMS2TS,3 H\2DLZPIJ8F4@23 P030*P.%?,30R"H *TU]Y>65R<F]R"HD*CPJ XM"LQ),#!!,0I),#!!-#H*P.0M,S#4"L#E+3,Q,"CQ*0JP"L0M,S'%+",R"L#F XM7WEY=F%L"L#E+3,QQ0K QRSM"DDP,$$V.@K Y2TS,-0*<V%L(.(Q"L#I7WEY XM<&%C=,<*S>DC+3$P,# *:F<@23 P03@*S$DP,$%!"DDP,$$X.@K-7WEY8VAA XM<O8*:F=E($DP,$%#"M-?>7EL97@*P%]Y>6-H87(LZPK-7WEY8VAA<O8*:F=E XM($DP,$%#"L!?>7EC:&%R]@I),#!!0SH*Q.E?>7EC:&%R"F]R(.GP"FIL($DP XM,$%!"LWI(S(R, IJ;"!),#!!,3(*S$DP,$%!"DDP,$$Q,CH*P.7P"G-A;"#B XM,0K Z5]Y>6%C=,<*P.7P"G-A;"#B,0K YE]Y>6-H87(*S5]Y>6-H:\<L[0K9 XM23 P04$*P%]Y>6-H87(L(RTQ"L#F7WEY;'9A; K 7WEY=F%L+.T*P"TS,-0L XM\ K-7WEY97)R9FQA9_8*:FQE($DP,$$R"O-?>7EE<G)F;&%G"LQ),#!!,@I) XM,#!!03H*P.4M,S#4"G-A;"#B,0K Z5]Y>61E9L<*S>DC+3(*V4DP,$$Q0PK- XM7WEY8VAA<O8*:F=E($DP,$$Q1@K37WEY;&5X"L!?>7EC:&%R+.L*S5]Y>6-H XM87+V"FIG92!),#!!,48*P%]Y>6-H87+V"DDP,$$Q1CH*P"TS,<XL(U]Y>65X XM8V$*23 P03(W.@K Y2TS,<X*S<<L(RTQ"ME),#!!,C4*P.4M,S'."L!A>"PM XM,S X*&)P*0IC;7 @,L<LZPIJ92!),#!!,D$*23 P03(U.@K$+3,QSBPC- K, XM23 P03(W"DDP,$$R03H*Q"TS,<XL(S0*P.4M,S'."LW']@IJ;"!),#!!,CD* XMP.4M,S'."L#F7WEY8VAA<@K-QRSM"ME),#!!,D$*23 P03(Y.@K Y2TS,<X* XMP.DRQPIO<B#I\ IJ9V4@23 P03%#"H<*@ K,23 P03$*23 P03%#.@IO<B#I XM\ K923 P03,S"L%?>7EE<G)F;&%G"LQ),#!!,S4*23 P03,W.@K X5\Q-#,* XM@ K37WEY97)R;W(*B0K<7WEY;F5R<G,*23 P03-!.@K 7WEY97)R9FQA9RPC XM,PI),#!!,T,Z"MOD+3,P,"CQ*0K-+3,Q,"CQ*2SK"FIB($DP,$$T,PK Y2TS XM,3 H\2D*P.7'"G-A;"#B,0K Y%]Y>7!A8W3'"L3A,C4V"L#IZPIO<B#I\ IJ XM;"!),#!!,T8*S>DC,C(P"FIG92!),#!!,T8*P.7P"G-A;"#B,0K Y5]Y>6%C XM=,<*<V%L(.(Q"LU?>7EC:&O'+",R-38*V4DP,$$S1@K Y? *<V%L(.(Q"L#D XM7WEY86-TQPK +3,PU"SK"LQ),#!!,@I),#!!,T8Z"L#E+3,Q,"CQ*0K Y<<* XM<V%L(.(Q"L#I7WEY<&%C=,<*Q"TS,3 H\2DL(RTR"L0M,S'%+",M,@K,23 P XM03-#"DDP,$$T,SH*CPJ "LQ),#!!,0I),#!!-#0Z"LU?>7EC:&%R]@K923 P XM030V"LQ),#!!-#,*23 P030V.@K 7WEY8VAA<BPC+3$*S$DP,$$V"DDP,$$S XM-3H*P.)?,30T"HT*S"YC<V$R"DDP,$$S,SH*P.7P"G-A;"#B,0K 8G@L7WEY XM<C(H8G@I"G-A;"#B,0KT[ K$Y2TS,3 H\2D*P"TS,3 H\2DL[ K Z"TS,<4* XMP.7P"G-A;"#B,0K Y5]Y>7(RQPIS86P@XC$*].P*Q.4M,S'%"L M,S'%+.P* XMP.4M,S'%"L#F,L<*P%]Y>79A;"SM"L M,S#%+/ *P.7P"G-A;"#B,0K Z5]Y XM>7(QQPK Y? *<V%L(.(Q"L%?>7EP9V_'"L#E+3,Q,"CQ*0J-"L3DQPK<ZPK XM+3,P,BCQ*2SK"LTM,S R*/$I+",R,C *:F=E($DP,$$T. K Y2TS,#(H\2D* XM<V%L(.(Q"L#D7WEY86-TQPK +3,PU"SK"L#E+3,PU IS86P@XC$*P.3P"O3K XM"LU?>7EC:&O'+.L*:F4@23 P030Y"DDP,$$T.#H*P.7P"G-A;"#B,0K Y5]Y XM>7!G;\<*<V%L(.(Q"L#D7WEY86-TQPK +3,PU"SK"DDP,$$T.3H*P2TS,,4* XMS$DP,$$T0PI),#!!-$4Z"MQ?=&EM969L86<*S$DP,$$R"DDP,$$T1CH*W%]Z XM;VYE9FQA9PK,23 P03(*23 P034P.@K<7V1A=&5F;&%G"LQ),#!!,@I),#!! XM-3$Z"MQ?9&%Y9FQA9PK,23 P03(*23 P034R.@K<7W)E;&9L86<*S$DP,$$R XM"DDP,$$U,SH*S5]T:6UE9FQA9_8*:F4@23 P034U"LU?9&%T969L86?V"FIE XM($DP,$$U-0K-7W)E;&9L86?V"ME),#!!-34*P.8H[RD*P%]Y96%R+.T*S$DP XM,$$R"DDP,$$U-3H*W%]T:6UE9FQA9PK XS$P, K Y"CO*0IC=V0*:?!V(.T* XMP%]H:"SK"L#D*.\I"F-W9 II\'8@[0K 7VUM+.X*;6]V(%]S<RPC, IM;W8@ XM7VUE<FED+",R- K,23 P03(*23 P034Y.@K YBTR*.\I"L!?:&@L[0K 7VUM XM]@K 7W-S]@K YBCO*0K 7VUE<FED+.T*S$DP,$$R"DDP,$$U03H*P.8M-"CO XM*0K 7VAH+.T*P.8H[RD*P%]M;2SM"L!?;65R:60L(S(T"LQ),#!!,@I),#!! XM-4(Z"L#F+38H[RD*P%]H:"SM"L#F+3(H[RD*P%]M;2SM"L#F*.\I"L!?;65R XM:60L[0K,23 P03(*23 P035#.@K YBTV*.\I"L!?:&@L[0K YBTR*.\I"L!? XM;6TL[0K 7VUE<FED+",R- K 7V1A>6QI9VAT+",R"L#C,3 P"L#D*.\I"F-W XM9 II\'8@[0K XC8P"FUU;"#L"H *P.0H[RD*8W=D"FGP=B#M"L/M"L3F[@KT XM[0K 7V]U<GIO;F4L[0K,23 P03(*23 P035$.@K YBTX*.\I"L!?:&@L[0K XMYBTT*.\I"L!?;6TL[0K YBCO*0K 7W-S+.T*P%]M97)I9"PC,C0*S$DP,$$R XM"DDP,$$U13H*P.8M,3 H[RD*P%]H:"SM"L#F+38H[RD*P%]M;2SM"L#F+3(H XM[RD*P%]S<RSM"L#F*.\I"L!?;65R:60L[0K,23 P03(*23 P035&.@K YBTQ XM,"CO*0K 7VAH+.T*P.8M-BCO*0K 7VUM+.T*P.8M,BCO*0K 7W-S+.T*P%]M XM97)I9"PC,C0*P%]D87EL:6=H="PC,@K XS$P, K Y"CO*0IC=V0*:?!V(.T* XMP.(V, IM=6P@[ J "L#D*.\I"F-W9 II\'8@[0K#[0K$YNX*].T*P%]O=7)Z XM;VYE+.T*S$DP,$$R"DDP,$$V,#H*P.8H[RD*;6]V(%]O=7)Z;VYE+.T*P%]D XM87EL:6=H="PC,@K,23 P03(*23 P038Q.@K YBCO*0K 7V]U<GIO;F4L[0K XM7V1A>6QI9VAT+",Q"LQ),#!!,@I),#!!-C(Z"L!?9&%Y;W)D+",Q"L#F*.\I XM"L!?9&%Y<F5Q+.T*S$DP,$$R"DDP,$$V,SH*P%]D87EO<F0L(S$*P.8M,BCO XM*0K 7V1A>7)E<2SM"LQ),#!!,@I),#!!-C0Z"L#F+3(H[RD*P%]D87EO<F0L XM[0K YBCO*0K 7V1A>7)E<2SM"LQ),#!!,@I),#!!-C4Z"L#F+30H[RD*P%]M XM;VYT:"SM"L#F*.\I"L!?9&%Y+.T*S$DP,$$R"DDP,$$V-CH*P.8M."CO*0K XM7VUO;G1H+.T*P.8M-"CO*0K 7V1A>2SM"L#F*.\I"L!?>65A<BSM"LQ),#!! XM,@I),#!!-C<Z"L#F+3(H[RD*P%]M;VYT:"SM"L#F*.\I"L!?9&%Y+.T*S$DP XM,$$R"DDP,$$V.#H*P.8M-BCO*0K 7VUO;G1H+.T*P.8M-"CO*0K 7V1A>2SM XM"L#F*.\I"L!?>65A<BSM"LQ),#!!,@I),#!!-CDZ"L#F*.\I"L!?;6]N=&@L XM[0K YBTR*.\I"L!?9&%Y+.T*S$DP,$$R"DDP,$$V03H*P.8M,BCO*0K 7VUO XM;G1H+.T*P.8M-"CO*0K 7V1A>2SM"L#F*.\I"L!?>65A<BSM"LQ),#!!,@I) XM,#!!-D(Z"L#D+3(H[RD*8W=D"L%?<F5L<V5C*S(*P5]R96QS96,*G J "L#A XM-C *R^?N"M,N;6QI- J<"H *P.0H[RD*8W=D"M,N;6QI- K#[0J)"L3FZPIA XM9&,@Y>X*P%]R96QS96,L[0K 7W)E;'-E8RLR+.P*S$DP,$$R"DDP,$$V0SH* XM;6]V(&%X+"CO*0IM=6P@+3(H[RD*8W=D"L3D7W)E;&UO;G1H"F%D8R#G7W)E XM;&UO;G1H*S(*P%]R96QM;VYT:"SK"L!?<F5L;6]N=&@K,BSN"LQ),#!!,@I) XM,#!!-D0Z"L#D+3(H[RD*8W=D"L3D7W)E;'-E8PIA9&,@YU]R96QS96,K,@K XM7W)E;'-E8RSK"L!?<F5L<V5C*S(L[@K,23 P03(*23 P039%.@K Y"CO*0IC XM=V0*P5]R96QS96,K,@K!7W)E;'-E8PJ<"H *P.$V, K+Y^X*TRYM;&DT"L/M XM"HD*Q.;K"F%D8R#E[@K 7W)E;'-E8RSM"L!?<F5L<V5C*S(L[ K,23 P03(* XM23 P039&.@K Y"CO*0IC=V0*Q.1?<F5L;6]N=&@*861C(.=?<F5L;6]N=&@K XM,@K 7W)E;&UO;G1H+.L*P%]R96QM;VYT:"LR+.X*S$DP,$$R"DDP,$$W,#H* XMQ%]R96QS96,L(S$*861C(%]R96QS96,K,O8*S$DP,$$R"DDP,$$W,3H*]%]R XM96QS96,*]%]R96QS96,K,@IS8F(@7W)E;'-E8RLR]@KT7W)E;&UO;G1H"O1? XM<F5L;6]N=&@K,@IS8F(@7W)E;&UO;G1H*S+V"LQ),#!!,@I),#!!-$,Z"L#B XM7S$T-0J-"LPN8W-A,@I),#!!,3H*C0K,+F1S@0K)7WEY=@JS"E]Y>78Z("YZ XM97)O=R S,# O,@I?;'!T<CH@+GIE<F]W(#(O,@K)7WEY=F%L"E]Y>79A;#H@ XM+GIE<F]W(#(O,@K)7WEY;'9A; I?>7EL=F%L.B N>F5R;W<@,B\R"E]O=7)Z XM;VYE.B N>F5R;W<@,B\R"E]Y96%R.B N>F5R;W<@,B\R"E]D87DZ("YZ97)O XM=R R+S(*7VUO;G1H.B N>F5R;W<@,B\R"E]D87ER97$Z("YZ97)O=R R+S(* XM7V1A>6]R9#H@+GIE<F]W(#(O,@I?9&%Y;&EG:'0Z("YZ97)O=R R+S(*7VUE XM<FED.B N>F5R;W<@,B\R"E]S<SH@+GIE<F]W(#(O,@I?;6TZ("YZ97)O=R R XM+S(*7VAH.B N>F5R;W<@,B\R"E]R96QM;VYT:#H@+GIE<F]W(#0O,@I?<F5L XM<V5C.B N>F5R;W<@-"\R"E]R96QF;&%G.B N>F5R;W<@,B\R"E]D87EF;&%G XM.B N>F5R;W<@,B\R"E]D871E9FQA9SH@+GIE<F]W(#(O,@I?>F]N969L86<Z XM("YZ97)O=R R+S(*7W1I;65F;&%G.B N>F5R;W<@,B\R"JX*7S(Z"L(R-#DS XM. K",S P-C(*PC(Y,C@Q"L(Q,C$*7S,Z"L(R-3DU. K",CDR.#(*PC(T.30Y XM"L(S,3 Y, JX"E\T.@K",C0Y-#$*PC(U-#4X"L(Q,#0*7S4Z"L(R.#<V.0K" XM,C8Y.30*PC$P. I?-CH*PC(T.30Q"L(Q,C$*7S<Z"L(S,# U. K",C4Y-C8* XMN I?.#H*PC,P,#4X"L(S,3 X- JX"E\Y.@K",S P-#D*PC,P,#4U"L(R.3@Q XM,0JX"E\Q,#H*PC(U.3<Q"L(R.3@P. K",C@P,#4*PC(U.34T"L(Q,30*7S$Q XM.@K",C4Y-S$*PC(Y.# X"K@*7S$R.@K",C4T-34*PC(X-3,R"L(R-3DU- K" XM,3$T"E\Q,SH*PC(X-3(V"L(R-3DW- K",C4Q.3<*PC(Y,C@U"K@*7S$T.@K" XM,C4Y-38*PC(U.34U"L(R-3$Y-PK",CDR.#4*N I?,34Z"L(S,# V-PJ_,3 * XMPC,Q,#<S"K@*7S$V.@K",C@U,C4*OS$P"L(S,3 W,PJX"E\Q-SH*PC,P,#8X XM"L(R.34T,0K",C0Y,S(*PC$R,0I?,3@Z"L(S,# V. K",CDU-#$*N I?,3DZ XM"L(R-3DW-0K",C@R-C *PC(Y-30Q"L(R-#DS,@HN=V]R9" Q,C$*7S(P.@K" XM,C4Y-S4*PC(X,C8P"L(R.34T,0JX"E\R,3H*PC(V-S0P"L(R.3,P,0J_,34* XMPC,Q,#<S"K@*7S(R.@K",C8W-# *PC(Y,S Q"K@*7S(S.@K",C8W-# *PC(Y XM,S Q"L(Q,34*7S(T.@K",CDR.#8*OS U"L(S,3 W,PJX"E\R-3H*PC(T.30W XM"L(S,# V. J_,30*PC,Q,#<S"K@*7S(V.@K",3$X-S,*PC$Q.#@U"K@*7S(W XM.@K",C@P,#$*N I?,C@Z"L(Q,3@X. K",3$X.#4*N I?,CDZ"L(R.# Q-@JX XM"E\S,#H*PC(Y-34P"L(Q,38*7S,Q.@K",3$X.#8*PC$Q.#DQ"L(Q,3@Y,@JX XM"E\S,CH*PC(Y-3,W"L(Q,38*7S,S.@K",3$X-S,*PC$Q.#DQ"L(Q,3@Y,@JX XM"E\S-#H*PC(U-CDW"L(Q,38*7S,U.@K",3$X-S,*PC$Q.#<V"L(Q,3@Y,@JX XM"E\S-CH*PC(Y-30Q"L(Q,38*7S,W.@K",3$X-S<*PC$Q.#DQ"L(Q,3@Y,@JX XM"E\S.#H*OS Q"L(Q,38*7S,Y.@K",3$X-S<*PC$Q.#<V"L(Q,3@Y,@JX"E\T XM,#H*PC(Y-3,Y"L(Q,38*7S0Q.@K",3$X-S4*PC$Q.#DQ"L(Q,3@Y,@JX"E\T XM,CH*PC(U-CDY"L(Q,38*7S0S.@K",3$X-S4*PC$Q.#<V"L(Q,3@Y,@JX"E\T XM-#H*PC(Y-30Y"L(Q,38*7S0U.@K",3$X.#4*PC$Q.#DQ"L(Q,3@Y,@HN=V]R XM9" P"E\T-CH*OS Y"L(Q,38*7S0W.@K",3$X.#4*PC$Q.#<V"L(Q,3@Y,@JX XM"E\T.#H*PC(Y-34R"L(Q,38*7S0Y.@K",3$X.#@*PC$Q.#DQ"L(Q,3@Y,@JX XM"E\U,#H*OS$R"L(Q,38*7S4Q.@K",3$X.#@*PC$Q.#<V"L(Q,3@Y,@JX"E\U XM,CH*PC(Y-38Q"L(Q,38*7S4S.@K",3$X.3<*PC$Q.#DQ"L(Q,3@Y,@JX"E\U XM-#H*OS(Q"L(Q,38*7S4U.@K",3$X.3<*PC$Q.#<V"L(Q,3@Y,@JX"E\U-CH* XMPC(Y-30T"L(Q,38*7S4W.@K",3$X.# *PC$Q.#DQ"L(Q,3@Y,@JX"E\U.#H* XMOS T"L(Q,38*7S4Y.@K",3$X.# *PC$Q.#<V"L(Q,3@Y,@JX"E\V,#H*PC(X XM,# W"L(Q,38*7S8Q.@K",3$X-SD*PC$Q.#@U"L(Q,3@Y,@JX"E\V,CH*PC(Y XM-3,X"L(Q,38*7S8S.@K",3$X-S0*PC$Q.#DQ"L(Q,3@Y,@JX"E\V-#H*PC(U XM.34W"L(Q,38*7S8U.@K",3$X-S<*PC$Q.#<W"L(Q,3@Y,@JX"E\V-CH*PC(U XM.34W"L(R.3@Q,0JX"E\V-SH*PC$Q.#<W"L(Q,3@W-PK",3$X.3$*PC$Q.#DR XM"K@*7S8X.@K",C4Y-C4*PC$Q-@I?-CDZ"L(Q,3@X-0K",3$X-S<*PC$Q.#DR XM"K@*7S<P.@K",C4Y-C4*PC(Y.#$Q"K@*7S<Q.@K",3$X.#4*PC$Q.#<W"L(Q XM,3@Y,0HN=V]R9" Q,3@Y,@JX"E\W,CH*PC(U.3<U"L(Q,38*7S<S.@K",3$X XM.34*PC$Q.#<W"L(Q,3@Y,@JX"E\W-#H*PC(U.3<U"L(R.3@Q,0JX"E\W-3H* XMPC$Q.#DU"L(Q,3@W-PK",3$X.3$*PC$Q.#DR"K@*7S<V.@K",CDU-#8*PC$Q XM-@I?-S<Z"L(Q,3@X,@K",3$X.3$*PC$Q.#DR"K@*7S<X.@K",C4Y-3,*PC(Y XM.#$Q"K@*7S<Y.@K",3$X-S,*PC$Q.#<W"L(Q,3@Y,0K",3$X.3(*N I?.# Z XM"L(R-3DU,PK",CDU-34*PC$Q-@I?.#$Z"L(Q,3@W,PK",3$X-S<*PC$Q.#DQ XM"L(Q,3@Y,0K",3$X.3(*N I?.#(Z"L(R-30T,0K",CDX,3$*N I?.#,Z"L(Q XM,3@W,PK",3$X-S4*PC$Q.#DQ"L(Q,3@Y,@JX"E\X-#H*PC(U-#0Q"L(R.34U XM-0K",3$V"E\X-3H*PC$Q.#<S"L(Q,3@W-0K",3$X.3$*PC$Q.#DQ"L(Q,3@Y XM,@JX"E\X-CH*PC,P-38Q"L(R.3@Q,0JX"E\X-SH*PC$Q.#<S"L(Q,3@Y-0K" XM,3$X.3$*PC$Q.#DR"K@*7S@X.@K",C4Y-S<*PC(Y,C@Q"K@*7S@Y.@K",C@U XM,C4*PC(Y.# V"L(Q,#0*7SDP.@K",C@U,3@*PC(Y.#$P"L(R-CDY, K",C8W XM,C<*PC$Q-@I?.3$Z"L(R-3DW-0K",C<T.3,*N I?.3(Z"L(R-#DS,@K",3(Q XM"E\Y,SH*PC(X-3(P"L(R.3,P,0HN=V]R9" P"E\Y-#H*+G=O<F0@,C8Y.#D* XMPC,P,#8R"L(R-3DW,@JX"E\Y-3H*PC(V.3@Y"L(Q,3 *7SDV.@K",C4Y-S$* XMPC(X-3$U"K\Q, JX"E\Y-SH*PC(U.3<Q"L(Y.0I?.3@Z"L(R.#4S,@K",C@U XM,C4*PC(Y,CDX"L(S,#4W-0JX"E\Y.3H*PC(U.3<W"L(R.3@Q,0K",CDR.#4* XMPC(T.3,R"L(Q,C$*7S$P,#H*PC(X-3,R"L(R-#DS,@K",3(Q"E\Q,#$Z"L(R XM.#4R-@K",3$Y"E\Q,#(Z"L(R-#DT, K",CDX,3$*N I?,3 S.@K",C8W-# * XMPC(Y-30U"K@*7S$P-#H*PC(U.38V"L(R.3@Q-@JX"E\Q,#4Z"L(R-CDX,@K" XM,CDU-30*PC$Q-@I?,3 V.@K",C8W-# *PC(Y,C@Y"L(Q,# *7S$P-SH*PC(X XM-3$X"L(R.3,P,0K",C8W-# *N I?,3 X.@K",C8Y.#(*PC(Y-SDX"L(Q,#0* XM7S$P.3H*PC(V.3DU"L(R.3@Q-@K",3 T"E\Q,3 Z"L(R-3DW,0K",C4Y-S0* XMPC(Y.# V"L(Q,#0*7S$Q,3H*PC(V.3@Q"L(R.3<Y.0K",3 T"E\Q,3(Z"L(R XM-CDY, K",CDX,#8*PC$P- I?,3$S.@K",C4Y-S(*PC(Y.# V"L(Q,#0*7S$Q XM-#H*PC(W-S0Y"L(S,#,P.0K",C@R-C$*PC(V-S0P"K@*7S$Q-3H*PC,P-3@P XM"L(R-S<T.0K",CDW.3@*PC$P- I?,3$V.@K",C8T-C4*PC$Q,0I?,3$W.@K" XM.3<*7S$Q.#H*PCDX"E\Q,3DZ"BYW;W)D(#DY"E\Q,C Z"L(Q,# *7S$R,3H* XMPC$P,0I?,3(R.@K",3 R"E\Q,C,Z"L(Q,#,*7S$R-#H*PC$P- I?,3(U.@K" XM,3 U"E\Q,C8Z"L(Q,#<*7S$R-SH*PC$P. I?,3(X.@K",3 Y"E\Q,CDZ"L(Q XM,3 *7S$S,#H*PC$Q,0I?,3,Q.@K",3$R"E\Q,S(Z"L(Q,3,*7S$S,SH*PC$Q XM- I?,3,T.@K",3$U"E\Q,S4Z"L(Q,38*7S$S-CH*PC$Q-PI?,3,W.@K",3$X XM"E\Q,S@Z"L(Q,3D*7S$S.3H*PC$R, I?,30P.@K",3(Q"E\Q-#$Z"L(Q,C(* XM7S$T,CH*PC(T.34S"L(R-30T,PK",CDT-S(*PC(T.30X"L(R-S0Y,0K",C@T XM-#@*PC(U.3<T"L(R-C(R-@K",C@U,C0*PC$Q.0I?,30S.@K",S$P.3$*PC(Y XM.# V"L(S,#@Q-PK",C4X.#@*PC(Y,CDX"L(R.3(Y-0HN=V]R9" P"BYT97AT X!"C V X Xend END_OF_FILE if test 26072 -ne `wc -c <'getdate.s.uu'`; then echo shar: \"'getdate.s.uu'\" unpacked with wrong size! fi # end of 'getdate.s.uu' fi echo shar: End of shell archive. exit 0 -- "Zeta Microcomputer Software" ACSnet: nick@ultima.cs.uts.oz UUCP: ...!uunet!munnari!ultima.cs.uts.oz!nick Fidonet: Nick Andrew on 3:713/602 (Zeta)
nick@ultima.cs.uts.oz (Nick Andrew) (12/07/89)
#! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of shell archive." # Contents: control.c readr.c # Wrapped by nick@nswitgould on Thu Dec 7 22:40:20 1989 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'control.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'control.c'\" else echo shar: Extracting \"'control.c'\" \(26215 characters\) sed "s/^X//" >'control.c' <<'END_OF_FILE' X/* X * This software is Copyright (c) 1986 by Rick Adams. X * X * Permission is hereby granted to copy, reproduce, redistribute or X * otherwise use this software as long as: there is no monetary X * profit gained specifically from the use or reproduction or this X * software, it is not sold, rented, traded or otherwise marketed, and X * this copyright notice is included prominently in any copy X * made. X * X * The author make no claims as to the fitness or correctness of X * this software for any use whatsoever, and it is provided as is. X * Any use of this software is at the user's own risk. X * X * Control message handling code. Deal with messages which are to be X * acted on by netnews itself rather than by people. X * X * See defs.h "news_version" for the real version of netnews. X */ X X#ifdef SCCSID Xstatic char *SccsId = "@(#)control.c 2.54 4/10/87"; X#endif /* SCCSID */ X X#include "iparams.h" X X#define eq(msg) (msg[0] == cargv[0][0] && strcmp(msg, cargv[0]) == 0) X Xint cargc; Xchar **cargv; X XFILE *hfopen(); XFILE *popen(), *mhopen(), *mailhdr(); X X#define NCARGS 30 Xchar *senderof(); X#ifdef u370 Xstatic struct hbuf htmp; X#endif /* u370 */ X X/* X * The global structure is initialized to NOTIFY as the default (if defined) X * uid to send mail to for every state. The following conditions are X * dealt with (assumes NOTIFY defined): X * X * 1) LIB/notify exists and is empty (or contains no recognizable control X * message types). X * Action: force TELLME = ""; X * 2) LIB/notify contains the control message name "all" and no associated X * address. X * Action: force TELLME = ""; X * 3) LIB/notify contains the control message name "all" and has an address. X * Action: set TELLME = AlloCpy(address); X * 4) LIB/notify contains only some of the known control message types. X * Action: initialize all addresses to "" and set declared addresses X * to listed address. X */ X X Xcontrol(h) Xstruct hbuf *h; X{ X register char *ctlmsgtext; X register struct msgtype *mp; X X if (strncmp(h->title, "cmsg ", 5) == 0) { X register char *cp1, *cp2; X cp1 = h->title; X cp2 = h->title + 5; X while (*cp1++ = *cp2++) X ; X } X X if (*h->ctlmsg) X ctlmsgtext = h->ctlmsg; X else X ctlmsgtext = h->title; X log("Ctl Msg %s from %s: %s", h->nbuf, h->path, ctlmsgtext); X /* X * Control messages have the standard format X * command [args] X * much like shell commands. Each site has the option X * of customizing this code to deal with control messages X * as they see fit, but we would like to buy back the X * code, ifdeffed or otherwise parameterized, to simplify X * the maintenence issues. X */ X argparse(ctlmsgtext); X X /* X * We look for a match of the control message name and then X * set TELLME to the value parsed from the LIB/notify file X * (if any). X */ X for(mp=msgtype; mp->m_name; mp++) { X if(eq(mp->m_name) ) { /* hit */ X#ifdef NOTIFY X TELLME = mp->m_who_to; /* reset whom to tell */ X#endif /* NOTIFY */ X return (*mp->m_func)(cargc, cargv); /* do it */ X } X } X if( !mp->m_name ) { X#ifdef NOTIFY X TELLME = NOTIFY; X#endif /* NOTIFY */ X c_unknown(h, ctlmsgtext); X } X return 0; X} X X/* X * Parse the string str into separate words in cargc and cargv X * as per the usual UNIX convention. Nothing fancy here, just X * blanks and tabs separating words. X */ Xargparse(str) Xchar *str; X{ X static char *cavpbuf[NCARGS]; X static char cavbuf[256]; X char *nextfree = cavbuf; X X if (str == '\0') X error("Control message %s has no title", header.ident); X cargc = (*str != '\0'); X cargv = cavpbuf; X cargv[0] = cavbuf; X X while (*str) { X if (*str <= ' ') { X /* skip over white space */ X while (*str != '\0' && *str <= ' ') X str++; X if (*str == '\0') /* line ends in white space */ X return; X *nextfree++ = 0; X cargv[cargc] = nextfree; X if (cargc++ >= NCARGS) X xerror("Too many arguments to control message %s", X header.ident); X } else X *nextfree++ = *str++; X } X} X X/* X * ihave <artid> ... <remotesys> X * or X * ihave <remotesys> X * with <artid>s in message body. X * X * The other system is telling you it has article <artid>, in case X * you decide you want it to transmit it to you. X * The assumption is that the other system only tells you about articles X * in newsgroups you subscribe to. X * X * We turn the incoming ihave into an outgoing sendme on the fly. X * It then gets saved in the SPOOL directory and transmitted to the X * remote system. (This way the sendme messages can be batched.) X */ Xc_ihave(argc, argv) Xregister char ** argv; X{ X register int i; X char list[sizeof header.title]; X extern char * findhist(); X extern char * mydomain(); X X if (argc < 2) X error("ihave: Too few arguments."); X if (strncmp(PATHSYSNAME, argv[argc - 1], SNLN) == 0) X return 0; X list[0] = '\0'; X if (argc > 2) { X for (i = 1; i < (argc - 1); ++i) X if (findhist(argv[i]) == NULL) { X (void) strcat(list, " "); X (void) strcat(list, argv[i]); X } X if (list[0] == '\0') X return 0; X } else { X register FILE * outfp; X register long outpos, inpos; X char myid[256]; X X outfp = xfopen(INFILE, "a"); X outpos = ftell(outfp); X inpos = ftell(infp); X while (ftell(infp) < outpos) { X if (fgets(myid, sizeof myid, infp) != myid) X error("iline: Can't reread article"); X myid[strlen(myid) - 1] = '\0'; X if (findhist(myid) == NULL) X (void) fprintf(outfp, "%s\n", myid); X } X if (outpos == ftell(outfp)) { /* if nothing is wanted */ X (void) fclose(outfp); X (void) fseek(infp, inpos, 0); X return 0; X } X (void) fclose(outfp); X /* X ** The close and open may just be paranoia. X */ X (void) fclose(infp); X infp = xfopen(INFILE, "r"); X (void) fseek(infp, outpos, 0); X } X /* X ** Turn the ihave into a sendme. X */ X (void) sprintf(header.nbuf, "to.%s.ctl", argv[argc - 1]); X (void) sprintf(header.title, "sendme%s %s", list, PATHSYSNAME); X (void) strcpy(header.ctlmsg, header.title); X getident(&header); X (void) sprintf(header.from, "%s@%s", "usenet", FROMSYSNAME); X (void) strcpy(header.path, NEWSUSR); X header.subdate[0] = header.expdate[0] = '\0'; X dates(&header); X /* X ** What else of this kind should be done? X */ X header.organization[0] = header.distribution[0] = '\0'; X header.numlines[0] = '\0'; X for (i = 0; i < NUNREC && header.unrec[i] != NULL; ++i) { X free(header.unrec[i]); X header.unrec[i] = NULL; X } X /* X ** Note that we do *not* change the history line X ** so that if the "ihave" message comes in again it gets rejected. X */ X return 0; X} X X/* X * sendme <artid> ... <remotesys> X * or X * sendme <remotesys> X * with <artid>s in message body. X * The other system wants me to send out article <artid>. X * Give it to them with no fuss. X */ X#ifdef MULTICAST Xstatic int c_mc; Xstatic char ** c_sysnames; X#endif /* MULTICAST */ Xc_sendme(argc, argv) Xregister char **argv; X{ X struct srec srec; X X if (argc < 2) X error("sendme: Too few arguments."); X if (strncmp(PATHSYSNAME, argv[argc - 1], SNLN) == 0) X return 0; X if (s_find(&srec, argv[argc - 1]) != TRUE) X error("sendme: Can't find sys record for %s", argv[argc - 1]); X#ifdef MULTICAST X c_mc = index(srec.s_flags, 'M') != 0; X if (c_mc) { X struct srec trec; X X c_sysnames = &argv[argc - 1]; X if (s_find(&trec, srec.s_xmit) != TRUE) X error("sendme: Can't find sys record for %s for %s", X srec.s_xmit, argv[argc - 1]); X srec = trec; X } else c_sysnames = NULL; X#endif /* MULTICAST */ X /* Send the articles. */ X if (argc == 2) { X register FILE * fp; X char buf[256]; X X fp = xfopen(INFILE, "r"); X while (fgets(buf, sizeof buf, fp) == buf) { X buf[strlen(buf) - 1] = '\0'; /* zap trailing '\n' */ X sendmefunc(buf, &srec); X } X (void) fclose(fp); X } else { /* argc > 2 */ X register int i; X X for (i = 1; i < (argc - 1); ++i) X sendmefunc(argv[i], &srec); X } X return 0; X} X Xstatic Xsendmefunc(id, sp) Xregister char * id; Xregister struct srec * sp; X{ X register FILE * fp; X register char * cp; X char savedbufname[256]; X extern char firstbufname[]; X extern char * dirname(); X extern char * findfname(); X X cp = findfname(id); X if (cp == NULL) { X logerr("System %s wants unavailable article %s.", X#ifdef MULTICAST X (c_mc ? c_sysnames[0] : sp->s_name), id); X#else /* !MULTICAST */ X sp->s_name, id); X#endif /* !MULTICAST */ X return; X } X cp = dirname(cp); X fp = fopen(cp, "r"); X if (fp == NULL) { X logerr("Article %s unopenable as %s.", id, cp); X return; X } X (void) strcpy(savedbufname, firstbufname); X (void) strcpy(firstbufname, cp); X#ifdef MULTICAST X transmit(sp, fp, FALSE, c_sysnames, c_mc); X#else /* !MULTICAST */ X transmit(sp, fp, FALSE, (char **) NULL, 0); X#endif /* !MULTICAST */ X /* transmit closes fp */ X (void) strcpy(firstbufname, savedbufname); X} X X/* X * newgroup <groupname> X * A new newsgroup has been created. X * The body of the article, if present, is a description of the X * purpose of the newsgroup. X * X */ Xc_newgroup(argc, argv) Xchar **argv; X{ X FILE *fd; X char abuf[BUFLEN], subjline[BUFLEN]; X int didcreate = 0; X register char *p, *q; X# ifdef NONEWGROUPS X# ifdef ORGDISTRIB X /* local or ORGDISTRIB */ X int can_change = (strcmp(header.distribution, "local") == 0) || X (strcmp(header.distribution, ORGDISTRIB) == 0); X# else /* ! ORGDISTRIB */ X /* local only */ X int can_change = strcmp(header.distribution, "local") == 0; X# endif /* ORGDISTRIB */ X# else /* ! NONEWGROUPS */ X int can_change = 1; /* allow changes for all distributions */ X# endif /* NONEWGROUPS */ X X if (argc < 2) X error("newgroup: Too few arguments."); X X if (header.approved[0] == '\0') { X logerr("newgroup: %s not approved", argv[1]); X return 1; X } X X lock(); X /* see if it already exists */ X (void) rewind(actfp); clearerr(actfp); X while(fgets(abuf, BUFLEN, actfp) != NULL) { X p = abuf; X q = argv[1]; X while (*p++ == *q++) X ; X if (*--q == '\0' && *--p == ' ') { X int modified = 0; X /* Now check if it's correctly moderated/unmoderated */ X while (*p++) X ; X p -= 3; X if (argc > 2 && strcmp(argv[2], "moderated") == 0) { X if (*p == 'm') { X unlock(); X return 0; X } X# ifdef NONEWGROUPS X if(can_change) { X *p = 'm'; X modified = 1; X } X# else /* ! NONEWGROUPS */ X *p = 'm'; X modified = 1; X#endif /* NONEWGROUPS */ X } else { X if (*p != 'm') { X unlock(); X return 0; X } X# ifdef NONEWGROUPS X if(can_change) { X *p = 'y'; X modified = 1; X } X# else /* ! NONEWGROUPS */ X *p = 'y'; X modified = 1; X# endif /* NONEWGROUPS */ X } X# ifdef NOTIFY X (void) sprintf(subjline, X "Newsgroup %s change from %smoderated to %smoderated", X argv[1], *p=='y' ? "" : "un", X *p=='y' ? "un" : ""); X fd = mailhdr((struct hbuf *)NULL, subjline); X if (fd != NULL) { X if(modified) X fprintf(fd, X"%s has been changed from %smoderated to %smoderated as requested by\n%s\n", X argv[1], *p=='y' ? "" : "un", X *p=='y' ? "un":"", header.path); X else { X fprintf(fd, X"%s\nhas requested that %s be changed from %smoderated to %smoderated\n", X header.path, argv[1], X *p=='y' ? "" : "un", X *p=='y' ? "un" : ""); X#ifdef ORGDISTRIB X fprintf(fd, X"You can accomplish this by re-creating the newsgroup with a distribution\n"); X fprintf(fd, X"of '%s' by executing the command:\n", ORGDISTRIB); X fprintf(fd, X "%s/inews -d %s -C %s moderated\n", X LIB, ORGDISTRIB, argv[1]); X#else /* !ORGDISTRIB */ X fprintf(fd, X"You can accomplish this by re-creating the newsgroup by executing the command:\n"); X fprintf(fd, "%s/inews -C %s moderated\n", X LIB, argv[1]); X#endif /* !ORGDISTRIB */ X } X (void) mclose(fd); X } X# endif /* NOTIFY */ X# ifdef NONEWGROUPS X /* X * No permission to change X */ X if(!can_change) { X unlock(); X return 0; X } X# endif /* NONEWGROUPS */ X /* The active file was wrong about the state of the X * group. Rewrite the active file X */ X (void) fseek(actfp, -2L, 1); /* back up 2 characters */ X putc(*p, actfp); X fflush(actfp); X if (*p != 'm') X logerr("Newsgroup %s changed from moderated to unmoderated", X argv[1]); X else X logerr("Newsgroup %s changed from unmoderated to moderated", X argv[1]); X unlock(); X return 0; X } X } X X /* It doesn't already exist, we must create it */ X X if(can_change) { X didcreate++; X (void) fseek(actfp, 0L, 2); clearerr(actfp); X fprintf(actfp, "%s 00000 00001 %c\n", argv[1], X (argc > 2 && strcmp(argv[2], "moderated") == 0) X ? 'm' : 'y'); X#if defined(USG) || defined(MG1) X /* X * U G L Y K L U D G E X * This utter piece of tripe is the only way I know of X * to get around the fact that ATT BROKE standard IO X * in System 5.2. Basically, you can't open a file for X * "r+" and then try and write to it. This hack works X * on all "real" USG Unix systems, It will probably X * break on some obscure look alike that doesnt use the X * real ATT stdio.h X * also broken in WCW MG-1 42nix 2.0 X * Don't blame me, blame ATT. stdio should have X * already done the following line for us, but it didn't X */ X actfp->_flag |= _IOWRT; X#endif /* USG */ X fflush(actfp); X } X X# ifdef NOTIFY X (void) sprintf(subjline, "Newsgroup %s created", argv[1]); X fd = mailhdr((struct hbuf *)NULL, subjline); X if (fd != NULL) { X if (didcreate) X fprintf(fd, X "A new newsgroup called '%s' has been created by %s.\n", X argv[1], header.path); X else { X fprintf(fd, X "%s requested that a new newsgroup called '%s' be created.\n", X header.path, argv[1]); X fprintf(fd,"It was approved by %s\n\n",header.approved); X fprintf(fd, X "You can accomplish this by creating the newgroup yourself\n"); X# ifdef ORGDISTRIB X fprintf(fd,"with a distribution of '%s'.\n", X ORGDISTRIB); X fprintf(fd, X "In other words, by executing the command:\n"); X fprintf(fd, "%s/inews -d %s -C %s %s\n", LIB, X ORGDISTRIB, argv[1], argc > 2 ? argv[2] : ""); X# else /* !ORGDISTRIB */ X fprintf(fd, "In other words, by executing the command:\n"); X fprintf(fd, "%s/inews -C %s %s\n", LIB, argv[1], X argc > 2 ? argv[2] : ""); X# endif /* !ORGDISTRIB */ X } X (void) mclose(fd); X } X# endif /* NOTIFY */ X unlock(); X return 0; X} X X/* X * rmgroup <groupname> X * An old newsgroup is being cancelled on a network wide basis. X */ Xc_rmgroup(argc, argv) Xchar **argv; X{ X FILE *fd; X int shouldremove = 0; X#ifdef NOTIFY X char subjline[BUFLEN]; X#endif /* NOTIFY */ X X if (argc < 2) X error("rmgroup: Too few arguments."); X if (!validng(argv[1])) X return 0; X if (header.approved[0] == '\0') { X logerr("rmgroup: %s not approved", argv[1]); X return 1; X } X X#ifdef MANUALLY X#ifdef ORGDISTRIB X /* X * Allow local as well as organizational removals X */ X if (!strcmp(ORGDISTRIB, header.distribution) X || !strcmp("local", header.distribution)) X#else /* !ORGDISTRIB */ X if (!strcmp("local", header.distribution)) X#endif /* !ORGDISTRIB */ X#endif /* MANUALLY */ X shouldremove++; X#ifdef NOTIFY X sprintf(subjline, "Received rmgroup for %s", argv[1]); X fd = mailhdr((struct hbuf *)NULL, subjline); X if (fd != NULL) { X if (shouldremove) { X fprintf(fd, "Newsgroup '%s' has been removed by %s.\n\n", X argv[1], header.path); X# ifdef USG X fprintf(fd, "You may need to remove the directory %s by hand\n", X dirname(argv[1])); X# endif X } else { X fprintf(fd, "%s requested that newsgroup %s be removed.\n", X header.path, argv[1]); X fprintf(fd, "You should remove it by hand\n"); X fprintf(fd, "To do this, execute the command\n"); X fprintf(fd, "\t%s/rmgroup %s\n", LIB, argv[1]); X } X (void) mclose(fd); X } X#endif /* NOTIFY */ X X if (shouldremove) { X int pid, status; X /* We let the shell do all the work. X * See the rmgrp shell script. X */ X lock(); X (void) sprintf(bfr, "%s/rmgroup", LIB); X X if (pid = vfork()) { X status = fwait(pid); X } else { X (void) setuid(duid); X execvp(bfr, argv); X } X unlock(); X if (status) X log("rmgroup status %d", status); X } X return 0; X} X X/* X * cancel <artid> X * Cancel the named article X */ Xc_cancel(argc, argv) Xchar **argv; X{ X char *line, *p, *q, *r, *poster; X char *findhist(); X register FILE *fp; X char whatsisname[BUFLEN], nfilename[BUFLEN]; X time_t t; X int su = 0; X#ifndef u370 X struct hbuf htmp; X#endif /* !u370 */ X X if (argc < 2) X error("cancel: Too few arguments."); X (void) strcpy(whatsisname, senderof(&header)); X line = findhist(argv[1]); X if (line == NULL) { X struct tm *tm; X log("Can't cancel %s: non-existent", argv[1]); X (void) time(&t); X tm = localtime(&t); X#ifdef USG X sprintf(bfr,"%s\t%2.2d/%2.2d/%d %2.2d:%2.2d\tcancelled", X#else /* !USG */ X sprintf(bfr,"%s\t%02d/%02d/%d %02d:%02d\tcancelled", X#endif /* !USG */ X argv[1], tm->tm_mon+1, tm->tm_mday, tm->tm_year, tm->tm_hour, X tm->tm_min); X savehist(bfr); X return -1; X } X X q = index(line, '\t'); X p = index(q+1, '\t'); X if (p == NULL || *++p == '\0' || *p == '\n') { X *q = '\0'; X log("Expired article %s", line); X return -1; X } X if (strcmp(p, "cancelled") == 0) { X *q = '\0'; X log("Already Cancelled %s", line); X return -1; X } else X log("Cancelling %s", line); X if ((uid == ROOTID||uid == 0) && ( X#ifdef ORGDISTRIB X strcmp(header.distribution, ORGDISTRIB) == 0 || X#endif /* ORGDISTRIB */ X strcmp(header.distribution, "local") == 0)) X su = 1; X while (*p) { X q = index(p, ' '); X if (q) X *q = '\0'; X (void) strcpy(nfilename, dirname(p)); X fp = fopen(nfilename, "r"); X if (fp == NULL) { X log("Can't cancel %s: %s", line, errmsg(errno)); X return 1; X } X htmp.unrec[0] = NULL; X if (hread(&htmp, fp, TRUE) == NULL) { X if (bfr[0] == '/') { X fp = fopen(bfr, "r"); X if (fp == NULL X || hread(&htmp, fp, TRUE) == NULL) X error("Article is garbled."); X } else X error("Article is garbled."); X } X (void) fclose(fp); X poster = senderof(&htmp); X /* only compare up to '.' or ' ' */ X r = index(poster,'.'); X if (r == NULL) X r = index(poster,' '); X if (r != NULL) X *r = '\0'; X if (!su && strncmp(whatsisname, poster,strlen(poster))) { X error("Not contributor: posted by %s, and you are %s", poster, whatsisname); X } X X (void) unlink(nfilename); X p = q+1; X } X return 0; X} X X/* X * sendsys (no arguments) X * X * Mail the sys file to the person submitting the article. X * POLICY: the contents of your sys file are public information X * and as such, you should not change this code. You may feel X * free to arrange for it to manually notify you, in the event X * that you want to do something to clean it up before it goes out. X * Secret sites on the net are expressly frowned on. X * X * The purpose of this command is for making a network map. The X * details of your link and which newsgroups are forwarded are not X * important, in case you want to sanitize them. Since the definition X * of USENET is those sites getting net.announce, you can disable this X * on sites not getting net articles, but if you take out the list of X * forwarded newsgroups, and you have sites that only get local newsgroups, X * you should make this clear, or remove those sites from what you send out. X */ X/* ARGSUSED */ Xc_sendsys(argc, argv) Xchar **argv; X{ X register FILE *f, *u; X int c; X X#ifdef NOTIFY X f = mailhdr((struct hbuf *)NULL, "sendsys control message"); X if (f != NULL) { X fprintf(f, "%s requested your %s/sys file.\n", header.path, LIB); X fprintf(f, "It has been sent.\n"); X (void) mclose(f); X } X#endif /* NOTIFY */ X f = mailhdr(&header, "response to your sendsys request"); X u = fopen(SUBFILE, "r"); X if (f != NULL && u != NULL) { X while ((c=getc(u)) != EOF) X putc(c, f); X (void) fclose(u); X (void) mclose(f); X } X return 0; X} X X/* X * Send the version number to the right person. X */ X/* ARGSUSED */ Xc_version(argc, argv) Xchar **argv; X{ X register FILE *f; X X f = mailhdr(&header, "Our news version"); X if (f == NULL) X error("Cannot send back error message"); X fprintf(f, "Currently running news version %s.\n\n", news_version); X fprintf(f, "The header of your message follows:\n\n"); X (void) hwrite(&header, f); X (void) mclose(f); X return 0; X} X X/* X * Check the active file for old or missing newsgroups X * Body of article is list of valid groups X */ X/* ARGSUSED */ Xc_checkgroups(argc, argv) Xchar **argv; X{ X int rc; X X (void) setuid(geteuid()); X /* dont change the cat %s| to < %s, it breaks some "unix" systems */ X (void) sprintf(bfr, "cat %s | %s/checkgroups %s", INFILE, LIB, X#ifdef NOTIFY X (TELLME && *TELLME) ? TELLME : NEWSUSR ); X#else /* !NOTIFY */ X NEWSUSR); X#endif /* !NOTIFY */ X rc = system(bfr); X log("system(%s) status %d", bfr, rc); X return 0; X} X X/* X * An unknown control message has been received. X */ Xc_unknown(h, ctlmsgtext) Xstruct hbuf *h; Xchar *ctlmsgtext; X{ X register FILE *f; X X log("UNKNOWN Ctl Msg %s from %s", ctlmsgtext, h->path); X#ifdef NOTIFY X f = mailhdr((struct hbuf *)NULL, "Unrecognized Control Message"); X if (f != NULL) { X fprintf(f, "Currently running news version %s.\n\n", news_version); X fprintf(f, "The header of the message follows:\n\n"); X (void) hwrite(h, f); X (void) mclose(f); X } X#endif /* NOTIFY */ X return 0; X} X X/* ARGSUSED */ Xc_unimp(argc, argv) Xchar **argv; X{ X register FILE *f; X X#ifdef NOTIFY X f = mailhdr((struct hbuf*)NULL, "Unimplemented Control Message"); X if (f != NULL) { X fprintf(f, "Currently running news version B %s.\n\n", news_version); X fprintf(f, "The header of the message follows:\n\n"); X (void) hwrite(&header, f); X (void) mclose(f); X } X#endif /* NOTIFY */ X return 0; X} X X/* X * This is a modified version of popen, made more secure. Rather than X * forking off a shell, you get a bare process. You must have exactly X * one argument, and the command must be mail (or sendmail if you have it). X */ X#define RDR 0 X#define WTR 1 Xstatic int mopen_pid[20]; Xchar *replyname(); X XFILE * Xmhopen(hptr) Xstruct hbuf *hptr; X{ X int p[2]; X register myside, hisside, pid; X char *sendto = "usenet"; X X if (hptr) X sendto = replyname(hptr); X else { X#ifdef NOTIFY X if (TELLME) X sendto = TELLME; X#endif /* NOTIFY */ X if (sendto == NULL || *sendto == NULL) X return NULL; X } X verifyname(sendto); X if(pipe(p) < 0) X return NULL; X myside = p[WTR]; X hisside = p[RDR]; X if((pid = vfork()) == 0) { X /* myside and hisside reverse roles in child */ X (void) close(myside); X (void) close(0); X (void) dup(hisside); X (void) close(hisside); X (void) setgid(gid); X (void) setuid(uid); X#ifdef SENDMAIL X execl(SENDMAIL, "sendmail", "-oi", "-oeq", sendto, (char *)NULL); X#endif /* SENDMAIL */ X#ifdef MMDF X execl(MMDF, "inews-mail", "-smuxto,cc*", (char *)NULL); X#endif /* MMDF */ X execl("/bin/mail", "mail", sendto, (char *)NULL); X execl("/usr/bin/mail", "mail", sendto, (char *)NULL); X execl("/usr/ucb/mail", "mail", sendto, (char *)NULL); X _exit(1); X } X if(pid == -1) X return NULL; X mopen_pid[myside] = pid; X (void) close(hisside); X return(fdopen(myside, "w")); X} X Xmclose(ptr) XFILE *ptr; X{ X register f, r, (*hstat)(), (*istat)(), (*qstat)(); X int status; X X f = fileno(ptr); X (void) fclose(ptr); X istat = signal(SIGINT, SIG_IGN); X qstat = signal(SIGQUIT, SIG_IGN); X hstat = signal(SIGHUP, SIG_IGN); X while((r = wait(&status)) != mopen_pid[f] && r != -1) X ; X if(r == -1) X status = -1; X signal(SIGINT, istat); X signal(SIGQUIT, qstat); X signal(SIGHUP, hstat); X return status; X} X X/* X * mhopen a pipe to mail, write out a std header, and return the file ptr. X * X * We don't include a From: field because this is probably uucp, i.e. X * explicitly routed. Leave it up to the recipient's mailer. X * Always include the To: field because if we ge back failed mail, we X * might be able to deliver it by hand if we know to wom it was addressed. X * By convention, hptr==NULL means to send the message to the local contact person. X */ XFILE * Xmailhdr(hptr, subject) Xstruct hbuf *hptr; Xchar *subject; X{ X FILE *fp; X time_t now; X char *to = "usenet"; X extern char *mydomain(); X X#ifdef NOTIFY X if (TELLME && *TELLME) X to = TELLME; X#endif /* NOTIFY */ X if (hptr) X to = replyname(hptr); X X if ((fp = mhopen(hptr)) != NULL) { X (void) time(&now); X fprintf(fp, "Date: %s\n", arpadate(&now)); X#ifdef MMDF X fprintf(fp, "From: The News System <usenet@%s>\n", X FROMSYSNAME); X#endif /* MMDF */ X fprintf(fp, "To: %s\n", to); X fprintf(fp, "Subject: %s\n", subject); X fprintf(fp, "Responding-System: %s\n\n", LOCALSYSNAME); X } X return fp; X} X X/* X * verify that the name mail is being sent to does not contain any X * nasty hooks to invoke funny functions from the shell or the like. X */ Xverifyname(sendto) Xchar *sendto; X{ X /* Be sure we DO allow alphabetics, !, :, ., -, @. *. */ X char *nasty = "\"'\\`^|;& <>/~"; X register char *p; X X if (sendto[0] <= ' ') { X xerror("nasty mail name %s from %s", sendto, header.path); X } X for (p=sendto; *p; p++) { X if (*p == ' ') { X *p = 0; X break; X } X } X if (strpbrk(sendto, nasty) != NULL) X error("nasty mail name %s from %s", sendto, header.path); X X for (nasty = sendto; (nasty = index(nasty, '.')) != NULL; ) { X if (*++nasty == '.') /* check for .. */ X error("nasty mail name %s from %s", sendto, header.path); X } X} X X/* X * Checks to make sure the control message is OK to post. X */ Xctlcheck() X{ X char msg[BUFLEN]; X char *p; X X if (!is_ctl) X return; X X if (header.ctlmsg[0]) X (void) strcpy(msg, header.ctlmsg); X else X (void) strcpy(msg, header.title); X X p = index(msg, ' '); X if (p) X *p = 0; X X if (strcmp(msg, "ihave") == 0 || strcmp(msg, "sendbad") == 0 || X strcmp(msg, "sendme") == 0) { X return; /* no restrictions */ X } else if (strcmp(msg, "newgroup") == 0) { X suser(); X } else if (strcmp(msg, "rmgroup") == 0) { X suser(); X } else if (strcmp(msg, "sendsys") == 0) { X suser(); X } else if (strcmp(msg, "checkgroups") == 0) { X suser(); X } else if (strcmp(msg, "version") == 0) { X return; /* no restrictions */ X } else if (strcmp(msg, "cancel") == 0) { X return; /* no restrictions at this level */ X } else if (strcmp(msg, "delsub") == 0) { X if (!prefix(header.nbuf, "to.")) { X log("Must be in a 'to.system' newsgroup."); X xxit(0); X } X return; X } else { X log("Unrecognized control message - %s\n", msg); X xxit(0); X } X} X X/* Make sure this guy is special. */ Xsuser() X{ X if (uid == 0 || uid == ROOTID) X return; X /* X * We assume that since our real uid is the same as NEWSUSR X * (the euid) we were run by rootid and it did a setuid. X * Too bad we can't set just the effective uid like suid does. X */ X if (uid == geteuid()) X return; X#ifdef IHCC X printf("Please use the command:\n\ttoolnews providers\n"); X printf("then call one of the news people.\n"); X#else X printf("Get your local netnews contact to do it for you.\n"); X#endif X xxit(0); X} END_OF_FILE if test 26215 -ne `wc -c <'control.c'`; then echo shar: \"'control.c'\" unpacked with wrong size! fi # end of 'control.c' fi if test -f 'readr.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'readr.c'\" else echo shar: Extracting \"'readr.c'\" \(25018 characters\) sed "s/^X//" >'readr.c' <<'END_OF_FILE' X/* X * This software is Copyright (c) 1986 by Rick Adams. X * X * Permission is hereby granted to copy, reproduce, redistribute or X * otherwise use this software as long as: there is no monetary X * profit gained specifically from the use or reproduction or this X * software, it is not sold, rented, traded or otherwise marketed, and X * this copyright notice is included prominently in any copy X * made. X * X * The author make no claims as to the fitness or correctness of X * this software for any use whatsoever, and it is provided as is. X * Any use of this software is at the user's own risk. X * X * readr - /bin/mail and msgs interface and associated functions. X */ X X#ifdef SCCSID Xstatic char *SccsId = "@(#)readr.c 2.61 3/21/87"; X#endif /* SCCSID */ X X#include "rparams.h" X#if defined(BSD4_2) || defined(BSD4_1C) X#include <sys/dir.h> X#else X#include "ndir.h" X#endif /* !BSD4_2 && !BSD4_1C */ X#include <setjmp.h> X#include <errno.h> X Xextern int errno; X Xchar *Progname = "readnews"; /* used by xerror to identify failing program */ X Xstatic char lbuf[BUFLEN*2]; Xlong atol(); X X#define saveart oobit = bit;strcpy(ofilename1, filename);strcpy(ogroupdir, groupdir);hptr = h;h = hold;hold = hptr;ongsize = pngsize X#define NLINES(h, fp) (h->numlines[0] ? h->intnumlines : (h->intnumlines=linecnt(fp),sprintf(h->numlines, "%d", h->intnumlines), h->intnumlines)) X Xchar *tft = "/tmp/folXXXXXX"; X X/* X * These were made static for u370 with its buggy cc. X * I judged it better to have one copy with no ifdefs than X * to conditionally compile them as automatic variables X * in readr (which they originally were). Performance X * considerations might warrant moving some of the simple X * things into register variables, but I don't know what X * breaks the u370 cc. X */ Xstatic char goodone[BUFLEN]; /* last decent article */ Xstatic char ogroupdir[BUFLEN]; /* last groupdir */ Xstatic char address[PATHLEN]; /* for reply copy */ Xstatic char edcmdbuf[128]; Xstatic int rfq = 0; /* for last article */ Xstatic long ongsize; /* Previous ngsize */ Xstatic long pngsize; /* Printing ngsize */ Xstatic char *bptr; /* temp pointer. */ Xstatic struct srec srec; /* srec for sys file entries */ Xstatic char *tfilename; /* temporary file name */ Xstatic char ofilename1[BUFLEN]; /* previous file name */ Xstatic struct hbuf hbuf1, hbuf2, /* for minusing */ X *h = &hbuf1, /* current header */ X *hold = &hbuf2, /* previous header */ X *hptr; /* temporary */ Xstatic char *ptr1, *ptr2, *ptr3; /* for reply manipulation */ Xstatic int abs = FALSE; /* TRUE if we asked absolutely */ Xstatic char tf[100]; Xstatic long oobit; /* last bit, really */ Xstatic int dgest = 0; Xstatic FILE *ofp; /* Current output file to terminal*/ Xstatic FILE *fp; /* current article to be printed*/ Xstatic int holdup; /* 1 iff should stop before hdr */ Xstatic int ignorenews; /* 1 iff readnews -p > /dev/null*/ Xstatic time_t timelastsaved; /* time newsrc last written out */ Xstatic jmp_buf sigjmpbuf; /* for signal processing */ Xstatic int canlongjmp; /* TRUE if setjmp on sigjmp valid */ Xshort ospeed; /* terminal speed NOT STATIC */ X /* used in readnews.c, declared here */ X /* to match declaration in visual.c */ X Xint catchcont(); Xreadr() X{ X register char *m = getenv("MORE"); X register char *m2, cc; X X /* X * Turn of more's 'l' option, so \f kludge will work. X * This is really revolting! X */ X if (m2 = m) { X while (cc = *m++) X if (cc != 'l') X *m2++ = cc; X *m2 = '\0'; X } X X#ifdef DEBUG X fprintf(stderr, "readr()\n"); X#endif X if (aflag) { X if (*datebuf) { X if ((atime = cgtdate(datebuf)) == -1) X xerror("Cannot parse date string"); X } else X atime = 0; X } X X if (pflag && ignoring()) X ignorenews = TRUE; X X if (xflag) X uflag = 0; X if (uflag) X (void) time(&timelastsaved); X X ofp = stdout; X if (cflag && coptbuf[0] != '\0') { X (void) umask(022); X (void) mktemp(outfile); /* get "unique" file name */ X (void) close(creat(outfile,0666)); X ofp = xfopen(outfile, "w"); X (void) umask(N_UMASK); X cflag = FALSE; X pflag = TRUE; X } X X /* loop reading articles. */ X fp = NULL; X obit = -1; X nextng(); X for ( ;; ) { X if (getnextart(FALSE)) X break; X#ifdef DEBUG X fprintf(stderr,"after getnextart, fp %x, pos %ld, bit %ld, group '%s', filename '%s'\n", X fp, ftell(fp), bit, groupdir, filename); X#endif X (void) strcpy(goodone, filename); X if (pflag || lflag || eflag) { X /* This code should be gotten rid of */ X if (SigTrap) { X qfflush(ofp); X fprintf(ofp, "\n"); X cdump(ofp); X xxit(0); /* kludge! drop when qfflush works */ X return; X } X clear(bit); X nextbit(); X FCLOSE(fp); X continue; X } X for ( ;; ) { X char *pp; X int nlines; X int (*ointr)(); X#ifdef SIGCONT X int (*ocont)(); X#endif X (void) setjmp(sigjmpbuf); X canlongjmp = TRUE; X X SigTrap = FALSE; X if (!cflag) { X if (rfq) X (void) sprintf(bfr, "Last article. [qfr] "); X else { X nlines = NLINES(h, fp); X if (nlines <= 0) { X (void) sprintf(bfr, "(0 lines) Next? [nqfr] "); X FCLOSE(fp); X } else { X (void) sprintf(bfr, "(%d lines) More? [ynq] ", nlines); X } X } X } else X (void) sprintf(bfr, "? "); X fprintf(ofp, "%s", bfr); X (void) fflush(ofp); X bptr = lbuf; X ointr = signal(SIGINT, catchcont); X#ifdef SIGCONT X ocont = signal(SIGCONT, catchcont); X#endif X pp = fgets(bptr, BUFLEN, stdin); X canlongjmp = FALSE; X (void) signal(SIGINT, ointr); X#ifdef SIGCONT X (void) signal(SIGCONT, ocont); X#endif X if (pp != NULL) X break; X if (!SigTrap) X return; X#ifdef SIGCONT X if (SigTrap != SIGCONT) X#endif X fprintf(ofp, "\n"); X } X (void) nstrip(bptr); X while (*bptr == ' ' || *bptr == '\t') X bptr++; X if (command()) X break; X } X X if (!pflag && !news) { X fprintf(stderr, "No news.\n"); X } X cout(ofp); X} X X#define EOL() if (*bptr != '\0') { fprintf(ofp, "? for commands.\n"); return FALSE; } X/* X * Process one command, which has already been typed in. X */ Xcommand() X{ X char *findhist(); X long i; X X switch (*bptr++) { X X /* display list of articles in current group */ X case 'l': X case 'L': X list_group(groupdir, atoi(bptr), X (*(bptr - 1) == 'l') ? FALSE : TRUE, pngsize); X break; X X /* No. Go on to next article. */ X case 'n': X EOL(); X readmode = NEXT; X if (!cflag) X FCLOSE(fp); X fprintf(ofp, "\n"); X clear(bit); X saveart; X nextbit(); X break; X X /* Undigestify the article. */ X case 'd': X dgest = 1; X /* fall through */ X X /* yes: print this article, go on. */ X case 'y': X EOL(); X /* fall through. */ X X /* The user hit return. Default is 'y' unless rfq, then it's 'q'. */ X case '\0': X if (!bptr[-1] && rfq) X return TRUE; X readmode = NEXT; X showtail(fp); X clear(bit); X saveart; X nextbit(); X break; X X /* X * Unsubscribe to the newsgroup and go on to next group X */ X case 'u': X fprintf(ofp, "To unsubscribe, use 'U'\n"); X break; X X case 'U': X fprintf(ofp, "Unsubscribing to newsgroup: %s\n", groupdir); X obit = -1; X FCLOSE(fp); X if (cflag) X clear(bit); X else X putc('\n', ofp); X rfq = 0; X zapng = TRUE; X saveart; X if (nextng()) { X if (actdirect == BACKWARD) X fprintf(ofp, "Can't back up.\n"); X else X return TRUE; X } X break; X X /* Print the current version of news */ X case 'v': X fprintf(ofp, "News version: %s\n", news_version); X break; X X /* reprint the article */ X case 'p': X EOL(); X if (!cflag) X goto minus; X readmode = NEXT; X if (!cflag) { X FCLOSE(fp); X bit = last; X putc('\n', ofp); X } X obit = -1; X break; X X /* decrypt joke */ X case 'D': X caesar_command(); X readmode = NEXT; X clear(bit); X saveart; X nextbit(); X break; X X /* write out the article someplace */ X case 's': X case 'w': X { X char *grn = groupdir; X tfilename = filename; X if (*bptr == '-') { X bptr++; X grn = ogroupdir; X if (*ofilename1) X tfilename = ofilename1; X } X if (*bptr != '\0' && *bptr != ' ') { X fprintf(ofp, "Bad file name.\n"); X break; X } X while (*bptr == ' ') X bptr++; X if (*bptr != '|' && *bptr != '/') { X char hetyped[BUFLEN]; X char *boxptr; X struct stat stbf; X (void) strcpy(hetyped, bptr); X if (hetyped[0] == '~' && hetyped[1] == '/') { X strcpy(hetyped, bptr+2); X strcpy(bptr, userhome); X } else if (boxptr = getenv("NEWSBOX")) { X if (index(boxptr, '%')) { X sprintf(bptr, boxptr, grn); X if (stat(bptr, &stbf) < 0) { X if (mkdir(bptr, 0777) < 0) { X fprintf(ofp, "Cannot create directory %s", bptr); X break; X } X } else if ((stbf.st_mode & S_IFMT) != S_IFDIR) { X fprintf(ofp, "%s is not a directory", bptr); X break; X } X } else X strcpy(bptr, boxptr); X } else X (void) strcpy(bptr, "."); X (void) strcat(bptr, "/"); X if (hetyped[0] != '\0') X (void) strcat(bptr, hetyped); X else X (void) strcat(bptr, "Articles"); X } X fwait(fsubr(save, tfilename, bptr)); X } X break; X X /* back up */ X case '-': Xminus: X rfq = 0; X abs = TRUE; X if (!*ofilename1) { X fprintf(ofp, "Can't back up.\n"); X break; X } X if (cflag) X clear(bit); X else { X FCLOSE(fp); X putc('\n', ofp); X } X hptr = h; X h = hold; X hold = hptr; X (void) strcpy(bfr, filename); X (void) strcpy(filename, ofilename1); X (void) strcpy(ofilename1, bfr); X obit = bit; X if (strcmp(groupdir, ogroupdir)) { X (void) strcpy(bfr, groupdir); X selectng(ogroupdir, TRUE, FALSE); X (void) strcpy(groupdir, ogroupdir); X (void) strcpy(ogroupdir, bfr); X ngrp = 1; X back(); X } X bit = oobit; X oobit = obit; X obit = -1; X (void) getnextart(TRUE); X return FALSE; X X /* skip forwards */ X case '+': Xcaseplus: X if (*bptr == '\0') X (void) strcat(bptr, "1"); X rfq = 0; X if (cflag) X clear(bit); X saveart; X last = bit; X for (i = 0; i < atol(bptr); i++) { X nextbit(); X if ((bit > pngsize) || (rflag && bit < 1)) X break; X } X if (!cflag) { X putc('\n', ofp); X FCLOSE(fp); X } X obit = -1; X break; X X /* exit - time updated to that of most recently read article */ X case 'q': X EOL(); X return TRUE; X X /* exit - no time update. */ X case 'x': X EOL(); X xxit(0); X X /* cancel the article. */ X case 'c': X (void) cancel_command(); X break; X X /* escape to shell */ X case '!': X fwait(fsubr(ushell, bptr, (char *)NULL)); X fprintf(ofp, "\n"); X hdr(); X break; X X /* mail reply */ X case 'r': X (void) reply_command(); X break; X X /* send to some system */ X case 'X': X xmit_command(); X break; X /* mark the rest of the articles in this group as read */ X case 'K': X saveart; X while (bit <= pngsize && bit >= minartno) { X clear(bit); X nextbit(); X } X FCLOSE(fp); X break; X X /* next newsgroup */ X case 'P': X *bptr = '-'; X case 'N': X FCLOSE(fp); X if (next_ng_command()) X return TRUE; X break; X X case 'b': /* back up 1 article */ X i = bit - 1; X goto tryartnum; X case '0': /* specific no. */ X case '1': X case '2': X case '3': X case '4': X case '5': X case '6': X case '7': X case '8': X case '9': X (void) sscanf(--bptr, "%ld", &i); X if (i == 0) { X fprintf(ofp, "Bad article no.\n"); X break; X } X if (i > pngsize) { X fprintf(ofp, "Not that many articles.\n"); X break; X } Xtryartnum: X readmode = SPEC; X abs = TRUE; X bit = i; X obit = -1; X if (!cflag) { X putc('\n', ofp); X FCLOSE(fp); X } X rfq = 0; X break; X X /* specific message ID. */ X case '<': X ptr1 = findhist(--bptr); X if (ptr1 == NULL) { X fprintf(ofp, "No such article: %s.\n", bptr); X break; X } X ptr2 = index(ptr1, '\t'); X ptr3 = index(++ptr2, '\t'); X ptr2 = index(++ptr3, ' '); X if (ptr2) X *ptr2 = '\0'; X ptr2 = index(ptr3, '/'); X if (!ptr2) { X if (strcmp(ptr3, "cancelled") == 0) { X fprintf(ofp, "Article %s has been cancelled.\n", X bptr); X break; X } X fprintf(ofp, "Article %s (dated %s) has expired.\n", X bptr, index(ptr1, '\t')+1); X break; X } X *ptr2++ = '\0'; X abs = TRUE; X if (cflag) X clear(bit); X else { X FCLOSE(fp); X putc('\n', ofp); X } X saveart; X (void) strcpy(ogroupdir, ptr3); X if (strcmp(groupdir, ogroupdir)) { X (void) strcpy(bfr, groupdir); X selectng(ogroupdir, TRUE, PERHAPS); X (void) strcpy(groupdir, ogroupdir); X (void) strcpy(ogroupdir, bfr); X ngrp = 1; X back(); X } X (void) sscanf(ptr2, "%ld", &bit); X oobit = obit; X obit = -1; X i = bit; X (void) getnextart(TRUE); X if (bit != i || strcmp(groupdir, ptr3) != 0) { X (void) fprintf(ofp, "Can't read %s/%ld.\n", ptr3, i); X goto minus; X } X rfq = 0; X break; X X /* follow-up article */ X case 'f': X if (strcmp(h->followto, "poster") == 0) { X (void) reply_command(); X break; X } X X if (*bptr == '-') X tfilename = ofilename1; X else X tfilename = filename; X (void) sprintf(bfr,"%s/%s %s", BIN, "postnews", tfilename); X (void) system(bfr); X break; X X /* erase - pretend we haven't seen this article. */ X case 'e': X if (rfq || *bptr == '-') { X if (strcmp(groupdir, ogroupdir)) { X i = bit; X (void) strcpy(bfr, groupdir); X selectng(ogroupdir, FALSE, PERHAPS); X set(oobit); X fprintf(ofp,"Holding article %ld newsgroup %s\n" X ,oobit, ogroupdir); X (void) strcpy(groupdir, ogroupdir); X selectng(bfr, FALSE, FALSE); X bit = i; X } else { X fprintf(ofp,"Holding article %ld\n", oobit); X set(oobit); X } X } else { X fprintf(ofp,"Holding article %ld\n", bit); X set(bit); X goto caseplus; /* skip this article for now */ X } X break; X X case 'H': X case 'h': X if (!hflag) X dash(8, ofp); X if (*bptr == '-') { X if (oobit > 0) X fprintf(ofp, "Article %ld:\n", oobit); X hprint(hold, ofp, 1 + (bptr[-1]=='H')); X } else { X fprintf(ofp, "Article %ld of %ld: %s\n", X rfq ? oobit : bit, pngsize, h->ident); X hprint(h, ofp, 1 + (bptr[-1]=='H')); X } X if (!hflag) X dash(8, ofp); X break; X X case '#': X fprintf(ofp, "Article %ld of %ld: newsgroup %s\n", X rfq ? oobit : bit, pngsize, rfq ? ogroupdir : groupdir); X break; X X /* error */ X case '?': X help(ofp); X break; X default: X fprintf(ofp, "? for commands.\n"); X break; X } X X return FALSE; X} X Xcancel_command() X{ X int notauthor; X tfilename = filename; X hptr = h; X if (*bptr == '-') { X if (*ofilename1) { X tfilename = ofilename1; X hptr = hold; X } X bptr++; X } X EOL(); X readmode = SPEC; X (void) strcpy(rcbuf, hptr->path); X ptr1 = index(rcbuf, ' '); X if (ptr1) X *ptr1 = 0; X notauthor = strcmp(username, rcbuf); X if (uid != ROOTID && uid && notauthor) { X fprintf(ofp, "Can't cancel what you didn't write.\n"); X return FALSE; X } X if (!cancel(ofp, hptr, notauthor) && hptr == h) { X clear(bit); X saveart; X nextbit(); X obit = -1; X if (!cflag) X putc('\n', ofp); X FCLOSE(fp); X } X return TRUE; X} X Xreply_command() X{ X register char *pathptr; X int edit = 1; X char *ed, *fbp; X int idlen; X FILE *tfp; X char *replyname(); X char subj[BUFLEN]; X char folbuf[BUFLEN]; X struct stat statb; X long creatm; X X hptr = h; X while (*bptr && index("d-", *bptr)) { X switch (*bptr) { X /* Followup the previous article. */ X case '-': X hptr = hold; X break; X X /* Don't edit the headers */ X case 'd': X edit = 0; X break; X } X bptr++; X } X EOL(); X ptr1 = index(MAILPARSER, ' '); X if (ptr1) X *ptr1 = '\0'; X if (edit && access(MAILPARSER, 1)) { X#ifdef IHCC X fprintf(stderr, "Can't edit headers, 'recmail' missing.\n"); X#else X fprintf(stderr, "Can't edit headers without %s\n", MAILPARSER); X#endif X edit = 0; X } X if (ptr1) X *ptr1 = ' '; X X *rcbuf = '\0'; X pathptr = replyname(hptr);; X for (ptr1 = address, ptr2 = pathptr; *ptr2; ptr1++, ptr2++) { X if (index("\"\\$", *ptr2)) X *ptr1++ = '\\'; X *ptr1 = *ptr2; X } X *ptr1 = '\0'; X X folbuf[0] = '\0'; /* References */ X if (hptr->followid[0]) { X fbp = hptr->followid; X idlen = strlen(hptr->ident); X X /* X * If the references line is too long, truncate it. X * The "3" is for the comma, the space, and the '\0' at X * the end of the string. X */ X while (fbp && strlen(fbp) + idlen > BUFLEN - 3) X fbp = index(fbp + 1, '<'); X if (fbp != NULL) { X (void) strcpy(folbuf, fbp); X (void) strcat(folbuf, " "); X } X } X (void) strcat(folbuf, hptr->ident); X X (void) strcpy(subj, hptr->title); /* Subject */ X while (isspace(*bptr)) X bptr++; X if (*bptr != '\0') X (void) strcpy(subj, bptr); X if (!prefix(subj, "Re:")){ X (void) strcpy(bfr, subj); X (void) sprintf(subj, "Re: %s", bfr); X } X if (!edit) { X fprintf(ofp, "To: %s\n", pathptr); X ed = index(MAILER, '%'); X if (ed && ed[1] == 's') X fprintf(ofp, "Subject: %s\n", subj); X (void) fflush(ofp); X } X X /* Put the user in the editor to create the body of the followup. */ X if (edit) { X int oumask; X X (void) strcpy(tf, tft); X (void) mktemp(tf); X X ed = getenv("EDITOR"); X if (ed == NULL) X ed = DFTEDITOR; X X oumask = umask(077); X if ((tfp = fopen(tf, "w")) == NULL) { X perror(tf); X creatm = 0L; X } else { X fprintf(tfp, "To: %s\n", pathptr); X fprintf(tfp, "Subject: %s\n", subj); X#ifdef INTERNET X fprintf(tfp, "News-Path: %s\n", hptr->path); X#endif /* INTERNET */ X fprintf(tfp, "References: %s\n\n", folbuf); X fstat(fileno(tfp), &statb); X creatm = statb.st_mtime; X (void) fclose(tfp); X } X (void) umask(oumask); X X (void) sprintf(edcmdbuf, "%s %s", ed, tf); X (void) system(edcmdbuf); X (void) strcpy(rcbuf, MAILPARSER); X (void) strcat(rcbuf, " -t"); X (void) strcat(rcbuf, " < "); X (void) strcat(rcbuf, tf); X if (access(tf, 4) || stat(tf, &statb)) { X fprintf(stderr, "Reply not sent: no input file.\n"); X return FALSE; X } X if (statb.st_mtime == creatm) { X fprintf(stderr, "Reply not sent: cancelled.\n"); X (void) unlink(tf); X return FALSE; X } X fprintf(ofp,"Sending reply.\n"); X (void) fflush(stdout); X if (vfork() == 0) { X (void) system(rcbuf); X (void) unlink(tf); X _exit(0); X } X } else { X (void) sprintf(rcbuf, MAILER, hptr->title); X (void) sprintf(bfr, "%s %s", rcbuf, address); X (void) system(bfr); X } X hdr(); X return TRUE; X} X Xxmit_command() X{ X tfilename = filename; X if (*bptr == '-') { X if (*ofilename1) X tfilename = ofilename1; X bptr++; X } X if (*bptr != '\0' && *bptr != ' ') { X fprintf(ofp, "Bad system name.\n"); X return; X } X while (*bptr == ' ') X bptr++; X if (*bptr == '\0') { X fprintf(ofp, "Missing system name.\n"); X return; X } X if (s_find(&srec, bptr) == NULL) { X fprintf(ofp, "%s not in SYSFILE\n", bptr); X return; X } X (void) transmit(&srec, tfilename); X} X Xnext_ng_command() X{ X obit = -1; X if (!*bptr || *bptr == '-') { X if (cflag) X clear(bit); X else X putc('\n', ofp); X if (*bptr) X actdirect = BACKWARD; X rfq = 0; X saveart; X if (nextng()) { X if (actdirect == BACKWARD) X fprintf(ofp, "Can't back up.\n"); X else X return TRUE; X } X return FALSE; X } X while (isspace(*bptr)) X bptr++; X if (!validng(bptr)) { X fprintf(ofp, "No such group.\n"); X return FALSE; X } X if (cflag) X clear(bit); X else X putc('\n', ofp); X readmode = SPEC; X rfq = 0; X saveart; X back(); X selectng(bptr, TRUE, TRUE); X return FALSE; X} X Xcaesar_command() X{ X char temp[BUFLEN]; X FILE *pfp, *popen(); X X fprintf(stderr, "Caesar decoding:\n"); X (void) sprintf(temp, "%s/%s", LIB, "caesar"); X if (*bptr) { X (void) strcat(temp, " "); X (void) strcat(temp, bptr); X } X if (NLINES(h, fp) > LNCNT && *PAGER) { X (void) strcat(temp, " | "); X (void) strcat(temp, PAGER); X } X pfp = popen(temp, "w"); X tprint(fp, pfp, FALSE); X FCLOSE(fp); X (void) pclose(pfp); X} X X/* X * Show the user the tail, if any, of the message on file X * descriptor fd, and close fd. The digester is considered, X * and the pager is used if appropriate. X */ Xshowtail(fd) XFILE *fd; X{ X if (fd == NULL) X return; X X if (dgest) { X digest(fd, ofp, h); X } else if (!lflag && !pflag && !eflag) { X pprint(fd); X } X (void) fclose(fd); X} X X/* X * Print out the rest of the article through the pager. X */ Xpprint(fd) XFILE *fd; X{ X#ifdef PAGE X /* Filter the tail of long messages through PAGER. */ X if (NLINES(h, fd) > LNCNT && *PAGER) { X if (!index(PAGER, FMETA)) { X FILE *pfp, *popen(); X X pfp = popen(PAGER, "w"); X if (pfp == NULL) X pfp = ofp; X /* X * What follows is an attempt to prevent the X * next message from scrolling part of this X * message off the top of the screen before X * the poor luser can read it. X */ X tprint(fd, pfp, FALSE); X putc('\f', pfp); X putc('\n', pfp); X putc(' ', pfp); X (void) pclose(pfp); X } X else X pout(ofp); X holdup = TRUE; X } X else X#endif X tprint(fd, ofp, FALSE); X} X X/* X * Find the next article we want to consider, if we're done with X * the last one, and show the header. X */ Xgetnextart(minus) Xint minus; X{ X int noaccess; X register DIR *dirp; X register struct direct *dir; X long nextnum, tnum; X X noaccess = 0; X X if (minus) X goto nextart2; /* Kludge for "-" command. */ X X if (bit == obit) /* Return if still on same article as last time */ X return 0; X X SigTrap = FALSE; X Xnextart: X#ifdef DEBUG X fprintf(stderr,"nextart:\n"); X#endif /* DEBUG */ X dgest = 0; X X if (bit < minartno && !rflag) X bit = minartno; X X /* If done with this newsgroup, find the next one. */ X while (ngsize <= 0 || (!rflag && ((long) bit > ngsize)) || (rflag && bit < minartno)) { X if (nextng()) { X if (actdirect == BACKWARD) { X fprintf(ofp, "Can't back up.\n"); X actdirect = FORWARD; X continue; X } else X if (rfq++ || pflag || cflag) X return 1; X break; X } X if (rflag) X bit = ngsize + 1; X else X bit = minartno - 1; X if (uflag && !xflag) { X time_t now; X (void) time(&now); X if (now - timelastsaved > 5*60 /* 5 minutes */) { X if (!xflag) X fprintf(stderr,"[Saving .newsrc]\n"); X writeoutrc(); X timelastsaved = now; X } X } X noaccess = 0; X } X Xnextart2: X#ifdef DEBUG X fprintf(stderr, "article: %s/%ld\n", groupdir, bit); X#endif X if (rcreadok) X rcreadok = 2; /* have seen >= 1 article */ X (void) sprintf(filename, "%s/%ld", dirname(groupdir), bit); X if (rfq && goodone[0]) X strcpy(filename, goodone); X if (SigTrap) { X if (SigTrap == SIGHUP) X return 1; X if (!rcreadok) X xxit(0); X fprintf(ofp, "Abort (n)? "); X (void) fflush(ofp); X (void) gets(bfr); X if (*bfr == 'y' || *bfr == 'Y') X xxit(0); X SigTrap = FALSE; X } X#ifdef DEBUG X fprintf(stderr, "filename = '%s'\n", filename); X#endif X /* Decide if we want to show this article. */ X if (bit <= 0 || (fp = art_open(filename, "r")) == NULL) { X /* don't show the header if the article was specifically X * requested and it isn't there X */ X if (lbuf[0] == '<') { X lbuf[0] = '\0'; X bit = -1; X return 1; X } X /* since there can be holes in legal article numbers, */ X /* we wait till we hit 5 consecutive bad articles */ X /* before we haul off and scan the directory */ X if (++noaccess < 5) X goto badart; X noaccess = 0; X dirp = opendir(dirname(groupdir)); X if (dirp == NULL) { X if (errno != EACCES) X fprintf(stderr,"Can't open %s\n", dirname(groupdir)); X goto badart; X } X nextnum = rflag ? minartno - 1 : ngsize + 1; X while ((dir = readdir(dirp)) != NULL) { X tnum = atol(dir->d_name); X if (tnum <= 0) X continue; X if (rflag ? (tnum > nextnum && tnum < bit) X : (tnum < nextnum && tnum > bit)) X nextnum = tnum; X } X closedir(dirp); X if (rflag ? (nextnum >= bit) : (nextnum <= bit)) X goto badart; X#ifdef DEBUG X fprintf(stderr,"nextnum = %ld\n",nextnum); X#endif /* DEBUG */ X do { X clear(bit); X nextbit(); X } while (rflag ? (nextnum < bit) : (nextnum > bit)); X obit = -1; X abs = FALSE; X if (ignorenews) /* ignored news is still news */ X news = TRUE; X goto nextart; X } else X noaccess = 0; X X if (ignorenews || hread(h, fp, TRUE) == NULL X || (!rfq && !aselect(h, abs))) { X if (ignorenews) X news = TRUE; X badart: X#ifdef DEBUG X fprintf(stderr, "Bad article '%s'\n", filename); X#endif X FCLOSE(fp); X clear(bit); X obit = -1; X nextbit(); X abs = FALSE; X goto nextart; X } X abs = FALSE; X actdirect = FORWARD; X news = TRUE; X hdr(); X if (pflag) X tprint(fp, ofp, FALSE); X else if (cflag && !lflag && !eflag) { X (void) fflush(ofp); X pprint(fp); X } X if (cflag || lflag || eflag || pflag) { X SigTrap = FALSE; X FCLOSE(fp); X } X obit = bit; X return 0; X} X X/* X * Print out whatever the appropriate header is X */ Xhdr() X{ X char *briefdate(); X X if (rfq) X return; X X if (lflag || eflag) { X hprint(h, ofp, 0); X return; X } X X /* Print out a header */ X if (ngrp) { X pngsize = ngsize; X ngrp--; X nghprint(groupdir); X } X if (!hflag) X fprintf(ofp, "Article %ld of %ld, %s.\n", X bit, pngsize, briefdate(h->subdate)); X hprint(h, ofp, pflag ? 1 : 0); X} X Xnghprint(title) Xchar *title; X{ X char *tstr = "Newsgroup "; X int l = strlen(title) + strlen(tstr); X X fprintf(ofp, "\n"); X if (!hflag) { X dash(l, ofp); X fprintf(ofp, "%s%s\n", tstr, title); X dash(l, ofp); X } else { X fprintf(ofp, "%s%s, ", tstr, title); X if (bit == pngsize) X fprintf(ofp, "%ld\n", pngsize); X else X fprintf(ofp, "%ld-%ld\n", bit, pngsize); X } X fprintf(ofp, "\n"); X} X X/* X * Routine to catch a continue signal. X */ Xcatchcont(sig) Xint sig; X{ X (void) signal(sig, catchcont); X SigTrap = sig; X (void) fflush(ofp); X#ifdef SIGCONT X if (fp && sig == SIGCONT) X hdr(); X if (sig != SIGCONT) X#endif /* SIGCONT */ X putc('\n', ofp); X if (canlongjmp) X longjmp(sigjmpbuf,1); X} X Xxxit(status) Xint status; X{ X (void) unlink(infile); X (void) unlink(outfile); X#ifdef SORTACTIVE X if (strncmp(ACTIVE,"/tmp/", 5) == 0) X (void) unlink(ACTIVE); X#endif /* SORTACTIVE */ X exit(status); X} END_OF_FILE if test 25018 -ne `wc -c <'readr.c'`; then echo shar: \"'readr.c'\" unpacked with wrong size! fi # end of 'readr.c' fi echo shar: End of shell archive. exit 0 -- "Zeta Microcomputer Software" ACSnet: nick@ultima.cs.uts.oz UUCP: ...!uunet!munnari!ultima.cs.uts.oz!nick Fidonet: Nick Andrew on 3:713/602 (Zeta)
nick@ultima.cs.uts.oz (Nick Andrew) (12/07/89)
#! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of shell archive." # Contents: virtterm.c rfuncs.c header.c # Wrapped by nick@nswitgould on Thu Dec 7 22:40:34 1989 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'virtterm.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'virtterm.c'\" else echo shar: Extracting \"'virtterm.c'\" \(20326 characters\) sed "s/^X//" >'virtterm.c' <<'END_OF_FILE' X/* X * Virtual terminal handler X * Written by Kenneth Almquist, AGS Computers (HO 4C601, X7105). X * Modified by Stephen Hemminger, to use TERMCAP (without curses) X */ X X#ifdef SCCSID Xstatic char *SccsId = "@(#)virtterm.c 1.13 12/16/86"; X#endif /* SCCSID */ X X/*LINTLIBRARY*/ X X#include <stdio.h> X#include <ctype.h> X#include <sys/types.h> X#include <sys/ioctl.h> X#include <signal.h> X#ifdef USG X#include <termio.h> X#else /* !USG */ X#include <sgtty.h> X#endif /* !USG */ X X/* X * These values for MAXPLEN and MAXLLEN are used to dimension arrays X * that hold strings of relative cursor motions. The actual arrays that X * are used to hold screen images are malloc'd. X */ X#define MAXPLEN 90 X#define MAXLLEN 160 X X#define BOTLINE (ROWS - 1) X#define DIRTY 01 X X/* terminal escape sequences from termcap */ X#define HO _tstr[0] /* home */ X#define CL _tstr[1] /* clear screen */ X#define CD _tstr[2] /* clear to end of screen */ X#define CE _tstr[3] /* clear to end of line */ X#define xUP _tstr[4] /* up one line */ X#define DO _tstr[5] /* down one line */ X#define US _tstr[6] /* underline */ X#define UE _tstr[7] /* underline end */ X#define BT _tstr[8] /* backtab */ X#define xBC _tstr[9] /* backspace */ X#define AL _tstr[10] /* insert line */ X#define DL _tstr[11] /* delete line */ X#define CM _tstr[12] /* cursor move */ X#define CH _tstr[13] /* cursor horizontal move */ X#define CV _tstr[14] /* cursor vertical move */ X#define CS _tstr[15] /* scrolling region */ X#define SF _tstr[16] /* scroll forwards */ X#define SR _tstr[17] /* scroll backwards */ X#define TI _tstr[18] /* start cursor mode */ X#define TE _tstr[19] /* end cursor mode */ X#define TA _tstr[20] /* tab char (if not \t) */ X#define CR _tstr[21] /* carriage return (if not \r) */ X#define xPC _tstr[22] /* for reading pad character */ Xchar PC; /* pad character */ Xchar *BC, *UP; /* external variables for tgoto */ X Xstatic char sname[] = "hoclcdceupdousuebtbcaldlcmchcvcssfsrtitetacrpc"; Xchar *_tstr[23]; Xint HOlen; /* length of HO string */ X X X/* terminal flags */ X#define BS _tflg[0] /* can backspace */ X#define AM _tflg[1] /* has auto margins */ X#define XN _tflg[2] /* no newline after wrap */ X#define RET !_tflg[3] /* has carriage return */ X#define NS _tflg[4] /* has SF (scroll forward) */ X#define PT _tflg[5] /* has tabs */ X#define XT _tflg[6] /* tabs are destructive */ Xint GT = 1; /* tab stops on terminal are set */ X Xstatic char bname[] = "bsamxnncnsptxt"; Xchar _tflg[7]; X X Xextern char *tgoto(), *tgetstr(); Xextern char *getenv(), *strcpy(); X X#define ULINE 0200 X X/* Constants accessable by user */ Xint hasscroll; /* scrolling type, 0 == no scrolling */ Xint ROWS; /* number of lines on screen */ Xint COLS; /* width of screen */ X Xstruct line { X short len; /* should really be u_char */ X char flags; X char *l; /* pointer to actual line text, NO NULL @ end */ X}; X Xint _row, _col; Xint _srow, _scol; Xstruct line *_virt; /* what we want the screen to look like */ Xstruct line *_actual; /* What it actually looks like */ Xint _uline = 0; Xint _junked = 1; Xint _curjunked; Xint _dir = 1; Xint _shifttop, _shiftbot; Xint _shift; Xint _scratched; Xint vputc(); X X/* X * Tell refresh to shift lines in region upwards count lines. Count X * may be negative. The virtual image is not shifted; this may change X * later. The variable _scratched is set to supress all attempts to X * shift. X */ X Xushift(top, bot, count) X{ X if (_scratched) X return; X if (_shift != 0 && (_shifttop != top || _shiftbot != bot)) { X _scratched++; X return; X } X _shifttop = top; X _shiftbot = bot; X _shift += count; X} X X/* X * generate a beep on the terminal X */ Xbeep() X{ X vputc('\7'); X} X X/* X * Move to one line below the bottom of the screen. X */ Xbotscreen() X{ X _amove(BOTLINE, 0); X vputc('\n'); X vflush(); X} X Xmove(row, col) X{ X if (row < 0 || row >= ROWS || col < 0 || col >= COLS) X return; X _row = row; X _col = col; X} X X X X/* X * Output string at specified location. X */ Xmvaddstr(row, col, str) Xchar *str; X{ X move(row, col); X addstr(str); X} X Xaddstr(s) Xchar *s; X{ X register char *p; X register struct line *lp; X register int col = _col; X X lp = &_virt[_row]; X if (lp->len < col) { X p = &lp->l[lp->len]; X while (lp->len < col) { X *p++ = ' '; X lp->len++; X } X } X for (p = s; *p != '\0'; p++) { X if (*p == '\n') { X lp->len = col; X lp->flags |= DIRTY; X col = 0; X if (++_row >= ROWS) X _row = 0; X lp = &_virt[_row]; X } X else { X lp->l[col] = *p; X lp->flags |= DIRTY; X if (++col >= COLS) { X lp->len = COLS; X col = 0; X if (++_row >= ROWS) X _row = 0; X lp = &_virt[_row]; X } X } X } X if (lp->len <= col) X lp->len = col; X _col = col; X} X Xaddch(c) X{ X register struct line *lp; X register char *p; X X lp = &_virt[_row]; X if (lp->len < _col) { X p = &lp->l[lp->len]; X while (lp->len < _col) { X *p++ = ' '; X lp->len++; X } X } X lp->l[_col] = c; X if (lp->len == _col) X lp->len++; X if (++_col >= COLS) { X _col = 0; X if (++_row >= ROWS) X _row = 0; X } X lp->flags |= DIRTY; X} X X/* X * Clear an entire line. X */ Xclrline(row) X{ X register struct line *lp; X X lp = &_virt[row]; X if (lp->len > 0) { X lp->len = 0; X lp->flags |= DIRTY; X } X} X Xerase() X{ X register i; X X for (i = 0; i < ROWS; i++) { X _virt[i].len = 0; X _virt[i].flags |= DIRTY; X } X} X Xrefresh() X{ X register i; X register char *p, *q; X register int j, len; X X if (checkin()) X return; X i = 1; X if (_junked) { X _sclear(); X _junked = 0; X } else if (! _scratched) { X if (_shift > 0) { X _ushift(_shifttop, _shiftbot, _shift); X } else if (_shift < 0) { X i = _dshift(_shifttop, _shiftbot, -_shift); X } else { X i = _dir; X } X } X _dir = i; X _shift = 0; X if (checkin()) X return; X _fixlines(); X for (i = _dir > 0 ? 0 : BOTLINE; i >= 0 && i < ROWS; i += _dir) { X if ((_virt[i].flags & DIRTY) == 0) X continue; X _ckclrlin(i); /* decide whether to do a clear line */ X /* probably should consider cd too */ X len = _virt[i].len; X if (_actual[i].len < len) X len = _actual[i].len; X p = _virt[i].l; X q = _actual[i].l; X for (j = 0; j < len; j++) { X if (*p != *q) { X /* Inline test for speed */ X if (i != _srow || j != _scol || _curjunked) X _amove(i, j); X _aputc(*p); X *q = *p; X } X p++; X q++; X } X len = _virt[i].len; X if (_actual[i].len > len) { X _clrtoeol(i, len); X } else { X for (; j < len; j++) { X if (*p != ' ') { X /* Inline test for speed */ X if (i != _srow || j != _scol || _curjunked) X _amove(i, j); X _aputc(*p); X } X *q++ = *p++; X } X _actual[i].len = len; X } X if (checkin()) X return; X } X _dir = 1; X _amove(_row, _col); X vflush(); /* flush output buffer */ X _scratched = 0; X} X X_dshift(top, bot, count) X{ X register i; X X if (count >= bot - top || hasscroll < 4) { /* must have CS or AL/DL */ X _scratched++; X return 1; X } X for (i = bot - count; _actual[i].len == 0; i--) X if (i == top) X return 1; X for (i = top; i <= bot; i++) X _virt[i].flags |= DIRTY; X for (i = bot; i >= top + count; i--) { X /* FIXME, this should be done by recirculating the pointers */ X register j; X j = _actual[i].len = _actual[i - count].len; X _actual[i].flags = _actual[i - count].flags; X strncpy(_actual[i].l, _actual[i - count].l, j); X } X for (; i >= top; i--) X _actual[i].len = 0; X X if (hasscroll != 5) { /* can we define scrolling region, and scroll back */ X tputs(tgoto(CS, bot, top), 1, vputc);/* define scroll region */ X _curjunked = 1; X _amove(top, 0); X for (i = count; --i >= 0;) X tputs(SR, 1, vputc);/* scroll back */ X tputs(tgoto(CS, BOTLINE, 0), 1, vputc); X _curjunked = 1; X } else { X _amove(bot - count + 1, 0); X if (CD && bot == BOTLINE) X tputs(CD, 1, vputc); X else { X for (i = count; --i >= 0;) X tputs(DL, ROWS - _srow, vputc); X } X _amove(top, 0); X for (i = count; --i >= 0;) X tputs(AL, ROWS - _srow, vputc); X } X return -1; X} X X X_ushift(top, bot, count) X{ X register i; X X if (count >= bot - top || hasscroll == 0) { X _scratched++; X return; X } X for (i = top + count; _actual[i].len == 0; i++) X if (i == bot) X return; X if (hasscroll == 1 || hasscroll == 3) { X /* we cheat and shift the entire screen */ X /* be sure we are shifting more lines into than out of position */ X if ((bot - top + 1) - count <= ROWS - (bot - top + 1)) X return; X top = 0, bot = BOTLINE; X } X for (i = top; i <= bot; i++) X _virt[i].flags |= DIRTY; X for (i = top; i <= bot - count; i++) { X /* FIXME, this should be done by recirculating the pointers */ X register int j; X j = _actual[i].len = _actual[i + count].len; X _actual[i].flags = _actual[i + count].flags; X strncpy(_actual[i].l, _actual[i + count].l, j); X } X for (; i <= bot; i++) X for (; i <= bot; i++) X _actual[i].len = 0; X X if (hasscroll != 5) { X if (top != 0 || bot != BOTLINE) { X tputs(tgoto(CS, bot, top), 0, vputc); X _curjunked = 1; X } X _amove(bot, 0); /* move to bottom */ X for (i = 0; i < count; i++) { X if (SF) /* scroll forward */ X tputs(SF, 1, vputc); X else X vputc('\n'); X } X if (top != 0 || bot != BOTLINE) { X tputs(tgoto(CS, BOTLINE, 0), 0, vputc); X _curjunked = 1; X } X } else { X _amove(top, 0); X for (i = count; --i >= 0;) X tputs(DL, ROWS - _srow, vputc); X if (bot < BOTLINE) { X _amove(bot - count + 1, 0); X for (i = count; --i >= 0;) X tputs(AL, ROWS - _srow, vputc); X } X } X} X X_sclear() X{ X register struct line *lp; X X tputs(CL, 0, vputc); X _srow = _scol = 0; X for (lp = _actual; lp < &_actual[ROWS]; lp++) { X lp->len = 0; X } X for (lp = _virt; lp < &_virt[ROWS]; lp++) { X if (lp->len != 0) X lp->flags |= DIRTY; X } X} X X_clrtoeol(row, col) X{ X register struct line *lp = &_actual[row]; X register i; X X if (CE && lp->len > col + 1) { X _amove(row, col); X tputs(CE, 1, vputc); X } else { X for (i = col ; i < lp->len ; i++) { X if (lp->l[i] != ' ') { X _amove(row, i); X _aputc(' '); X } X } X } X lp->len = col; X} X X_fixlines() X{ X register struct line *lp; X register char *p; X register int i; X X for (i = 0; i < ROWS; i++) { X lp = &_virt[i]; X if (lp->flags & DIRTY) { X for (p = &lp->l[lp->len]; --p >= lp->l && *p == ' ';) X ; X lp->len = (int) (p - lp->l) + 1; X if (lp->len == _actual[i].len && strncmp(lp->l, _actual[i].l, lp->len) == 0) X lp->flags &= ~DIRTY; X } X } X} X X X/* X * Consider clearing the line before overwriting it. X * We always clear a line if it has underlined characters in it X * because these can cause problems. Otherwise decide whether X * that will decrease the number of characters to change. This X * routine could probably be simplified with no great loss. X */ X X_ckclrlin(i) X{ X int eval; X int len; X int first; X register struct line *vp, *ap; X register int j; X X if (!CE) X return; X ap = &_actual[i]; X vp = &_virt[i]; X len = ap->len; X eval = -strlen(CE); X if (len > vp->len) { X len = vp->len; X eval = 0; X } X for (j = 0; j < len && vp->l[j] == ap->l[j]; j++) X ; X if (j == len) X return; X first = j; X while (j < len) { X if (vp->l[j] == ' ') { X if (ap->l[j] != ' ') { X while (++j < len && vp->l[j] == ' ' && ap->l[j] != ' ') { X eval++; X } X if (j == len) X eval++; X continue; X } X } X else { X if (vp->l[j] == ap->l[j]) { X while (++j < len && vp->l[j] == ap->l[j]) { X eval--; X } X continue; X } X } X j++; X } X if (US) { X for (j = 0 ; j < ap->len ; j++) { X if (ap->l[j] & ULINE) { X eval = 999; X if (first > j) X first = j; X break; X } X } X } X for (j = first; --j >= 0;) X if (vp->l[j] != ' ') X break; X if (j < 0) X first = 0; X if (eval > 0) { X _amove(i, first); X tputs(CE, 0, vputc); X _actual[i].len = first; X } X} X X X X/* X * Move routine X * first compute direct cursor address string and cost X * then relative motion string and cost, X * then home then relative and cost X * choose smallest and do it. X * X * The plod stuff is to build the strings (with padding) then decide X */ Xstatic char *plodstr; /* current location in relmove string */ X Xplodput(c) X{ X *plodstr++ = c; X} X X/* FIXME: speedup 1-char horiz moves: print the char that's there. */ X/* FIXME: avoid funniness if cm works. */ X/* FIXME: Avoid setul(0) if cursor motion OK in standout (XM?) */ X_amove(row, col) X{ X char direct[20]; X char rel[MAXPLEN*10 + MAXLLEN*10]; /* longest move is full screen */ X char ho[MAXPLEN*10 + MAXLLEN*10]; X int cost, newcost; X register char *movstr; X X if (row == _srow && col == _scol && _curjunked == 0) X return; X if (_uline) X _setul(0); /* Inline test for speed */ X X cost = 999; X if (CM) { X plodstr = direct; X tputs(tgoto(CM, col, row), 0, plodput); X cost = plodstr - direct; X movstr = direct; X } X if (_curjunked == 0) { X plodstr = rel; X if (_vmove(_srow, row) >= 0 X && (plodstr - rel) < cost /* after vmove */ X && _hmove(_scol, col, row) >= 0 X && (newcost = plodstr - rel) < cost) { /* after both */ X cost = newcost; X movstr = rel; X } X } X if (cost > HOlen) { /* is it worth calculating */ X plodstr = ho; X tputs(HO, 0, plodput); X if (_vmove(0, row) >= 0 X && (plodstr - ho) < cost /* after ho, vmove */ X && _hmove(0, col, row) >= 0 X && (newcost = plodstr - ho) < cost) { /* after all three */ X cost = newcost; X movstr = ho; X } X } X X if (cost < 999) X while (--cost >= 0) X vputc(*movstr++); X X _srow = row; X _scol = col; X _curjunked = 0; X} X X_vmove(orow, nrow) X{ X char direct[128]; X char *saveplod = plodstr; X X if (CV) { X plodstr = direct; X tputs(tgoto(CV, nrow, nrow), 0, plodput); X *plodstr = '\0'; X plodstr = saveplod; X } X if (orow > nrow) { /* cursor up */ X if (! UP) X return -1; X while (orow > nrow) { X tputs(UP, 1, plodput); X orow--; X } X } X while (orow < nrow) { /* cursor down */ X if (DO) X tputs(DO, 1, plodput); X else X *plodstr++ = '\n'; X orow++; X } X if (CV && plodstr - saveplod >= strlen(direct)) { X register char *p; X plodstr = saveplod; X for (p = direct ; *plodstr = *p++ ; plodstr++) X ; X } X return 0; X} X X_hmove(ocol, ncol, row) X{ X char direct[128]; X char ret[MAXLLEN*10]; X char *saveplod = plodstr; X char *movstr; X int cost, newcost; X X cost = 999; X if (CH) { X plodstr = direct; X tputs(tgoto(CH, ncol, ncol), 0, plodput); X cost = plodstr - direct; X movstr = direct; X plodstr = saveplod; X } X if (RET && ocol > ncol) { /* consider doing carriage return */ X plodstr = ret; X if (CR) X tputs(CR, 1, plodput); X else X *plodstr++ = '\r'; X if (_relhmove(0, ncol, row) >= 0 X && (newcost = plodstr - ret) < cost) { X cost = newcost; X movstr = ret; X } X plodstr = saveplod; X } X if (_relhmove(ocol, ncol, row) < 0) { X if (cost == 999) X return -1; X goto copy; X } X if (plodstr - saveplod > cost) { Xcopy: plodstr = saveplod; X while (--cost >= 0) X *plodstr++ = *movstr++; X } X return 0; X} X X_relhmove(ocol, ncol, row) X{ X int tab; X X if (ocol < ncol && PT && GT) { /* tab (nondestructive) */ X while ((tab = (ocol + 8) & ~07) <= ncol) { X if (TA) X tputs(TA, 1, plodput); X else X *plodstr++ = '\t'; X ocol = tab; X } X if (tab < COLS && tab - ncol < ncol - ocol) { X if (TA) X tputs(TA, 1, plodput); X else X *plodstr++ = '\t'; X ocol = tab; X } X } else if (BT && GT && ocol > ncol) { /* backwards tab */ X while ((tab = (ocol - 1) &~ 07) >= ncol) { X if (BS && tab == ocol - 1) { X if (BC) X tputs(BC, 1, plodput); X else X *plodstr++ = '\b'; X } else X tputs(BT, 1, plodput); X ocol = tab; X } X if (ncol - tab + 1 < ocol - ncol) { X tputs(BT, 1, plodput); X ocol = tab; X } X } X if (ocol > ncol) { /* cursor left */ X if (! BS) X return -1; X while (ocol > ncol) { X if (BC != NULL) X tputs(BC, 1, plodput); X else X *plodstr++ = '\b'; X ocol--; X } X } X if (ocol < ncol) { /* cursor right */ X register struct line *lp = &_actual[row]; X /* X * This code doesn't move over underlined characters properly, X * but in practice this doesn't seem to matter. X */ X while (ocol < ncol) { X if (ocol < lp->len) X *plodstr++ = lp->l[ocol]; X else X *plodstr++ = ' '; X ocol++; X } X } X return 0; X} X X_aputc(c) X{ X if (_uline != (c & ULINE)) /* Inline for speed */ X _setul(c & ULINE); X if (++_scol >= COLS) { X if (_srow == ROWS - 1) { X /* Don't ever paint last char of last line */ X _scol--; X return; X } X _curjunked++; /* Don't assume AM is right */ X } X vputc(c & ~ULINE); X} X X X_setul(on) X{ X if (on) { X if (_uline == 0 && US != NULL) { X tputs(US, 1, vputc); X _uline = ULINE; X } X } X else { X if (_uline != 0 && UE != NULL) { X tputs(UE, 1, vputc); X _uline = 0; X } X } X} X X/* X * Initialize termcap strings for later use. X */ X X/* X * Hacks to help with some Tek terminals X * rad@tek X */ Xint tputs_len; Xcountit(c) { tputs_len++; } X Xinitterm() X{ X static char tcbuf[1024]; /* termcap buffer */ X register char *cp; X#ifdef USG X struct termio tio; X#else /* !USG */ X struct sgttyb ttyb; X#endif /* !USG */ X X if ((cp = getenv("TERM")) == NULL) X xerror("TERM not set in environment"); X X switch (tgetent(tcbuf, cp)) { X case 0: X xerror("Terminal not found in TERMCAP"); X case -1: X xerror("Can't open /etc/termcap"); X case 1: X break; X } X#ifdef TIOCGWINSZ X { X struct winsize ws; X int winch(); X X COLS = ROWS = -1; X if(ioctl(1, TIOCGWINSZ, &ws) == 0) { X ROWS = ws.ws_row; X COLS = ws.ws_col; X } X if(ROWS <= 0) X ROWS = tgetnum("li"); X if(COLS <= 0) X COLS = tgetnum("co"); X if ((ROWS <= 0) || (COLS <= 0)) X xerror("Can't get screen size"); X X signal(SIGWINCH, winch); /* allow for changing window size */ X } X#else /* !TIOCGWINSZ */ X if ((ROWS = tgetnum("li")) == -1 X || (COLS = tgetnum("co")) == -1) X xerror("Can't get screen size"); X#endif /* !TIOCGWINSZ */ X _zap(); X X if (CL == NULL) X xerror ("No clear screen defined"); X X if (HO == NULL && CM == NULL) X xerror("No home or cursor addressing"); X if (HO) X HOlen = strlen(HO); X else X HOlen = 999; X X PC = xPC ? xPC[0] : 0; X BC = xBC; X UP = xUP; X /* X * _vmove() may be called with a full-screen traverse, X * meaning it will put the UP (along with any padding) into X * the buffer as many as MAXPLEN times. This means that X * if the UP string would be more than 10 chars long (defined X * in _amove() ), the buffer might be overflowed (assuming X * CH is also large). X * This actually occurs with the Tek4023 termcap, where :up=1000UP: X * is used to fake vi into using :cm instead, due to the fact X * that a 4023 can't do upline relative motion at all. X * -rdoty@tek X */ X if (UP) { X tputs_len = 0; X tputs(UP, 1, countit); X if (tputs_len > 10 ) X UP = 0; X } X X if (tgetnum("ug") > 0) X US = UE = NULL; X X if (XT) /* Destructive tab code not included */ X PT = 0; /* to keep things simple */ X X#ifdef USG X if (ioctl(0, TCGETA, &tio) == 0) X GT = tio.c_oflag&TAB3; X#else /* !USG */ X if (ioctl(0, TIOCGETP, &ttyb) == 0) X GT = ttyb.sg_flags&XTABS; X#endif /* !USG */ X X { X char *thelines; X int i; X char *malloc(); X X thelines = malloc(2 * ROWS * COLS); X _virt = (struct line *)malloc(2 * ROWS * sizeof (struct line)); X _actual = _virt + ROWS; X for (i = 0; i < ROWS; i++) { X _virt[i].len = 0; X _virt[i].flags = 0; X _actual[i].len = 0; X _actual[i].flags = 0; X _virt[i].l = thelines; X thelines += COLS; X _actual[i].l = thelines; X thelines += COLS; X } X } X X /* Select article scrolling algorithm. We prefer scrolling region X over insert/delete line because it's faster on the HP */ X hasscroll = 0; X if (!NS) { X hasscroll = 1; X if (SR) X hasscroll = 3; X if (CS) X hasscroll++; X } X if (AL && DL && hasscroll != 4) X hasscroll = 5; X} X Xrawterm() X{ X if (TI != NULL) X tputs(TI, 0, vputc); X} X Xcookedterm() X{ X if (TE != NULL) { X tputs(TE, 0, vputc); X vflush(); X } X} X X/* get strings from termcap */ X_zap() X{ X static char tstrbuf[1024]; X static char *tp; X register char *namp, **sp, *bp; X X tp = tstrbuf; X sp = _tstr; X for (namp = sname; *namp; namp += 2) { X *sp++ = tgetstr(namp, &tp); X } X bp = _tflg; X for (namp = bname; *namp; namp += 2) { X *bp++ = tgetflag(namp, &tp); X } X} X#ifdef TIOCGWINSZ X/* X * window changed size -- update ROWS and COLS X * and then redraw screen X */ Xwinch() X{ X struct winsize ws; X int cols, rows; X X cols = rows = -1; X if(ioctl(1, TIOCGWINSZ, &ws) == 0) { X rows = ws.ws_row; X cols = ws.ws_col; X } X if (rows == ROWS && cols == COLS) { /* just redraw it if no change */ X _junked = 1; /* redraw */ X updscr(); X return; X } X X if(rows > 0) X ROWS = rows; X if(cols > 0) X COLS = cols; X X if (ROWS > MAXPLEN) X ROWS = MAXPLEN; X if (COLS > MAXLLEN) { X COLS = MAXLLEN; X AM = XN = 1; X } X X winch_upd(); X} X#endif /* TIOCGWINSZ */ END_OF_FILE if test 20326 -ne `wc -c <'virtterm.c'`; then echo shar: \"'virtterm.c'\" unpacked with wrong size! fi # end of 'virtterm.c' fi if test -f 'rfuncs.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'rfuncs.c'\" else echo shar: Extracting \"'rfuncs.c'\" \(18733 characters\) sed "s/^X//" >'rfuncs.c' <<'END_OF_FILE' X/* X * This software is Copyright (c) 1986 by Rick Adams. X * X * Permission is hereby granted to copy, reproduce, redistribute or X * otherwise use this software as long as: there is no monetary X * profit gained specifically from the use or reproduction or this X * software, it is not sold, rented, traded or otherwise marketed, and X * this copyright notice is included prominently in any copy X * made. X * X * The author make no claims as to the fitness or correctness of X * this software for any use whatsoever, and it is provided as is. X * Any use of this software is at the user's own risk. X * X * rfuncs - functions for readnews. X */ X X#ifdef SCCSID Xstatic char *SccsId = "@(#)rfuncs.c 2.40 2/22/87"; X#endif /* SCCSID */ X X/*LINTLIBRARY*/ X X#include "rparams.h" X Xchar lentab[LINES]; /* length of newsgroupname for each rcline */ Xlong nngsize; /* The next upcoming value of ngsize. */ Xlong nminartno; /* Smallest article number in this group */ Xint BITMAPSIZE = 0; X Xnextng() X{ X long curpos; X#ifdef DEBUG X fprintf(stderr, "nextng()\n"); X#endif X curpos = ftell(actfp); X Xnext: X#ifdef DEBUG X fprintf(stderr, "next:\n"); X#endif X if (actdirect == BACKWARD) { X if (back()) { X (void) fseek(actfp, curpos, 0); X return 1; X } X if (back()) { X (void) fseek(actfp, curpos, 0); X return 1; X } X } X if (fgets(afline, BUFLEN, actfp) == NULL) X return 1; X if (sscanf(afline, "%s %ld %ld", bfr, &nngsize, &nminartno) < 3) { X bfr[0] = '\0'; X nngsize = 0; X nminartno = 0; X } X#ifdef DEBUG X fprintf(stderr, "bfr = '%s'\n", bfr); X#endif X X if (!ngmatch(bfr, header.nbuf)) X goto next; X if (xflag) X readmode = SPEC; X else X readmode = NEXT; X if (selectng(bfr, TRUE, FALSE)) X goto next; X return 0; X} X X Xselectng(name, fastcheck, resubscribe) Xchar *name; X{ X register char *ptr, punct = ','; X register int i; X register char *p; X register long cur; X long next = 0; X FILE *af; X long s, sm; X char buf[100], n[100]; X X#ifdef DEBUG X fprintf(stderr,"selectng: groupdir = %s\n", groupdir); X#endif /* DEBUG */ X if (*groupdir) X updaterc(); X last = 1; X if (strcmp(name, bfr)) { X af = xfopen(ACTIVE, "r"); X while (fgets(buf, sizeof buf, af) != NULL) { X if (sscanf(buf, "%s %ld %ld", n, &s, &sm) == 3 && X strcmp(n, name) == 0) { X ngsize = s; X minartno = sm; X break; X } X } X (void) fclose(af); X } else { X ngsize = nngsize; X minartno = nminartno; X } X#ifdef DEBUG X fprintf(stderr, "selectng(%s) sets ngsize to %ld, minartno to %ld\n", X name, ngsize, minartno); X#endif X (void) strcpy(groupdir, name); X if (!xflag) { X i = findrcline(name); X if (i >= 0) { X if (p = index(rcline[i], '!')) { X switch (resubscribe) { X case FALSE: X groupdir[0] = 0; X return 1; X case TRUE: X *p = ':'; X break; X case PERHAPS: X zapng = TRUE; X break; X } X } else X p = index(rcline[i], ':'); X if (!p) /* shouldn't happen */ X p = rcline[i]; X while (*++p == ' ') X ; X (void) sprintf(rcbuf, "%s%s%ld", rcline[i], X *p == '\0' ? " " : ",", ngsize+1); X } X else X (void) sprintf(rcbuf, "ng: %ld", ngsize+1); X } else X (void) sprintf(rcbuf, "ng: %ld", ngsize+1); X#ifdef DEBUG X fprintf(stderr, "rcbuf set to %s\n", rcbuf); X#endif /* DEBUG */ X X /* X * Fast check for common case: 1-### X */ X if (fastcheck) { X p = rcbuf; X while (*p != ' ') X p++; X while (*p == ' ') X p++; X if (*p++ == '1' && *p++ == '-') { X cur = 0; X while (isdigit(*p)) X cur = 10 * cur + *p++ - '0'; X if (*p == ',' && cur == ngsize) { X#ifdef DEBUG X fprintf(stderr, "Group: %s, all read\n", groupdir); X#endif X groupdir[0] = 0; X return 1; X } X if (cur > ngsize) { X /* X * Claim to have read articles X * which "active" believes have X * never existed - we believe "active" X */ X fprintf(stderr, X "%s %s...\r\n\t%s %ld to %ld\r\n", X "Warning: newsgroup", groupdir, X "last article claimed read reset from", X cur, ngsize); X } X } X } X X/* X * The key to understanding this piece of code is that a bit is set iff X * that article has NOT been read. Thus, we fill in the holes when X * commas are found (e.g. 1-20,30-35 will result in filling in the 21-29 X * holes), and so we assume the newsrc file is properly ordered, the way X * we write it out. X */ X if ((ngsize-minartno) > BITMAPSIZE) { X /* resize the bitmap array */ X (void) free (bitmap); X BITMAPSIZE = 8 * (((ngsize - minartno) + 7) / 8); X bitmap = malloc((unsigned)BITMAPSIZE/8); X if (bitmap == NULL) X xerror("Can't malloc bitmap"); X } X X cur = 0; X bzero(bitmap, (int) (ngsize-minartno)/8+1); /* 8 bits per character */ X X /* Decode the .newsrc line indicating what we have read. */ X for (ptr = rcbuf; *ptr && *ptr != ':'; ptr++) X ; X while (*ptr) { X while (!isdigit(*ptr) && *ptr) X ptr++; X if (!*ptr) X break; X (void) sscanf(ptr, "%ld", &next); X if (punct == ',') { X while (++cur < next) { X set(cur); X } X } X cur = next; X while (!ispunct(*ptr) && *ptr) X ptr++; X punct = *ptr; X } X if (rflag) X bit = ngsize+1; X else X bit = minartno -1; X nextbit(); X ngrp = 1; X return 0; X} X X#ifdef TMAIL Xcatchterm() X{ X (void) unlink(infile); X (void) unlink(outfile); X xxit(0); X} X X X/* X * The -M (Mail) interface. This code is a reasonably simple model for X * writing other interfaces. We write out all relevant articles to X * a temp file, then invoke Mail with an option to have it tell us which X * articles it read. Finally we count those articles as really read. X */ XMail() X{ X register FILE *fp = NULL, *ofp; X struct hbuf h; X register char *ptr, *fname; X int news = 0; X register int i; X X for(i=0;i<NUNREC;i++) X h.unrec[i] = NULL; X X ofp = xfopen(mktemp(outfile), "w"); X if (aflag && *datebuf) X if ((atime = cgtdate(datebuf)) == -1) X xerror("Cannot parse date string"); X while (!nextng()) X while (bit <= ngsize) { X (void) sprintf(filename, "%s/%ld", dirname(groupdir), bit); X if (access(filename, 4) X || ((fp = art_open (filename, "r")) == NULL) X || (hread(&h, fp, TRUE) == NULL) X || !aselect(&h, FALSE)) { X#ifdef DEBUG X fprintf(stderr, "Bad article '%s'\n", filename); X#endif X if (fp != NULL) { X (void) fclose(fp); X fp = NULL; X } X clear(bit); X nextbit(); X continue; X } X fname = ptr = index(h.from, '('); X if (fname) { X while (ptr && ptr[-1] == ' ') X ptr--; X if (ptr) X *ptr = 0; X fname++; X ptr = fname + strlen(fname) - 1; X if (*ptr == ')') X *ptr = 0; X } X h.subtime = cgtdate(h.subdate); X fprintf(ofp, "From %s %s", X#ifdef INTERNET X h.from[0] ? h.from : X#endif X h.path, ctime(&h.subtime)); X if (fname) X fprintf(ofp, "Full-Name: %s\n", fname); X fprintf(ofp, "Newsgroups: %s\n", h.nbuf); X fprintf(ofp, "Subject: %s\n", h.title); X fprintf(ofp, "Article-ID: %s/%ld\n\n", groupdir, bit); X tprint(fp, ofp, TRUE); X putc('\n', ofp); X news = TRUE; X (void) fclose(fp); X fp = NULL; X nextbit(); X } X updaterc(); X (void) fclose(ofp); X if (!news) { X fprintf(stderr, "No news.\n"); X (void) unlink(outfile); X return; X } X (void) signal(SIGHUP, catchterm); X (void) signal(SIGTERM, catchterm); X (void) sprintf(bfr, "%s -f %s -T %s", TMAIL, outfile, mktemp(infile)); X fwait(fsubr(ushell, bfr, (char *)NULL)); X ofp = xfopen(infile, "r"); X (void) fseek(actfp, 0L, 0); X while (fgets(afline, BUFLEN, actfp) != NULL) { X last = 0; X if (sscanf(afline, "%s %ld", bfr, &nngsize) < 2) { X bfr[0] = '\0'; X nngsize = 0; X } X if (!ngmatch(bfr, header.nbuf)) X continue; X *groupdir = 0; X if (selectng(bfr, TRUE, FALSE)) X continue; X (void) fseek(ofp, 0L, 0); X while (fgets(groupdir, BUFLEN, ofp) != NULL) { X (void) nstrip(groupdir); X ptr = index(groupdir, '/'); X *ptr = 0; X if (strcmp(bfr, groupdir)) X continue; X (void) sscanf(++ptr, "%ld", &last); X clear(last); X } X if (last) { X (void) strcpy(groupdir, bfr); X updaterc(); X } X } X (void) unlink(infile); X (void) unlink(outfile); X} X#endif X Xupdaterc() X{ X register long cur = 1, next = 1; X register int i; X register char *ptr; X char oldptr; X X sprintf(rcbuf, "%s%c ", groupdir, zapng ? '!' : ':'); X X zapng = FALSE; Xagain: X ptr = &rcbuf[strlen(rcbuf)]; X while (get(next) && next <= ngsize) X next++; X cur = next; X while (!(get(next)) && next <= ngsize) X next++; X if (cur == next) { X next = ngsize + 1; X goto skip; X } X if (ptr[-1] != ' ') X *ptr++ = ','; X if (cur + 1 == next) X (void) sprintf(ptr, "%ld", cur); X else X (void) sprintf(ptr, "%ld-%ld", cur, next - 1); Xskip: X if ((long) next > ngsize) { X if (strpbrk(rcbuf, ":!") == NULL) /* bad line, huh?? */ X return; X ptr = index(rcbuf, ' '); X if (ptr == NULL) /* impossible */ X return; X ptr--; X oldptr = *ptr; X ptr[0] = ':'; X ptr[1] = '\0'; X i = findrcline(groupdir); X if (i >= 0) { X ptr[0] = oldptr; X ptr[1] = ' '; X rcline[i] = realloc(rcline[i], (unsigned)(strlen(rcbuf) + 1)); X if (rcline[i] == NULL) X xerror("Cannot realloc"); X (void) strcpy(rcline[i], rcbuf); X#ifdef DEBUG X fprintf(stderr," new rcline = %s\n", rcline[i]); X#endif /* DEBUG */ X return; X } X if (++line > LINES) X xerror("Too many newsgroups"); X ptr[0] = oldptr; X ptr[1] = ' '; X if ((rcline[line] = malloc((unsigned)(strlen(rcbuf) + 1))) == NULL) X xerror("Not enough memory"); X (void) strcpy(rcline[line], rcbuf); X#ifdef DEBUG X fprintf(stderr," new rcline2 = %s\n", rcline[line]); X#endif /* DEBUG */ X return; X } X cur = next; X goto again; X} X Xnewrc(rcname) Xchar *rcname; X{ X register FILE *fp; X X if (close(creat(rcname, 0666))) { X (void) sprintf(bfr, "Cannot create %s", newsrc); X xerror(bfr); X } X X sprintf(bfr, "%s/users", LIB); X if ((fp = fopen(bfr, "a")) != NULL) { X fprintf(fp, "%s\n", username); X (void) fclose(fp); X (void) chmod(bfr, 0666); X } X} X Xnextbit() X{ X#ifdef DEBUG X fprintf(stderr,"nextbit() bit = %ld\n", bit); X#endif /* DEBUG */ X last = bit; X if (readmode == SPEC || xflag) { X if (rflag) X bit--; X else X bit++; X return; X } X if (rflag) X while (--bit, !get(bit) && bit > minartno) X ; X else X while (++bit, !get(bit) && bit <= ngsize) X ; X#ifdef DEBUG X fprintf(stderr,"nextng leaves bit as %ld\n", bit); X#endif /* DEBUG */ X} X X/* X * Return TRUE if the user has not ruled out this article. X */ Xaselect(hp, insist) Xregister struct hbuf *hp; Xint insist; X{ X if (insist) X return TRUE; X if (tflag && !titmat(hp, header.title)) X return FALSE; X if (aflag && cgtdate(hp->subdate) < atime) X return FALSE; X if (index(hp->nbuf, ',') && !rightgroup(hp)) X return FALSE; X if (fflag && (hp->followid[0] || prefix(hp->title, "Re:"))) X return FALSE; X return TRUE; X} X X/* X * Code to avoid showing multiple articles for news. X * Works even if you exit news. X * Returns nonzero if we should show this article. X */ Xrightgroup(hp) Xstruct hbuf *hp; X{ X char ng[BUFLEN]; X register char *p, *g; X int i, flag; X X strcpy(ng, hp->nbuf); X g = ng; X flag = 1; X while (g != NULL) { X p = index(g, ','); X if (p != NULL) { X *p++ = '\0'; X while (*p == ' ') X p++; X } X if (strcmp(g, groupdir) == 0) X return flag; X if (ngmatch(g, header.nbuf) X && ((i = findrcline(g)) >= 0 X && index(rcline[i], '!') == NULL)) X flag = 0; X g = p; X } X /* we must be in "junk" or "control" */ X return TRUE; X} X Xback() X{ X while (fseek(actfp, -2L, 1) != -1 && ftell(actfp) > 0L) { X if (getc(actfp) == '\n') X return 0; X } X if (ftell(actfp) == 0L) X return 0; X return 1; X} X X/* X * Trap interrupts. X */ Xonsig(n) Xint n; X{ X (void) signal(n, onsig); X SigTrap = n; X if (rcreadok < 2) { X fprintf(stderr, "Aborted early\n"); X xxit(0); X } X} X X/* X * finds the line in your .newsrc file (actually the in-core "rcline" X * copy of it) and returns the index into the array where it was found. X * -1 means it didn't find it. X * X * We play clever games here to make this faster. It's inherently X * quadratic - we spend lots of CPU time here because we search through X * the whole .newsrc for each line. The "prev" variable remembers where X * the last match was found; we start the search there and loop around X * to the beginning, in the hopes that the calls will be roughly in order. X */ Xint Xfindrcline(name) Xregister char *name; X{ X register char * p; X register int i; X register int top; X register int len; X static int prev; X static int didthru; X X for ( ; didthru <= line; ++didthru) X if ((p = index(rcline[didthru], '!')) != 0 || X (p = index(rcline[didthru], ':')) != 0) { X lentab[didthru] = (int)(p - rcline[didthru]); X } X len = strlen(name); X top = line; X i = prev; Xloop: X for ( ; i <= top; ++i) X if (lentab[i] == len && rcline[i] != NULL && X strncmp(name, rcline[i], len) == 0) X return prev = i; X if (i > line && line > prev - 1) { X i = 0; X top = prev - 1; X goto loop; X } X return -1; X} X X/* X * sortactive - make a local copy of the active file, sorted according X * to the user's preferences, according to his .newsrc file. X */ X Xstruct table_elt { X int rcindex; X long maxart, minart; X char yn; X}; X X#ifdef SORTACTIVE Xstatic int Xrcsort(a, b) Xchar *a, *b; X{ X return(((struct table_elt *)a)->rcindex - X ((struct table_elt *)b)->rcindex); X} X Xstatic char *newactivename = "/tmp/newsaXXXXXX"; X#endif /* SORTACTIVE */ X Xsortactive() X{ X register struct table_elt *tp; X register char *p; X register FILE *nfp, *afp; X char aline[BUFLEN], ngname[BUFLEN]; X struct table_elt table[LINES]; X int nlines = 0, i, delta, lastline; X X#ifdef SORTACTIVE X /* make a new sorted copy of ACTIVE */ X nfp = fopen(mktemp(newactivename), "w"); X (void) chmod(newactivename, 0600); X if (nfp == NULL) { X perror(newactivename); X return; X } X X /* look up all the lines in ACTIVE, finding their positions in .newsrc */ X p = ACTIVE; X ACTIVE = newactivename; X afp = xfopen(p, "r"); X#else /* !SORTACTIVE */ X afp = xfopen(ACTIVE, "r"); X#endif /* !SORTACTIVE */ X tp = table; X while (fgets(aline, sizeof aline, afp) != NULL) { X if (sscanf(aline,"%s %ld %ld %c", ngname, &tp->maxart, X &tp->minart, &tp->yn) != 4) X xerror("Active file corrupt"); X delta = tp->maxart - tp->minart; X if (delta >= BITMAPSIZE) X BITMAPSIZE = delta + 1; X if (Kflag && tp->maxart > 0 && ngmatch(ngname, header.nbuf)) { X int j; X X j = findrcline(ngname); X if (j >= 0 && index(rcline[j], '!') == NULL) { X char rbuf[BUFLEN]; X if (tp->maxart == 1) X sprintf(rbuf, "%s: 1", ngname); X else X sprintf(rbuf, "%s: 1-%ld", ngname, tp->maxart); X rcline[j] = realloc(rcline[j], X (unsigned)(strlen(rbuf)+1)); X if (rcline[j] == NULL) X xerror("Not enough memory"); X strcpy(rcline[j], rbuf); X } X } X#ifdef SORTACTIVE X tp->rcindex = findrcline(ngname); X if (tp->rcindex < 0) { X if (++line > LINES) X xerror("Too many newsgroups"); X strcat(ngname, ":"); X rcline[line] = malloc((unsigned)(strlen(ngname) + 1)); X if (rcline[line] == NULL) X xerror("Not enough memory"); X strcpy(rcline[line], ngname); X tp->rcindex = line; X } X tp++; X#endif /* SORTACTIVE */ X } X (void) fclose(afp); X BITMAPSIZE = 8 * ((BITMAPSIZE+7) / 8); X bitmap = malloc((unsigned)BITMAPSIZE/8); X if (bitmap == NULL) X xerror("Can't malloc bitmap"); X X#ifdef SORTACTIVE X /* sort by position in user's .newsrc file (new groups come up last) */ X nlines = tp - table; X qsort((char *)table, nlines, sizeof table[0], rcsort); X X tp = table; X lastline = tp->rcindex - 1; X /* copy active to newactive, in the new order */ X for (i = 0; i < nlines; i++) { X while (++lastline < tp->rcindex) { X if (strncmp(rcline[lastline], "options ", 8) == 0) { X fprintf(nfp, "%s\n", rcline[lastline]); X } else { X fprintf(stderr, "Duplicate .newsrc line or bad group %s\n", X rcline[lastline]); X lentab[lastline] = 0; X free(rcline[lastline]); X rcline[lastline] = NULL; X } X } X if (rcline[tp->rcindex] == NULL) X continue; X p = rcline[tp->rcindex]; X while (*p != ':' && *p != '!') X fputc(*p++, nfp); X (void) fprintf(nfp, " %ld %ld %c\n", tp->maxart, tp->minart, X tp->yn); X tp++; X } X (void) fclose(nfp); X#endif /* SORTACTIVE */ X} X X#if defined(BSD4_2) || defined(BSD4_1C) X#include <sys/dir.h> X# else X#include "ndir.h" X#endif X#include <errno.h> X X/* X * Routine to display header lines for all articles in newsgroup. If the flag X * argument is FALSE then only articles which are not marked as read in the X * bitmap will be displayed. This routine makes no attempt to determine if X * the article is in multiple groups and therefore should not be displayed at X * this time. X */ X Xstatic int *lg_array = NULL; Xstatic int *lg_entry; Xstatic int lg_max = 0; Xstatic int int_sig; Xextern int errno; X Xlg_cmp(p1, p2) Xint *p1, *p2; X{ X return *p1 - *p2; X} X Xlist_group(lgroup, displines, flag, pngsize) Xchar *lgroup; Xint displines, flag; Xlong pngsize; X{ X char *briefdate(); X struct hbuf hh; X register DIR *dirp; X register struct direct *dir; X register FILE *fp_art; X int i; X int entries; X unsigned int alloc_size; X int (*old_sig) (); X extern lg_trap(); X char *gets(); X X /* This should get the numbers from the active file XXX */ X if ((dirp = opendir(dirname(lgroup))) == NULL) { X printf("Can't open %s\r\n", dirname(lgroup)); X return; X } X entries = 0; X if (lg_array == NULL) { X lg_max = 50; X alloc_size = lg_max * sizeof(int); X lg_array = (int *) malloc(alloc_size); X } X while ((dir = readdir(dirp)) != NULL) { X if (dir->d_ino == 0) X continue; X i = atoi(dir->d_name); X if ((i < 1) || (i > pngsize)) X continue; X if (flag == FALSE) { X if (get(i) == 0) X continue; X } X if (++entries > lg_max) { X lg_max += 50; X alloc_size = lg_max * sizeof(int); X lg_array = (int *) realloc((char *) lg_array, alloc_size); X } X lg_array[entries - 1] = i; X } X if (entries == lg_max) { X lg_max++; X alloc_size = lg_max * sizeof(int); X lg_array = (int *) realloc((char *) lg_array, alloc_size); X } X qsort(lg_array, entries, sizeof *lg_array, lg_cmp); X lg_array[entries] = 0; X int_sig = 0; X old_sig = signal(SIGINT, lg_trap); X hh.unrec[0] = NULL; X for (lg_entry = lg_array; *lg_entry != 0 && int_sig == 0; lg_entry++) { X (void) sprintf(filename, "%s/%d", dirname(lgroup), *lg_entry); X fp_art = fopen(filename, "r"); X if (fp_art == NULL) X continue; X if (hread(&hh, fp_art, TRUE) == NULL) { X (void) fclose(fp_art); X continue; X } X printf("%5d %-20.20s %-13s %s\r\n", X *lg_entry, hh.from, X briefdate(hh.subdate), hh.title); X for (i = 0; i < displines;) { X if (fgets(bfr, LBUFLEN, fp_art) == NULL) { X break; X } X if ((bfr[0] == '\n') || (bfr[0] == '>')) { X continue; X } X printf("%s", bfr); X i++; X } X (void) fclose(fp_art); X } X (void) fflush(stdout); X X closedir(dirp); X (void) signal(SIGINT, old_sig); /* restore to old value */ X X printf("[Press RETURN to continue]"); X (void) fflush(stdout); X X while (TRUE) { X errno = 0; X i = getchar(); X if (errno == EINTR) X continue; X if (i == '\n' || i == '\r') X break; X if (i == EOF) X break; X if (i == '\4') X break; X } X (void) free(lg_array); X lg_array = NULL; X X} X Xlg_trap(code) Xint code; X{ X X int_sig = 1; X (void) signal(code, lg_trap); /* reset signal */ X X} END_OF_FILE if test 18733 -ne `wc -c <'rfuncs.c'`; then echo shar: \"'rfuncs.c'\" unpacked with wrong size! fi # end of 'rfuncs.c' fi if test -f 'header.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'header.c'\" else echo shar: Extracting \"'header.c'\" \(16672 characters\) sed "s/^X//" >'header.c' <<'END_OF_FILE' X/* X * This software is Copyright (c) 1986 by Rick Adams. X * X * Permission is hereby granted to copy, reproduce, redistribute or X * otherwise use this software as long as: there is no monetary X * profit gained specifically from the use or reproduction or this X * software, it is not sold, rented, traded or otherwise marketed, and X * this copyright notice is included prominently in any copy X * made. X * X * The author make no claims as to the fitness or correctness of X * this software for any use whatsoever, and it is provided as is. X * Any use of this software is at the user's own risk. X * X * header.c - header functions plus some other goodies X */ X X#ifdef SCCSID Xstatic char *SccsId = "@(#)header.c 2.48 3/20/87"; X#endif /* SCCSID */ X X#include <stdio.h> X#include "params.h" X#include "patchlevel.h" X Xchar *hfgets(); X Xchar *news_version = NEWS_VERSION; X X/* X * Read header from file fp into *hp. If wholething is FALSE, X * it's an incremental read, otherwise start from scratch. X * Return (FILE *) if header okay, else NULL. X */ XFILE * Xhread(hp, fp, wholething) Xregister struct hbuf *hp; XFILE *fp; Xint wholething; X{ X#ifndef GENERICPATH X register int len; X#endif /* GENERICPATH */ X register int i; X#ifdef OLD X char *p; X#endif /* OLD */ X X if (wholething) { X for(i=0;i<NUNREC;i++) X if (hp->unrec[i] != NULL) X free(hp->unrec[i]); X else X break; X bzero((char *)hp, sizeof (*hp)); X for (i=0;i<NUNREC;i++) X hp->unrec[i] = NULL; X } X X /* Check that it's a B news style header. */ X if (hfgets(bfr, PATHLEN, fp) != NULL && isalpha(bfr[0]) X && index(bfr, ':')) X if (frmread(fp, hp)) X goto strip; X X if (!nstrip(bfr+1)) X return NULL; X X /* It's not. Try A news (begins with PROTO). */ X if (bfr[0] != PROTO) X return NULL; X#ifndef OLD X logerr("Can not process A news format article without OLD defined"); X#else /* OLD */ X /* Read in an A news format article. */ X p = index(bfr+1, '.'); X if (p == NULL) { X (void) strcpy(hp->ident, bfr+1); X return NULL; X } X *p++ = '\0'; X (void) sprintf(hp->ident, "<%s@%s%s>", p, bfr+1, ".UUCP"); X X /* Newsgroup List */ X if (hfgets(hp->nbuf, BUFLEN, fp) == NULL || !nstrip(hp->nbuf)) X return NULL; X /* source path */ X if (hfgets(hp->path, PATHLEN, fp) == NULL || !nstrip(hp->path)) X return NULL; X /* date */ X if (hfgets(hp->subdate, DATELEN, fp) == NULL || !nstrip(hp->subdate)) X return NULL; X /* title */ X if (hfgets(hp->title, BUFLEN, fp) == NULL || !nstrip(hp->title)) X return NULL; X#endif /* OLD */ X Xstrip: /* strip off sys! from front of path. */ X#ifndef GENERICPATH X if (strncmp(PATHSYSNAME, hp->path, (len = strlen(PATHSYSNAME))) == 0 X && index(NETCHRS, hp->path[len])) X (void) strcpy(hp->path, &(hp->path[len+1])); X#endif /* GENERICPATH */ X lcase(hp->nbuf); X X /* Intuit the From: line if only a path was given. */ X if (wholething) { X#ifdef OLD X if (hp->from[0] == '\0') X intuitfrom(hp); X else X#endif /* OLD */ X fixfrom(hp); X } X X return fp; X} X X X/* X * Get header info from mail-format file. X * Return non-zero on success. X */ X#define FROM 1 X#define NEWSGROUP 2 X#define TITLE 3 X#define SUBMIT 4 X#define RECEIVE 5 X#define EXPIRE 6 X#define ARTICLEID 7 X#define MESSAGEID 8 X#define REPLYTO 9 X#define FOLLOWID 10 X#define CONTROL 11 X#define SENDER 12 X#define FOLLOWTO 13 X#define PATH 14 X#define POSTVERSION 15 X#define RELAYVERSION 16 X#define DISTRIBUTION 17 X#define ORGANIZATION 18 X#define NUMLINES 19 X#define KEYWORDS 20 X#define APPROVED 21 X#define NFID 22 X#define NFFROM 23 X#define XREF 24 X#define SUMMARY 25 X#define XPATH 26 X#define OTHER 99 X Xchar *malloc(); X Xfrmread(fp, hp) Xregister FILE *fp; Xregister struct hbuf *hp; X{ X int unreccnt = 0; X register int i; X long curpos; X X i = type(bfr); X do { X curpos = ftell(fp); X switch (i) { X case PATH: X getfield(hp->path, sizeof(hp->path)); X break; X case FROM: X getfield(hp->from, sizeof(hp->from)); X break; X case NEWSGROUP: X getfield(hp->nbuf, sizeof(hp->nbuf)); X break; X case TITLE: X getfield(hp->title, sizeof(hp->title)); X break; X case SUBMIT: X getfield(hp->subdate, sizeof(hp->subdate)); X break; X case EXPIRE: X getfield(hp->expdate, sizeof(hp->expdate)); X break; X#ifdef OLD X case ARTICLEID: X /* Believe Message-ID in preference to Article-ID */ X if (hp->ident[0] == '\0') { X register char *p; X char msgb[NAMELEN]; X getfield(msgb, sizeof msgb); X p = index(msgb, '.'); X if (p == NULL) { X (void) strcpy(hp->ident, msgb); X } else { X *p++ = '\0'; X (void) sprintf(hp->ident, "<%s@%s%s>", p, msgb, ".UUCP"); X } X } X break; X#endif /* OLD */ X case MESSAGEID: X getfield(hp->ident, sizeof(hp->ident)); X break; X case REPLYTO: X getfield(hp->replyto, sizeof(hp->replyto)); X break; X case FOLLOWID: X getfield(hp->followid, sizeof(hp->followid)); X break; X case SENDER: X getfield(hp->sender, sizeof(hp->sender)); X break; X case FOLLOWTO: X getfield(hp->followto, sizeof(hp->followto)); X break; X case CONTROL: X getfield(hp->ctlmsg, sizeof(hp->ctlmsg)); X break; X case DISTRIBUTION: X getfield(hp->distribution, sizeof(hp->distribution)); X if (strcmp(hp->distribution, "net") == 0) X hp->distribution[0] = '\0'; X break; X case ORGANIZATION: X getfield(hp->organization, sizeof(hp->organization)); X break; X case NUMLINES: X getfield(hp->numlines, sizeof(hp->numlines)); X hp->intnumlines = atoi(hp->numlines); X break; X case KEYWORDS: X getfield(hp->keywords, sizeof(hp->keywords)); X break; X case APPROVED: X getfield(hp->approved, sizeof(hp->approved)); X break; X case NFID: X getfield(hp->nf_id, sizeof(hp->nf_id)); X break; X case NFFROM: X getfield(hp->nf_from, sizeof(hp->nf_from)); X break; X /* discard these lines */ X case XREF: X case XPATH: X case RELAYVERSION: X case POSTVERSION: X case RECEIVE: X break; X case SUMMARY: X getfield(hp->summary, sizeof(hp->summary)); X break; X case OTHER: X if (unreccnt < NUNREC) { X if ((hp->unrec[unreccnt] = malloc((unsigned)(strlen(bfr) + 1))) != NULL ) { X (void) strcpy(hp->unrec[unreccnt], bfr); X (void) nstrip(hp->unrec[unreccnt]); X unreccnt++; X } else X xerror("frmread: out of memory"); X } X break; X } X } while ((i = type(hfgets(bfr, LBUFLEN, fp))) > 0); X X if (*bfr != '\n') X fseek(fp, curpos, 0); X if ((hp->from[0] || hp->path[0]) && hp->subdate[0] && hp->ident[0]) X return TRUE; X return FALSE; X} X X#ifdef OLD X/* X * There was no From: line in the message (because it was generated by X * an old news program). Guess what it should have been and create it. X */ Xintuitfrom(hp) Xregister struct hbuf *hp; X{ X char *tp; X char *user, *host; X char *tailpath(), *rindex(); X char *at, *dot; X char pathbuf[PATHLEN]; X char fullname[BUFLEN]; X extern char *mydomain(); X X tp = tailpath(hp); X user = rindex(tp, '!'); X if (user == NULL) X user = tp; X else X *user++ = '\0'; X X /* Check for an existing Internet address on the end. */ X at = index(user, '@'); X if (at) { X dot = index(at, '.'); X if (dot) { X (void) strcpy(hp->from, user); X return; X } X /* @ signs are illegal except for the biggie, so */ X *at = '%'; X } X X if (tp[0] == '.') X host = index(tp, '!') + 1; X else if (user == tp) X host = FROMSYSNAME; X else X host = tp; X X tp = index(host, '@'); X if (tp != NULL) X *tp = 0; X if (index(host, '.') != NULL) X (void) sprintf(hp->from, "%s@%s%s", user, host, mydomain()); X else X (void) sprintf(hp->from, "%s@%s", user, host); X X skin(pathbuf, fullname, hp->path); /* remove RFC822-style comments */ X if (fullname[0] != '\0') { X strcat(hp->from, " ("); X (void) strcat(hp->from, fullname); X strcat(hp->from, ")"); X } X strcpy(hp->path, pathbuf); /* and stick it back in */ X} X#endif /* OLD */ X X/* X * Canonicalize the "From:" line into the form X * X * From: <mail-address> (full-name) X * X * RFC822 doesn't require the comment to be at the end of the string X * like that. X */ Xfixfrom(hp) Xregister struct hbuf *hp; X{ X char frombuf[PATHLEN]; X char fullname[BUFLEN]; X X skin(frombuf, fullname, hp->from); /* remove RFC822-style comments */ X if (fullname[0] != '\0') { X strcat(frombuf, " ("); X strcat(frombuf, fullname); X strcat(frombuf, ")"); X } X strcpy(hp->from, frombuf); /* stick the canonicalized "from" back in */ X} X Xskin(name, fullname, hfield) Xchar *name; Xchar *fullname; Xchar *hfield; X{ X register int c; X register char *cp, *cp2; X char *bufend; X int gotlt, parenlev, lastsp; X int seenfullname = FALSE; X X *fullname = '\0'; /* no full name yet */ X if (strpbrk(hfield, "(< ") == NULL) { /* include ',' ?? */ X strcpy(name, hfield); X return; X } X gotlt = 0; X parenlev = 0; X lastsp = 0; X bufend = name; X for (cp = hfield, cp2 = bufend; c = *cp++; ) { X switch (c) { X case '(': X /* X * Start of a "comment". X * Ignore it, or save it in "fullname" if we haven't X * seen a comment yet. X */ X parenlev++; X while ((c = *cp) != 0) { X cp++; X switch (c) { X case '\\': X if ((c = *cp) == 0) X goto outcm; X cp++; X break; X case '(': X parenlev++; X break; X case ')': X parenlev--; X if (parenlev == 0) X goto outcm; X break; X } X if (!seenfullname) X *fullname++ = c; X } X outcm: X parenlev = 0; X lastsp = 0; X if (!seenfullname) { X *fullname = '\0'; X seenfullname = TRUE; /* only extract first comment */ X } X break; X X case '"': X /* X * Start of a "quoted-string". X * Copy it in its entirety. X */ X while ((c = *cp) != 0) { X cp++; X switch (c) { X case '\\': X if ((c = *cp) == 0) X goto outqs; X cp++; X break; X case '"': X goto outqs; X } X *cp2++ = c; X } X outqs: X lastsp = 0; X break; X X case ' ': X if (cp[0] == 'a' && cp[1] == 't' && cp[2] == ' ') X cp += 3, *cp2++ = '@'; X else X if (cp[0] == '@' && cp[1] == ' ') X cp += 2, *cp2++ = '@'; X else X lastsp = 1; X break; X X case '<': X if (!seenfullname) { X *cp2 = '\0'; X strcpy(fullname, name); X seenfullname = TRUE; X } X cp2 = bufend; X gotlt++; X lastsp = 0; X break; X X case '>': X if (gotlt) { X gotlt = 0; X /* X * this doesn't seem reasonable, what about (,) X * or "," ?? X */ X while (*cp != ',' && *cp != 0) X cp++; X if (*cp == 0 ) X goto done; X *cp2++ = ','; X *cp2++ = ' '; X bufend = cp2; X break; X } X X /* Fall into . . . */ X X default: X if (lastsp) { X lastsp = 0; X *cp2++ = ' '; X } X *cp2++ = c; X break; X } X } Xdone: X *cp2 = 0; X} X X X#ifdef OLD Xchar * Xoident(ident) Xchar *ident; X{ X char lbuf[BUFLEN]; X static char oidbuf[BUFLEN]; X register char *p, *q; X X (void) strcpy(lbuf, ident); X p = index(lbuf, '@'); X if (p == NULL) X return ident; X *p++ = '\0'; X q = index(p, '.'); X if (q == NULL) X q = index(p, '>'); X if (q) X *q++ = '\0'; X p[SNLN] = '\0'; X (void) sprintf(oidbuf, "%s.%s", p, lbuf+1); X return oidbuf; X} X#endif /* OLD */ X X/* X * Get the given field of a header (char * parm) from bfr, but only X * if there's something actually there (after the colon). Don't X * bother if we already have an entry for this field. X */ Xgetfield(hpfield, size) Xchar *hpfield; Xint size; X{ X register char *ptr; X X if (hpfield[0]) X return; X for (ptr = index(bfr, ':'); isspace(*++ptr); ) X ; X if (*ptr != '\0') { X (void) strncpy(hpfield, ptr, size - 1); X (void) nstrip(hpfield); X } X} X X X#define its(type) (prefix(ptr, type)) Xtype(ptr) Xregister char *ptr; X{ X register char *colon, *space; X X if (ptr == NULL) X return FALSE; X if (its("From: ")) X if (index(ptr, '@') || !index(ptr, '!')) X return FROM; X else X return PATH; X if (its("Path: ")) X return PATH; X if (its("Newsgroups: ")) X return NEWSGROUP; X if (its("Subject: ")) X return TITLE; X if (its("Date: ")) X return SUBMIT; X if (its("Date-Received: ")) X return RECEIVE; X#ifdef OLD X if (its("Title: ")) X return TITLE; X if (its("Posted: ")) X return SUBMIT; X if (its("Received: ")) X return RECEIVE; X#endif /* OLD */ X if (its("Expires: ")) X return EXPIRE; X if (its("Article-I.D.: ")) X return ARTICLEID; X if (its("Message-ID: ")) X return MESSAGEID; X if (its("Reply-To: ")) X return REPLYTO; X if (its("References: ")) X return FOLLOWID; X if (its("Control: ")) X return CONTROL; X if (its("Sender: ")) X return SENDER; X if (its("Followup-To: ")) X return FOLLOWTO; X if (its("Posting-Version: ")) X return POSTVERSION; X if (its("Relay-Version: ")) X return RELAYVERSION; X if (its("Distribution: ")) X return DISTRIBUTION; X if (its("Organization: ")) X return ORGANIZATION; X if (its("Lines: ")) X return NUMLINES; X if (its("Summary: ")) X return SUMMARY; X if (its("Keywords: ")) X return KEYWORDS; X if (its("Approved: ")) X return APPROVED; X if (its("Nf-ID: ")) X return NFID; X if (its("Nf-From: ")) X return NFFROM; X if (its("Xref: ")) X return XREF; X if (its("Xpath: ")) X return XPATH; X if (!isalpha(*ptr)) X return FALSE; X colon = index(ptr, ':'); X space = index(ptr, ' '); X if (!colon || space && space < colon) X return FALSE; X return OTHER; X} X X/* X * Write header at 'hp' on stream 'fp' in B+ format. Include received date X * if wr is 1. Leave off sysname if wr is 2. X */ Xihwrite(hp, fp, wr) Xregister struct hbuf *hp; Xregister FILE *fp; Xint wr; X{ X int iu; X time_t t; X time_t cgtdate(); X X /* X * We're being tricky with Path/From because of upward compatibility X * issues. The new version considers From and Path to be separate. X * The old one thinks they both mean "Path" but only believes the X * first one it sees, so will ignore the second. X */ X if (prefix(hp->path, PATHSYSNAME) && X index(NETCHRS, hp->path[strlen(PATHSYSNAME)])) X fprintf(fp, "Path: %s\n", hp->path); X else X fprintf(fp, "Path: %s!%s\n", PATHSYSNAME, hp->path); X if (hp->from[0]) X fprintf(fp, "From: %s\n", hp->from); X X fprintf(fp, "Newsgroups: %s\n", hp->nbuf); X fprintf(fp, "Subject: %s\n", hp->title); X if (*hp->summary) X fprintf(fp, "Summary: %s\n", hp->summary); X if (*hp->keywords) X fprintf(fp, "Keywords: %s\n", hp->keywords); X fprintf(fp, "Message-ID: %s\n", hp->ident); X t = cgtdate(hp->subdate); X fprintf(fp, "Date: %s\n", arpadate(&t)); X#ifdef OLD X fprintf(fp, "Article-I.D.: %s\n", oident(hp->ident)); X fprintf(fp, "Posted: %s", ctime(&t)); X#endif /* OLD */ X if (*hp->expdate) X fprintf(fp, "Expires: %s\n", hp->expdate); X if (*hp->followid) { X register char *dp, *cp; X X dp = cp = hp->followid; X while (*cp != '\0') X if (*cp == '<' && *(cp + 1) == '>') X cp += 2; X else X *dp++ = *cp++; X *dp = '\0'; X if (*hp->followid) X fprintf(fp, "References: %s\n", hp->followid); X } X if (*hp->ctlmsg) X fprintf(fp, "Control: %s\n", hp->ctlmsg); X if (*hp->sender) X fprintf(fp, "Sender: %s\n", hp->sender); X if (*hp->replyto) X fprintf(fp, "Reply-To: %s\n", hp->replyto); X if (*hp->followto) X fprintf(fp, "Followup-To: %s\n", hp->followto); X if (*hp->distribution) X fprintf(fp, "Distribution: %s\n", hp->distribution); X if (*hp->organization) X fprintf(fp, "Organization: %s\n", hp->organization); X if (*hp->numlines) X fprintf(fp, "Lines: %s\n", hp->numlines); X if (*hp->approved) X fprintf(fp, "Approved: %s\n", hp->approved); X if (*hp->nf_id) X fprintf(fp, "Nf-ID: %s\n", hp->nf_id); X if (*hp->nf_from) X fprintf(fp, "Nf-From: %s\n", hp->nf_from); X#ifdef DOXREFS X if ( wr ==1 && *hp->xref) X fprintf(fp, "Xref: %s\n", hp->xref); X#endif /* DOXREFS */ X for (iu = 0; iu < NUNREC; iu++) { X if (hp->unrec[iu]) X fprintf(fp, "%s\n", &hp->unrec[iu][0]); X } X putc('\n', fp); X} X X X#ifndef BSD4_2 X/* X * Set nc bytes, starting at cp, to zero. X */ Xbzero(cp, nc) Xregister char *cp; Xregister int nc; X{ X if (nc > 0) X do { X *cp++ = 0; X } while (--nc); X} X#endif /* !BSD4_2 */ X X/* X * hfgets is like fgets, but deals with continuation lines. X * It also ensures that even if a line that is too long is X * received, the remainder of the line is thrown away X * instead of treated like a second line. X */ Xchar * Xhfgets(buf, len, fp) Xchar *buf; Xint len; XFILE *fp; X{ X register int c; X register int n = 0; X register char *cp; X X cp = buf; X while (n < len && (c = getc(fp)) != EOF) { X if (c == '\n') X break; X if (isprint(c) || c == '\b' || c == ' ' || c == '\t') { X *cp++ = c; X n++; X } X } X if (c == EOF && cp == buf) X return NULL; X *cp = '\0'; X X if (c != '\n') { X /* Line too long - part read didn't fit into a newline */ X while ((c = getc(fp)) != '\n' && c != EOF) X ; X } else if (cp == buf) { X /* Don't look for continuation of blank lines */ X *cp++ = '\n'; X *cp = '\0'; X return buf; X } X X while ((c = getc(fp)) == ' ' || c == '\t') { /* for each cont line */ X /* Continuation line. */ X if ((n += 2) < len) { X *cp++ = '\n'; X *cp++ = c; X } X while ((c = getc(fp)) != '\n' && c != EOF) X if ((isprint(c) || c == '\b' || c == ' ' || c == '\t') X && n++ < len) X *cp++ = c; X } X if (n >= len - 1) X cp = buf + len - 2; X *cp++ = '\n'; X *cp = '\0'; X if (c != EOF) X (void) ungetc(c, fp); /* push back first char of next header */ X return buf; X} END_OF_FILE if test 16672 -ne `wc -c <'header.c'`; then echo shar: \"'header.c'\" unpacked with wrong size! fi # end of 'header.c' fi echo shar: End of shell archive. exit 0 -- "Zeta Microcomputer Software" ACSnet: nick@ultima.cs.uts.oz UUCP: ...!uunet!munnari!ultima.cs.uts.oz!nick Fidonet: Nick Andrew on 3:713/602 (Zeta)
nick@ultima.cs.uts.oz (Nick Andrew) (12/07/89)
#! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of shell archive." # Contents: makeactive.sh funcs2.c getdate.y funcs.c # Wrapped by nick@nswitgould on Thu Dec 7 22:41:08 1989 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'makeactive.sh' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'makeactive.sh'\" else echo shar: Extracting \"'makeactive.sh'\" \(15147 characters\) sed "s/^X//" >'makeactive.sh' <<'END_OF_FILE' X: "Create active file and newsgroup hierarchy for new machine" X: "Usage: sh makeactive.sh LIBDIR SPOOLDIR NEWSUSR NEWSGRP" X: '@(#)makeactive 1.23 12/16/86' XLIBDIR=$1 XSPOOLDIR=$2 XNEWSUSR=$3 XNEWSGRP=$4 Xcat <<"E_O_F" > /tmp/$$groups Xgeneral Articles that should be read by everyone on your local system Xnet.sources For the posting of software packages & documentation. Xnet.sources.bugs For bug fixes and features discussion Xnet.sources.games Postings of recreational software Xnet.sources.mac Software for the Apple Macintosh Xmod.announce General announcements of interest to all. (Moderated) Xmod.announce.newusers Explanatory postings for new users. (Moderated) Xmod.ai Discussions about Artificial Intelligence (Moderated) Xmod.amiga Commodore Amiga micros -- info, uses, but no programs. (Moderated) Xmod.amiga.binaries Encoded public domain programs in binary form. (Moderated) Xmod.amiga.sources Public domain software in source code format. (Moderated) Xmod.compilers Discussion about compiler construction, theory, etc. (Moderated) Xmod.computers Discussion about various computers and related. (Moderated) Xmod.computers.68k 68000-based systems. (Moderated) Xmod.computers.apollo Apollo computer systems. (Moderated) Xmod.computers.masscomp The Masscomp line of computers. (Moderated) Xmod.computers.ibm-pc The IBM PC, PC-XT, and PC-AT. (Moderated) Xmod.computers.laser-printers Laser printers, hardware and software. (Moderated) Xmod.computers.pyramid Pyramid 90x computers. (Moderated) Xmod.computers.ridge Ridge 32 computers and ROS. (Moderated) Xmod.computers.sequent Sequent systems, (esp. Balance 8000). (Moderated) Xmod.computers.sun Sun "workstation" computers (Moderated) Xmod.computers.vax DEC's VAX* line of computers & VMS. (Moderated) Xmod.computers.workstations Various workstation-type computers. (Moderated) Xmod.conferences Calls for papers and conference announcements. (Moderated) Xmod.comp-soc Discussion on the impact of technology on society. (Moderated) Xmod.graphics Graphics software, hardware, theory, etc. (Moderated) Xmod.human-nets Computer aided communications digest. (Moderated) Xmod.mac Apple Macintosh micros -- info, uses, but no programs. (Moderated) Xmod.mac.binaries Encoded public domain programs in binary form. (Moderated) Xmod.mac.sources Public domain software in source code format. (Moderated) Xmod.mag.otherrealms Edited science fiction and fantasy "magazine". (Moderated) Xmod.map Various maps, including UUCP maps (Moderated) Xmod.music Reviews and discussion of things musical (Moderated) Xmod.music.gaffa Progressive music discussions (e.g., Kate Bush). (Moderated) Xmod.newprod Announcements of new products of interest to readers (Moderated) Xmod.newslists Postings of news-related statistics and lists (Moderated) Xmod.os Disussions about operating systems and related areas. (Moderated) Xmod.os.os9 Discussions about the os9 operating system. (Moderated) Xmod.os.unix Discussion of UNIX* features and bugs. (Moderated) Xmod.philosophy Discussion of philosphical issues and concepts. (Moderated) Xmod.philosophy.tech Technical philosophy: math, science, logic, etc (Moderated) Xmod.politics Discussions on political problems, systems, solutions. (Moderated) Xmod.politics.arms-d Arms discussion digest. (Moderated) Xmod.protocols Various forms and types of FTP protocol discussions. (Moderated) Xmod.protocols.appletalk Applebus hardware & software discussion. (Moderated) Xmod.protocols.kermit Information about the Kermit package. (Moderated) Xmod.protocols.tcp-ip TCP and IP network protocols. (Moderated) Xmod.psi Discussion of paranormal abilities and experiences. (Moderated) Xmod.rec Discussions on pastimes (not currently active) (Moderated) Xmod.rec.guns Discussions about firearms (Moderated) Xmod.recipes A "distributed cookbook" of screened recipes. (Moderated) Xmod.religion Top-level group with no moderator (as of yet). (Moderated) Xmod.religion.christian Discussions on Christianity and related topics. (Moderated) Xmod.risks Risks to the public from computers & users. (Moderated) Xmod.sources postings of public-domain sources. (Moderated) Xmod.sources.doc Archived public-domain documentation. (Moderated) Xmod.sources.games Postings of public-domain game sources (Moderated) Xmod.std Discussion about various standards (Moderated) Xmod.std.c Discussion about C language standards (Moderated) Xmod.std.mumps Discussion for the X11.1 committee on Mumps (Moderated) Xmod.std.unix Discussion for the P1003 committee on UNIX (Moderated) Xmod.techreports Announcements and lists of technical reports. (Moderated) Xmod.telecom Telecommunications digest. (Moderated) Xcomp.ai Artificial intelligence discussions. Xcomp.arch Computer architecture. Xcomp.bugs.2bsd Reports of UNIX* version 2BSD related bugs. Xcomp.bugs.4bsd Reports of UNIX version 4BSD related bugs. Xcomp.bugs.misc General bug reports and fixes (includes V7 & uucp). Xcomp.bugs.sys5 Reports of USG (System III, V, etc.) bugs. Xcomp.cog-eng Cognitive engineering. Xcomp.databases Database and data management issues and theory. Xcomp.dcom.lans Local area network hardware and software. Xcomp.dcom.modems Data communications hardware and software. Xcomp.edu Computer science education. Xcomp.emacs EMACS editors of different flavors. Xcomp.graphics Computer graphics, art, animation, image processing, Xcomp.lang.ada Discussion about Ada*. Xcomp.lang.apl Discussion about APL. Xcomp.lang.c Discussion about C. Xcomp.lang.c++ The object-oriented C++ language. Xcomp.lang.forth Discussion about Forth. Xcomp.lang.fortran Discussion about FORTRAN. Xcomp.lang.lisp Discussion about LISP. Xcomp.lang.misc Different computer languages not specifically listed. Xcomp.lang.modula2 Discussion about Modula-2. Xcomp.lang.pascal Discussion about Pascal. Xcomp.lang.prolog Discussion about PROLOG. Xcomp.lang.smalltalk Discussion about Smalltalk 80. Xcomp.lsi Large scale integrated circuits. Xcomp.mail.headers Gatewayed from the ARPA header-people list. Xcomp.mail.misc General discussions about computer mail. Xcomp.mail.uucp Mail in the uucp network environment. Xcomp.misc General topics about computers not covered elsewhere. Xcomp.org.decus DEC* Users' Society newsgroup. Xcomp.org.usenix USENIX Association events and announcements. Xcomp.os.cpm Discussion about the CP/M operating system. Xcomp.os.eunice The SRI Eunice system. Xcomp.os.misc General OS-oriented discussion not carried elsewhere. Xcomp.periphs Peripheral devices. Xcomp.sources.d For any discussion of source postings. Xcomp.sources.wanted Requests for software and fixes. Xcomp.std.internat Discussion about international standards Xcomp.sys.amiga Discussion about the Amiga micro. Xcomp.sys.apple Discussion about Apple micros. Xcomp.sys.atari.8bit Discussion about 8 bit Atari micros. Xcomp.sys.atari.st Discussion about 16 bit Atari micros. Xcomp.sys.att Discussions about AT&T microcomputers Xcomp.sys.cbm Discussion about Commodore micros. Xcomp.sys.dec Discussions about DEC computer systems. Xcomp.sys.hp Discussion about Hewlett/Packard's. Xcomp.sys.ibm.pc Discussion about IBM personal computers. Xcomp.sys.intel Disucussions about Intel systems and parts. Xcomp.sys.m6809 Discussion about 6809's. Xcomp.sys.m68k Discussion about 68k's. Xcomp.sys.mac Discussions about the Apple Macintosh & Lisa. Xcomp.sys.misc Micro computers of all kinds. Xcomp.sys.nsc.32k National Semiconductor 32000 series chips Xcomp.sys.tandy Discussion about TRS-80's. Xcomp.sys.ti Discussion about Texas Instruments. Xcomp.terminals All sorts of terminals. Xcomp.text Text processing. Xcomp.unix.questions UNIX neophytes group. Xcomp.unix.wizards Discussions, bug reports, and fixes on and for UNIX. Xcomp.unix.xenix Discussion about the Xenix OS. Xmisc.consumers Consumer interests, product reviews, etc. Xmisc.consumers.house Discussion about owning and maintaining a house. Xmisc.forsale Short, tasteful postings about items for sale. Xmisc.headlines Current interest: drug testing, terrorism, etc. Xmisc.invest Investments and the handling of money. Xmisc.jobs Job announcements, requests, etc. Xmisc.kids Children, their behavior and activities. Xmisc.legal Legalities and the ethics of law. Xmisc.misc Various discussions not fitting in any other group. Xmisc.taxes Tax laws and advice. Xmisc.test For testing of network software. Very boring. Xmisc.wanted Requests for things that are needed (NOT software). Xnews.admin Comments directed to news administrators. Xnews.config Postings of system down times and interruptions. Xnews.groups Discussions and lists of newsgroups Xnews.lists News-related statistics and lists (Moderated) Xnews.misc Discussions of USENET itself. Xnews.newsites Postings of new site announcements. Xnews.software.b Discussion about B news software. Xnews.software.notes Notesfile software from the Univ. of Illinois. Xnews.stargate Discussion about satellite transmission of news. Xnews.sysadmin Comments directed to system administrators. Xrec.arts.books Books of all genres, shapes, and sizes. Xrec.arts.comics The funnies, old and new. Xrec.arts.drwho Discussion about Dr. Who. Xrec.arts.movies Reviews and discussions of movies. Xrec.arts.poems For the posting of poems. Xrec.arts.sf-lovers Science fiction lovers' newsgroup. Xrec.arts.startrek Star Trek, the TV show and the movies. Xrec.arts.tv The boob tube, its history, and past and current shows. Xrec.arts.tv.soaps Postings about soap operas. Xrec.arts.wobegon "A Prairie Home Companion" radio show discussion. Xrec.audio High fidelity audio. Xrec.autos Automobiles, automotive products and laws. Xrec.autos.tech Technical aspects of automobiles, et. al. Xrec.aviation Aviation rules, means, and methods. Xrec.bicycles Bicycles, related products and laws. Xrec.birds Hobbyists interested in bird watching. Xrec.boats Hobbyists interested in boating. Xrec.food.cooking Food, cooking, cookbooks, and recipes. Xrec.food.drink Wines and spirits. Xrec.food.veg Vegetarians. Xrec.games.board Discussion and hints on board games. Xrec.games.bridge Hobbyists interested in bridge. Xrec.games.chess Chess & computer chess. Xrec.games.empire Discussion and hints about Empire. Xrec.games.frp Discussion about Fantasy Role Playing games. Xrec.games.go Discussion about Go. Xrec.games.hack Discussion, hints, etc. about the Hack game. Xrec.games.misc Games and computer games. Xrec.games.pbm Discussion about Play by Mail games. Xrec.games.rogue Discussion and hints about Rogue. Xrec.games.trivia Discussion about trivia. Xrec.games.video Discussion about video games. Xrec.gardens Gardening, methods and results. Xrec.ham-radio Amateur Radio practices, contests, events, rules, etc. Xrec.ham-radio.packet Discussion about packet radio setups. Xrec.humor Jokes and the like. May be somewhat offensive. Xrec.humor.d Discussions on the content of rec.humor articles Xrec.mag Magazine summaries, tables of contents, etc. Xrec.misc General topics about recreational/participant sports. Xrec.motorcycles Motorcycles and related products and laws. Xrec.music.classical Discussion about classical music. Xrec.music.folk Folks discussing folk music of various sorts Xrec.music.gdead A group for (Grateful) Dead-heads Xrec.music.makers For performers and their discussions. Xrec.music.misc Music lovers' group. Xrec.music.synth Synthesizers and computer music Xrec.nude Hobbyists interested in naturist/nudist activities. Xrec.pets Pets, pet care, and household animals in general. Xrec.photo Hobbyists interested in photography. Xrec.puzzles Puzzles, problems, and quizzes. Xrec.railroad Real and model train fans' newsgroup. Xrec.scuba Hobbyists interested in SCUBA diving. Xrec.skiing Hobbyists interested in skiing. Xrec.skydiving Hobbyists interested in skydiving. Xrec.sport.baseball Discussion about baseball. Xrec.sport.basketball Discussion about basketball. Xrec.sport.football Discussion about football. Xrec.sport.hockey Discussion about hockey. Xrec.sport.misc Spectator sports. Xrec.travel Traveling all over the world. Xrec.video Video and video components. Xrec.woodworking Hobbyists interested in woodworking. Xsci.astro Astronomy discussions and information. Xsci.bio Biology and related sciences. Xsci.crypt Different methods of data en/decryption. Xsci.electronics Circuits, theory, electrons and discussions. Xsci.lang Natural languages, communication, etc. Xsci.math Mathematical discussions and pursuits Xsci.math.stat Statistics discussion. Xsci.math.symbolic Symbolic algebra discussion. Xsci.med Medicine and its related products and regulations. Xsci.misc Short-lived discussions on subjects in the sciences. Xsci.physics Physical laws, properties, etc. Xsci.research Research methods, funding, ethics, and whatever. Xsci.space Space, space programs, space related research, etc. Xsci.space.shuttle The space shuttle and the STS program. Xsoc.college College, college activities, campus life, etc. Xsoc.culture.african Discussions about Africa & things African Xsoc.culture.celtic Group about Celtics (*not* basketball!) Xsoc.culture.greek Group about Greeks. Xsoc.culture.indian Group for discussion about India & things Indian Xsoc.culture.jewish Group for discussion about Jewish culture & religion Xsoc.culture.misc Group for discussion about other cultures Xsoc.misc Socially-oriented topics not in other groups. Xsoc.motss Issues pertaining to homosexuality. Xsoc.roots Genealogical matters. Xsoc.singles Newsgroup for single people, their activities, etc. Xsoc.net-people Announcements, requests, etc. about people on the net. Xsoc.women Women's rights, discrimination, etc. Xtalk.abortion All sorts of discussions and arguments on abortion. Xtalk.bizarre The unusual, bizarre, curious, and often stupid. Xtalk.origins Evolution versus creationism (sometimes hot!). Xtalk.philosophy.misc Philosophical musings on all topics. Xtalk.politics.misc Political discussions and ravings of all kinds. Xtalk.politics.theory Theory of politics and political systems. Xtalk.religion.misc Religious, ethical, & moral implications. Xtalk.rumors For the posting of rumors. XE_O_F X: if active file is empty, create it Xif test ! -s $LIBDIR/active Xthen X sed 's/[ ].*/ 00000 00001/' /tmp/$$groups > $LIBDIR/active X cat <<'E_O_F' >>$LIBDIR/active Xcontrol 00000 00001 Xjunk 00000 00001 XE_O_F X set - group 0 1 Xelse X: make sure it is in the new format X set - `sed 1q $LIBDIR/active` X case $# in X 4) ed - $LIBDIR/active << 'EOF' Xg/^mod\./s/y$/m/ Xw Xq XEOF X ;; X 3) ;; X 2) ed - $LIBDIR/active << 'EOF' X1,$s/$/ 00001/ Xw Xq XEOF X echo X echo Active file updated to new format. X echo You must run expire immediately after this install X echo is done to properly update the tables.;; X *) echo Active file is in unrecognized format. Not upgraded.;; X esac Xfi Xif test $# -eq 3 -o $# -eq 2 Xthen X (sed '/^!net/!d Xs/^!// Xs!^!/! Xs!$! /s/$/ n/! X' $LIBDIR/ngfile X echo '/ n$/!s/$/ y/') >/tmp/$$sed X mv $LIBDIR/active $LIBDIR/oactive X sed -f /tmp/$$sed $LIBDIR/oactive >$LIBDIR/active X chown $NEWSUSR $LIBDIR/active X chgrp $NEWSGRP $LIBDIR/active X chmod 644 $LIBDIR/active Xfi Xsort /tmp/$$groups | $LIBDIR/checkgroups | tee /tmp/checkgroups.out Xecho the output of checkgroups has been copied into /tmp/checkgroups.out Xrm -f /tmp/$$* END_OF_FILE if test 15147 -ne `wc -c <'makeactive.sh'`; then echo shar: \"'makeactive.sh'\" unpacked with wrong size! fi # end of 'makeactive.sh' fi if test -f 'funcs2.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'funcs2.c'\" else echo shar: Extracting \"'funcs2.c'\" \(14115 characters\) sed "s/^X//" >'funcs2.c' <<'END_OF_FILE' X/* X * This software is Copyright (c) 1985 by Rick Adams. X * X * Permission is hereby granted to copy, reproduce, redistribute or X * otherwise use this software as long as: there is no monetary X * profit gained specifically from the use or reproduction or this X * software, it is not sold, rented, traded or otherwise marketed, and X * this copyright notice is included prominently in any copy X * made. X * X * The author make no claims as to the fitness or correctness of X * this software for any use whatsoever, and it is provided as is. X * Any use of this software is at the user's own risk. X * X * X * funcs2 - functions used by both inews and readnews. X */ X X#ifdef SCCSID Xstatic char *SccsId = "@(#)funcs2.c 1.20 3/20/87"; X#endif /* SCCSID */ X X#include "params.h" X X#ifdef SunIII X#ifndef INTERNET X#define INTERNET X#endif /* !INTERNET */ X#endif /* SunIII */ X X/*LINTLIBRARY*/ X X/* X * Get user name and home directory. X */ Xgetuser() X{ X static int flag = TRUE; X register struct passwd *p; X X if (flag) { X if ((p = getpwuid(uid)) == NULL) X xerror("Cannot get user's name"); X if ( username == NULL || username[0] == 0) X username = AllocCpy(p->pw_name); X userhome = AllocCpy(p->pw_dir); X flag = FALSE; X } X (void) strcpy(header.path, username); X} X Xstatic FILE *sysfile; X Xchar *fldget(); X Xstatic int sfline; X X/* X * Open SUBFILE. X */ Xs_openr() X{ X fprintf(stderr,"Opening subfile, %s\n",SUBFILE); X sysfile = xfopen(SUBFILE, "r"); X sfline = 0; X} X X/* X * Read SUBFILE. X */ Xs_read(sp) Xregister struct srec *sp; X{ X register char *p; X register int c; X char *e; X int chop_spaces = 0; Xagain: X p = bfr; X /* X * Read the SUBFILE (/usr/lib/news/sys) from the current X * position to the first unescaped newline. If a newline is X * escaped with a backslash (\) continue reading but throw away X * the backslash and newline; read the next line skipping spaces X * and tabs until the first non-space/tab character, then start X * looking for a newline again. Skipping the leading X * spaces/tabs after a escaped newline keeps the news groups X * together. If a line begins with a newline, just skip it. X */ X for (e=p+LBUFLEN; p < e && (c=getc(sysfile)) != EOF; p++) { X *p = c; X if (c == '\n') { X sfline++; X if (p == bfr || p[-1] != '\\') { X p[1] = '\0'; X break; X } else { X chop_spaces++; X p -= 2; X } X } else if (chop_spaces) { X if (c == '\t' || c == ' ') X p--; X else X chop_spaces = 0; X } X } X if (c == EOF) { X return FALSE; X } X p = bfr; X while (*p == ' ' || *p == '\t') /* skip leading white space */ X p++; X if (*p == '\n') X goto again; /* skip newlines */ X if (!nstrip(p)) X xerror("SUBFILE (%s) line %d too long.", SUBFILE, sfline); X if (*p == '#') X goto again; X sp->s_xmit[0] = '\0'; X sp->s_flags[0] = '\0'; X sp->s_nosend = (char *)0; X X p = fldget(sp->s_name, p); X if (*p++ == '\0') X xerror("Bad SUBFILE (%s) line %d.", SUBFILE, sfline); X /* X * A sys file line reading "ME" means the name of the local system. X */ X if (strcmp(sp->s_name, "ME") == 0) X (void) strcpy(sp->s_name, LOCALPATHSYSNAME); X e = index(sp->s_name, '/'); X if (e) { X *e++ = '\0'; X sp->s_nosend = e; X } X p = fldget(sp->s_nbuf, p); X lcase(sp->s_nbuf); X if (*p++ == '\0') X return TRUE; X X p = fldget(sp->s_flags, p); X if (*p++ == '\0') X return TRUE; X X (void) fldget(sp->s_xmit, p); X return TRUE; X} X Xchar * Xfldget(q, p) Xregister char *q, *p; X{ X while (*p && *p != ':') { X if (*p == '\\' && p[1]==':') X p++; X *q++ = *p++; X } X *q = '\0'; X return p; X} X X/* X * Find the SUBFILE record for a system. X */ Xs_find(sp, system) Xregister struct srec *sp; Xchar *system; X{ X s_openr(); X while (s_read(sp)) X if (strncmp(system, sp->s_name, SNLN) == 0) { X s_close(); X return TRUE; X } X s_close(); X return FALSE; X} X X/* X * Close sysfile. X */ Xs_close() X{ X (void) fclose(sysfile); X} X Xextern struct timeb Now; X Xtime_t Xcgtdate(datestr) Xchar *datestr; X{ X char junk[40],month[40],day[30],tod[60],year[50]; X static time_t lasttime; X static char lastdatestr[BUFLEN] = ""; X X if ( lastdatestr[0] && strcmp(datestr, lastdatestr) == 0) X return lasttime; X lasttime = getdate(datestr, &Now); X if (lasttime < 0 && X sscanf(datestr, "%s %s %s %s %s", junk, month, day, tod, year) == 5) { X (void) sprintf(bfr, "%s %s, %s %s", month, day, year, tod); X lasttime = getdate(bfr, &Now); X } X strncpy(lastdatestr, datestr, BUFLEN); X return lasttime; X} X Xlcase(s) Xregister char *s; X{ X register char *ptr; X X for (ptr = s; *ptr; ptr++) X if (isupper(*ptr)) X *ptr = tolower(*ptr); X} X X/* X * Return a compact representation of the person who posted the given X * message. A sender or internet name will be used, otherwise X * the last part of the path is used preceded by an optional ".." X */ Xchar * Xtailpath(hp) Xstruct hbuf *hp; X{ X char *p, *r; X static char resultbuf[BUFLEN]; X char pathbuf[PATHLEN]; X char *malloc(); X X /* X * This only happens for articles posted by old news software X * in non-internet format. X */ X resultbuf[0] = '\0'; X (void) strncpy(pathbuf, hp->path, PATHLEN); X p = index(pathbuf, ' '); X if (p) X *p = '\0'; /* Chop off trailing " (name)" */ X r = rindex(pathbuf, '!'); X if (r == 0) { X r = pathbuf; X } else { X while (r > pathbuf && *--r != '!') X ; X if (r > pathbuf) { X r++; X (void) strcpy(resultbuf, "..!"); X } X } X (void) strcat(resultbuf, r); X return resultbuf; X} X X/* X * arpadate is like ctime(3) except that the time is returned in X * an acceptable ARPANET time format instead of ctime format. X */ Xchar * Xarpadate(longtime) Xtime_t *longtime; X{ X register char *p, *q, *ud; X register int i; X static char b[40]; X extern struct tm *gmtime(); X X#ifndef MINIX X extern char *asctime(); X X /* Get current time. This will be used resolve the timezone. */ X ud = asctime(gmtime(longtime)); X#else X /* Get current time. This will be used resolve the timezone. */ X ud = ctime(longtime); X#endif X X /* Crack the UNIX date line in a singularly unoriginal way. */ X q = b; X X#ifdef notdef X/* until every site installs the fix to getdate.y, the day X of the week can cause time warps */ X p = &ud[0]; /* Mon */ X *q++ = *p++; X *q++ = *p++; X *q++ = *p++; X *q++ = ','; *q++ = ' '; X#endif X X p = &ud[8]; /* 16 */ X if (*p == ' ') X p++; X else X *q++ = *p++; X *q++ = *p++; *q++ = ' '; X X p = &ud[4]; /* Sep */ X *q++ = *p++; *q++ = *p++; *q++ = *p++; *q++ = ' '; X X p = &ud[22]; /* 1979 */ X *q++ = *p++; *q++ = *p++; *q++ = ' '; X X p = &ud[11]; /* 01:03:52 */ X for (i = 8; i > 0; i--) X *q++ = *p++; X X *q++ = ' '; X *q++ = 'G'; /* GMT */ X *q++ = 'M'; X *q++ = 'T'; X *q = '\0'; X X fprintf(stderr,"arpadate 2 asctime: %s\n",b); X return b; X} X Xchar * Xreplyname(hptr) Xstruct hbuf *hptr; X{ X register char *ptr; X static char tbuf[PATHLEN]; X X ptr = hptr->path; X if (prefix(ptr, PATHSYSNAME) && X index(NETCHRS, ptr[strlen(PATHSYSNAME)])) X ptr = index(ptr, '!') + 1; X#ifdef INTERNET X if (hptr->from[0]) X ptr = hptr->from; X if (hptr->replyto[0]) X ptr = hptr->replyto; X#endif X (void) strcpy(tbuf, ptr); X ptr = index(tbuf, '('); X if (ptr) { X while (ptr[-1] == ' ') X ptr--; X *ptr = 0; X } X#ifdef SunIII X if (ptr = rindex(tbuf, '.')) { X if (prefix(++ptr, "OZ")) { X /* some people only allow it in lower case ... */ X strcpy(ptr, "oz"); X return tbuf; X } X if (prefix(ptr, "UUCP") || prefix(ptr, "ARPA") || X prefix(ptr, "DEC") || prefix(ptr, "CSNET")) { X strcat(tbuf, "@munnari.oz"); /* via sun to munnari */ X return tbuf; X } X } X /* X * must(?) have come from a uucp site, lets look see if path passes X * through munnari, and if so delete the fake uucp path after that. X */ X for (ptr = tbuf ;; ptr++) { X if (prefix(ptr, "munnari!")) { X strcpy(tbuf, ptr+8); X break; X } X ptr = index(ptr, '!'); X if (ptr == (char *)0) X break; X } X /* X * now, just send the address we have left to munnari, and X * hope that something sensible will be done with it there. X * (This works in more cases than you'd think ...) X */ X strcat(tbuf, "@munnari.oz"); X#else /* !SunIII */ X#ifndef INTERNET X /* X * Play games stripping off multiple berknet X * addresses (a!b!c:d:e => a!b!d:e) here. X */ X for (ptr=tbuf; *ptr; ptr++) { X register char *ptr2; X X if (index(NETCHRS, *ptr) && *ptr == ':' && X (ptr2=index(ptr+1, ':'))) X (void) strcpy(ptr, ptr2); X } X#else /* INTERNET */ X { X char mbuf[BUFLEN], modadd[BUFLEN]; X FILE *mfd; X /* Let's find a path to the backbone */ X sprintf(mbuf, "%s/mailpaths", LIB); X mfd = xfopen(mbuf, "r"); X do { X if (fgets(mbuf, sizeof mbuf, mfd) == NULL) X xerror("Can't find internet in %s/mailpaths", X LIB); X } while (!prefix(mbuf, "internet")); X if (sscanf(mbuf, "%*s %s", modadd) != 1) X xerror("backbone address corrupted"); X (void) fclose(mfd); X (void)strcpy(mbuf, tbuf); X /* If we are lucky, there is no ! or @ in the forward address */ X if (strpbrk(modadd, "!@") == NULL) { X sprintf(tbuf, modadd, mbuf); X } else { X char *cp = index(mbuf, '@'); X if (index(modadd, '@') == NULL && cp) { X /* we have to rearrange the address so no @ are in it */ X char atbuf[BUFLEN]; X *cp++ = '\0'; X sprintf(atbuf, "%s!%s", cp, mbuf); X sprintf(tbuf, modadd, atbuf); X } else if (cp) { X /* some days you don't get lucky. presume the % hack */ X *cp = '%'; X sprintf(tbuf, modadd, mbuf); X } X } X } X#endif /* INTERNET */ X#endif /* !SunIII */ X return tbuf; X} X X#ifdef DBM Xtypedef struct { X char *dptr; X int dsize; X} datum; X#endif /* DBM */ X X/* X * Given an article ID, find the line in the history file that mentions it. X * Return the text of the line, or NULL if not found. A pointer to a X * static area is returned. X */ Xchar * Xfindhist(artid) Xchar *artid; X{ X static char lbuf[256]; X char oidbuf[BUFSIZ]; X FILE *hfp; X register char *p; X#ifdef DBM X datum lhs, rhs; X datum fetch(); X long fpos; /* We have to use an explicit variable to insure alignment */ X#else /* !DBM */ X char *histfile(); X#endif /* !DBM */ X X /* Try to understand old artid's as well. Assume .UUCP domain. */ X if (artid[0] != '<') { X p = index(artid, '.'); X if (p) X *p++ = '\0'; X (void) sprintf(oidbuf, "<%s@%s.UUCP>", p, artid); X if (p) X *--p = '.'; X } else X (void) strcpy(oidbuf, artid); X lcase(oidbuf); X#ifdef DBM X initdbm(ARTFILE); X lhs.dptr = oidbuf; X lhs.dsize = strlen(lhs.dptr) + 1; X rhs = fetch(lhs); X if (rhs.dptr == NULL) X return NULL; X hfp = xfopen(ARTFILE, "r"); X /* The bcopy is NECESSARY to insure alignment on some machines */ X xbcopy(rhs.dptr, (char *)&fpos, sizeof (long)); X fseek(hfp, fpos, 0); X#else /* !DBM */ X hfp = xfopen(histfile(oidbuf), "r"); X#endif /* !DBM */ X while (fgets(lbuf, BUFLEN, hfp) != NULL) { X p = index(lbuf, '\t'); X if (p == NULL) X p = index(lbuf, '\n'); X *p = 0; X if (strcmp(lbuf, artid) == 0 || strcmp(lbuf, oidbuf) == 0) { X (void) fclose(hfp); X *p = '\t'; X *(lbuf + strlen(lbuf) - 1) = 0; /* zap the \n */ X return lbuf; X } X#ifdef DBM X break; X#endif /* DBM */ X } X (void) fclose(hfp); X return NULL; X} X X/* X * Hunt up the article "artid", and return the newsgroup/artnum X * where it can be found. X */ Xchar * Xfindfname(artid) Xchar *artid; X{ X char *line, *p, *q; X char *findhist(); X static char fname[BUFLEN]; X X line = findhist(artid); X if (line) { X /* Look for it stored as an article, where it should be */ X p = index(line, '\t'); X p = index(p+1, '\t'); X p++; X if (*p) { X q = index(p, ' '); X if (q) X *q = 0; X (void) strcpy(fname, p); X return fname; X } X } X return NULL; X} X X/* X * Hunt up the article "artid", fopen it for read, and return a X * file descriptor to it. We look everywhere we can think of. X */ XFILE * Xhfopen(artid) Xchar *artid; X{ X char *p; X char *findhist(); X FILE *rv = NULL; X char fname[BUFLEN]; X X p = findfname(artid); X if (p) { X (void) strcpy(fname, dirname(p)); X rv = fopen(fname, "r"); /* NOT xfopen! */ X if (rv == NULL) X xerror("Cannot hfopen article %s", artid); X } X return rv; X} X X#ifdef DBM X/* X** Avoid problems of multiple dbminit calls. X*/ Xinitdbm(name) Xchar *name; X{ X static int called = 0; X X if (called != 0) X return; X called = 1; X (void) dbminit(name); X} X#endif X X/* X * move n bytes from a to b X */ Xxbcopy(a, b, n) Xregister char *a, *b; Xregister n; X{ X while (--n >= 0) X *b++ = *a++; X} X X#if !defined(BSD4_2) && !defined(BSD4_1C) Xrename(from,to) Xregister char *from, *to; X{ X (void) unlink(to); X if (link(from, to) < 0) X return -1; X X (void) unlink(from); X return 0; X} X#endif /* !BSD4_2 && ! BSD4_1C */ X X#ifndef DBM X/* X** Generate the appropriate history subfile name X*/ Xchar * Xhistfile(hline) Xchar *hline; X{ X char chr; /* least significant digit of article number */ X static char subfile[BUFLEN]; X X chr = findhfdigit(hline); X sprintf(subfile, "%s.d/%c", ARTFILE, chr); X return subfile; X} X Xfindhfdigit(fn) Xchar *fn; X{ X register char *p; X register int chr; X X p = index(fn, '@'); X if (p != NULL && p > fn) X chr = *(p - 1); X else X chr = '0'; X if (!isdigit(chr)) X chr = '0'; X return chr; X} X#endif /* !DBM */ X X#ifdef VMS X/* X * These functions open an article with one level of indirection, X * to support symbolic links. xart_open exits if the open fails. X */ XFILE * Xxart_open (filename,mode) Xchar *filename,*mode; X{ X FILE *fp = art_open (filename, mode); X extern int errno; X if (fp == NULL) X xerror("Cannot open article %s (%s): %s\n", X filename, mode, errmsg(errno)); X return fp; X} X XFILE * Xart_open (filename,mode) Xchar *filename,*mode; X{ X char linkfile[BUFSIZ]; X FILE *fp; X X if ((fp = fopen (filename, mode)) == NULL) X return NULL; X if (fgets (linkfile, BUFSIZ, fp) == NULL || linkfile[0] != '/') { X rewind (fp); X return fp; X } X/* Chase the symbolic link. */ X (void) fclose (fp); X if ((fp = fopen (linkfile, mode)) == NULL) X/* Clean up dangling link, if we have the power. Ignore error if we don't. */ X (void) unlink (filename); X return fp; X} X#endif /* VMS */ X X/* X * Generate the name of the person responsible for posting this article, X * in order to check that two articles were posted by the same person. X */ Xchar * Xsenderof(hp) Xstruct hbuf *hp; X{ X register char *r, *q, *tp; X char *tailpath(); X static char senderbuf[BUFLEN]; X X if (hp->sender[0]) X tp = hp->sender; X else if (hp->from[0]) X tp = hp->from; X else X tp = tailpath(hp); X X (void) strncpy(senderbuf, tp, BUFLEN); X /* Remove full name */ X q = index(senderbuf, ' '); X if (q) X *q = '\0'; X X return senderbuf; X} END_OF_FILE if test 14115 -ne `wc -c <'funcs2.c'`; then echo shar: \"'funcs2.c'\" unpacked with wrong size! fi # end of 'funcs2.c' fi if test -f 'getdate.y' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'getdate.y'\" else echo shar: Extracting \"'getdate.y'\" \(12591 characters\) sed "s/^X//" >'getdate.y' <<'END_OF_FILE' X%token ID MONTH DAY MERIDIAN NUMBER UNIT MUNIT SUNIT ZONE DAYZONE AGO X%{ X /* Originally from: Steven M. Bellovin (unc!smb) */ X /* Dept. of Computer Science */ X /* University of North Carolina at Chapel Hill */ X /* @(#)getdate.y 2.15 12/16/86 */ X X#include <sys/types.h> X#ifdef USG Xstruct timeb X{ X time_t time; X unsigned short millitm; X short timezone; X short dstflag; X}; X#else X#include <sys/timeb.h> X#endif X#include <ctype.h> X X#include "defs.h" X#if defined(BSD4_2) || defined (BSD4_1C) X#include <sys/time.h> X#else /* sane */ X#include <time.h> X#endif /* sane */ X X#define NULL 0 X#define daysec (24L*60L*60L) X static int timeflag, zoneflag, dateflag, dayflag, relflag; X static time_t relsec, relmonth; X static int hh, mm, ss, merid, daylight; X static int dayord, dayreq; X static int month, day, year; X static int ourzone; X#define AM 1 X#define PM 2 X#define DAYLIGHT 1 X#define STANDARD 2 X#define MAYBE 3 X%} X X%% Xtimedate: /* empty */ X | timedate item; X Xitem: tspec = X {timeflag++;} X | zone = X {zoneflag++;} X | dtspec = X {dateflag++;} X | dyspec = X {dayflag++;} X | rspec = X {relflag++;} X | nspec; X Xnspec: NUMBER = X {if (timeflag && dateflag && !relflag) year = $1; X else {timeflag++;hh = $1/100;mm = $1%100;ss = 0;merid = 24;}}; X Xtspec: NUMBER MERIDIAN = X {hh = $1; mm = 0; ss = 0; merid = $2;} X | NUMBER ':' NUMBER = X {hh = $1; mm = $3; merid = 24;} X | NUMBER ':' NUMBER MERIDIAN = X {hh = $1; mm = $3; merid = $4;} X | NUMBER ':' NUMBER NUMBER = X {hh = $1; mm = $3; merid = 24; X daylight = STANDARD; ourzone = -($4%100 + 60*($4/100));} X | NUMBER ':' NUMBER ':' NUMBER = X {hh = $1; mm = $3; ss = $5; merid = 24;} X | NUMBER ':' NUMBER ':' NUMBER MERIDIAN = X {hh = $1; mm = $3; ss = $5; merid = $6;} X | NUMBER ':' NUMBER ':' NUMBER NUMBER = X {hh = $1; mm = $3; ss = $5; merid = 24; X daylight = STANDARD; ourzone = -($6%100 + 60*($6/100));}; X Xzone: ZONE = X {ourzone = $1; daylight = STANDARD;} X | DAYZONE = X {ourzone = $1; daylight = DAYLIGHT;}; X Xdyspec: DAY = X {dayord = 1; dayreq = $1;} X | DAY ',' = X {dayord = 1; dayreq = $1;} X | NUMBER DAY = X {dayord = $1; dayreq = $2;}; X Xdtspec: NUMBER '/' NUMBER = X {month = $1; day = $3;} X | NUMBER '/' NUMBER '/' NUMBER = X {month = $1; day = $3; year = $5;} X | MONTH NUMBER = X {month = $1; day = $2;} X | MONTH NUMBER ',' NUMBER = X {month = $1; day = $2; year = $4;} X | NUMBER MONTH = X {month = $2; day = $1;} X | NUMBER MONTH NUMBER = X {month = $2; day = $1; year = $3;}; X X Xrspec: NUMBER UNIT = X {relsec += 60L * $1 * $2;} X | NUMBER MUNIT = X {relmonth += $1 * $2;} X | NUMBER SUNIT = X {relsec += $1;} X | UNIT = X {relsec += 60L * $1;} X | MUNIT = X {relmonth += $1;} X | SUNIT = X {relsec++;} X | rspec AGO = X {relsec = -relsec; relmonth = -relmonth;}; X%% X Xstatic int mdays[12] = X {31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; X#define epoch 1970 X Xextern struct tm *localtime(); X Xtime_t Xdateconv(mm, dd, yy, h, m, s, mer, zone, dayflag) Xint mm, dd, yy, h, m, s, mer, zone, dayflag; X{ X time_t tod, jdate; X register int i; X time_t timeconv(); X X if (yy < 0) yy = -yy; X if (yy < 100) yy += 1900; X mdays[1] = 28 + (yy%4 == 0 && (yy%100 != 0 || yy%400 == 0)); X if (yy < epoch || yy > 1999 || mm < 1 || mm > 12 || X dd < 1 || dd > mdays[--mm]) return (-1); X jdate = dd-1; X for (i=0; i<mm; i++) jdate += mdays[i]; X for (i = epoch; i < yy; i++) jdate += 365 + (i%4 == 0); X jdate *= daysec; X jdate += zone * 60L; X if ((tod = timeconv(h, m, s, mer)) < 0) return (-1); X jdate += tod; X if (dayflag==DAYLIGHT || (dayflag==MAYBE&&localtime(&jdate)->tm_isdst)) X jdate += -1*60*60; X return (jdate); X} X Xtime_t Xdayconv(ord, day, now) Xint ord, day; time_t now; X{ X register struct tm *loctime; X time_t tod; X time_t daylcorr(); X X tod = now; X loctime = localtime(&tod); X tod += daysec * ((day - loctime->tm_wday + 7) % 7); X tod += 7*daysec*(ord<=0?ord:ord-1); X return daylcorr(tod, now); X} X Xtime_t Xtimeconv(hh, mm, ss, mer) Xregister int hh, mm, ss, mer; X{ X if (mm < 0 || mm > 59 || ss < 0 || ss > 59) return (-1); X switch (mer) { X case AM: if (hh < 1 || hh > 12) return(-1); X return (60L * ((hh%12)*60L + mm)+ss); X case PM: if (hh < 1 || hh > 12) return(-1); X return (60L * ((hh%12 +12)*60L + mm)+ss); X case 24: if (hh < 0 || hh > 23) return (-1); X return (60L * (hh*60L + mm)+ss); X default: return (-1); X } X} Xtime_t Xmonthadd(sdate, relmonth) Xtime_t sdate, relmonth; X{ X struct tm *ltime; X time_t dateconv(); X time_t daylcorr(); X int mm, yy; X X if (relmonth == 0) return 0; X ltime = localtime(&sdate); X mm = 12*ltime->tm_year + ltime->tm_mon + relmonth; X yy = mm/12; X mm = mm%12 + 1; X return daylcorr(dateconv(mm, ltime->tm_mday, yy, ltime->tm_hour, X ltime->tm_min, ltime->tm_sec, 24, ourzone, MAYBE), sdate); X} X Xtime_t Xdaylcorr(future, now) Xtime_t future, now; X{ X int fdayl, nowdayl; X X nowdayl = (localtime(&now)->tm_hour+1) % 24; X fdayl = (localtime(&future)->tm_hour+1) % 24; X return (future-now) + 60L*60L*(nowdayl-fdayl); X} X Xstatic char *lptr; X Xyylex() X{ X extern int yylval; X int sign; X register char c; X register char *p; X char idbuf[20]; X int pcnt; X X for (;;) { X while (isspace(*lptr)) X lptr++; X X if (isdigit(c = *lptr) || c == '-' || c == '+') { X if (c== '-' || c == '+') { X if (c=='-') sign = -1; X else sign = 1; X if (!isdigit(*++lptr)) { X /* yylval = sign; return (NUMBER); */ X return yylex(); /* skip the '-' sign */ X } X } else sign = 1; X yylval = 0; X while (isdigit(c = *lptr++)) X yylval = 10*yylval + c - '0'; X yylval *= sign; X lptr--; X return (NUMBER); X X } else if (isalpha(c)) { X p = idbuf; X while (isalpha(c = *lptr++) || c=='.') X *p++ = c; X *p = '\0'; X lptr--; X return (lookup(idbuf)); X } X X else if (c == '(') { X pcnt = 0; X do { X c = *lptr++; X if (c == '\0') return(c); X else if (c == '(') pcnt++; X else if (c == ')') pcnt--; X } while (pcnt > 0); X } X X else return (*lptr++); X } X} X Xstruct table { X char *name; X int type, value; X}; X Xstruct table mdtab[] = { X {"january", MONTH, 1}, X {"february", MONTH, 2}, X {"march", MONTH, 3}, X {"april", MONTH, 4}, X {"may", MONTH, 5}, X {"june", MONTH, 6}, X {"july", MONTH, 7}, X {"august", MONTH, 8}, X {"september", MONTH, 9}, X {"sept", MONTH, 9}, X {"october", MONTH, 10}, X {"november", MONTH, 11}, X {"december", MONTH, 12}, X X {"sunday", DAY, 0}, X {"monday", DAY, 1}, X {"tuesday", DAY, 2}, X {"tues", DAY, 2}, X {"wednesday", DAY, 3}, X {"wednes", DAY, 3}, X {"thursday", DAY, 4}, X {"thur", DAY, 4}, X {"thurs", DAY, 4}, X {"friday", DAY, 5}, X {"saturday", DAY, 6}, X {0, 0, 0}}; X X#define HRS *60 X#define HALFHR 30 Xstruct table mztab[] = { X {"a.m.", MERIDIAN, AM}, X {"am", MERIDIAN, AM}, X {"p.m.", MERIDIAN, PM}, X {"pm", MERIDIAN, PM}, X {"nst", ZONE, 3 HRS + HALFHR}, /* Newfoundland */ X {"n.s.t.", ZONE, 3 HRS + HALFHR}, X {"ast", ZONE, 4 HRS}, /* Atlantic */ X {"a.s.t.", ZONE, 4 HRS}, X {"adt", DAYZONE, 4 HRS}, X {"a.d.t.", DAYZONE, 4 HRS}, X {"est", ZONE, 5 HRS}, /* Eastern */ X {"e.s.t.", ZONE, 5 HRS}, X {"edt", DAYZONE, 5 HRS}, X {"e.d.t.", DAYZONE, 5 HRS}, X {"cst", ZONE, 6 HRS}, /* Central */ X {"c.s.t.", ZONE, 6 HRS}, X {"cdt", DAYZONE, 6 HRS}, X {"c.d.t.", DAYZONE, 6 HRS}, X {"mst", ZONE, 7 HRS}, /* Mountain */ X {"m.s.t.", ZONE, 7 HRS}, X {"mdt", DAYZONE, 7 HRS}, X {"m.d.t.", DAYZONE, 7 HRS}, X {"pst", ZONE, 8 HRS}, /* Pacific */ X {"p.s.t.", ZONE, 8 HRS}, X {"pdt", DAYZONE, 8 HRS}, X {"p.d.t.", DAYZONE, 8 HRS}, X {"yst", ZONE, 9 HRS}, /* Yukon */ X {"y.s.t.", ZONE, 9 HRS}, X {"ydt", DAYZONE, 9 HRS}, X {"y.d.t.", DAYZONE, 9 HRS}, X {"hst", ZONE, 10 HRS}, /* Hawaii */ X {"h.s.t.", ZONE, 10 HRS}, X {"hdt", DAYZONE, 10 HRS}, X {"h.d.t.", DAYZONE, 10 HRS}, X X {"gmt", ZONE, 0 HRS}, X {"g.m.t.", ZONE, 0 HRS}, X {"bst", DAYZONE, 0 HRS}, /* British Summer Time */ X {"b.s.t.", DAYZONE, 0 HRS}, X {"eet", ZONE, 0 HRS}, /* European Eastern Time */ X {"e.e.t.", ZONE, 0 HRS}, X {"eest", DAYZONE, 0 HRS}, /* European Eastern Summer Time */ X {"e.e.s.t.", DAYZONE, 0 HRS}, X {"met", ZONE, -1 HRS}, /* Middle European Time */ X {"m.e.t.", ZONE, -1 HRS}, X {"mest", DAYZONE, -1 HRS}, /* Middle European Summer Time */ X {"m.e.s.t.", DAYZONE, -1 HRS}, X {"wet", ZONE, -2 HRS }, /* Western European Time */ X {"w.e.t.", ZONE, -2 HRS }, X {"west", DAYZONE, -2 HRS}, /* Western European Summer Time */ X {"w.e.s.t.", DAYZONE, -2 HRS}, X X {"jst", ZONE, -9 HRS}, /* Japan Standard Time */ X {"j.s.t.", ZONE, -9 HRS}, /* Japan Standard Time */ X /* No daylight savings time */ X X {"aest", ZONE, -10 HRS}, /* Australian Eastern Time */ X {"a.e.s.t.", ZONE, -10 HRS}, X {"aesst", DAYZONE, -10 HRS}, /* Australian Eastern Summer Time */ X {"a.e.s.s.t.", DAYZONE, -10 HRS}, X {"acst", ZONE, -(9 HRS + HALFHR)}, /* Australian Central Time */ X {"a.c.s.t.", ZONE, -(9 HRS + HALFHR)}, X {"acsst", DAYZONE, -(9 HRS + HALFHR)}, /* Australian Central Summer */ X {"a.c.s.s.t.", DAYZONE, -(9 HRS + HALFHR)}, X {"awst", ZONE, -8 HRS}, /* Australian Western Time */ X {"a.w.s.t.", ZONE, -8 HRS}, /* (no daylight time there, I'm told */ X {0, 0, 0}}; X Xstruct table unittb[] = { X {"year", MUNIT, 12}, X {"month", MUNIT, 1}, X {"fortnight", UNIT, 14*24*60}, X {"week", UNIT, 7*24*60}, X {"day", UNIT, 1*24*60}, X {"hour", UNIT, 60}, X {"minute", UNIT, 1}, X {"min", UNIT, 1}, X {"second", SUNIT, 1}, X {"sec", SUNIT, 1}, X {0, 0, 0}}; X Xstruct table othertb[] = { X {"tomorrow", UNIT, 1*24*60}, X {"yesterday", UNIT, -1*24*60}, X {"today", UNIT, 0}, X {"now", UNIT, 0}, X {"last", NUMBER, -1}, X {"this", UNIT, 0}, X {"next", NUMBER, 2}, X {"first", NUMBER, 1}, X /* {"second", NUMBER, 2}, */ X {"third", NUMBER, 3}, X {"fourth", NUMBER, 4}, X {"fifth", NUMBER, 5}, X {"sixth", NUMBER, 6}, X {"seventh", NUMBER, 7}, X {"eigth", NUMBER, 8}, X {"ninth", NUMBER, 9}, X {"tenth", NUMBER, 10}, X {"eleventh", NUMBER, 11}, X {"twelfth", NUMBER, 12}, X {"ago", AGO, 1}, X {0, 0, 0}}; X Xstruct table milzone[] = { X {"a", ZONE, 1 HRS}, X {"b", ZONE, 2 HRS}, X {"c", ZONE, 3 HRS}, X {"d", ZONE, 4 HRS}, X {"e", ZONE, 5 HRS}, X {"f", ZONE, 6 HRS}, X {"g", ZONE, 7 HRS}, X {"h", ZONE, 8 HRS}, X {"i", ZONE, 9 HRS}, X {"k", ZONE, 10 HRS}, X {"l", ZONE, 11 HRS}, X {"m", ZONE, 12 HRS}, X {"n", ZONE, -1 HRS}, X {"o", ZONE, -2 HRS}, X {"p", ZONE, -3 HRS}, X {"q", ZONE, -4 HRS}, X {"r", ZONE, -5 HRS}, X {"s", ZONE, -6 HRS}, X {"t", ZONE, -7 HRS}, X {"u", ZONE, -8 HRS}, X {"v", ZONE, -9 HRS}, X {"w", ZONE, -10 HRS}, X {"x", ZONE, -11 HRS}, X {"y", ZONE, -12 HRS}, X {"z", ZONE, 0 HRS}, X {0, 0, 0}}; X Xlookup(id) Xchar *id; X{ X#define gotit (yylval=i->value, i->type) X X char idvar[128]; X register char *j, *k; X register struct table *i; X int abbrev; X X (void) strcpy(idvar, id); X j = idvar; X k = id - 1; X while (*++k) X *j++ = isupper(*k) ? tolower(*k) : *k; X *j = '\0'; X X if (strlen(idvar) == 3) X abbrev = 1; X else X if (strlen(idvar) == 4 && idvar[3] == '.') { X abbrev = 1; X idvar[3] = '\0'; X } X else X abbrev = 0; X X for (i = mdtab; i->name; i++) { X k = idvar; X for (j = i->name; *j++ == *k++;) { X if (abbrev && j == i->name+3) X return gotit; X if (j[-1] == 0) X return gotit; X } X } X X for (i = mztab; i->name; i++) X if (strcmp(i->name, idvar) == 0) X return gotit; X X for (i=mztab; i->name; i++) X if (strcmp(i->name, idvar) == 0) X return gotit; X X for (i=unittb; i->name; i++) X if (strcmp(i->name, idvar) == 0) X return gotit; X X if (idvar[strlen(idvar)-1] == 's') X idvar[strlen(idvar)-1] = '\0'; X X for (i=unittb; i->name; i++) X if (strcmp(i->name, idvar) == 0) X return gotit; X X for (i = othertb; i->name; i++) X if (strcmp(i->name, idvar) == 0) X return gotit; X X if (strlen(idvar) == 1 && isalpha(*idvar)) { X for (i = milzone; i->name; i++) X if (strcmp(i->name, idvar) == 0) X return gotit; X } X X return ID; X} X Xtime_t Xgetdate(p, now) Xchar *p; Xstruct timeb *now; X{ X#define mcheck(f) if (f>1) err++ X time_t monthadd(); X int err; X struct tm *lt; X struct timeb ftz; X X time_t sdate, tod; X X lptr = p; X if (now == ((struct timeb *) NULL)) { X now = &ftz; X ftime(&ftz); X } X lt = localtime(&now->time); X year = lt->tm_year; X month = lt->tm_mon+1; X day = lt->tm_mday; X relsec = 0; relmonth = 0; X timeflag=zoneflag=dateflag=dayflag=relflag=0; X ourzone = now->timezone; X daylight = MAYBE; X hh = mm = ss = 0; X merid = 24; X X if (err = yyparse()) return (-1); X X mcheck(timeflag); X mcheck(zoneflag); X mcheck(dateflag); X mcheck(dayflag); X X if (err) return (-1); X if (dateflag || timeflag || dayflag) { X sdate = dateconv(month,day,year,hh,mm,ss,merid,ourzone,daylight); X if (sdate < 0) return -1; X } X else { X sdate = now->time; X if (relflag == 0) X sdate -= (lt->tm_sec + lt->tm_min*60 + X lt->tm_hour*(60L*60L)); X } X X sdate += relsec; X sdate += monthadd(sdate, relmonth); X X if (dayflag && !dateflag) { X tod = dayconv(dayord, dayreq, sdate); X sdate += tod; X } X X return sdate; X} X Xyyerror(s) char *s; X{} END_OF_FILE if test 12591 -ne `wc -c <'getdate.y'`; then echo shar: \"'getdate.y'\" unpacked with wrong size! fi # end of 'getdate.y' fi if test -f 'funcs.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'funcs.c'\" else echo shar: Extracting \"'funcs.c'\" \(12952 characters\) sed "s/^X//" >'funcs.c' <<'END_OF_FILE' X/* X * This software is Copyright (c) 1986 by Rick Adams. X * X * Permission is hereby granted to copy, reproduce, redistribute or X * otherwise use this software as long as: there is no monetary X * profit gained specifically from the use or reproduction or this X * software, it is not sold, rented, traded or otherwise marketed, and X * this copyright notice is included prominently in any copy X * made. X * X * The author make no claims as to the fitness or correctness of X * this software for any use whatsoever, and it is provided as is. X * Any use of this software is at the user's own risk. X * X * funcs - functions used by many programs X */ X X#ifdef SCCSID Xstatic char *SccsId = "@(#)funcs.c 2.35 12/16/86"; X#endif /* SCCSID */ X X/*LINTLIBRARY*/ X X#include "params.h" X#include <errno.h> X#if defined(USG) || defined(BSD4_2) || defined(BSD4_1C) X#include <fcntl.h> X#endif /* !v7 */ X Xextern char *Progname; X X/* X * News group matching. X * X * nglist is a list of newsgroups. X * sublist is a list of subscriptions. X * sublist may have "meta newsgroups" in it. X * All fields are NGDELIM separated, X * and there is an NGDELIM at the end of each argument. X * X * Currently implemented glitches: X * sublist uses 'all' like shell uses '*', and '.' like shell '/'. X * If subscription X matches Y, it also matches Y.anything. X */ Xngmatch(nglist, sublist) Xregister char *nglist, *sublist; X{ X register char *n, *s; X register int rc; X X rc = FALSE; X for (n = nglist; *n != '\0' && rc == FALSE;) { X for (s = sublist; *s != '\0';) { X if (*s != NEGCHAR) X rc = rc || ptrncmp(s, n); X else X rc = rc && !ptrncmp(s+1, n); X while (*s++ != NGDELIM && *s != '\0') X ; X } X while (*n++ != NGDELIM && *n != '\0') X ; X } X return rc; X} X X/* X * Compare two newsgroups for equality. X * The first one may be a "meta" newsgroup. X */ Xptrncmp(ng1, ng2) Xregister char *ng1, *ng2; X{ X while (*ng1 != NGDELIM && *ng1 != '\0') { X if (ng1[0]=='a' && ng1[1]=='l' && ng1[2]=='l') { X ng1 += 3; X while (*ng2 != NGDELIM && *ng2 != '.' && *ng2 != '\0') X if (ptrncmp(ng1, ng2++)) X return(TRUE); X return ptrncmp(ng1, ng2); X } else if (*ng1++ != *ng2++) X return FALSE; X } X return *ng2 == '.' || *ng2 == NGDELIM || *ng2 == '\0'; X} X X/* X * Exec the shell. X * This version resets uid, gid, and umask. X * Called with fsubr(ushell, s, NULL) X */ X/* ARGSUSED */ Xushell(s, dummy) Xchar *s, *dummy; X{ X (void) umask(savmask); X (void) setgid(gid); X (void) setuid(uid); X xshell(s); X} X X/* X * Exec the shell. X */ X X#ifdef lint Xchar **environ; X#else /* !lint */ Xextern char **environ; X#endif /* !lint */ X Xxshell(s) Xchar *s; X{ X char *env[100], **envp; X char a[BUFLEN + 2]; X extern char filename[]; X /* set $A */ X (void) sprintf(a, "A=%s", filename); X env[0] = a; X for (envp = env + 1 ; *environ != NULL && envp < env + 98 ; environ++) X if ((*environ)[0] != 'A' || (*environ)[1] != '=') X *envp++ = *environ; X *envp = NULL; X X execle(SHELL, SHELL, "-c", s, (char *)0, env); X xerror("No shell!"); X} X X/* X * Fork and call a subroutine with two args. X * Return pid without waiting. X */ Xfsubr(f, s1, s2) Xint (*f)(); Xchar *s1, *s2; X{ X register int pid; X X /* this may NOT be a vfork */ X while ((pid = fork()) == -1) X sleep((unsigned)1); X if (pid == 0) { X (*f)(s1, s2); X exit(0); X } X return pid; X} X X/* X * Wait on a child process. X */ Xfwait(pid) Xregister int pid; X{ X register int w; X int status; X int (*onhup)(), (*onint)(); X X onint = signal(SIGINT, SIG_IGN); X onhup = signal(SIGHUP, SIG_IGN); X while ((w = wait(&status)) != pid && w != -1) X ; X if (w == -1) X status = -1; X (void) signal(SIGINT, onint); X (void) signal(SIGHUP, onhup); X return status; X} X X/* X * Strip trailing newlines, blanks, and tabs from 's'. X * Return TRUE if newline was found, else FALSE. X */ Xnstrip(s) Xregister char *s; X{ X register char *p; X register int rc; X X rc = FALSE; X p = s; X while (*p) X if (*p++ == '\n') X rc = TRUE; X while (--p >= s && (*p == '\n' || *p == ' ' || *p == '\t')); X *++p = '\0'; X return rc; X} X X/* X * Local open routine. X */ XFILE * Xxfopen(name, fmode) Xregister char *name, *fmode; X{ X register FILE *fp; X char *fname; X extern int errno; X X if (!strcmp(fmode,"")) { X fprintf(stderr,"Opening %s, mode %s\n",name,fmode); X fmode="r"; X } X X if ((fp = fopen(name, fmode)) == NULL) { X#ifdef IHCC X /* X * IHCC users only see the "filename" that was in trouble, X * not the whole path. (for security!) X */ X fname = rindex(name, '/') + 1; X#else X fname = name; X#endif X xerror("Cannot open %s (%s): %s", fname, fmode, errmsg(errno)); X } X /* kludge for setuid not being honored for root */ X if ((uid == 0) && (duid != 0) && ((*fmode == 'a') || (*fmode == 'w'))) X (void) chown(name, duid, dgid); X return fp; X} X Xchar * Xerrmsg(code) Xint code; X{ X extern int sys_nerr; X extern char *sys_errlist[]; X static char ebuf[6+5+1]; X X if (code > sys_nerr) { X (void) sprintf(ebuf, "Error %d", code); X return ebuf; X } else X return sys_errlist[code]; X} X Xprefix(full, pref) Xregister char *full, *pref; X{ X register char fc, pc; X X while ((pc = *pref++) != '\0') { X fc = *full++; X if (isupper(fc)) X fc = tolower(fc); X if (isupper(pc)) X pc = tolower(pc); X if (fc != pc) X return FALSE; X } X return TRUE; X} X Xchar * Xdirname(ngname) Xchar *ngname; X{ X static char rbuf[BUFLEN]; X register char *p; X X (void) sprintf(rbuf, "%s/%s", SPOOL, ngname); X X for (p=rbuf+strlen(SPOOL); *p; p++) X if (*p == '.') X *p = '/'; X return rbuf; X} X X/* X * Return TRUE iff ngname is a valid newsgroup name X */ Xvalidng(ngname) Xchar *ngname; X{ X register FILE *fp; X register char *p, *q; X char abuf[BUFLEN]; X X fp = xfopen(ACTIVE, "r"); X while(fgets(abuf, BUFLEN, fp) != NULL) { X p = abuf; X q = ngname; X while (*p++ == *q++) X ; X if (*--q == '\0' && *--p == ' ') { X (void) fclose(fp); X return TRUE; X } X } X (void) fclose(fp); X return FALSE; X} X X/* VARARGS1 */ Xxerror(message, arg1, arg2, arg3) Xchar *message; Xlong arg1, arg2, arg3; X{ X char buffer[LBUFLEN]; X X fflush(stdout); X (void) sprintf(buffer, message, arg1, arg2, arg3); X logerr(buffer); X xxit(1); X} X X/* VARARGS1 */ Xlog(fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9) Xchar *fmt; Xlong a1, a2, a3, a4, a5, a6, a7, a8, a9; X{ X _dolog(0, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9); X} X X/* VARARGS1 */ Xlogerr(fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9) Xchar *fmt; Xlong a1, a2, a3, a4, a5, a6, a7, a8, a9; X{ X _dolog(1, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9); X} X Xchar *lfsuffix[] = { X "log", X "errlog", X NULL, X}; X X/* X * Log the given message, with printf strings and parameters allowed, X * on the log file, if it can be written. The date and an attempt at X * figuring out the remote system name are also logged. X */ X/* VARARGS1 */ X_dolog(which, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9) Xchar *fmt; Xlong a1, a2, a3, a4, a5, a6, a7, a8, a9; X{ X FILE *logfile; X register char *p, *logtime; X int i; X char logfname[BUFLEN]; /* the log file */ X char rmtsys[BUFLEN]; X char msg[LBUFLEN]; X time_t t; X X (void) strcpy(rmtsys, header.path); X p = index(rmtsys, '!'); X if (p == NULL) X p = index(rmtsys, ':'); X if (p) X *p = 0; X else { X p = rindex(rmtsys, '@'); X if (p) X (void) strcpy(rmtsys, p+1); X else X (void) strcpy(rmtsys, "local"); X } X X (void) time(&t); X logtime = ctime(&t); X logtime[16] = 0; X logtime += 4; X X X (void) sprintf(msg, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9); X X if (which) X fprintf(stderr,"%s: %s\n", Progname, msg); X X for (i=0; i<=which;i++) { X (void) sprintf(logfname, "%s/%s", LIB, lfsuffix[i]); X X if (access(logfname, 0) == 0 && (logfile = fopen(logfname, "a")) != NULL) { X#if defined(USG) || defined(BSD4_2) || defined(BSD4_1C) X int flags; X flags = fcntl(fileno(logfile), F_GETFL, 0); X (void) fcntl(fileno(logfile), F_SETFL, flags|O_APPEND); X#else /* v7 */ X (void) lseek(fileno(logfile), 0L, 2); X#endif /* v7 */ X if (i) X fprintf(logfile, "%s\t%s\t%s: %s\n", logtime, X header.ident[0] ? header.ident : username, Progname, msg); X else X fprintf(logfile, "%s\t%s\t%s\n", logtime, X rmtsys, msg); X (void) fclose(logfile); X } X } X} X#ifdef VMS X X/* X * vmslink allows simulation of file linking under VMS. X */ Xvmslink(infile,outfile) Xchar *infile, *outfile; X{ X FILE *fp; X X if (access(outfile,0) == 0) { X errno = EEXIST; X return -1; X } X X fp = fopen(outfile, "w"); X if (fp == NULL) { X errno = EACCES; X return -1; X } X X (void) fprintf(fp, "%s", infile); X (void) fclose(fp); X X return 0; X} X X/* X * vmsdelete deletes all revisions of a file. It attempts to X * appear as unlink(2) under conventional Unix in other respects. X */ Xvmsdelete(file) Xchar *file; X{ X int i; X X i = unlink(file); X if (i != 0) X return i; X X i = errno; X while (unlink(file) == 0) X ; X errno = i; X X return 0; X} X X/* X * Convert a Unix file to a VMS fixed record format file by X * executing the 'unixtovms' command. X */ Xunixtovms(file) Xchar *file; X{ X char buf[BUFLEN]; X sprintf(buf, "exec /etc/unixtovms %s", file); X return system(buf); X} X X/* X * Convert a VMS fixed record format file to a Unix file by X * executing the 'vmstounix' command. X */ Xvmstounix(file) Xchar *file; X{ X char buf[BUFLEN]; X sprintf(buf,"exec /etc/vmstounix %s", file); X return system(buf); X} X#endif /* VMS */ X X#if !defined(BSD4_2) && !defined(BSD4_1C) X/* X * make a directory. Also make sure that the directory is owned X * by the right userid X */ Xmkdir(path, perm) Xchar *path; Xint perm; X{ X int pid, status; X#ifdef USG X char parent[200]; X char *p; X struct stat sbuf; X X /* X * Make parent directory writable, because we will X * be creating a directory owned by the real user, X * rather than by news. X */ X (void) strcpy(parent, path); X if (p = rindex(parent, '/')) { X *p = '\0'; X if (stat(parent, &sbuf) == 0) X (void) chmod(parent, 0777); X else X return -1; X } else X return -1; X#endif X X if (pid=vfork()) { X status = fwait(pid); X#if defined(USG) && !defined(CHEAP) X if (pid=vfork()) X (void) fwait(pid); X else { X setgid(gid); X setuid(uid); X if (chown(path, duid, dgid) == 0) X (void) chmod(path, perm&(~N_UMASK)); X _exit(0); X } X#endif /* USG && !CHEAP */ X } else { X (void) setgid(dgid); X if (setuid(duid) < 0) X (void) umask(0); X else X (void) umask(perm&N_UMASK); X (void) execlp("mkdir", "mkdir", path, (char *)NULL); X perror(path); X _exit(1); X } X#ifdef USG X (void) chmod(parent, sbuf.st_mode); /* Restore mode of parent */ X#endif X return status; X} X#endif /* !BSD4_2 && ! BSD4_1C */ X#ifndef USG Xchar * Xstrpbrk(str, chars) Xregister char *str, *chars; X{ X register char *cp; X X do { X cp = chars - 1; X while (*++cp) { X if (*str == *cp) X return str; X } X } while (*str++); X return NULL; X} X#endif /* !USG */ X X#ifdef FASCIST X/* X * This routine checks to see if the posting user is allowed to X * post to the given newsgroup. If the username is not in the file X * $LIBDIR/authorized then the default in the symbol FASCIST is used. X * X * Format of the call: X * fascist(user, newgroups) X * X * Returns: X * FALSE, if authorized X * TRUE, if not X * X * Format of the file "authorized" is: X * user:allowed groups X * X * Example: X * root:net.all,mod.all X * naughty_person:junk,net.politics X * operator:!net.all,general,test,mod.unix X * X * An open environment could have FASCIST set to "all" X * and then individual entries could be made in the authorized file X * to prevent certain individuals from posting to such a wide X * area. X * X * Note that a distribution of "all" does NOT mean to allow postings X * only to local groups -- "all" includes "all.all". X * Use "all,!all.all" to get this behavior X * X * Eugene Spafford spaf@gatech May 22, 1985 X */ X Xfascist(user, newsgroups) Xregister char *user, *newsgroups; X{ X FILE *facfd; X char facuser[BUFLEN], facgroups[BUFLEN], factemp[BUFLEN]; X register char *facptr; X X /* First, open the necessary file...$LIBDIR/authorized and see if there X * is an entry for this user X */ X X (void) strncpy(facgroups, FASCIST, BUFLEN); X sprintf(factemp, "%s/%s", LIB, "authorized"); X facfd = fopen(factemp, "r"); X X if (facfd != NULL) { /* If no such file, we go with the global default */ X while (fscanf(facfd, "%[^:]:%s\n", facuser, factemp) != EOF) X if (strncmp(facuser, user, BUFLEN) == 0) { X (void) strcat(facgroups, ","); X (void) strcat(facgroups, factemp); X break; X } X fclose (facfd); X } X#ifdef DEBUG X fprintf(stderr, "facgroups = %s\n", facgroups); X fprintf(stderr, "newsgroups = %s\n", newsgroups); X#endif /* DEBUG */ X X /* We step through the newsgroups being posted to and check each against X * the restriction list. *ALL* posted groups must match the restriction X * list or we don't allow the posting. X */ X X while (*newsgroups != '\0') { X facptr = factemp; X while (*newsgroups != '\0' && *newsgroups != NGDELIM) X *facptr++ = *newsgroups++; X *facptr = '\0'; X if (*newsgroups == NGDELIM) X newsgroups++; X X#ifdef DEBUG X fprintf(stderr, "Checking newsgroup '%s'\n", factemp); X#endif X X if (ngmatch(factemp, facgroups) == FALSE) X return TRUE; X } X X /* must be okay -- return */ X#ifdef DEBUG X fprintf (stderr, "Newsgroups approved for this poster.\n"); X#endif /* DEBUG */ X return FALSE; X} X#endif /* FASCIST */ END_OF_FILE if test 12952 -ne `wc -c <'funcs.c'`; then echo shar: \"'funcs.c'\" unpacked with wrong size! fi # end of 'funcs.c' fi echo shar: End of shell archive. exit 0 -- "Zeta Microcomputer Software" ACSnet: nick@ultima.cs.uts.oz UUCP: ...!uunet!munnari!ultima.cs.uts.oz!nick Fidonet: Nick Andrew on 3:713/602 (Zeta)
nick@ultima.cs.uts.oz (Nick Andrew) (12/07/89)
#! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of shell archive." # Contents: rfuncs2.c pathinit.c checknews.c install.sh recnews.c # Wrapped by nick@nswitgould on Thu Dec 7 22:41:34 1989 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'rfuncs2.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'rfuncs2.c'\" else echo shar: Extracting \"'rfuncs2.c'\" \(11135 characters\) sed "s/^X//" >'rfuncs2.c' <<'END_OF_FILE' X/* X * This software is Copyright 1986 by Rick Adams. X * X * Permission is hereby granted to copy, reproduce, redistribute or X * otherwise use this software as long as: there is no monetary X * profit gained specifically from the use or reproduction or this X * software, it is not sold, rented, traded or otherwise marketed, and X * this copyright notice is included prominently in any copy X * made. X * X * The author make no claims as to the fitness or correctness of X * this software for any use whatsoever, and it is provided as is. X * Any use of this software is at the user's own risk. X * X * rfuncs2 - more routines needed by readr. X */ X X#ifdef SCCSID Xstatic char *SccsId = "@(#)rfuncs2.c 1.35 3/21/87"; X#endif /* SCCSID */ X X/*LINTLIBRARY*/ X X#include "rparams.h" X Xstatic char lbuf[LBUFLEN]; Xextern char *replyname(); X XFILE *popen(); X X/* X * Match title. X */ Xtitmat(h, titlist) Xregister struct hbuf *h; Xregister char *titlist; X{ X register char *p; X X while (*titlist != '\0') { X X if (strcmp(titlist, h->ident) == 0) X return TRUE; X for (p = h->title; *p != '\0'; p++) X if (prefix(p, titlist)) { X return TRUE; X } X while (*titlist++ != '\0') X ; X } X return FALSE; X} X X X/* X * Save the news item in the user's file. X * Allow files with first character as '|' to write article X * to program across a pipe. X */ X X#define PIPECHAR '|' X Xsave(file, to) Xregister char *file, *to; X{ X register FILE *ufp, *hfp; X#ifdef u370 X static struct hbuf hh; X#else /* !u370 */ X struct hbuf hh; X#endif /* !u370 */ X int isprogram = 0; X int isnew = 1; X register int i; X X for(i=0;i<NUNREC;i++) X hh.unrec[i] = NULL; X X if ((hfp = art_open(file, "r")) == NULL) { X fprintf(stderr, "Can't get article.\n"); X return; X } X if (hread(&hh, hfp, TRUE) == NULL) { X fprintf(stderr, "Article is garbled.\n"); X return; X } X ufp = fopen(to, "r"); X if (ufp != NULL) { X (void) fclose(ufp); X isnew = 0; X } X (void) setgid(gid); X (void) setuid(uid); X (void) umask(savmask); X X if (*to == PIPECHAR) { X if ((ufp = popen (&to[1], "w")) == NULL) { X fprintf(stderr,"Cannot execute %s\n", &to[1]); X return; X } X isprogram++; X } else if ((ufp = fopen(to, "a")) == NULL) { X fprintf(stderr,"Cannot append to %s.\n", to); X return; X } X /* X * V7MAIL code is here to conform to V7 mail format. X * If you need a different format to be able to X * use your local mail command (such as four ^A's X * on the end of articles) substitute it here. X */ X#ifdef MMDF X if (!isprogram) X fprintf(ufp, "\001\001\001\001\n"); /* MMDF message header */ X#endif /* MMDF */ X#ifdef V7MAIL X hh.subtime = cgtdate(hh.subdate); X fprintf(ufp, "From %s %s", replyname(&hh), ctime(&hh.subtime)); X#endif X hprint(&hh, ufp, 2); X#ifdef V7MAIL X tprint(hfp, ufp, TRUE); X putc('\n', ufp); /* force blank line at end (ugh) */ X#else X tprint(hfp, ufp, FALSE); X#endif X (void) fclose(hfp); X#ifdef MMDF X if (!isprogram) X fprintf(ufp, "\001\001\001\001\n"); /* MMDF message header */ X#endif /* MMDF */ X if (isprogram) X (void) pclose (ufp); X else X (void) fclose(ufp); X if (!isprogram) X printf("%s: %s\n", to, isnew ? "New file" : "Appended"); X} X X X/* X * Print out the rest of the article. X */ Xtprint(ifp, ofp, checkfrom) Xregister FILE *ifp, *ofp; Xint checkfrom; X{ X while ((fgets(bfr, sizeof bfr, ifp)) != NULL && !SigTrap) { X if (checkfrom && strncmp(bfr, "From ", 5) == 0) X putc('>', ofp); X (void) fputs(bfr, ofp); X if (ferror(ofp)) break; /* E.g. disk full */ X } X if (SigTrap) X qfflush(ofp); X (void) fflush(ofp); X fprintf(ofp, (SigTrap ? "\n\n" : "\n")); X SigTrap = FALSE; X} X X X/* X * Print the file header. X */ Xhprint(hp, ofp, verbose) Xregister struct hbuf *hp; Xint verbose; Xregister FILE *ofp; X{ X register char *p1, *p2; X char fname[BUFLEN]; X char *tailpath(); X X fname[0] = '\0'; /* init name holder */ X X if (verbose == 2) { X lhwrite(hp, ofp); X return; X } X X if (lflag || eflag) { X char buf1[80], buf2[200]; X char *cp; X X (void) strcpy(bfr, groupdir); X for (cp=bfr; *cp; cp++) X if (*cp == '/') X *cp = '.'; X (void) sprintf(buf1, "%s/%ld", bfr, bit); X (void) sprintf(buf2, "%-20s %s", buf1, hp->title); X fprintf(ofp, "%.76s\n", buf2); X return; X } X X p1 = index(hp->from, '('); /* Find the sender's full name. */ X if (p1 == NULL && hp->path[0]) X p1 = index(hp->path, '('); X if (p1 != NULL) { X strcpy(fname, p1+1); X p2 = index(fname, ')'); X if (p2 != NULL) X *p2 = '\0'; X } X X fprintf(ofp, "Subject: %s\n", hp->title); X if (!hflag && hp->summary[0]) X fprintf(ofp, "Summary: %s\n", hp->summary); X if (!hflag && hp->keywords[0]) X fprintf(ofp, "Keywords: %s\n", hp->keywords); X if (verbose) { X fprintf(ofp, "From: %s\n", hp->from); X fprintf(ofp, "Path: %s\n", hp->path); X if (hp->organization[0]) X fprintf(ofp, "Organization: %s\n", hp->organization); X } X else { X if (p1 != NULL) X *--p1 = '\0'; /* bump over the '(' */ X#ifdef INTERNET X /* X * Prefer Path line if it's in internet format, or if we don't X * understand internet format here, or if there is no reply-to. X */ X fprintf(ofp, "From: %s", hp->from); X#else X fprintf(ofp, "Path: %s", tailpath(hp)); X#endif X if (fname[0] || hp->organization[0]) { X if (fname[0] == '\0') { X (void) strcpy(fname,hp->from); X p2 = index(fname,'@'); X if (p2) X *p2 = '\0'; X } X fprintf(ofp, " (%s", fname); X if (hp->organization[0] && !hflag) X fprintf(ofp, " @ %s", hp->organization); X fprintf(ofp, ")"); X } X fprintf(ofp, "\n"); X if (p1 != NULL) X *p1 = ' '; X } X X if (verbose) { X fprintf(ofp, "Newsgroups: %s\n", hp->nbuf); X fprintf(ofp, "Date: %s\n", hp->subdate); X if (hp->sender[0]) X fprintf(ofp, "Sender: %s\n", hp->sender); X if (hp->replyto[0]) X fprintf(ofp, "Reply-To: %s\n", hp->replyto); X if (hp->followto[0]) X fprintf(ofp, "Followup-To: %s\n", hp->followto); X } X else if (index(hp->nbuf, ',') || strcmp(groupdir, "junk") == 0) X fprintf(ofp, "Newsgroups: %s\n", hp->nbuf); X X if (pflag || ofp != stdout) X putc('\n', ofp); X} X X X/* X * If ofp != stdout, close it and run the script in coptbuf. X */ Xcout(ofp) XFILE *ofp; X{ X register char *p, *q, *r; X X if (ofp == stdout || ofp == NULL) X return; X (void) fclose(ofp); X p = coptbuf; X q = lbuf; X while ((*q = *p++) != '\0') X if (*q++ == FMETA) { X q--; X r = outfile; X while ((*q++ = *r++) != '\0') X ; X q--; X } X fwait(fsubr(ushell, lbuf, (char *)NULL)); X (void) unlink(outfile); X} X X Xcdump(ofp) Xregister FILE *ofp; X{ X if (ofp == stdout) X return; X fclose(ofp); X unlink(outfile); X} X X X/* X * Quiet 'flush'. X * Empty (without fflush()) the buffer for stream fp. X */ X/* ARGSUSED */ Xqfflush(fp) XFILE *fp; X{ X#ifdef fileno X int fno, err; X X fno = fileno(fp); X err = ferror(fp); X fileno(fp) = -1; X (void) fflush(fp); X fileno(fp) = fno; X if (!err) X (void) clearerr(fp); X#endif /* fileno */ X} X X/* X * Count the number of remaining lines in file fp. X * Do not move the file pointer. X */ Xlinecnt(fp) XFILE *fp; X{ X long curpos; X register int nlines = 0; X register int c; X X if (fp == NULL) X return 0; X curpos = ftell(fp); X while ((c = getc(fp)) != EOF) X if (c == '\n') X nlines++; X (void) fseek(fp, curpos, 0); X return nlines; X} X X X/* X * Transmit file to system. X */ Xtransmit(sp, file) Xregister struct srec *sp; Xchar *file; X{ X register FILE *ifp, *ofp; X register int c, i; X#ifdef u370 X static struct hbuf hh; X#else /* !u370 */ X struct hbuf hh; X#endif /* !u370 */ X char TRANS[BUFLEN]; X X#ifdef DEBUG X fprintf(stderr, "xmit %s to %s using %s\n", file, sp->s_name, sp->s_xmit); X#endif X bzero((char *)&hh, sizeof hh); X ifp = xart_open(file, "r"); X if (hread(&hh, ifp, TRUE) == NULL) X return; X strcpy(TRANS, "/tmp/trXXXXXX"); X ofp = xfopen(mktemp(TRANS), "w"); X if (index(sp->s_flags, 'A') == NULL) X hwrite(&hh, ofp); X else { X#ifdef OLD X fprintf(ofp, "A%s\n%s\n%s!%s\n%s\n%s\n", oident(hh.ident), hh.nbuf, PATHSYSNAME, X hh.path, hh.subdate, hh.title); X#else /* !OLD */ X logerr("Must have OLD defined to use A flag for xmit"); X unlink(TRANS); X return; X#endif /* !OLD */ X } X while ((c = getc(ifp)) != EOF) X putc(c, ofp); X (void) fclose(ifp); X (void) fclose(ofp); X for (i=0;i<NUNREC;i++) X if (hh.unrec[i] != NULL) X free(hh.unrec[i]); X if (*sp->s_xmit == '\0' || strpbrk(sp->s_flags, "FUMH")) X (void) sprintf(bfr, DFTXMIT, sp->s_name, TRANS); X else X (void) sprintf(bfr, "(%s) < %s", sp->s_xmit, TRANS); X#ifdef DEBUG X fprintf(stderr, "%s\n", bfr); X#endif X (void) system(bfr); X (void) unlink(TRANS); X} X X X/* X * Cancel the article whose header is in hp, by posting a control message X * to cancel it. The scope of the control message depends on who would X * really be willing to cancel it. It is sent as far as it will do any good. X * notauthor is true iff the person posting this article is not the X * real author of the article being cancelled. X */ Xcancel(ofp, hp, notauthor) XFILE *ofp; Xstruct hbuf *hp; Xint notauthor; X{ X int pid; X X fflush(ofp); X pid = vfork(); X if (pid < 0) { X perror("readnews: cancel"); X return 0; X } X if (pid > 0) X return 0; X if (notauthor) X (void) sprintf(bfr, "%s/%s -c 'cancel %s' -n %s -d %s < /dev/null", X LIB, "inews", hp->ident, hp->nbuf, X#ifdef ORGDISTRIB X ORGDISTRIB); X#else /* !ORGDISTRIB */ X "local"); X#endif /* !ORGDISTRIB */ X else { X if (hp->distribution[0] == '\0') X (void) sprintf(bfr, "%s/%s -c 'cancel %s' -n %s < /dev/null", X LIB, "inews", hp->ident, hp->nbuf); X else X (void) sprintf(bfr, "%s/%s -c 'cancel %s' -n %s -d %s < /dev/null", X LIB, "inews", hp->ident, hp->nbuf, hp->distribution); X } X execl("/bin/sh", "sh", "-c", bfr, (char *) 0); X perror(bfr); X for ( ; ; ) X exit(1); X} X X Xdash(num, ofp) Xregister int num; Xregister FILE *ofp; X{ X register int i; X X for (i = 0; i < num; i++) X putc('-', ofp); X putc('\n', ofp); X} X X Xhelp(ofp) Xregister FILE *ofp; X{ X register FILE *fp; X register int c; X char temp[BUFLEN]; X X if (cflag) { Xoneline: X fprintf(ofp, "(n)ext re(p)rint (w)rite (q)uit (r)eply\ X (c)ancel -[n] +[n] (f)ollowup (N)ext (U)nsubscribe (v)ersion\n"); X return; X } X (void) sprintf(temp, "%s/%s", LIB, "help"); X if ((fp = fopen(temp, "r")) == NULL) { X fprintf(ofp, "No help file.\n"); X goto oneline; X } X while ((c = getc(fp)) != EOF && !SigTrap) X putc(c, ofp); X (void) fclose(fp); X} X X Xpout(ofp) XFILE *ofp; X{ X register char *p, *q, *r; X X p = PAGER; X q = lbuf; X while ((*q = *p++) != '\0') X if (*q++ == FMETA) { X q--; X r = filename; X while ((*q++ = *r++) != '\0') X ; X q--; X } X fwait(fsubr(ushell, lbuf, (char *)NULL)); X fprintf(ofp, "\n"); X} X X/* X * Print a very brief version of the date in question. X */ Xchar * Xbriefdate(datestr) Xchar *datestr; X{ X time_t dt, now; X char *tmstr; X char *wkday, *monthdate, *timeofday; X static char rbuf[20]; X X dt = cgtdate(datestr); X tmstr = ctime(&dt); X X wkday = tmstr; tmstr[3] = '\0'; X monthdate = tmstr+4; tmstr[10] = '\0'; X timeofday = tmstr+11; tmstr[16] = '\0'; X X (void) time(&now); X if (now - dt < WEEKS) X (void) strcpy(rbuf, wkday); X else X (void) strcpy(rbuf, monthdate); X (void) strcat(rbuf, " "); X (void) strcat(rbuf, timeofday); X return rbuf; X} X X/* X * Return TRUE iff stdout is /dev/null. X */ Xignoring() X{ X struct stat ss, ns; X X if (fstat(1, &ss) < 0) X return FALSE; X if (stat("/dev/null", &ns) < 0) X return FALSE; X if (ss.st_dev == ns.st_dev && ss.st_rdev == ns.st_rdev) X return TRUE; X return FALSE; X} END_OF_FILE if test 11135 -ne `wc -c <'rfuncs2.c'`; then echo shar: \"'rfuncs2.c'\" unpacked with wrong size! fi # end of 'rfuncs2.c' fi if test -f 'pathinit.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'pathinit.c'\" else echo shar: Extracting \"'pathinit.c'\" \(10623 characters\) sed "s/^X//" >'pathinit.c' <<'END_OF_FILE' X/* X * This software is Copyright (c) 1986 by Rick Adams. X * X * Permission is hereby granted to copy, reproduce, redistribute or X * otherwise use this software as long as: there is no monetary X * profit gained specifically from the use or reproduction or this X * software, it is not sold, rented, traded or otherwise marketed, and X * this copyright notice is included prominently in any copy X * made. X * X * The author make no claims as to the fitness or correctness of X * this software for any use whatsoever, and it is provided as is. X * Any use of this software is at the user's own risk. X * X * This function initializes all the strings used for the various X * filenames. They cannot be compiled into the program, since that X * would be non-portable. With this convention, the netnews sub-system X * can be owned by any non-privileged user. It is also possible X * to work when the administration randomly moves users from one X * filesystem to another. The convention is that a particular user X * (HOME, see Makefile) is searched for in /etc/passwd and all files X * are presumed relative to there. This method also allows one copy X * of the object code to be used on ANY machine. (this code runs X * un-modified on 50+ machines at IH!!) X * X * The disadvantage to using this method is that all netnews programs X * (inews, readnews, rnews, checknews) must first search /etc/passwd X * before they can start up. This can cause significant overhead if X * you have a big password file. X * X * Some games are played with ifdefs to get four .o files out of this X * one source file. INEW is defined for inews, READ for readnews, X * CHKN for checknews, and EXP for expire. X */ X X#ifdef SCCSID Xstatic char *SccsId = "@(#)pathinit.c 1.23 4/6/87"; X#endif /* SCCSID */ X X#if defined(INEW) || defined(EXP) X#include "iparams.h" X#endif /* INEW || EXP */ X X#ifdef READ X#include "rparams.h" X#endif /* READ */ X X#if defined(CHKN) X#include "params.h" X#endif /* CHKN */ X X Xchar *FROMSYSNAME, *PATHSYSNAME, *LOCALSYSNAME, *LOCALPATHSYSNAME; Xchar *SPOOL, *LIB, *BIN, *ACTIVE, *SUBFILE, *ARTFILE, X *username, *userhome; X X#ifdef INEW Xchar *LOCKFILE, *SEQFILE, *ARTICLE, *INFILE, *TELLME; X Xint c_cancel(), c_newgroup(), c_ihave(), c_sendme(), c_rmgroup(), X c_sendsys(), c_version(), c_checkgroups(), c_unimp(); X Xstruct msgtype msgtype[] = { X "cancel", NULL, c_cancel, X "newgroup", NULL, c_newgroup, X "ihave", NULL, c_ihave, X "sendme", NULL, c_sendme, X "sendbad", NULL, c_sendme, X "rmgroup", NULL, c_rmgroup, X "sendsys", NULL, c_sendsys, X "version", NULL, c_version, X "checkgroups", NULL, c_checkgroups, X "delsub", NULL, c_unimp, X NULL, NULL, NULL X}; X#endif /* INEW */ X X#if defined(INEW) || defined(READ) Xchar *ALIASES; X#endif /* INEW || READ */ X X#ifdef EXP Xchar *OLDNEWS; X#endif /* EXP */ X X#ifdef READ Xchar *MAILPARSER; X#endif /* READ */ X X Xstruct passwd *getpwnam(); Xchar *rindex(); X X#define Sprintf(where,fmt,arg) (void) sprintf(bfr,fmt,arg); where = AllocCpy(bfr) X Xchar * XAllocCpy(cp) Xregister char *cp; X{ X register char *mp; X char *malloc(); X X mp = malloc((unsigned)strlen(cp) + 1); X X if (mp == NULL) X xerror("malloc failed on %s", cp); X X (void) strcpy(mp, cp); X return mp; X} X Xpathinit() X{ X#ifndef ROOTID X struct passwd *pw; /* struct for pw lookup */ X#endif /* !ROOTID */ X#ifdef EXP X char *p; X#endif /* EXP */ X#ifndef CHKN X struct utsname ubuf; X char buf[BUFLEN]; X extern char *mydomain(); X X uname(&ubuf); X X#ifdef HIDDENNET_IN_LOCALSYSNAME X /* old compatibility code, remove when HIDDENNET is used no more */ X if (strcmp(ubuf.nodename, HIDDENNET) != 0) X (void) sprintf(buf, "%s.%s%s", ubuf.nodename, HIDDENNET, X mydomain()); X else X#endif X (void) sprintf(buf, "%s%s", ubuf.nodename, mydomain()); X LOCALSYSNAME = AllocCpy(buf); X X#ifdef GENERICFROM X (void) sprintf(buf, GENERICFROM, ubuf.nodename, mydomain()); X FROMSYSNAME = AllocCpy(buf); X#else /* !GENERICFROM */ X FROMSYSNAME = LOCALSYSNAME; X#endif /* !GENERICFROM */ X X LOCALPATHSYSNAME = AllocCpy(ubuf.nodename); X X#ifdef GENERICPATH X (void) sprintf(buf, GENERICPATH, ubuf.nodename, mydomain()); X PATHSYSNAME = AllocCpy(buf); X#else /* !GENERICPATH */ X PATHSYSNAME = LOCALPATHSYSNAME; X#endif /* !GENERICPATH */ X X#endif /* !CHKN */ X X#ifdef HOME X /* Relative to the home directory of user HOME */ X (void) sprintf(bfr, "%s/%s", logdir(HOME), SPOOLDIR); X SPOOL = AllocCpy(bfr); X (void) sprintf(bfr, "%s/%s", logdir(HOME), LIBDIR); X LIB = AllocCpy(bfr); X#else /* !HOME */ X /* Fixed paths defined in Makefile */ X SPOOL = AllocCpy(SPOOLDIR); X LIB = AllocCpy(LIBDIR); X#endif /* !HOME */ X X#ifdef IHCC X (void) sprintf(bfr, "%s/%s", logdir(HOME), BINDIR); X BIN = AllocCpy(bfr); X#else /* !IHCC */ X Sprintf(BIN, "%s", BINDIR); X#endif /* !IHCC */ X X Sprintf(ACTIVE, "%s/active", LIB); X X#ifdef EXP X (void) strcpy(bfr, SPOOL); X p = rindex(bfr, '/'); X if (p) { X strcpy(++p, "oldnews"); X OLDNEWS = AllocCpy(bfr); X } else X OLDNEWS = AllocCpy("oldnews"); X#endif /* EXP */ X X#ifndef CHKN X Sprintf(SUBFILE, "%s/sys", LIB); X Sprintf(ARTFILE, "%s/history", LIB); X# endif /* !CHKN */ X X# ifdef READ X#ifdef SENDMAIL X Sprintf(MAILPARSER, "%s -oi -oem", SENDMAIL); X#else /* !SENDMAIL */ X Sprintf(MAILPARSER, "%s/recmail", LIB); X#endif /* !SENDMAIL */ X# endif /* READ */ X X# if defined(READ) || defined(INEW) X Sprintf(ALIASES, "%s/aliases", LIB); X# endif /* READ || INEW */ X# ifdef INEW X Sprintf(LOCKFILE, "%s/LOCK", LIB); X Sprintf(SEQFILE, "%s/seq", LIB); X Sprintf(ARTICLE, "%s/.arXXXXXX", SPOOL); X Sprintf(INFILE, "%s/.inXXXXXX", SPOOL); X/* X * The person notified by the netnews sub-system. Again, no name is X * compiled in, but instead the information is taken from a file. X * If the file does not exist, a "default" person will get the mail. X * If the file exists, but is empty, nobody will get the mail. This X * may seem backwards, but is a better fail-safe. X */ X# ifdef NOTIFY X parse_notify(); X# endif /* NOTIFY */ X X/* X * Since the netnews owner's id number is different on different X * systems, we'll extract it from the /etc/passwd file. If no entry, X * default to root. This id number seems to only be used to control who X * can input certain control messages or cancel any message. Note that X * entry is the name from the "notify" file as found above if possible. X * Defining ROOTID in defs.h hardwires in a number and avoids X * another search of /etc/passwd. X */ X# ifndef ROOTID X if ((pw = getpwnam(TELLME)) != NULL) X ROOTID = pw->pw_uid; X else if ((pw = getpwnam(HOME)) != NULL) X ROOTID = pw->pw_uid; X else X ROOTID = 0; /* nobody left, let only root */ X# endif /* !ROOTID */ X#endif /* INEW */ X} X X#ifdef INEW X#ifdef NOTIFY X/* X * Attempt to parse the LIB/notify file into the global structure msgtype[]. X */ Xparse_notify() X{ X FILE *nfd; X int valid = 0, done = 0; X register struct msgtype *mp; X char mtype[BUFLEN], addr[BUFLEN]; X X (void) sprintf(bfr, "%s/notify", LIB); X#ifndef ROOTID X TELLME = AllocCpy(NOTIFY); X#endif /* !ROOTID */ X if ( (nfd = fopen(bfr, "r")) == NULL) { X /* X * Set defaults to NOTIFY X */ X#ifdef debug X log("parse_notify: %s/notify not found", LIB); X#endif /* debug */ X (void)setmsg("all", NOTIFY); X return; X } X do { X mtype[0] = addr[0] = 0; X switch( get_notify(nfd, mtype, addr) ) { X case 0: X continue; X case 1: X valid += setmsg(mtype, ""); X break; X case 2: X valid += setmsg(mtype, addr); X break; X case -1: X if( !valid ) { X#ifdef debug X log("parse_notify: no valid entries found."); X#endif /* debug */ X setmsg("all", ""); /* send mail to no one */ X } X done = 1; X } X } while( !done ); X X /* X * point to zero length string for all entries we haven't touched X */ X for(mp=msgtype; mp->m_name; mp++) X if(mp->m_who_to == 0) X mp->m_who_to = ""; X} X Xsetmsg(what, to) Xchar *what, *to; X{ X register struct msgtype *mp; X#ifdef debug X log("setmsg: what='%s', to='%s'", what, to); X#endif /* debug */ X /* X * Special case for "all" X */ X if(strcmp(what, "all") == 0) { X for(mp=msgtype; mp->m_name; mp++) { X mp->m_who_to = AllocCpy(to); X#ifdef debug X log("setmsg: '%s'='%s'", mp->m_name, mp->m_who_to); X#endif /* debug */ X } X return 1; X } X X for(mp=msgtype; mp->m_name; mp++) X if(strcmp(mp->m_name, what) == 0) { X mp->m_who_to = AllocCpy(to); X#ifdef debug X log("setmsg: '%s'='%s'", mp->m_name, mp->m_who_to); X#endif /* debug */ X return 1; X } X return 0; X} X Xstatic Xget_notify(fp, s, t) XFILE *fp; Xregister char *s, *t; X{ X register char *cp; X char pbuf[BUFSIZ]; X X if( cp=fgets(pbuf, sizeof(pbuf), fp ) ) { X if( *cp == '\n' ) X return 0; X while(*cp && *cp != ' ' && *cp != '\t' && *cp != '\n') X *s++ = *cp++; X *s = '\0'; /* terminate first string */ X X while(*cp && (*cp == ' ' || *cp == '\t' || *cp == '\n') ) X cp++; /* look for start of second */ X if( !*cp || *cp == '\n' ) X return 1; /* no second string */ X X while( *cp && *cp != '\n' ) X *t++ = *cp++; X *t = '\0'; X return 2; X } else X return -1; X} X#endif /* NOTIFY */ X#endif /* INEW */ X X#ifndef CHKN X/* X * At sites where the are many mail domains within the support area of a single X * news administrator, it is much nicer to be able to read the local domain of X * a machine from a file. What we do here is: X * 1) Check for the presence of a LIBDIR/localdomain file. If it doesn't X * exist,assume that MYDOMAIN should be used instead. X * 2) If it does exist, we make the following assumptions: X * a) If it is empty, has only comments, or only blank lines; we assume X * the domain is desired to be a zero length string ( ie ""). (this X * implies that the domain name is contained in the hostname.) X * b) If it is not empty, we assume the first line not beginning with a X * '#', blank/tab, or newline is the desired domain name. X * A like '.UUCP' or '.TEK.COM' should be used. We could insure that X * the line begin with a '.' to be a valid domain name, but I don't X * think it is necessary to put that restriction on it. X */ Xchar * Xmydomain() X{ X static char *md = NULL; X register char *cp; X FILE *fp = NULL; X char fbuf[BUFLEN]; X extern char *malloc(), *strcpy(), *index(); X X if(md) /* we've been here before, so just return what we found */ X return(md); X X (void) sprintf(fbuf,"%s/localdomain", LIBDIR); X if ( (fp = fopen(fbuf,"r")) == NULL) { X md = MYDOMAIN; /* No localdomain file, use MYDOMAIN instead */ X } else { X while(fgets(fbuf, sizeof(fbuf), fp) ) { X if( *fbuf == '\n' || *fbuf == '#' X || *fbuf == ' ' || *fbuf == '\t') X continue; X X if( cp = index(fbuf, '\n') ) X *cp = '\0'; X X if ( (md = malloc(strlen(fbuf) + 1)) == NULL) X md = MYDOMAIN; /* punt here */ X else X (void)strcpy(md, fbuf); X break; X } X } X X if(fp) X (void)fclose(fp); X X if( md == NULL) X md = ""; X X return md; X} X#endif /* !CHKN */ END_OF_FILE if test 10623 -ne `wc -c <'pathinit.c'`; then echo shar: \"'pathinit.c'\" unpacked with wrong size! fi # end of 'pathinit.c' fi if test -f 'checknews.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'checknews.c'\" else echo shar: Extracting \"'checknews.c'\" \(11026 characters\) sed "s/^X//" >'checknews.c' <<'END_OF_FILE' X/* X * This software is Copyright (c) 1986 by Rick Adams. X * X * Permission is hereby granted to copy, reproduce, redistribute or X * otherwise use this software as long as: there is no monetary X * profit gained specifically from the use or reproduction or this X * software, it is not sold, rented, traded or otherwise marketed, and X * this copyright notice is included prominently in any copy X * made. X * X * The author make no claims as to the fitness or correctness of X * this software for any use whatsoever, and it is provided as is. X * Any use of this software is at the user's own risk. X * X * checknews - news checking program X */ X X#ifdef SCCSID Xstatic char *SccsId = "@(#)checknews.c 2.29 4/6/87"; X#endif /* SCCSID */ X Xchar *Progname = "checknews"; /* used by xerror */ X X#include "params.h" X Xchar optbuf[BUFLEN]; /* NEWSOPTS buffer */ Xint y, e, n, q; Xint verbose; /* For debugging. */ Xint nflag; /* for spec. newsgroup */ Xchar narggrp[BUFLEN]; /* spec newsgroup */ X X#ifdef MINIX X/* make 'em external */ Xextern char bfr[LBUFLEN]; /* general-use scratch area */ Xextern char newsrc[],*rcline[],rcbuf[],*argvrc[]; Xextern FILE *rcfp, *actfp; X#else Xchar bfr[LBUFLEN]; /* general-use scratch area */ Xchar newsrc[BUFLEN],*rcline[LINES],rcbuf[LBUFLEN],*argvrc[LINES]; XFILE *rcfp, *actfp; X#endif X Xint mode = 1; Xextern int line; X X X#ifndef SHELL X#ifdef MINIX X/* Make it extern */ Xextern X#endif X Xchar *SHELL; X#endif X Xmain(argc, argv) Xint argc; Xregister char **argv; X{ X register char *ptr; /* pointer to rest of buffer */ X char *user, *home; X struct passwd *pw; X struct group *gp; X int sflag = 0, optflag = FALSE, space = FALSE; X int i; X X y = 0; X n = 0; X e = 0; X q = 0; X nflag = 0; X pathinit(); X if (--argc > 0) { X for (argv++; **argv; ++*argv) { X switch(**argv) { X case 'y': X y++; X break; X case 'q': X q++; X break; X case 'v': X verbose++; X break; X case 'n': X n++; X break; X case 'N': X nflag++; X if (argc <= 1) X xerror("No newsgroup specified with -N"); X strcpy(narggrp,argv[1]); X strcat(narggrp,","); X break; X case 'e': X case 'f': X e++; X break; X } X } X } X if (!n && !e && !y && !q) X y++; X if (nflag) X argv++; X X#ifndef V6 X if ((user = getenv("USER")) == NULL) X user = getenv("LOGNAME"); X if ((home = getenv("HOME")) == NULL) X home = getenv("LOGDIR"); X if (user == NULL || home == NULL) X getuser(); X else { X username = AllocCpy(user); X userhome = AllocCpy(home); X } X if (ptr = getenv("NEWSOPTS")) X strcpy(rcbuf, ptr); X else X *rcbuf = '\0'; X if (*rcbuf) { X strcat(rcbuf, " \1"); X ptr = rcbuf; X while (*++ptr) X if (isspace(*ptr)) X *ptr = '\0'; X for (ptr = rcbuf;; ptr++) { X if (!*ptr) X continue; X if (*ptr == '\1') X break; X if (++line > LINES) X xerror("Too many options."); X if ((rcline[line] = malloc(strlen(ptr) + 1)) == NULL) X xerror("Not enough memory."); X argvrc[line] = rcline[line]; X strcpy(rcline[line], ptr); X while (*ptr) X ptr++; X } X } X#else X getuser(); X#endif X ptr = getenv("NEWSRC"); X if (ptr == NULL) X sprintf(newsrc, "%s/%s", userhome, NEWSRC); X else X strcpy(newsrc, ptr); X if ((rcfp = fopen(newsrc, "r")) != NULL) { X while (fgets(rcbuf, LBUFLEN, rcfp) != NULL) { X if (!(space = isspace(*rcbuf))) X optflag = FALSE; X if (!strncmp(rcbuf, "options ", 8)) X optflag = TRUE; X if (optflag) { X strcat(rcbuf, "\1"); X if (space) X ptr = rcbuf - 1; X else X ptr = &rcbuf[7]; X while (*++ptr) X if (isspace(*ptr)) X *ptr = '\0'; X if (space) X ptr = rcbuf; X else X ptr = &rcbuf[8]; X for (;; ptr++) { X if (!*ptr) X continue; X if (*ptr == '\1') X break; X if (++line > LINES) X xerror("Too many options."); X if ((rcline[line] = malloc(strlen(ptr) + 1)) == NULL) X xerror("Not enough memory."); X argvrc[line] = rcline[line]; X strcpy(rcline[line], ptr); X while (*ptr) X ptr++; X } X } X } X fclose(rcfp); X } X header.nbuf[0] = 0; X if (line != -1) { X#ifdef DEBUG X for (i = 0; i <= line; i++) X fprintf(stderr, "options: %s\n", rcline[i]); X#endif X process(line+2, argvrc); X do { X#ifdef DEBUG X fprintf(stderr, "Freeing %d\n", line); X#endif X free(rcline[line]); X } while (line--); X } X X if (!*header.nbuf) { X strcpy(header.nbuf, DFLTSUB); X ngcat(header.nbuf); X } X strcat(header.nbuf, ADMSUB); X ngcat(header.nbuf); X if (*header.nbuf) X lcase(header.nbuf); X makehimask(header.nbuf, "junk"); X makehimask(header.nbuf, "control"); X makehimask(header.nbuf, "test"); X if (access(newsrc, 0)) { X if (verbose > 1) X printf("No newsrc\n"); X yep(argv); X } X if ((rcfp = fopen(newsrc, "r")) == NULL) X xerror("Cannot open .newsrc file"); X while (fgets(rcbuf, LBUFLEN, rcfp) != NULL) { X if (!nstrip(rcbuf)) X xerror(".newsrc line too long"); X if (++line >= LINES) X xerror("Too many .newsrc lines"); X if ((rcline[line] = malloc(strlen(rcbuf)+1)) == NULL) X xerror("Not enough memory"); X strcpy(rcline[line], rcbuf); X } X if ((actfp = fopen(ACTIVE, "r")) == NULL) X xerror("Cannot open active newsgroups file"); X X#ifdef DEBUG X fprintf(stderr, "header.nbuf = %s\n", header.nbuf); X#endif X nchk(argv); X exit(0); X} X Xnchk(argv) Xchar **argv; X{ X register int i; X register char *ptr; X long l; X long narts; X char saveptr; X int isnews = 0; X char aline[BUFLEN]; X X#ifdef DEBUG X fprintf(stderr, "nchk()\n"); X#endif X while (fgets(aline, sizeof aline, actfp) != NULL) { X sscanf(aline, "%s %ld", bfr, &narts); X#ifdef DEBUG X fprintf(stderr, "bfr = '%s'\n", bfr); X#endif X if (narts == 0) X continue; X ngcat(bfr); X if (!ngmatch(bfr, nflag ? narggrp : header.nbuf)) X continue; X ngdel(bfr); X i = findrcline(bfr); X if (i < 0) { X if (verbose>1) X printf("No newsrc line for newsgroup %s\n", bfr); X strcpy(rcbuf, " 0"); X } else X strcpy(rcbuf, rcline[i]); X ptr = rcbuf; X X if (index(rcbuf, '!') != NULL) X continue; X if (index(rcbuf, ',') != NULL) { X if (verbose > 1) X printf("Comma in %s newsrc line\n", bfr); X else { X isnews++; X continue; X } X } X while (*ptr) X ptr++; X while (!isdigit(*--ptr) && *ptr != ':' && ptr >= rcbuf) X ; X if (*ptr == ':') X continue; X if (ptr < rcbuf) { X if (verbose > 1) X printf("Ran off beginning of %s newsrc line.\n", bfr); X yep(argv); X } X while (isdigit(*--ptr)) X ; X sscanf(++ptr, "%ld", &l); X if (narts > l) { X if (verbose) { X printf("News: %s ...\n", bfr); X if (verbose < 2) X y = 0; X } X yep(argv); X } Xcontin:; X } X if (isnews) X yep(argv); X if (n) X printf("No news is good news.\n"); X} X Xyep(argv) Xchar **argv; X{ X if (y) { X if (verbose) X printf("There is probably news"); X else X printf("There is news"); X if (nflag) { X narggrp[strlen(narggrp)-1] = '.'; X printf(" in %s\n",narggrp); X } X else X printf(".\n"); X } X if (e) { X#ifdef V6 X execv("/usr/bin/readnews", argv); X#else X execvp("readnews", argv); X#endif X perror("Cannot exec readnews."); X } X if (q) X exit(1); X else X exit(0); X} X Xxerror(message, arg1, arg2) Xchar *message; Xint arg1, arg2; X{ X char buffer[128]; X X sprintf(buffer, message, arg1, arg2); X fprintf(stderr, "checknews: %s.\n", buffer); X exit(1); X} X X/* X * Append NGDELIM to string. X */ Xngcat(s) Xregister char *s; X{ X if (*s) { X while (*s++); X s -= 2; X if (*s++ == NGDELIM) X return; X } X *s++ = NGDELIM; X *s = '\0'; X} X X/* X * News group matching. X * X * nglist is a list of newsgroups. X * sublist is a list of subscriptions. X * sublist may have "meta newsgroups" in it. X * All fields are NGDELIM separated, X * and there is an NGDELIM at the end of each argument. X * X * Currently implemented glitches: X * sublist uses 'all' like shell uses '*', and '.' like shell '/'. X * If subscription X matches Y, it also matches Y.anything. X */ Xngmatch(nglist, sublist) Xregister char *nglist, *sublist; X{ X register char *n, *s; X register int rc; X X rc = FALSE; X for (n = nglist; *n != '\0' && rc == FALSE;) { X for (s = sublist; *s != '\0';) { X if (*s != NEGCHAR) X rc |= ptrncmp(s, n); X else X rc &= ~ptrncmp(s+1, n); X while (*s++ != NGDELIM); X } X while (*n++ != NGDELIM); X } X return(rc); X} X X/* X * Compare two newsgroups for equality. X * The first one may be a "meta" newsgroup. X */ Xptrncmp(ng1, ng2) Xregister char *ng1, *ng2; X{ X while (*ng1 != NGDELIM) { X if (ng1[0]=='a' && ng1[1]=='l' && ng1[2]=='l') { X ng1 += 3; X while (*ng2 != NGDELIM && *ng2 != '.') X if (ptrncmp(ng1, ng2++)) X return(TRUE); X return (ptrncmp(ng1, ng2)); X } else if (*ng1++ != *ng2++) X return(FALSE); X } X return (*ng2 == '.' || *ng2 == NGDELIM); X} X X/* X * Get user name and home directory. X */ Xgetuser() X{ X static int flag = TRUE; X register struct passwd *p; X X if (flag) { X if ((p = getpwuid(getuid())) == NULL) X xerror("Cannot get user's name"); X if (username == NULL || *username == '\0') X username = AllocCpy(p->pw_name); X userhome = AllocCpy(p->pw_dir); X flag = FALSE; X } X} X X/* X * Strip trailing newlines, blanks, and tabs from 's'. X * Return TRUE if newline was found, else FALSE. X */ Xnstrip(s) Xregister char *s; X{ X register char *p; X register int rc; X X rc = FALSE; X p = s; X while (*p) X if (*p++ == '\n') X rc = TRUE; X while (--p >= s && (*p == '\n' || *p == ' ' || *p == '\t')); X *++p = '\0'; X return(rc); X} X X/* X * Delete trailing NGDELIM. X */ Xngdel(s) Xregister char *s; X{ X if (*s++) { X while (*s++); X s -= 2; X if (*s == NGDELIM) X *s = '\0'; X } X} X Xlcase(s) Xregister char *s; X{ X register char *ptr; X X for (ptr = s; *ptr; ptr++) X if (isupper(*ptr)) X *ptr = tolower(*ptr); X} X X/* X * finds the line in your .newsrc file (actually the in-core "rcline" X * copy of it) and returns the index into the array where it was found. X * -1 means it didn't find it. X * X * We play clever games here to make this faster. It's inherently X * quadratic - we spend lots of CPU time here because we search through X * the whole .newsrc for each line. The "prev" variable remembers where X * the last match was found; we start the search there and loop around X * to the beginning, in the hopes that the calls will be roughly in order. X */ Xint Xfindrcline(name) Xchar *name; X{ X register char *p, *ptr; X register int cur; X register int i; X register int top; X static int prev = 0; X X top = line; i = prev; Xloop: X for (; i <= top; i++) { X for (p = name, ptr = rcline[i]; (cur = *p++); ) { X if (cur != *ptr++) X goto contin2; X } X if (*ptr != ':' && *ptr != '!') X continue; X prev = i; X return i; Xcontin2: X ; X } X if (i > line && line > prev-1) { X i = 0; X top = prev-1; X goto loop; X } X return -1; X} X X/* X * Forbid newsgroup ng, unless he asked for it in nbuf. X */ Xmakehimask(nbuf, ng) Xchar *nbuf, *ng; X{ X if (!findex(nbuf, ng)) { X ngcat(nbuf); X strcat(nbuf, "!"); X strcat(nbuf, ng); X ngcat(nbuf); X } X} X X/* X * Return true if the string searchfor is in string, but not if preceded by !. X */ Xfindex(string, searchfor) Xchar *string, *searchfor; X{ X register char first; X register char *p; X X first = *searchfor; X for (p=index(string, first); p; p = index(p+1, first)) { X if (p>string && p[-1] != '!' && strncmp(p, searchfor, strlen(searchfor)) == 0) X return TRUE; X } X return FALSE; X} X Xxxit(i) X{ X exit(i); X} END_OF_FILE if test 11026 -ne `wc -c <'checknews.c'`; then echo shar: \"'checknews.c'\" unpacked with wrong size! fi # end of 'checknews.c' fi if test -f 'install.sh' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'install.sh'\" else echo shar: Extracting \"'install.sh'\" \(9680 characters\) sed "s/^X//" >'install.sh' <<'END_OF_FILE' X: '@(#)install.sh 1.17 12/16/86' X Xif test "$#" != 6 Xthen X echo "usage: $0 spooldir libdir bindir nuser ngroup ostype" X exit 1 Xfi XSPOOLDIR=$1 XLIBDIR=$2 XBINDIR=$3 XNEWSUSR=$4 XNEWSGRP=$5 XOSTYPE=$6 X X: Get name of local system Xcase $OSTYPE in X usg) SYSNAME=`uname -n` X if test ! -d $LIBDIR/history.d X then X mkdir $LIBDIR/history.d X chown $NEWSUSR $LIBDIR/history.d X chgrp $NEWSGRP $LIBDIR/history.d X fi;; X v7) SYSNAME=`uuname -l` X touch $LIBDIR/history.pag $LIBDIR/history.dir;; X *) echo "$0: Unknown Ostype" X exit 1;; Xesac X Xif test "$SYSNAME" = "" Xthen X echo "$0: Cannot get system name" X exit 1 Xfi X X: Ensure SPOOLDIR exists Xfor i in $SPOOLDIR $SPOOLDIR/.rnews Xdo X if test ! -d $i X then X mkdir $i X fi X chmod 777 $i X chown $NEWSUSR $i X chgrp $NEWSGRP $i Xdone X Xchown $NEWSUSR $LIBDIR Xchgrp $NEWSGRP $LIBDIR X X: Ensure certain files in LIBDIR exist Xtouch $LIBDIR/history $LIBDIR/active $LIBDIR/log $LIBDIR/errlog $LIBDIR/users Xchmod 666 $LIBDIR/users X X: If no sys file, make one. Xif test ! -f $LIBDIR/sys Xthen Xecho Xecho Making a $LIBDIR/sys file to link you to oopsvax. Xecho You must change oopsvax to your news feed. Xecho If you are not in the USA, remove '"usa"' from your line in the sys file. Xecho If you are not in North America, remove '"na"' from your line in the sys file. X cat > $LIBDIR/sys << EOF X$SYSNAME:world,comp,sci,news,rec,soc,talk,misc,net,mod,na,usa,to:: Xoopsvax:world,comp,sci,news,rec,soc,talk,misc,net,mod,na,usa,to.oopsvax:: XEOF Xfi X X: If no seq file, make one. Xif test ! -s $LIBDIR/seq Xthen X echo '100' >$LIBDIR/seq Xfi X X: If no mailpaths, make one. Xif test ! -s $LIBDIR/mailpaths Xthen X cat <<E_O_F >$LIBDIR/mailpaths Xbackbone %s Xinternet %s XE_O_F Xecho "I have created $LIBDIR/mailpaths for you. The paths are certainly wrong." Xecho "You must correct them manually to be able to post to moderated groups." Xfi X Xsh makeactive.sh $LIBDIR $SPOOLDIR $NEWSUSR $NEWSGRP X Xfor i in $LIBDIR/ngfile $BINDIR/inews $LIBDIR/localgroups $LIBDIR/moderators \ X $LIBDIR/cunbatch $LIBDIR/c7unbatch Xdo X if test -f $i X then X echo "$i is no longer used. You should remove it." X fi Xdone X Xfor i in $LIBDIR/csendbatch $LIBDIR/c7sendbatch Xdo X if test -f $i X then X echo "$i is no longer used. You should remove it after" X echo "changing your crontab entry to use sendbatch [flags]" X fi Xdone X Xif test -f $BINDIR/cunbatch Xthen X echo "$BINDIR/cunbatch is not used by the new batching scheme." X echo "You should remove it when all of your neighbors have upgraded." Xfi X Xcat >$LIBDIR/aliases.new <<EOF Xnet.audio rec.audio Xnet.auto rec.autos Xnet.auto.tech rec.autos.tech Xnet.aviation rec.aviation Xnet.bicycle rec.bicycles Xnet.rec.birds rec.birds Xnet.rec.boat rec.boats Xnet.cooks rec.food.cooking Xnet.wines rec.food.drink Xnet.veg rec.food.veg Xnet.games rec.games.misc Xnet.games.board rec.games.board Xnet.rec.bridge rec.games.bridge Xnet.games.chess rec.games.chess Xnet.games.emp rec.games.empire Xnet.games.frp rec.games.frp Xnet.games.go rec.games.go Xnet.games.hack rec.games.hack Xnet.games.pbm rec.games.pbm Xnet.games.rogue rec.games.rogue Xnet.games.trivia rec.games.trivia Xnet.games.video rec.games.video Xnet.garden rec.gardens Xnet.ham-radio rec.ham-radio Xnet.ham-radio.packet rec.ham-radio.packet Xnet.jokes rec.humor Xnet.jokes.d rec.humor.d Xmod.mag rec.mag Xnet.mag rec.mag Xnet.books rec.arts.books Xnet.comics rec.arts.comics Xnet.tv.drwho rec.arts.drwho Xmod.movies rec.arts.movies Xnet.movies rec.arts.movies Xnet.sf-lovers rec.arts.sf-lovers Xnet.startrek rec.arts.startrek Xnet.tv rec.arts.tv Xnet.tv.soaps rec.arts.tv.soaps Xnet.wobegon rec.arts.wobegon Xnet.rec rec.misc Xnet.cycle rec.motorcycles Xnet.music.classical rec.music.classical Xnet.music.folk rec.music.folk Xnet.music.gdead rec.music.gdead Xnet.music.makers rec.music.makers Xnet.music rec.music.misc Xnet.music.synth rec.music.synth Xnet.rec.nude rec.nude Xnet.pets rec.pets Xnet.rec.photo rec.photo Xnet.poems rec.arts.poems Xnet.puzzle rec.puzzles Xnet.railroad rec.railroad Xnet.rec.scuba rec.scuba Xnet.rec.ski rec.skiing Xnet.rec.skydive rec.skydiving Xnet.sport rec.sport.misc Xnet.sport.baseball rec.sport.baseball Xnet.sport.hoops rec.sport.basketball Xnet.sport.football rec.sport.football Xnet.sport.hockey rec.sport.hockey Xnet.travel rec.travel Xnet.video rec.video Xnet.rec.wood rec.woodworking Xnet.ai comp.ai Xnet.arch comp.arch Xnet.bugs.2bsd comp.bugs.2bsd Xnet.bugs.4bsd comp.bugs.4bsd Xnet.bugs.usg comp.bugs.sys5 Xnet.bugs.uucp comp.bugs.misc Xnet.bugs.v7 comp.bugs.misc Xnet.bugs comp.bugs.misc Xnet.cog-eng comp.cog-eng Xnet.cse comp.edu Xnet.database comp.databases Xnet.dcom comp.dcom.modems Xnet.decus comp.org.decus Xnet.emacs comp.emacs Xnet.eunice comp.os.eunice Xnet.graphics comp.graphics Xnet.info-terms comp.terminals Xnet.internat comp.std.internat Xnet.lan comp.dcom.lans Xnet.lang comp.lang.misc Xnet.lang.ada comp.lang.ada Xnet.lang.apl comp.lang.apl Xnet.lang.c comp.lang.c Xnet.lang.c++ comp.lang.c++ Xnet.lang.f77 comp.lang.fortran Xnet.lang.forth comp.lang.forth Xnet.lang.lisp comp.lang.lisp Xnet.lang.mod2 comp.lang.modula2 Xnet.lang.pascal comp.lang.pascal Xnet.lang.prolog comp.lang.prolog Xnet.lang.st80 comp.lang.smalltalk Xnet.lsi comp.lsi Xnet.mail comp.mail.uucp Xnet.mail.headers comp.mail.headers Xnet.micro comp.sys.misc Xnet.micro.6809 comp.sys.m6809 Xnet.micro.68k comp.sys.m68k Xnet.micro.apple comp.sys.apple Xnet.micro.amiga comp.sys.amiga Xnet.micro.atari16 comp.sys.atari.st Xnet.micro.atari8 comp.sys.atari.8bit Xnet.micro.att comp.sys.att Xnet.micro.cbm comp.sys.cbm Xnet.micro.cpm comp.os.cpm Xnet.micro.hp comp.sys.hp Xnet.micro.mac comp.sys.mac Xnet.micro.ns32k comp.sys.nsc.32k Xnet.micro.pc comp.sys.ibm.pc Xnet.micro.ti comp.sys.ti Xnet.micro.trs-80 comp.sys.tandy Xnet.news news.misc Xnet.news.adm news.admin Xnet.news.b news.software.b Xnet.news.config news.config Xnet.news.group news.groups Xnet.news.newsite news.newsites Xnet.news.notes news.software.notes Xnet.news.sa news.sysadmin Xnet.news.stargate news.stargate Xnet.periphs comp.periphs Xnet.sources.d comp.sources.d Xnet.text comp.text Xnet.unix comp.unix.questions Xnet.unix-wizards comp.unix.wizards Xnet.usenix comp.org.usenix Xnet.wanted.sources comp.sources.wanted Xnet.chess rec.games.chess Xnet.trivia rec.games.trivia Xnet.rec.radio rec.ham-radio Xnet.term comp.terminals Xnet.joke rec.humor Xnet.vlsi comp.lsi Xnet.micro.16k comp.sys.nsc.32k Xnet.music.gdea rec.music.gdead Xnet.notes news.software.notes Xnet.periph comp.periphs Xnet.puzzles rec.puzzles Xnet.unix.wizards comp.unix.wizards Xnet.sources.wanted comp.sources.wanted Xnet.consumers misc.consumers Xnet.consumers.house misc.consumers.house Xnet.house misc.consumers.house Xna.forsale misc.forsale Xnet.forsale misc.forsale Xnet.politics.terror misc.headlines Xnet.invest misc.invest Xnet.jobs misc.jobs Xnet.kids misc.kids Xmod.legal misc.legal Xnet.legal misc.legal Xnet.followup misc.misc Xnet.general misc.misc Xnet.misc misc.misc Xnet.suicide misc.misc Xnet.taxes misc.taxes Xmod.test misc.test Xnet.test misc.test Xnet.wanted misc.wanted Xnet.announce mod.announce Xnet.announce.newusers mod.announce.newusers Xmod.map.uucp mod.map Xnet.religion.christian mod.religion.christian Xnet.religion.xian mod.religion.christian Xnet.astro sci.astro Xnet.astro.expert sci.astro Xnet.bio sci.bio Xnet.crypt sci.crypt Xnet.analog sci.electronics Xnet.nlang sci.lang Xnet.math sci.math Xnet.stat sci.math.stat Xnet.math.stat sci.math.stat Xnet.math.symbolic sci.math.symbolic Xnet.med sci.med Xnet.sci sci.misc Xnet.physics sci.physics Xnet.research sci.research Xnet.space sci.space Xnet.columbia sci.space.shuttle Xnet.challenger sci.space.shuttle Xnet.college soc.college Xnet.nlang.africa soc.culture.african Xnet.nlang.celts soc.culture.celtic Xnet.nlang.greek soc.culture.greek Xnet.nlang.india soc.culture.indian Xnet.religion.jewish soc.culture.jewish Xnet.social soc.misc Xmod.motss soc.motss Xnet.motss soc.motss Xnet.net-people soc.net-people Xnet.roots soc.roots Xnet.singles soc.singles Xnet.women soc.women Xnet.abortion talk.abortion Xnet.bizarre talk.bizarre Xnet.origins talk.origins Xnet.philosophy talk.philosophy.misc Xnet.politics talk.politics.misc Xnet.politics.theory talk.politics.theory Xnet.religion talk.religion.misc Xtalk.religion talk.religion.misc Xnet.rumor talk.rumors Xtalk.rumor talk.rumors Xrec.skydive rec.skydiving Xcomp.sources.games net.sources.games Xcomp.sources.bugs net.sources.bugs Xcomp.sources.unix net.sources Xcomp.sources.mac net.sources.mac XEOF X: if no aliases file, make one Xif test ! -f $LIBDIR/aliases Xthen X mv $LIBDIR/aliases.new $LIBDIR/aliases Xelse X : see whats missing X sort $LIBDIR/aliases | sed -e 's/ */ /g' -e 's/ */ /g' >/tmp/$$aliases X sort $LIBDIR/aliases.new | sed -e 's/ */ /g' -e 's/ */ /g' >/tmp/$$aliases.new X comm -23 /tmp/$$aliases.new /tmp/$$aliases >/tmp/$$comm X if test -s /tmp/$$comm X then X echo "The following suggested aliases are missing or incorrect in your" X echo "$LIBDIR/aliases file. It is suggested you add them." X echo "" X cat /tmp/$$comm X echo "" X echo "A suggested aliases file has been left in $LIBDIR/aliases.new" X echo "for your convenience." X rm /tmp/$$comm /tmp/$$aliases X else X rm /tmp/$$comm /tmp/$$aliases $LIBDIR/aliases.new X fi Xfi X X: if no distributions file, make one Xif test ! -f $LIBDIR/distributions Xthen X cat >$LIBDIR/distributions <<EOF Xlocal Local to this site Xregional Everywhere in this general area Xusa Everywhere in the USA Xna Everywhere in North America Xworld Everywhere on Usenet in the world XEOF Xecho Xecho You may want to add distributions to $LIBDIR/distributions if your Xecho site particpates in a regional distribution such as '"ba"' or '"dc"'. Xfi X Xchown $NEWSUSR $LIBDIR/[a-z]* Xchgrp $NEWSGRP $LIBDIR/[a-z]* X Xecho Xecho Reminder: uux must permit rnews if running over uucp. Xrm -f /tmp/$$* END_OF_FILE if test 9680 -ne `wc -c <'install.sh'`; then echo shar: \"'install.sh'\" unpacked with wrong size! fi # end of 'install.sh' fi if test -f 'recnews.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'recnews.c'\" else echo shar: Extracting \"'recnews.c'\" \(8212 characters\) sed "s/^X//" >'recnews.c' <<'END_OF_FILE' X/* X * recnews [to newsgroup] [from user] X * X * Process a news article which has been mailed to some group like msgs. X * Such articles are in normal mail format and have never seen the insides X * of netnews. If the "to newsgroup" is included, the article is posted X * to this newsgroup instead of trying to intuit it from the headers. X * If the "from user" is included, the return address is forged to look X * like that user instead of what getuid or a from line says. X * X * It is recommended that you always include the to newsgroup, since the X * intuition code is flakey and out of date. The from user is probably X * appropriate for arpanet mailing lists being funnelled at ucbvax but X * not otherwise. Sample lines in /usr/lib/aliases (if you run delivermail): X * worldnews: "|/usr/lib/news/recnews net.general" X * Allows you to mail to worldnews rather than using inews. X * Intended for humans to mail to. X * post-unix-wizards: "|/usr/lib/news/recnews fa.unix-wizards unix-wizards" X * Causes mail to post-unix-wizards to be fed into fa.unix-wizards X * and the return address forged as unix-wizards on the local X * machine. post-unix-wizards (on the local machine) should X * be part of the master mailing list somewhere (on a different X * machine.) X * X * Recnews is primarily useful in remote places on the usenet which collect X * mail from mailing lists and funnel them into the network. It is also X * useful if you like to send mail to some user instead of invoking X * inews -t .. -n .. when you want to submit an article. (Many mailers give X * you nice facilities like editing the message.) It is not, however, X * essential to use recnews to be able to join usenet. X * X * WARNING: recnews disables the "recording" check - it has to because X * by the time inews is run, it's in the background and too late to X * ask permission. If you depend heavily on recordings you probably X * should not allow recnews (and thus the mail interface) to be used. X* X * 1) We leave the from line alone. Just escape the double quotes, but let the X * mailer do the rest. X * 2) We give precedence to "From:" over "From " or ">From " in determining X * who the article is really from. X * Modifications by rad@tek X */ X X#ifdef SCCSID Xstatic char *SccsId = "@(#)recnews.c 2.13 10/23/86"; X#endif /* SCCSID */ X X#include "defs.h" X X#include <stdio.h> X#include <ctype.h> X X/* X * Note: we assume there are 2 kinds of hosts using recnews: X * Those that have delivermail (and hence this program will never X * have to deal with more than one message at a time) and those on the arpanet X * that do not (and hence all messages end with a sentinel). It is X * supposed that regular v7 type systems without delivermail or some X * other automatic forwarding device will just use rnews. We do X * not attempt to tell where a message ends on all systems due to the X * different conventions in effect. (This COULD be fixed, I suppose.) X */ X X/* X * Kinds of lines in a message. X */ X#define FROM 001 /* From line */ X#define SUBJ 002 /* Subject */ X#define TO 003 /* To (newgroup based on this) */ X#define BLANK 004 /* blank line */ X#define EOM 005 /* End of message (4 ctrl A's) */ X#define HEADER 006 /* any unrecognized header */ X#define TEXT 007 /* anything unrecognized */ X#define INCLUSIVE 010 /* newsgroup is already in header */ X X/* X * Possible states program can be in. X */ X#define SKIPPING 0100 /* In header of message */ X#define READING 0200 /* In body of message */ X X#define BFSZ 250 X X#define EOT '\004' X Xchar from[BFSZ]; /* mailing address for replies */ Xchar sender[BFSZ]; /* mailing address of author, if different */ Xchar to[BFSZ]; /* Destination of mail (msgs, etc) */ Xchar subject[BFSZ]; /* subject of message */ Xchar newsgroup[BFSZ]; /* newsgroups of message */ Xint fromset; /* from passed on command line */ Xchar cmdbuf[BFSZ]; /* command to popen */ X Xextern char *strcat(), *strcpy(); Xextern FILE *popen(); Xchar *any(); X Xmain(argc, argv) Xint argc; Xchar **argv; X{ X char buf[BFSZ], inews[BFSZ]; X register char *p, *q; X register FILE *pipe = NULL; X register int state; X X /* build inews command */ X#ifdef IHCC X sprintf(inews, "%s/%s/%s", logdir(HOME), LIBDIR, "inews"); X#else X sprintf(inews, "%s/%s", LIBDIR, "inews"); X#endif X X if (argc > 1) X strcpy(to, argv[1]); X if (argc > 2) X strcpy(from, argv[2]); X X /* X * Flag that we know who message is from to avoid trying to X * decipher the From line. X */ X if (argc > 2 && (argv[2][0] != '\0')) X fromset++; X X#ifdef debug X printf("argv[0] is <%s>, argv[1] is <%s>, argv[2] is <%s>\n", X argv[0], argv[1], argv[2]); X#endif X state = SKIPPING; X while (fgets(buf, BFSZ, stdin) != NULL) { X if (state == READING) { X fputs(buf,pipe); X continue; X } X switch (type(buf)) { X X case FROM: X frombreak(buf, from); X break; X X case SUBJ: X p = any(buf, " \t"); X if (p == NULL) X p = buf + 8; X q = subject; X while (*++p) { X if (*p == '"') X *q++ = '\\'; X *q++ = *p; X } X q[-1] = '\0'; X break; X X case TO: X if (to[0]) X break; /* already have one */ X p = any(buf, " \t"); X if (p == NULL) X p = buf + 3; X q = to; X while (*++p) { X if (*p == '"') X *q++ = '\\'; X *q++ = *p; X } X q[-1] = '\0'; X break; X X case INCLUSIVE: X sprintf(cmdbuf,"exec %s -p", inews); X pipe = popen(cmdbuf,"w"); X if (pipe == NULL){ X perror("recnews: open failed"); X exit(1); X } X state = READING; X fputs(buf,pipe); X break; X X /* X * Kludge to compensate for messages without real headers X */ X case HEADER: X break; X X case BLANK: X state = READING; X strcpy(newsgroup, to); X sprintf(cmdbuf, "exec %s -t \"%s\" -n \"%s\" -f \"%s\"", X inews, *subject ? subject : "(none)", X newsgroup, from); X#ifdef debug X pipe = stdout; X printf("BLANK: %s\n", cmdbuf); X#else X pipe = popen(cmdbuf, "w"); X if (pipe == NULL) { X perror("recnews: popen failed"); X exit(1); X } X#endif X if (sender[0]) { X fputs(sender, pipe); X putc('\n', pipe); X } X break; X X case TEXT: X strcpy(newsgroup, to); X state = READING; X if (subject[0] == 0) { X strcpy(subject, buf); X if (subject[strlen(subject)-1] == '\n') X subject[strlen(subject)-1] = '\0'; X } X sprintf(cmdbuf, "exec \"%s\" -t \"%s\" -n \"%s\" -f \"%s\"", X inews, subject, newsgroup, from); X#ifdef debug X pipe = stdout; X printf("TEXT: %s\n", cmdbuf); X#else X pipe = popen(cmdbuf, "w"); X if (pipe == NULL) { X perror("pipe failed"); X exit(1); X } X#endif X if (sender[0]){ X fputs(sender, pipe); X putc('\n',pipe); X } X break; X } X } X exit(0); X} X Xtype(p) Xregister char *p; X{ X char *firstbl; X static char lasthdr = 1; /* prev line was a header */ X X if ((*p == ' ' || *p == '\t') && lasthdr) X return HEADER; /* continuation line */ X firstbl = any(p, " \t"); X while (*p == ' ' || *p == '?' || *p == '\t') X ++p; X X if (*p == '\n' || *p == 0) X return BLANK; X if (strncmp(p, ">From", 5) == 0 || strncmp(p, "From", 4) == 0) X return FROM; X if (strncmp(p, "Subj", 4)==0 || strncmp(p, "Re:", 3)==0 || X strncmp(p, "re:", 3)==0) X return SUBJ; X if (strncmp(p, "To", 2)==0) X return TO; X if (strncmp(p, "\1\1\1\1", 4)==0) X return EOM; X if (firstbl && firstbl[-1] == ':' && isalpha(*p)) X return HEADER; X lasthdr = 0; X return TEXT; X} X X/* X * Figure out who a message is from. X */ Xfrombreak(buf, fbuf) Xregister char *buf, *fbuf; X{ X register char *p, *q; X X if (fbuf[0] && fromset) { /* we already know who it's from */ X if (sender[0] == 0 || buf[4] == ':') { X#ifdef debug X printf("sender set to: %s", buf); X#endif X strcpy(sender, buf); X } X return; X } X /* X * Leave fancy Froms alone - this parsing is done by mail X * Just quote the double quotes to prevent interpetation X * by the shell. X * rad@tek X */ X p = any(buf, " \t"); X if (p==NULL) X p = buf + 4; X q = fbuf; X while (*++p) { X if (*p == '"') X *q++ = '\\'; X *q++ = *p; X } X q[-1] = '\0'; X if ((p=(char *)index(fbuf,'\n')) != NULL) X *p = '\0'; X if (buf[4] == ':') X fromset++; X} X X/* X * Return the ptr in sp at which a character in sq appears; X * NULL if not found X * X */ Xchar * Xany(sp, sq) Xchar *sp, *sq; X{ X register c1, c2; X register char *q; X X while (c1 = *sp++) { X q = sq; X while (c2 = *q++) X if (c1 == c2) X return(--sp); X } X return(NULL); X} END_OF_FILE if test 8212 -ne `wc -c <'recnews.c'`; then echo shar: \"'recnews.c'\" unpacked with wrong size! fi # end of 'recnews.c' fi echo shar: End of shell archive. exit 0 -- "Zeta Microcomputer Software" ACSnet: nick@ultima.cs.uts.oz UUCP: ...!uunet!munnari!ultima.cs.uts.oz!nick Fidonet: Nick Andrew on 3:713/602 (Zeta)
nick@ultima.cs.uts.oz (Nick Andrew) (12/07/89)
#! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of shell archive." # Contents: Makefile.minix Makefile readnews.c digest.c unbatch.c # recmail.c defs.minix # Wrapped by nick@nswitgould on Thu Dec 7 22:42:01 1989 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'Makefile.minix' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'Makefile.minix'\" else echo shar: Extracting \"'Makefile.minix'\" \(8385 characters\) sed "s/^X//" >'Makefile.minix' <<'END_OF_FILE' X# '@(#)Makefile.minix 1.23 3/23/87' X# Makefile for Minix. X# This is converted to USG/v7/etc by localize.sh X# which should at least be a copy of localize.v7 or localize.usg X X# definitions X XOSTYPE = v7 X X# HOME is the user name whose home dir has all the news stuff in it. XHOME= news X# Use the -DHOME line if you want dynamic lookup in /etc/passwd X#HOMENAME= -DHOME=\"$(HOME)\" XHOMENAME= X XNEWSUSR = news XNEWSGRP = news XSPOOLDIR = /usr/spool/news XBATCHDIR = /usr/spool/batch XLIBDIR = /usr/lib/news XBINDIR = /usr/local/bin XDESTDIR = XUUXFLAGS = -r -z -n -gd X XLNRNEWS = ln XDEBUG = XSCCSID = -DSCCSID XDEFS = -DRNEWS=\"$(BINDIR)/rnews\" -DSPOOLDIR=\"$(SPOOLDIR)\" \ X -DBATCHDIR=\"$(BATCHDIR)\" -DLIBDIR=\"$(LIBDIR)\" \ X -DBINDIR=\"$(BINDIR)\" -DNEWSUSR=\"$(NEWSUSR)\" \ X -DNEWSGRP=\"$(NEWSGRP)\" X X# Order is important here XINSCOMPRESS= XCOMPRESS= compress X XVFORK=-Dvfork=fork X X X# Originally CFLAGS = ${DEBUG} -O -DDBM ${DEFS} ${SCCSID} ${VFORK} XCFLAGS = ${DEBUG} -O -DMINIX ${DEFS} ${SCCSID} ${VFORK} XLFLAGS = ${DEBUG} -i XSRCHLIBS = -lcio X# originally: LIBS = -ldbm XLIBS = XLINTFLAGS = -chba -DDBM ${DEFS} X XTERMLIB = -ltermlib XFIXACTIVE = X X XMISC = uname.s ftime.s XOBJECTS = funcs.s funcs2.s getdate.s header.s ndir.s $(MISC) XIOBJECTS = inews.s ifuncs.s iextern.s control.s fullname.s \ X ipathinit.s $(OBJECTS) X XPOBJECTS = postnews.s rextern.s rpathinit.s funcs.s $(MISC) XROBJECTS = readnews.s rfuncs.s rfuncs2.s rextern.s readr.s \ X process.s rpathinit.s digest.s $(OBJECTS) XVOBJECTS = readnews.s rfuncs.s rfuncs2.s rextern.s process.s rpathinit.s \ X $(OBJECTS) visual.s virtterm.s XEXPOBJS = expire.s header.s funcs.s getdate.s iextern.s epathinit.s \ X funcs2.s ndir.s $(MISC) X XSRCS = funcs.c funcs2.c header.c XISRCS = inews.c ifuncs.c iextern.c control.c fullname.c $(SRCS) XPSRCS = postnews.c rextern.c funcs.c XRSRCS = readnews.c rfuncs.c rfuncs2.c rextern.c readr.c process.c \ X digest.c $(SRCS) XVSRCS = readnews.c rfuncs.c rfuncs2.c rextern.c process.c $(SRCS) \ X visual.c virtterm.c XESRCS = expire.c header.c funcs.c iextern.c \ X funcs2.c XOSRCS = uurec.c recnews.c sendnews.c batch.c unbatch.c \ X recmail.c compress.c X XUTILS = inews uurec recnews sendnews expire batch unbatch recmail \ X encode decode $(COMPRESS) XSCRIPTS = sendbatch rmgroup checkgroups XOTHERS = $(UTILS) $(SCRIPTS) X X# Cannot get readnews to work due to asld bug X# Cannot get vnews to work due to being too lazy X#COMMANDS = readnews checknews postnews vnews XCOMMANDS = checknews postnews X X# dependencies Xall: $(OTHERS) $(COMMANDS) X Xinstall: all help vnews.help X -mkdir $(DESTDIR)$(BINDIR) X -mkdir $(DESTDIR)$(LIBDIR) X cp $(COMMANDS) $(DESTDIR)$(BINDIR) X -cd $(DESTDIR)$(BINDIR); \ X chown $(NEWSUSR) $(COMMANDS); \ X chgrp $(NEWSGRP) $(COMMANDS); \ X chmod 755 $(COMMANDS) X cp help vnews.help $(OTHERS) $(DESTDIR)$(LIBDIR) X cd $(DESTDIR)$(LIBDIR); \ X chown $(NEWSUSR) $(OTHERS); \ X chgrp $(NEWSGRP) $(OTHERS); \ X chmod 755 $(OTHERS) X -rm -f $(DESTDIR)$(BINDIR)/rnews $(DESTDIR)$(BINDIR)/inews X ${LNRNEWS} $(DESTDIR)$(LIBDIR)/inews $(DESTDIR)$(BINDIR)/rnews X chown $(NEWSUSR) $(DESTDIR)$(LIBDIR)/inews X chgrp $(NEWSGRP) $(DESTDIR)$(LIBDIR)/inews X chmod 6755 $(DESTDIR)$(LIBDIR)/inews $(DESTDIR)$(BINDIR)/rnews X $(INSCOMPRESS) X Xbindir: $(COMMANDS) X cp $(COMMANDS) $(DESTDIR)$(BINDIR) X -cd $(DESTDIR)$(BINDIR); \ X chown $(NEWSUSR) $(COMMANDS); \ X chgrp $(NEWSGRP) $(COMMANDS); \ X chmod 755 $(COMMANDS) X X X# defs.h: defs.dist localize.sh X# sh localize.sh X# @echo Localize has been run. Restart the make. X# @exit 1 X X# Makefile: localize.sh Makefile.dst X# sh localize.sh X# @echo Localize has been run. Restart the make. X# @exit 1 X Xupdate: install.sh makeactive.sh X sh install.sh $(SPOOLDIR) $(LIBDIR) $(BINDIR) $(NEWSUSR) $(NEWSGRP) $(OSTYPE) X chmod 6755 $(LIBDIR)/inews X Xclean: X rm -f $(COMMANDS) $(OTHERS) *.s a.out X rm -f core index errs X Xinews: $(IOBJECTS) X $(CC) -T. $(LFLAGS) $(IOBJECTS) $(SRCHLIBS) -o inews $(LIBS) X cp inews $(LIBDIR) X Xreadnews: $(ROBJECTS) X $(CC) $(LFLAGS) $(ROBJECTS) $(SRCHLIBS) -o readnews $(LIBS) X Xfuncs.s: funcs.c params.h defs.h header.h X $(CC) $(CFLAGS) -c funcs.c X Xfuncs2.s: funcs2.c params.h defs.h header.h X $(CC) $(CFLAGS) -c funcs2.c X X# getdate.s: getdate.c defs.h X# @echo "expect 8 shift/reduce conflicts" X# @echo yacc getdate.y X# @echo mv y.tab.c getdate.c X# $(CC) $(CFLAGS) -c getdate.c X# @echo -rm -f getdate.c X Xinews.s: inews.c iparams.h defs.h params.h header.h X $(CC) $(CFLAGS) -c inews.c X Xifuncs.s: ifuncs.c iparams.h defs.h params.h header.h X $(CC) $(CFLAGS) $(HOMENAME) -c ifuncs.c X Xiextern.s: iextern.c iparams.h defs.h params.h header.h X $(CC) $(CFLAGS) $(HOMENAME) -c iextern.c X Xpostnews: $(POBJECTS) X $(CC) $(CFLAGS) $(LFLAGS) $(POBJECTS) $(SRCHLIBS) -o postnews X Xpostnews.s: postnews.c defs.h params.h header.h X $(CC) $(CFLAGS) -c postnews.c X Xreadnews.s: readnews.c rparams.h defs.h params.h header.h X $(CC) $(CFLAGS) $(HOMENAME) -c readnews.c X Xrfuncs.s: rfuncs.c rparams.h defs.h params.h header.h X $(CC) $(CFLAGS) -c rfuncs.c X Xrfuncs2.s: rfuncs2.c rparams.h defs.h params.h header.h X $(CC) $(CFLAGS) -c rfuncs2.c X Xrextern.s: rextern.c rparams.h defs.h params.h header.h X $(CC) $(CFLAGS) -c rextern.c X Xreadr.s: readr.c rparams.h defs.h params.h ndir.h header.h X $(CC) $(CFLAGS) -c readr.c X Xchecknews.s: checknews.c defs.h header.h params.h X $(CC) $(CFLAGS) -c checknews.c X Xvnews: $(VOBJECTS) X $(CC) $(LFLAGS) $(VOBJECTS) $(TERMLIB) $(LIBS) $(SRCHLIBS) -o $@ X Xvisual.s: visual.c rparams.h defs.h params.h ndir.h header.h X $(CC) $(CFLAGS) -c visual.c X Xcontrol.s: control.c defs.h iparams.h params.h header.h X $(CC) $(CFLAGS) -c control.c X Xlogdir.s: logdir.c X $(CC) $(CFLAGS) -c logdir.c X Xftime.s: ftime.c X $(CC) $(CFLAGS) -c ftime.c X Xuname.s: uname.c defs.h params.h header.h X $(CC) $(CFLAGS) -c uname.c X Xndir.s: ndir.c ndir.h defs.h X $(CC) $(CFLAGS) -c ndir.c X Xuurec: uurec.c defs.h X $(CC) $(CFLAGS) $(LFLAGS) uurec.c $(SRCHLIBS) -o uurec X Xrecnews: recnews.c defs.h header.h X $(CC) $(CFLAGS) $(LFLAGS) recnews.c $(SRCHLIBS) -o recnews X Xsendnews: sendnews.s X $(CC) $(LFLAGS) sendnews.s $(SRCHLIBS) -o sendnews X Xbatch: batch.c defs.h X $(CC) $(CFLAGS) $(LFLAGS) batch.c $(SRCHLIBS) -o batch X chmem =6144 batch X Xunbatch: unbatch.c X $(CC) $(CFLAGS) $(LFLAGS) unbatch.c $(SRCHLIBS) -o unbatch X chmem =6144 unbatch X Xencode: encode.c X $(CC) $(CFLAGS) $(LFLAGS) encode.c $(SRCHLIBS) -o encode X Xdecode: decode.c X $(CC) $(CFLAGS) $(LFLAGS) decode.c $(SRCHLIBS) -o decode X X# caesar: caesar.c X# $(CC) $(CFLAGS) $(LFLAGS) caesar.c $(SRCHLIBS) -o caesar -lm X Xcompress: compress.c X $(CC) $(CFLAGS) $(LFLAGS) $(SRCHLIBS) -o compress compress.c X Xrecmail: recmail.c defs.h params.h header.h X $(CC) $(CFLAGS) $(LFLAGS) recmail.c $(SRCHLIBS) -o recmail X Xprocess.s: process.c rparams.h defs.h params.h header.h X $(CC) $(CFLAGS) -c process.c X Xchecknews: checknews.s process.s cpathinit.s rextern.s X $(CC) $(LFLAGS) checknews.s process.s cpathinit.s rextern.s $(SRCHLIBS) -o checknews X Xsendbatch: sendbatch.sh X sed -e "s%LIBDIR%$(LIBDIR)%g" \ X -e "s%UUXFLAGS%$(UUXFLAGS)%g" \ X -e "s%BATCHDIR%$(BATCHDIR)%g" sendbatch.sh > sendbatch X Xrmgroup: rmgroup.sh X sed -e "s%LIBDIR%$(LIBDIR)%g" \ X -e "s%FIXACTIVE%$(FIXACTIVE)%g" \ X -e "s%SPOOLDIR%$(SPOOLDIR)%g" rmgroup.sh > rmgroup X Xcheckgroups: checkgroups.sh X sed -e "s%LIBDIR%$(LIBDIR)%g" checkgroups.sh > checkgroups X Xsendnews.s: sendnews.c defs.h X $(CC) $(CFLAGS) -c sendnews.c X Xfullname.s: fullname.c defs.h params.h header.h X $(CC) $(CFLAGS) -c fullname.c X Xexpire: $(EXPOBJS) X $(CC) $(LFLAGS) $(EXPOBJS) $(SRCHLIBS) -o expire $(LIBS) X Xheader.s: header.c header.h defs.h patchlevel.h params.h X $(CC) $(CFLAGS) -c header.c X Xexpire.s: expire.c defs.h params.h ndir.h header.h X $(CC) $(CFLAGS) -c expire.c X Xdigest.s: digest.c rparams.h X $(CC) -DMINIX -c digest.c X X# Some silliness here to get pathinit for both readnews & inews Xrpathinit.s: pathinit.c rparams.h header.h params.h defs.h X $(CC) $(CFLAGS) $(HOMENAME) -DREAD -c pathinit.c X mv pathinit.s rpathinit.s X Xipathinit.s: pathinit.c iparams.h header.h params.h defs.h X $(CC) $(CFLAGS) $(HOMENAME) -DINEW -c pathinit.c X mv pathinit.s ipathinit.s X Xcpathinit.s: pathinit.c iparams.h header.h params.h defs.h X $(CC) $(CFLAGS) $(HOMENAME) -DCHKN -c pathinit.c X mv pathinit.s cpathinit.s X Xepathinit.s: pathinit.c iparams.h header.h params.h defs.h X $(CC) $(CFLAGS) $(HOMENAME) -DEXP -c pathinit.c X mv pathinit.s epathinit.s X Xtags: /tmp X ctags -w *.h *.c X END_OF_FILE if test 8385 -ne `wc -c <'Makefile.minix'`; then echo shar: \"'Makefile.minix'\" unpacked with wrong size! fi # end of 'Makefile.minix' fi if test -f 'Makefile' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'Makefile'\" else echo shar: Extracting \"'Makefile'\" \(8385 characters\) sed "s/^X//" >'Makefile' <<'END_OF_FILE' X# '@(#)Makefile.minix 1.23 3/23/87' X# Makefile for Minix. X# This is converted to USG/v7/etc by localize.sh X# which should at least be a copy of localize.v7 or localize.usg X X# definitions X XOSTYPE = v7 X X# HOME is the user name whose home dir has all the news stuff in it. XHOME= news X# Use the -DHOME line if you want dynamic lookup in /etc/passwd X#HOMENAME= -DHOME=\"$(HOME)\" XHOMENAME= X XNEWSUSR = news XNEWSGRP = news XSPOOLDIR = /usr/spool/news XBATCHDIR = /usr/spool/batch XLIBDIR = /usr/lib/news XBINDIR = /usr/local/bin XDESTDIR = XUUXFLAGS = -r -z -n -gd X XLNRNEWS = ln XDEBUG = XSCCSID = -DSCCSID XDEFS = -DRNEWS=\"$(BINDIR)/rnews\" -DSPOOLDIR=\"$(SPOOLDIR)\" \ X -DBATCHDIR=\"$(BATCHDIR)\" -DLIBDIR=\"$(LIBDIR)\" \ X -DBINDIR=\"$(BINDIR)\" -DNEWSUSR=\"$(NEWSUSR)\" \ X -DNEWSGRP=\"$(NEWSGRP)\" X X# Order is important here XINSCOMPRESS= XCOMPRESS= compress X XVFORK=-Dvfork=fork X X X# Originally CFLAGS = ${DEBUG} -O -DDBM ${DEFS} ${SCCSID} ${VFORK} XCFLAGS = ${DEBUG} -O -DMINIX ${DEFS} ${SCCSID} ${VFORK} XLFLAGS = ${DEBUG} -i XSRCHLIBS = -lcio X# originally: LIBS = -ldbm XLIBS = XLINTFLAGS = -chba -DDBM ${DEFS} X XTERMLIB = -ltermlib XFIXACTIVE = X X XMISC = uname.s ftime.s XOBJECTS = funcs.s funcs2.s getdate.s header.s ndir.s $(MISC) XIOBJECTS = inews.s ifuncs.s iextern.s control.s fullname.s \ X ipathinit.s $(OBJECTS) X XPOBJECTS = postnews.s rextern.s rpathinit.s funcs.s $(MISC) XROBJECTS = readnews.s rfuncs.s rfuncs2.s rextern.s readr.s \ X process.s rpathinit.s digest.s $(OBJECTS) XVOBJECTS = readnews.s rfuncs.s rfuncs2.s rextern.s process.s rpathinit.s \ X $(OBJECTS) visual.s virtterm.s XEXPOBJS = expire.s header.s funcs.s getdate.s iextern.s epathinit.s \ X funcs2.s ndir.s $(MISC) X XSRCS = funcs.c funcs2.c header.c XISRCS = inews.c ifuncs.c iextern.c control.c fullname.c $(SRCS) XPSRCS = postnews.c rextern.c funcs.c XRSRCS = readnews.c rfuncs.c rfuncs2.c rextern.c readr.c process.c \ X digest.c $(SRCS) XVSRCS = readnews.c rfuncs.c rfuncs2.c rextern.c process.c $(SRCS) \ X visual.c virtterm.c XESRCS = expire.c header.c funcs.c iextern.c \ X funcs2.c XOSRCS = uurec.c recnews.c sendnews.c batch.c unbatch.c \ X recmail.c compress.c X XUTILS = inews uurec recnews sendnews expire batch unbatch recmail \ X encode decode $(COMPRESS) XSCRIPTS = sendbatch rmgroup checkgroups XOTHERS = $(UTILS) $(SCRIPTS) X X# Cannot get readnews to work due to asld bug X# Cannot get vnews to work due to being too lazy X#COMMANDS = readnews checknews postnews vnews XCOMMANDS = checknews postnews X X# dependencies Xall: $(OTHERS) $(COMMANDS) X Xinstall: all help vnews.help X -mkdir $(DESTDIR)$(BINDIR) X -mkdir $(DESTDIR)$(LIBDIR) X cp $(COMMANDS) $(DESTDIR)$(BINDIR) X -cd $(DESTDIR)$(BINDIR); \ X chown $(NEWSUSR) $(COMMANDS); \ X chgrp $(NEWSGRP) $(COMMANDS); \ X chmod 755 $(COMMANDS) X cp help vnews.help $(OTHERS) $(DESTDIR)$(LIBDIR) X cd $(DESTDIR)$(LIBDIR); \ X chown $(NEWSUSR) $(OTHERS); \ X chgrp $(NEWSGRP) $(OTHERS); \ X chmod 755 $(OTHERS) X -rm -f $(DESTDIR)$(BINDIR)/rnews $(DESTDIR)$(BINDIR)/inews X ${LNRNEWS} $(DESTDIR)$(LIBDIR)/inews $(DESTDIR)$(BINDIR)/rnews X chown $(NEWSUSR) $(DESTDIR)$(LIBDIR)/inews X chgrp $(NEWSGRP) $(DESTDIR)$(LIBDIR)/inews X chmod 6755 $(DESTDIR)$(LIBDIR)/inews $(DESTDIR)$(BINDIR)/rnews X $(INSCOMPRESS) X Xbindir: $(COMMANDS) X cp $(COMMANDS) $(DESTDIR)$(BINDIR) X -cd $(DESTDIR)$(BINDIR); \ X chown $(NEWSUSR) $(COMMANDS); \ X chgrp $(NEWSGRP) $(COMMANDS); \ X chmod 755 $(COMMANDS) X X X# defs.h: defs.dist localize.sh X# sh localize.sh X# @echo Localize has been run. Restart the make. X# @exit 1 X X# Makefile: localize.sh Makefile.dst X# sh localize.sh X# @echo Localize has been run. Restart the make. X# @exit 1 X Xupdate: install.sh makeactive.sh X sh install.sh $(SPOOLDIR) $(LIBDIR) $(BINDIR) $(NEWSUSR) $(NEWSGRP) $(OSTYPE) X chmod 6755 $(LIBDIR)/inews X Xclean: X rm -f $(COMMANDS) $(OTHERS) *.s a.out X rm -f core index errs X Xinews: $(IOBJECTS) X $(CC) -T. $(LFLAGS) $(IOBJECTS) $(SRCHLIBS) -o inews $(LIBS) X cp inews $(LIBDIR) X Xreadnews: $(ROBJECTS) X $(CC) $(LFLAGS) $(ROBJECTS) $(SRCHLIBS) -o readnews $(LIBS) X Xfuncs.s: funcs.c params.h defs.h header.h X $(CC) $(CFLAGS) -c funcs.c X Xfuncs2.s: funcs2.c params.h defs.h header.h X $(CC) $(CFLAGS) -c funcs2.c X X# getdate.s: getdate.c defs.h X# @echo "expect 8 shift/reduce conflicts" X# @echo yacc getdate.y X# @echo mv y.tab.c getdate.c X# $(CC) $(CFLAGS) -c getdate.c X# @echo -rm -f getdate.c X Xinews.s: inews.c iparams.h defs.h params.h header.h X $(CC) $(CFLAGS) -c inews.c X Xifuncs.s: ifuncs.c iparams.h defs.h params.h header.h X $(CC) $(CFLAGS) $(HOMENAME) -c ifuncs.c X Xiextern.s: iextern.c iparams.h defs.h params.h header.h X $(CC) $(CFLAGS) $(HOMENAME) -c iextern.c X Xpostnews: $(POBJECTS) X $(CC) $(CFLAGS) $(LFLAGS) $(POBJECTS) $(SRCHLIBS) -o postnews X Xpostnews.s: postnews.c defs.h params.h header.h X $(CC) $(CFLAGS) -c postnews.c X Xreadnews.s: readnews.c rparams.h defs.h params.h header.h X $(CC) $(CFLAGS) $(HOMENAME) -c readnews.c X Xrfuncs.s: rfuncs.c rparams.h defs.h params.h header.h X $(CC) $(CFLAGS) -c rfuncs.c X Xrfuncs2.s: rfuncs2.c rparams.h defs.h params.h header.h X $(CC) $(CFLAGS) -c rfuncs2.c X Xrextern.s: rextern.c rparams.h defs.h params.h header.h X $(CC) $(CFLAGS) -c rextern.c X Xreadr.s: readr.c rparams.h defs.h params.h ndir.h header.h X $(CC) $(CFLAGS) -c readr.c X Xchecknews.s: checknews.c defs.h header.h params.h X $(CC) $(CFLAGS) -c checknews.c X Xvnews: $(VOBJECTS) X $(CC) $(LFLAGS) $(VOBJECTS) $(TERMLIB) $(LIBS) $(SRCHLIBS) -o $@ X Xvisual.s: visual.c rparams.h defs.h params.h ndir.h header.h X $(CC) $(CFLAGS) -c visual.c X Xcontrol.s: control.c defs.h iparams.h params.h header.h X $(CC) $(CFLAGS) -c control.c X Xlogdir.s: logdir.c X $(CC) $(CFLAGS) -c logdir.c X Xftime.s: ftime.c X $(CC) $(CFLAGS) -c ftime.c X Xuname.s: uname.c defs.h params.h header.h X $(CC) $(CFLAGS) -c uname.c X Xndir.s: ndir.c ndir.h defs.h X $(CC) $(CFLAGS) -c ndir.c X Xuurec: uurec.c defs.h X $(CC) $(CFLAGS) $(LFLAGS) uurec.c $(SRCHLIBS) -o uurec X Xrecnews: recnews.c defs.h header.h X $(CC) $(CFLAGS) $(LFLAGS) recnews.c $(SRCHLIBS) -o recnews X Xsendnews: sendnews.s X $(CC) $(LFLAGS) sendnews.s $(SRCHLIBS) -o sendnews X Xbatch: batch.c defs.h X $(CC) $(CFLAGS) $(LFLAGS) batch.c $(SRCHLIBS) -o batch X chmem =6144 batch X Xunbatch: unbatch.c X $(CC) $(CFLAGS) $(LFLAGS) unbatch.c $(SRCHLIBS) -o unbatch X chmem =6144 unbatch X Xencode: encode.c X $(CC) $(CFLAGS) $(LFLAGS) encode.c $(SRCHLIBS) -o encode X Xdecode: decode.c X $(CC) $(CFLAGS) $(LFLAGS) decode.c $(SRCHLIBS) -o decode X X# caesar: caesar.c X# $(CC) $(CFLAGS) $(LFLAGS) caesar.c $(SRCHLIBS) -o caesar -lm X Xcompress: compress.c X $(CC) $(CFLAGS) $(LFLAGS) $(SRCHLIBS) -o compress compress.c X Xrecmail: recmail.c defs.h params.h header.h X $(CC) $(CFLAGS) $(LFLAGS) recmail.c $(SRCHLIBS) -o recmail X Xprocess.s: process.c rparams.h defs.h params.h header.h X $(CC) $(CFLAGS) -c process.c X Xchecknews: checknews.s process.s cpathinit.s rextern.s X $(CC) $(LFLAGS) checknews.s process.s cpathinit.s rextern.s $(SRCHLIBS) -o checknews X Xsendbatch: sendbatch.sh X sed -e "s%LIBDIR%$(LIBDIR)%g" \ X -e "s%UUXFLAGS%$(UUXFLAGS)%g" \ X -e "s%BATCHDIR%$(BATCHDIR)%g" sendbatch.sh > sendbatch X Xrmgroup: rmgroup.sh X sed -e "s%LIBDIR%$(LIBDIR)%g" \ X -e "s%FIXACTIVE%$(FIXACTIVE)%g" \ X -e "s%SPOOLDIR%$(SPOOLDIR)%g" rmgroup.sh > rmgroup X Xcheckgroups: checkgroups.sh X sed -e "s%LIBDIR%$(LIBDIR)%g" checkgroups.sh > checkgroups X Xsendnews.s: sendnews.c defs.h X $(CC) $(CFLAGS) -c sendnews.c X Xfullname.s: fullname.c defs.h params.h header.h X $(CC) $(CFLAGS) -c fullname.c X Xexpire: $(EXPOBJS) X $(CC) $(LFLAGS) $(EXPOBJS) $(SRCHLIBS) -o expire $(LIBS) X Xheader.s: header.c header.h defs.h patchlevel.h params.h X $(CC) $(CFLAGS) -c header.c X Xexpire.s: expire.c defs.h params.h ndir.h header.h X $(CC) $(CFLAGS) -c expire.c X Xdigest.s: digest.c rparams.h X $(CC) -DMINIX -c digest.c X X# Some silliness here to get pathinit for both readnews & inews Xrpathinit.s: pathinit.c rparams.h header.h params.h defs.h X $(CC) $(CFLAGS) $(HOMENAME) -DREAD -c pathinit.c X mv pathinit.s rpathinit.s X Xipathinit.s: pathinit.c iparams.h header.h params.h defs.h X $(CC) $(CFLAGS) $(HOMENAME) -DINEW -c pathinit.c X mv pathinit.s ipathinit.s X Xcpathinit.s: pathinit.c iparams.h header.h params.h defs.h X $(CC) $(CFLAGS) $(HOMENAME) -DCHKN -c pathinit.c X mv pathinit.s cpathinit.s X Xepathinit.s: pathinit.c iparams.h header.h params.h defs.h X $(CC) $(CFLAGS) $(HOMENAME) -DEXP -c pathinit.c X mv pathinit.s epathinit.s X Xtags: /tmp X ctags -w *.h *.c X END_OF_FILE if test 8385 -ne `wc -c <'Makefile'`; then echo shar: \"'Makefile'\" unpacked with wrong size! fi # end of 'Makefile' fi if test -f 'readnews.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'readnews.c'\" else echo shar: Extracting \"'readnews.c'\" \(7970 characters\) sed "s/^X//" >'readnews.c' <<'END_OF_FILE' X/* X * readnews - read news articles. X */ X X#ifdef SCCSID Xstatic char *SccsId = "@(#)readnews.c 2.32 3/21/87"; X#endif /* SCCSID */ X X#include "rparams.h" X X/* X * readnews - article reading program X */ X X#ifndef SYSBUF Xchar SYSBUF[BUFSIZ]; /* to buffer std out */ X#endif X X#define OPTION 0 /* pick up an option string */ X#define STRING 1 /* pick up a string of arguments */ X Xstruct timeb Now; X Xint onsig(), cleanup(); X X/* X * Authors: X * Matt Glickman ucbvax!glickman X * Mark Horton cbosg!mark X * Stephen Daniels duke!swd X * Tom Truscott duke!trt X */ X Xmain(argc, argv) Xint argc; Xregister char **argv; X{ X register char *ptr; /* pointer to rest of buffer */ X char *user = NULL, *home = NULL; X int optflag = FALSE, space = FALSE; X struct utsname ubuf; X char *myrc; X X /* set up defaults and initialize. */ X pathinit(); X mode = UNKNOWN; X header.title[0] = header.nbuf[0] = '\0'; X coptbuf[0] = datebuf[0] = '\0'; X uname(&ubuf); X strcpy(FROMSYSNAME, ubuf.nodename); X X savmask = umask(N_UMASK); /* set up mask */ X uid = getuid(); X gid = getgid(); X duid = 0; X dgid = 0; X (void) ftime(&Now); X X /* give reasonable error message if SPOOL directory X * is unaccessable... usually means system administrator X * has "turned off" news reading... X */ X if (access(SPOOL, 05)) X { X fputs("News articles are not available at this time\n",stderr); X xxit(1); X } X X#ifndef SHELL X if ((SHELL = getenv("SHELL")) == NULL) X SHELL = "/bin/sh"; X#endif X /* X * IHCC forces the use of 'getuser()' to prevent forgery of articles X * by just changing $LOGNAME X * Note that this shouldn't matter in readnews, since inews X * does all the actual posting of news. X */ X#ifndef IHCC X if ((user = getenv("USER")) == NULL) X user = getenv("LOGNAME"); X if ((home = getenv("HOME")) == NULL) X home = getenv("LOGDIR"); X#endif /* ! IHCC */ X if (user == NULL || home == NULL) X getuser(); X else { X username = AllocCpy(user); X (void) strcpy(header.path, username); X userhome = AllocCpy(home); X } X X if (!(MAILER = getenv("MAILER"))) X MAILER = "mail"; /* was /bin/mail */ X X#ifdef PAGE X if (myrc = getenv("PAGER")) X PAGER = AllocCpy(myrc); X else { X# ifdef IHCC X (void) sprintf(bfr, "%s/bin/%s", logdir(HOME), PAGE); X PAGER = AllocCpy(bfr); X# else /* !IHCC */ X PAGER = PAGE; X# endif /* !IHCC */ X } X#endif /* PAGE */ X X if (ptr = getenv("NEWSOPTS")) X (void) strcpy(rcbuf, ptr); X else X *rcbuf = '\0'; X if (*rcbuf) { X (void) strcat(rcbuf, " \1"); X ptr = rcbuf; X while (*++ptr) X if (isspace(*ptr)) X *ptr = '\0'; X for (ptr = rcbuf; ; ptr++) { X if (!*ptr) X continue; X if (*ptr == '\1') X break; X if (++line > LINES) X xerror("Too many options."); X if ((rcline[line] = malloc((unsigned)(strlen(ptr) + 1))) == NULL) X xerror("Not enough memory."); X argvrc[line] = rcline[line]; X (void) strcpy(rcline[line], ptr); X while (*ptr) X ptr++; X } X } X myrc = getenv("NEWSRC"); X if (myrc == NULL) { X myrc = NEWSRC; X (void) sprintf(newsrc, "%s/%s", userhome, myrc); X } else { X (void) strcpy(newsrc, myrc); X } X if (access(newsrc, 0)) X newrc(newsrc); X if ((rcfp = fopen(newsrc, "r")) != NULL) { X rcreadok = FALSE; X while (fgets(rcbuf, LBUFLEN, rcfp) != NULL) { X if (!(space = isspace(*rcbuf))) X optflag = FALSE; X if (!strncmp(rcbuf, "options ", 8)) X optflag = TRUE; X if (optflag) { X (void) strcat(rcbuf, "\1"); X if (space) X ptr = rcbuf - 1; X else X ptr = &rcbuf[7]; X while (*++ptr) X if (isspace(*ptr)) X *ptr = '\0'; X if (space) X ptr = rcbuf; X else X ptr = &rcbuf[8]; X for (; ; ptr++) { X if (!*ptr) X continue; X if (*ptr == '\1') X break; X if (++line > LINES) X xerror("Too many options."); X if ((rcline[line] = malloc((unsigned)(strlen(ptr) + 1))) == NULL) X xerror("Not enough memory."); X argvrc[line] = rcline[line]; X (void) strcpy(rcline[line], ptr); X while (*ptr) X ptr++; X } X } X } X (void) fclose(rcfp); X rcreadok = TRUE; X } X if (line != -1) { X#ifdef DEBUG X register int i; X for (i = 0; i <= line; i++) X fprintf(stderr, "options: %s\n", rcline[i]); X#endif X process(line + 2, argvrc); X do { X#ifdef DEBUG X fprintf(stderr, "Freeing %d\n", line); X#endif X free(rcline[line]); X } while (line--); X } X X argv++; X (void) strcat(header.nbuf, ADMSUB); X process(argc, argv); X if (!nflag) X (void) sprintf(header.nbuf, "%s,%s", ADMSUB, DFLTSUB); X else { X char *p = rindex(header.nbuf, ','); X if (p && p[1] == '\0') /* strip of trailing NGDELIM */ X *p ='\0'; X } X lcase(header.nbuf); X makehimask(header.nbuf, "junk"); X makehimask(header.nbuf, "control"); X makehimask(header.nbuf, "test"); X X setbuf(stdout, SYSBUF); X SigTrap = FALSE; /* true if a signal has been caught */ X if (!pflag && !lflag && !eflag) { X (void) signal(SIGQUIT, SIG_IGN); X (void) signal(SIGHUP, cleanup); X (void) signal(SIGINT, onsig); X (void) signal(SIGPIPE, onsig); X } else { X int (* old)(); X if ((old = signal(SIGQUIT, SIG_IGN)) != SIG_IGN) X (void) signal(SIGQUIT, cleanup); X if ((old = signal(SIGHUP, SIG_IGN)) != SIG_IGN) X (void) signal(SIGHUP, cleanup); X if ((old = signal(SIGINT, SIG_IGN)) != SIG_IGN) X (void) signal(SIGINT, cleanup); X } X X /* X * ALL of the command line has now been processed. (!) X */ X X if (!*header.nbuf) X strcpy(header.nbuf, DFLTSUB); X if (sflag) { X printf("Subscription list: %s\n", header.nbuf); X xxit(0); X } X if (xflag) X line = -1; X rcfp = xfopen(newsrc, "r"); X while (fgets(rcbuf, LBUFLEN, rcfp) != NULL) { X if (!nstrip(rcbuf)) X xerror(".newsrc line too long"); X if (++line >= LINES) X xerror("Too many .newsrc lines"); X if ((rcline[line] = malloc((unsigned)(strlen(rcbuf) + 1))) == NULL) X xerror("Not enough memory"); X (void) strcpy(rcline[line], rcbuf); X } X fclose(rcfp); X X if (SigTrap) { X if (SigTrap == SIGHUP || !rcreadok) X xxit(0); X fprintf(stdout, "Abort (n)? "); X (void) fflush(stdout); X if (gets(bfr) == NULL || *bfr == 'y' || *bfr == 'Y') X xxit(0); X SigTrap = FALSE; X } X sortactive(); X actfp = xfopen(ACTIVE, "r"); X X#ifdef DEBUG X fprintf(stderr, "header.nbuf = %s\n", header.nbuf); X#endif /* DEBUG */ X if (Kflag) X news++; X else { X switch (mode) { X case UNKNOWN: X readr(); X break; X#ifdef TMAIL X case MAIL: X Mail(); X break; X#endif /* TMAIL */ X } X } X X cleanup(0); X /*NOTREACHED*/ X} X Xcleanup(signo) X{ X extern short ospeed; X X (void) signal(SIGHUP, SIG_IGN); X (void) fflush(stdout); X if (news && !xflag && !lflag && !tflag) { X if (*groupdir && mode != MAIL) X updaterc(); X writeoutrc(); X } X /* X * stop vnews from clearing the screen if we're X * killed by a hangup X */ X if (signo == SIGHUP) X ospeed = 0; X xxit(0); X} X X/* X * Write out the .newsrc file. It's already been cleaned up by sortactive() X * Take care that data is all written, and flushed, before we destroy the X * old copy. X */ Xwriteoutrc() X{ X FILE *wrcfp; X char aline[BUFLEN]; X register int i; X X /* NEVER write it out if xflag */ X if (xflag || !rcreadok) X return; X X (void) strcpy(aline, newsrc); X (void) strcat(aline, ".new"); X X#ifdef VMS X (void) vmsdelete(aline); X#endif X wrcfp = xfopen(aline, "w"); X X for (i = 0; i <= line; i++) { X if (rcline[i] != NULL) X if (fprintf(wrcfp, "%s\n", rcline[i]) < 0) X goto fouled; X } X if (fclose(wrcfp) < 0) X goto fouled; X X#ifdef VMS X (void) vmsdelete(newsrc); X#endif X if (rename(aline, newsrc) < 0) X xerror("Cannot rename %s to %s", aline, newsrc); X return; X X fouled: X xerror("Error writing new .newsrc file - no changes made\n"); X return; X} X X/* X * Forbid newsgroup ng, unless he asked for it in nbuf. X */ Xmakehimask(nbuf, ng) Xchar *nbuf, *ng; X{ X if (!findex(nbuf, ng)) X (void) sprintf(rindex(nbuf, '\0'), ",!%s", ng); X} X X/* X * Return true if the string searchfor is in string, but not if preceded by !. X */ Xfindex(string, searchfor) Xchar *string, *searchfor; X{ X register char first; X register char *p; X X first = *searchfor; X for (p=index(string, first); p; p = index(p+1, first)) { X if (((p==string) || (p[-1]!='!')) && strncmp(p, searchfor, strlen(searchfor)) == 0) X return TRUE; X } X return FALSE; X} END_OF_FILE if test 7970 -ne `wc -c <'readnews.c'`; then echo shar: \"'readnews.c'\" unpacked with wrong size! fi # end of 'readnews.c' fi if test -f 'digest.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'digest.c'\" else echo shar: Extracting \"'digest.c'\" \(8135 characters\) sed "s/^X//" >'digest.c' <<'END_OF_FILE' X/* X * digest - process ARPANET digests X * X * digest(ifile, ofile, header) X * FILE *ifile, *ofile; X * struct header *header; X * X * returns: TRUE EOF reached, exit from readnews. X * FALSE normal exit, continue reading news. X */ X X#ifdef SCCSID Xstatic char *SccsId = "@(#)digest.c 1.7 9/19/86"; X#endif /* SCCSID */ X X#include "rparams.h" X Xstruct art { X long a_hdr; X long a_bod; X int a_blen; X int a_hlen; X}; X X#define loop for(;;) X#define getnum(p, n) for (n=0; *p>='0' && *p<='9'; p++) n = n*10 + *p-'0' X#define errchk(p) if (*p) goto badopt X X#define MAXART 128 X Xstruct art *arts; Xint lastart; X Xdigest(ifp, ofp, h) XFILE *ifp, *ofp; Xstruct hbuf *h; X{ X register int n, curart; X struct art artbuf[MAXART]; X int printh, eod, nomore; X char cbuf[BUFLEN], *cmd; X X arts = artbuf; X printh = TRUE; X nomore = eod = FALSE; X curart = 1; X X if (dscan(ifp)) X return FALSE; X X dprint(0, ifp, ofp); X X loop { X if (nomore) break; X if (curart < 1) { X curart = 1; X eod = nomore = FALSE; X } X if (curart > lastart) curart = lastart; X if (eod) nomore = TRUE; X if (printh && !nomore) X (void) dhprint(curart, ifp, ofp); X getcmd: X loop { X SigTrap = FALSE; X fprintf(ofp, "Digest article %d of %d ", curart, lastart); X if (curart==lastart && nomore) X fprintf(ofp, "Last digest article "); X fprintf(ofp, "(%d lines) More? [%s] ", X arts[curart].a_blen, nomore?"snq":"ynq"); X (void) fflush(ofp); X cmd = cbuf; X if (fgets(cmd, BUFLEN, stdin)) X break; X if (!SigTrap) X return(TRUE); X putc('\n', ofp); X } X (void) nstrip(cmd); X while (*cmd==' ' || *cmd=='\t') X cmd++; X printh = TRUE; X X switch (*cmd++) { X case '#': X fprintf(ofp, "%d articles in digest\n", lastart); X (void) fflush(ofp); X printh = FALSE; X break; X X case '$': X curart = lastart; X break; X X case '!': X fwait(fsubr(ushell, cmd, (char *)NULL)); X fprintf(ofp, "!\n"); X printh = FALSE; X break; X X case '\0': X if (nomore) { X putc('\n', ofp); X return(FALSE); X } X cmd--; X case 'y': X case 'p': X errchk(cmd); X dprint(curart++, ifp, ofp); X if (curart > lastart) X eod = TRUE; X break; X X case 'n': X errchk(cmd); X if (++curart > lastart) { X putc('\n', ofp); X return(FALSE); X } X break; X X case '+': X getnum(cmd, n); X errchk(cmd); X if (nomore) { X putc('\n', ofp); X return(FALSE); X } X if (n) curart += n; X else { X curart += 1; X if (curart > lastart) X eod = TRUE; X } X break; X X case '-': X getnum(cmd, n); X errchk(cmd); X eod = nomore = FALSE; X curart -= (n) ? n : 1; X break; X X case '0': case '1': case '2': case '3': case '4': X case '5': case '6': case '7': case '8': case '9': X cmd--; X getnum(cmd, n); X errchk(cmd); X curart = n; X eod = nomore = FALSE; X break; X X case 'q': X case 'x': X putc('\n', ofp); X return(FALSE); X X case '?': X fprintf(ofp, "\nDigester options:\n\n"); X fprintf(ofp, "y\tyes, print article.\n"); X fprintf(ofp, "n\tno, go to next article.\n"); X fprintf(ofp, "q\texit from digester.\n"); X fprintf(ofp, "h\tprint article header.\n"); X fprintf(ofp, "s file\tsave article in file.\n"); X fprintf(ofp, "t\ttable of contents.\n"); X fprintf(ofp, "+[n]\tforward n articles (1).\n"); X fprintf(ofp, "-[n]\tback n articles (1).\n"); X fprintf(ofp, "\nh and s may be followed by '-'\n"); X (void) fflush(ofp); X break; X X case 'h': X n = curart; X if (*cmd=='-') { X cmd++; X if (n > 1) n--; X } X errchk(cmd); X (void) dhprint(n, ifp, ofp); X nomore = printh = FALSE; X if (n!=curart) X putc('\n', ofp); X break; X X case 's': X case 'w': X n = curart; X if (*cmd=='-') { X cmd++; X if (n > 1) n--; X } X while (*cmd==' ' || *cmd=='\t') X cmd++; X dsaveart(n, ifp, ofp, cmd); X nomore = printh = FALSE; X if (n!=curart) X putc('\n', ofp); X break; X X case 'H': X errchk(cmd); X hprint(h, ofp, 1); X eod = nomore = FALSE; X break; X X case 'T': X case 't': X errchk(cmd); X if (cmd[-1]=='T') X hprint(h, ofp, 0); X dprint(0, ifp, ofp); X eod = nomore = FALSE; X break; X X default: X badopt: X if (!nomore) X fprintf(ofp, "y (yes), n (no), "); X fprintf(ofp, "q (quit), s file (save), h (header), t (table of contents)\n"); X fprintf(ofp, "? for help\n"); X goto getcmd; X } X } X putc('\n', ofp); X return(FALSE); X} X Xdscan(ifp) Xregister FILE *ifp; X{ X char scanbuf[BUFLEN]; X register int n, len; X register char *s; X register long pos; X short wasblank, ishead; X X n = len = 0; X wasblank = FALSE; X s = scanbuf; X arts[0].a_bod = arts[1].a_hdr = ftell(ifp); X arts[0].a_hdr = 0L; X arts[1].a_bod = -1L; X X loop { X if (SigTrap) X return(TRUE); X pos = ftell(ifp); X if (fgets(s, BUFLEN, ifp)==NULL) X *s = '\0'; X if (wasblank && isheader(s)) { X long lastpos; X short is_blank; X short nhlines; X arts[n++].a_blen = len; X len = 0; X nhlines = 0; X arts[n].a_hdr = pos; X is_blank = FALSE; X ishead = TRUE; X do { X lastpos = pos; X wasblank = is_blank; X nhlines++; X pos = ftell(ifp); X if (fgets(s, BUFLEN, ifp)==NULL) X *s = '\0'; X else X len++; X is_blank = (*s=='\n') ? TRUE : FALSE; X if (is_blank && nhlines==1) X /* one liner--not a header */ X break; X if (!ishead || (s[0] != ' ' && s[0] != '\t')) X ishead = isheader(s); X } while ((is_blank && !wasblank) || ishead); X if ((!is_blank && !wasblank) || nhlines < 2) { X /* oops! not a header... back off */ X arts[n].a_hdr = arts[n-1].a_bod; X len += arts[--n].a_blen; X } else { X if (wasblank) X pos = lastpos; X arts[n].a_hlen = len; X arts[n].a_bod = arts[n+1].a_hdr = pos; X arts[n+1].a_bod = -1L; X arts[n+1].a_hlen = 3; /* average header len */ X len = 0; X } X } X if (*s=='\0') X break; X wasblank = (*s=='\n') ? TRUE : FALSE; X len++; X } X arts[n].a_blen = len; X arts[n+1].a_hdr = pos; X lastart = n; X return FALSE; X} X Xdhprint(art, ifp, ofp) Xregister int art; Xregister FILE *ifp, *ofp; X{ X register char c; X register long pos = arts[art].a_hdr; X register long epos = arts[art].a_bod; X register int nlines = 1; X X putc('\n', ofp); X fseek(ifp, pos, 0); X while (pos++ < epos && !SigTrap) { X if ((c = getc(ifp))=='\n') X nlines++; X putc(c, ofp); X } X (void) fflush(ofp); X SigTrap = FALSE; X return nlines; X} X Xdprint(art, ifp, ofp) Xint art; XFILE *ifp, *ofp; X{ X#ifdef PAGE X register int cnt; X FILE *pfp, *popen(); X X if (art && arts[art].a_blen > 23-arts[art+1].a_hlen && *PAGER) { X if (!index(PAGER, FMETA)) { X if ((pfp = popen(PAGER, "w"))==NULL) X (void) dprinta(art, ifp, ofp); X else { X cnt = dprinta(art, ifp, pfp) % 23; X if (cnt > 23-arts[art+1].a_hlen) X while (cnt++ < 24) X putc('\n', pfp); X (void) pclose(pfp); X } X } else X pout(ofp); X } else X#endif /* PAGE */ X (void) dprinta(art, ifp, ofp); X} X Xdprinta(art, ifp, ofp) Xint art; Xregister FILE *ifp, *ofp; X{ X register char c; X register long pos = arts[art].a_bod; X register long epos = arts[art+1].a_hdr; X register int nlines = 0; X X (void) fseek(ifp, pos, 0); X while (pos++ < epos && !SigTrap) { X if ((c = getc(ifp))=='\n') X nlines++; X putc(c, ofp); X } X (void) fflush(ofp); X SigTrap = FALSE; X return nlines; X} X Xdsaveart(art, ifp, ofp, name) Xint art; Xregister FILE *ifp, *ofp; Xregister char *name; X{ X register FILE *nfp; X char fname[BUFLEN]; X char *strcat(), *strcpy(), *getenv(); X register char *nb; X X while (*name==' ' || *name=='\t') X name++; X X if (*name=='|') { X fprintf(ofp, "don't know how to pipe yet.\n"); X (void) fflush(ofp); X return; X } else if (*name=='/') X (void) strcpy(fname, name); X else { X if (nb = getenv("NEWSBOX")) X (void) strcpy(fname, nb); X else X (void) strcpy(fname, userhome); X (void) strcat(fname, "/"); X (void) strcat(fname, name); X } X X fprintf(ofp, "Save digest article %d in \"%s\"", art, fname); X (void) fflush(ofp); X if ((nfp = fopen(fname, "a"))!=NULL) { X int ln; X ln = dhprint(art, ifp, nfp); X ln += dprinta(art, ifp, nfp); X fprintf(ofp, " [Appended] %d lines\n", ln); X (void) fclose(nfp); X } else X fprintf(ofp, " cannot append to.\n"); X} X Xisheader(s) Xregister char *s; X{ X if (isupper(*s) || islower(*s)) { X while (*s && *s!=':' && !isspace(*s)) X s++; X if (*s==':' && *++s==' ') X return TRUE; X } X return FALSE; X} END_OF_FILE if test 8135 -ne `wc -c <'digest.c'`; then echo shar: \"'digest.c'\" unpacked with wrong size! fi # end of 'digest.c' fi if test -f 'unbatch.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'unbatch.c'\" else echo shar: Extracting \"'unbatch.c'\" \(6310 characters\) sed "s/^X//" >'unbatch.c' <<'END_OF_FILE' X/* X * unbatchnews: extract news in batched format and process it one article X * at a time. The format looks like X * #! rnews 1234 X * article containing 1234 characters X * #! rnews 4321 X * article containing 4321 characters X * X * or X * X * #! cunbatch X * calls LIBDIR/compress and writes the output to a temp file X * executes rnews for every article in the temp file X * unlinks the temp file X * X * or X * X * #! command [args] X * calls LIBDIR/command [args] to process the news X */ X X#ifdef SCCSID Xstatic char *SccsId = "@(#)unbatch.c 1.26 3/21/87"; X#endif /* SCCSID */ X X#define MAXARGS 32 X X#include "defs.h" X#include <stdio.h> X#include <ctype.h> X X#if defined(USG) || defined(BSD4_2) || defined(BSD4_1C) || defined(MINIX) X#include <fcntl.h> X#endif /* USG */ X Xchar xbuf[BUFSIZ]; Xchar sibuf[BUFSIZ]; X Xmain() X{ X register int c; X register FILE *pfn; X register long size; X char *filename; X int pid, wpid, exstat; X char *mktemp(), *gets(); X long atol(); X X filename = mktemp("/tmp/unbnewsXXXXXX"); X setbuf(stdin, (char *)NULL); /* only for the first line */ X if (gets(xbuf) == NULL) { X (void) unlink(filename); X exit(0); X } X if (strncmp(xbuf, "#! cunbatch", 11) == 0) { X docunbatch(xbuf); X /* should not return */ X logerr("unbatch: docunbatch returned!"); X exit(1); X } X X if (strncmp(xbuf, "#! rnews ", 9) != 0) { X docmd(xbuf); X /* should not return */ X logerr("unbatch: docmd returned!"); X exit(1); X } X X setbuf(stdin, sibuf); /* buffer the rest of the file */ X X do { X while (strncmp(xbuf, "#! rnews ", 9) X && strncmp(xbuf, "! rnews ", 8)) { /* kludge for bug */ X register char *cp; X for (cp = xbuf; *cp != '\0'; ++cp) X if (!isascii(*cp) || X (!isprint(*cp) && !isspace(*cp))) X *cp = '?'; X logerr("out of sync, skipping %s", xbuf); X if (gets(xbuf) == NULL) X exit(0); X } X size = atol(xbuf + (xbuf[0] == '#' ? 9 : 8)); X if(size <= 0) { X logerr("nonsense size %ld", size); X continue; X } X#ifdef VMS X/* The loop is to delete all versions. */ X while (unlink(filename) == 0) X ; X#endif /* VMS */ X pfn = fopen(filename, "w"); X while(--size >= 0 && (c = getc(stdin)) != EOF) X putc(c, pfn); X if (ferror(pfn) || fclose(pfn)) { /* disk full? */ X logerr("error writing temporary file"); X break; X } X X /* X * If we got a truncated batch, don't process the X * last article; it will probably be received again. X */ X if (size > 0) { X logerr("truncated batch"); X break; X } X X /* X * rnews < filename X */ X while ((pid = vfork()) == -1) { X logerr("fork failed, waiting...\n"); X sleep(60); X } X if (pid == 0) { X (void) close(0); X (void) open(filename, 0); X#ifdef IHCC X (void) sprintf(xbuf, "%s/%s", logdir(HOME), RNEWS); X#else X strcpy(xbuf, RNEWS); X#endif X#ifdef SPOOLNEWS X execlp(xbuf, "rnews", "-S", (char *)0); X#else /* !SPOOLNEWS */ X execlp(xbuf, "rnews", (char *)0); X#endif /* !SPOOLNEWS */ X perror("rnews"); X exit(1); X } X while ((wpid = wait(&exstat)) >= 0 && wpid != pid) X ; X } while (gets(xbuf) != NULL); X (void) unlink(filename); X exit(0); X} X Xdocmd(p) Xregister char *p; X{ X char *args[MAXARGS]; X register char **ap = args; X char path[BUFSIZ]; X char *rindex(), *cp; X X while (*p && !isspace(*p)) /* skip leading #! crud */ X p++; X X while (isspace(*p)) X p++; X X while (*p != '\0') { X *ap++ = p; X if (ap >= &args[MAXARGS]) { X logerr("unbatch: Too many args to %s", args[0]); X exit(2); X } X while (*p && !isspace(*p)) X p++; X if (*p) X *p++ = '\0'; X while (isspace(*p)) X p++; X } X *ap = (char *)0; X X if (ap == args) { X logerr("unbatch: no command to execute"); X exit(2); X } X X /* strip off any leading pathname in case someone gets tricky */ X cp = rindex(args[0], '/'); X if (cp++ == NULL) X cp = args[0]; X X# ifdef HOME X sprintf(path, "%s/%s/%s", logdir(HOME), LIBDIR, cp); X# else /* !HOME */ X sprintf(path, "%s/%s", LIBDIR, cp); X# endif /* HOME */ X X /* X * "path" is absolute, no searching is needed, we use X * 'execvp' solely so that sh scripts will be handled X */ X (void) execvp(path, args); X perror(path); X exit(2); X} X X/* docunbatch ... feed a compressed batch into compress & put output to X * a temporary file. Used to conserve memory when rnews is running. X */ X Xdocunbatch(arg) Xchar *arg; X{ X char cmd[200]; X int pid, wpid, exstat; X char *filename; X char *mktemp(); X X filename = mktemp("/usr/tmp/unbnewsXXXXXX"); X /* feed stdin into compress */ X sprintf(cmd,"%s/compress -d >%s", LIBDIR, filename); X X if ((pid=vfork()) == 0) { X execl("/bin/sh", "news-decompress", "-c", cmd, (char *) 0); X logerr("execl /bin/sh -c compress failed!\n"); X exit(2); X } else { X while ((wpid = wait(&exstat)) >= 0 && wpid != pid) X ; X } X X if (exstat) { X logerr("Decompress failed\n"); X exit(3); X } X X /* now run unbatch (hey, that's us!) on the file */ X /* redirect stdin to point to the file */ X fclose(stdin); X if (open(filename, O_RDONLY) != 0) { X logerr("unbatch cannot reopen stdin\n"); X unlink(filename); X exit(2); X } X X sprintf(cmd, "%s/unbatch", LIBDIR); X X if ((pid=vfork()) == 0) { X execl(cmd, "news-unpack", (char *) 0); X logerr("execl LIBDIR/unbatch failed!\n"); X unlink(filename); X exit(2); X } else { X while ((wpid = wait(&exstat)) >= 0 && wpid != pid) X ; X } X X unlink(filename); X if (exstat) { X logerr("Unbatch failed\n"); X exit(3); X } X X exit(0); X} X X X/* X * Log the given message, with printf strings and parameters allowed, X * on the log file, if it can be written. X */ X/* VARARGS1 */ Xlogerr(fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9) Xchar *fmt; Xlong a1, a2, a3, a4, a5, a6, a7, a8, a9; X{ X FILE *logfile; X char lfname[BUFSIZ]; /* the log file */ X char bfr[BUFSIZ]; X char *logtime, *ctime(); X long t; X X (void) time(&t); X logtime = ctime(&t); X logtime[16] = 0; X logtime += 4; X X#ifdef IHCC X (void) sprintf(lfname, "%s/%s/errlog", logdir(HOME), LIBDIR); X#else X (void) sprintf(lfname, "%s/errlog", LIBDIR); X#endif X X (void) sprintf(bfr, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9); X (void) fprintf(stderr, "%s\n", bfr); X if (access(lfname, 0) == 0 && (logfile = fopen(lfname, "a")) != NULL) { X#if defined(USG) || defined(BSD4_2) || defined(BSD4_1C) X int flags; X flags = fcntl(fileno(logfile), F_GETFL, 0); X (void) fcntl(fileno(logfile), F_SETFL, flags|O_APPEND); X#else /* v7 */ X (void) lseek(fileno(logfile), 0L, 2); X#endif /* v7 */ X fprintf(logfile, "%s\tbatch\t%s\n", logtime, bfr); X (void) fclose(logfile); X } X} END_OF_FILE if test 6310 -ne `wc -c <'unbatch.c'`; then echo shar: \"'unbatch.c'\" unpacked with wrong size! fi # end of 'unbatch.c' fi if test -f 'recmail.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'recmail.c'\" else echo shar: Extracting \"'recmail.c'\" \(6021 characters\) sed "s/^X//" >'recmail.c' <<'END_OF_FILE' X/* X * This software is Copyright (c) 1986 by Rick Adams. X * X * Permission is hereby granted to copy, reproduce, redistribute or X * otherwise use this software as long as: there is no monetary X * profit gained specifically from the use or reproduction or this X * software, it is not sold, rented, traded or otherwise marketed, and X * this copyright notice is included prominently in any copy X * made. X * X * The author make no claims as to the fitness or correctness of X * this software for any use whatsoever, and it is provided as is. X * Any use of this software is at the user's own risk. X * X * recmail: read a mail message on stdin, grab all addresses in To and Cc X * lines, and pass the full message to all addressees. This is useful to X * send the output of a recently edited mail message (with headers edited too). X * It is similar to sendmail -t, but only assumes /bin/mail. X * To use your own mailer, e. g. nmail, compile with -DMAILER=my_mailer. X */ X X#ifdef SCCSID Xstatic char *SccsId = "@(#)recmail.c 1.15 10/23/86"; X#endif /* SCCSID */ X X#include "params.h" X X#ifndef MAILER X#define MAILER "/bin/mail" X#endif Xchar mailer[] = MAILER; X X#define MAXRECIPS 100 Xchar *recips[MAXRECIPS]; Xint nrecips = 0; X Xmain() X{ X FILE *fd; X char *tmpf; X FILE *errfd; X char *errf; X char linebuf[1024]; X int i, pid, wpid; X int exstat; X char *mypath; X int goodcnt, badcnt; X char *mktemp(), *getenv(); X X tmpf = mktemp("/tmp/rmXXXXXX"); X (void) close(creat(tmpf,0666)); X fd = fopen(tmpf, "w"); X errf = mktemp("/tmp/rmXXXXXX"); X (void) close(creat(errf,0666)); X errfd = fopen(errf, "w"); X fprintf(errfd, "Subject: Returned mail\n"); X fprintf(errfd, "\n ----- Transcript of session follows -----\n"); X (void) fflush(errfd); X goodcnt = badcnt = 0; X X while (fgets(linebuf, sizeof linebuf, stdin) != NULL) { X if ((strncmp(linebuf, "Bcc: ", 5) == 0 || X strncmp(linebuf, "bcc: ", 5) == 0 || X strncmp(linebuf, "BCC: ", 5) == 0)) { X if (linebuf[5] != '\n') X addrecips(linebuf+5); X } X else if (fputs(linebuf, fd) == EOF) X goto werror; X if (linebuf[0] == '\n') X break; X if ((strncmp(linebuf, "To: ", 4) == 0 || X strncmp(linebuf, "to: ", 4) == 0 || X strncmp(linebuf, "TO: ", 4) == 0 || X strncmp(linebuf, "Cc: ", 4) == 0 || X strncmp(linebuf, "cc: ", 4) == 0 || X strncmp(linebuf, "CC: ", 4) == 0) && X linebuf[4] != '\n') X addrecips(linebuf+4); X } X if (!feof(stdin)) { X while (fgets(linebuf, sizeof linebuf, stdin) != NULL) { X if (fputs(linebuf, fd) == EOF) { Xwerror: X printf("write error on temp file\n"); X exit(2); X } X } X } X /* X * Append the contents of the .signature file (if it exists) to X * the end of the mail message X */ X { X char sigbuf[BUFSIZ]; X register c; X register char *p = getenv("HOME"); X FILE *infp; X X if (p) { X (void) sprintf(sigbuf, "%s/%s", p, ".signature"); X if (infp = fopen(sigbuf, "r")) { X fprintf(fd,"---\n"); X while ((c = getc(infp)) != EOF) X putc(c,fd); X (void) fclose(infp); X } X } X } X (void) fclose(fd); X X /* X * Force the path to only consider /bin and /usr/bin, since X * that's the version of mail we want (not /usr/ucb/mail) X */ X if (mailer[0] != '/') { X register int e; X extern char **environ; X for (e = 0; environ[e] != NULL; ++e) X if (strncmp(environ[e], "PATH=", 5) == 0) { X environ[e] = "PATH=/bin:/usr/bin"; X break; X } X } X mypath = getenv("PATH"); X if (mypath) X strcpy(mypath, "/bin:/usr/bin"); X X /* X * We send the copies out separately, because of a bug in X * USG's /bin/mail which will generate ANOTHER To: line, X * even though we already have one, if there are at least X * two recipients. X */ X for (i=0; i<nrecips; i++) { X /* X * mail recips[i] < tmpf X */ X pid = mailto(tmpf, errfd, recips[i]); X exstat = -1; X while ((wpid = wait(&exstat)) >= 0 && wpid != pid) X ; X if (exstat == 0) X goodcnt++; X else X badcnt++; X } X if (badcnt) { X mailback(errfd, tmpf, errf); X (void) unlink(tmpf); X (void) unlink(errf); X exit(1); X } else if (goodcnt == 0) { X fprintf(errfd, "recmail: no 'To:' line\n"); X mailback(errfd, tmpf, errf); X (void) unlink(tmpf); X (void) unlink(errf); X exit (1); X } X (void) unlink(tmpf); X (void) unlink(errf); X exit (0); X} X X#define isok(c) (isprint(c) && (c) != ' ' && c != ',') Xaddrecips(line) Xchar *line; X{ X char *front, *back, *tail; X char *malloc(); X X tail = line + strlen(line); X for (front=line; front < tail; ) { X while (!isok(*front) && front < tail) X front++; X if (front >= tail) X break; /* skip end of line garbage */ X for (back=front; isok(*back); back++) X ; X *back=0; X if (nrecips >= MAXRECIPS) { X printf("Too many destinations\n"); X exit(2); X } X if ((recips[nrecips] = malloc(strlen(front) + 1)) == NULL) { X printf("Out of space\n"); X exit(2); X } X (void) strcpy(recips[nrecips], front); X nrecips++; X front = back+1; X } X} X Xint Xmailto(tmpf, errfd, recip) Xchar *tmpf; XFILE *errfd; Xchar *recip; X{ X register int pid; X X /* X * mail recips < tmpf X */ X while ((pid = vfork()) == -1) { X fprintf(stderr, "fork failed, waiting...\r\n"); X sleep(60); X } X if (pid == 0) { X (void) close(0); X (void) open(tmpf, 0); X if (errfd != NULL) { X (void) close(1); X (void) dup(fileno(errfd)); X (void) fclose(errfd); X (void) close(2); X (void) dup(1); X } X execlp(mailer, mailer, recip, (char *)0); X perror(mailer); X exit(1); X } X return pid; X} X Xmailback(errfd, tmpf, errf) Xregister FILE *errfd; Xchar *tmpf; Xchar *errf; X{ X register FILE *fd; X register int c; X int exstat; X register int pid, wpid; X char *logn; X char *getlogin(), *getenv(); X register struct passwd *pwd; X X if ((fd = fopen(tmpf, "r")) != NULL) { X fprintf(errfd, "\n ----- Unsent message follows -----\n"); X while ((c = getc(fd)) != EOF) X putc(c, errfd); X (void) fclose(fd); X } X (void) fclose(errfd); X if ((logn = getlogin()) == NULL && (logn = getenv("USER")) == NULL) { X if ((pwd = getpwent(getuid())) == NULL) X return; X logn = pwd->pw_name; X } X pid = mailto(errf, (FILE *)NULL, logn); X while ((wpid = wait(&exstat)) >= 0 && wpid != pid) X ; X} END_OF_FILE if test 6021 -ne `wc -c <'recmail.c'`; then echo shar: \"'recmail.c'\" unpacked with wrong size! fi # end of 'recmail.c' fi if test -f 'defs.minix' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'defs.minix'\" else echo shar: Extracting \"'defs.minix'\" \(5776 characters\) sed "s/^X//" >'defs.minix' <<'END_OF_FILE' X/* X * This software is Copyright (c) 1986 by Rick Adams. X * X * Permission is hereby granted to copy, reproduce, redistribute or X * otherwise use this software as long as: there is no monetary X * profit gained specifically from the use or reproduction or this X * software, it is not sold, rented, traded or otherwise marketed, and X * this copyright notice is included prominently in any copy X * made. X * X * The author make no claims as to the fitness or correctness of X * this software for any use whatsoever, and it is provided as is. X * Any use of this software is at the user's own risk. X * X */ X X/* @(#)defs.dist 2.58 4/10/87 */ X X/* X * defs.h - defines for news-related programs. X * X * If you remove any lines here or in your Makefile, make the change X * to localize.sh so you won't have to redo it for each news release. X * X * If TMAIL is undefined, the -M option will be disabled. X * X * By convention, the version of the software you are running is taken X * to be news_version below. X */ X X#define DAYS (60L*60L*24L) X#define WEEKS (7*DAYS) X/* Things that very well may require local configuration */ X#ifndef HOME X#define ROOTID 10 /* uid of person allowed to cancel anything */ X#endif X#define N_UMASK 002 /* mask for umask call, 022 for secure system */ X#define DFLTEXP 2*WEEKS /* default no. of seconds to expire in */ X#define HISTEXP 4*WEEKS /* default no. of seconds to forget in */ X#define DFLTSUB "general,all.announce" /* default subscription list */ X#define TMAIL "/usr/bin/Mail" /* Mail program that understands -T */ X#define ADMSUB "general,all.announce" /* Mandatory subscription list */ X#define PAGE "/usr/bin/more" /* Default pager */ X#define NOTIFY "usenet" /* Tell him about certain ctl messages */ X /* Default xmit command - remove -z if */ X#define DFTXMIT "uux - -r -z -gd %s!rnews < %s" /* your uux can't do it */ X#define UXMIT "uux -r -z -gd -c %s!rnews '<' %s" /* If uux -c is ok */ X#define DFTEDITOR "mined" /* Default editor, see also postnews. */ X/* #define UUPROG "euuname" /* omit for uuname, put in LIBDIR */ X#define MANUALLY /* Don't execute rmgroups, just notify. */ X/* #define NONEWGROUPS /* Don't create new groups, just notify.*/ X/* #define SPOOLNEWS /* Spool incoming rnews, don't process */ X/* #define SPOOLINEWS /* Spool local inews, don't process */ X/* #define LOCALNAME /* There is no full name database. */ X#define INTERNET /* Internet mail works locally */ X#define MYDOMAIN ".OZ" /* Local domain */ X/* #define CHEAP /* don't chown files to news */ X/* #define OLD /* Add extra headers for old neighbors */ X/* #define UNAME /* If uname call returns your nodename */ X/* #define GHNAME /* If gethostname call is available. */ X#define UUNAME "/etc/uucpname" /* If your nodename is stored in a file */ X#define V7MAIL /* Local mail format is V7 ("From ") */ X#define SORTACTIVE /* if you want news presented in the order of the .newsrc */ X#define ZAPNOTES /* if you want old style notes headers moved into the headers */ X#define DIGPAGE /* allow digestifying in vnews */ X/* #define DOXREFS /* Generate xref line for rn to use */ X#define MULTICAST /* If you want to be able to multicast news */ X/* #define BSD4_2 /* If you are running 4.2 or 4.3 BSD */ X/* #define BSD4_1C /* If you are running 4.1C BSD */ X/* #define LOCKF /* If you have the lockf() sys call */ X/* #define ALWAYSALIAS /* temporary kludge for conversion */ X/* #define SENDMAIL "/usr/bin/sendmail" /* command line to run "sendmail" if you have it */ X/* #define MMDF "/usr/mmdf/submit" /* command line to run mmdf if you have it */ X#define MYORG "Minix support BBS, NSW, Australia" /* My organization. Please */ X /* include your city (and state, and */ X /* country, if not obvious) in MYORG, */ X /* and please keep it short. */ X/* #define HIDDENNET "frooz" /* if you have a local network and want */ X /* The mail address to look like it came */ X /* from one machine */ X/* NOTE: The following two macros replace the use of HIDDENNET */ X/* #define GENERICPATH "frooz" /* If you are using a shared USENET/UUCP node */ X/* #define GENERICFROM "Frobozz.COM" /* If you want generic From:-addresses */ X/* #define NICENESS 4 /* does a nice(NICENESS) in rnews */ X/* #define FASCIST "all,!all.all" /* only permit posting to certain groups */ X /* see installation guide for details */ X#define SMALL_ADDRESS_SPACE /* If your machine can't address > 32767 */ X/* #define ORGDISTRIB "froozum" /* For organization wide control message handling */ X X/* Things you might want to change */ X#define NEWSRC ".newsrc" /* name of .newsrc file (in home dir) */ X#define LINES 512 /* maximum no. of lines in .newsrc */ X#define NEGCHAR '!' /* newsgroup negation character */ X#define DEADTIME 45 /* no. of seconds to wait on deadlock */ X#define FMETA '%' /* file meta-character for c option */ X#if defined(pdp11) || defined(SMALL_ADDRESS_SPACE) X# define BUFLEN 128 /* standard buffer size */ X#else X# define BUFLEN 256 /* standard buffer size */ X#endif X#define LBUFLEN 1024 /* big buffer size */ X#define SBUFLEN 32 /* small buffer size (for system names, etc) */ X#define LNCNT 14 /* Articles with > LNCNT lines go through pager */ X X/* Things you probably won't want to change */ X#define PATHLEN 512 /* length of longest source string */ X#define DATELEN 64 /* length of longest allowed date string */ X#define NAMELEN 128 /* length of longest possible message ID */ X#define SNLN 8 /* max significant characters in sysname */ X#define PROTO 'A' /* old protocol name */ X#define NETCHRS "!:@^%,"/* Punct. chars used for various networks */ X#define TRUE 1 /* boolean true */ X#define FALSE 0 /* boolean false */ X#define PERHAPS 2 /* indeterminate boolean value */ X#define NGDELIM ',' /* delimit character in news group line */ X END_OF_FILE if test 5776 -ne `wc -c <'defs.minix'`; then echo shar: \"'defs.minix'\" unpacked with wrong size! fi # end of 'defs.minix' fi echo shar: End of shell archive. exit 0 -- "Zeta Microcomputer Software" ACSnet: nick@ultima.cs.uts.oz UUCP: ...!uunet!munnari!ultima.cs.uts.oz!nick Fidonet: Nick Andrew on 3:713/602 (Zeta)
nick@ultima.cs.uts.oz (Nick Andrew) (12/07/89)
#! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of shell archive." # Contents: defs.h defs.dist batch.c uurec.c process.c decode.c # checkgroups.sh uname.c rparams.h # Wrapped by nick@nswitgould on Thu Dec 7 22:42:33 1989 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'defs.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'defs.h'\" else echo shar: Extracting \"'defs.h'\" \(5776 characters\) sed "s/^X//" >'defs.h' <<'END_OF_FILE' X/* X * This software is Copyright (c) 1986 by Rick Adams. X * X * Permission is hereby granted to copy, reproduce, redistribute or X * otherwise use this software as long as: there is no monetary X * profit gained specifically from the use or reproduction or this X * software, it is not sold, rented, traded or otherwise marketed, and X * this copyright notice is included prominently in any copy X * made. X * X * The author make no claims as to the fitness or correctness of X * this software for any use whatsoever, and it is provided as is. X * Any use of this software is at the user's own risk. X * X */ X X/* @(#)defs.dist 2.58 4/10/87 */ X X/* X * defs.h - defines for news-related programs. X * X * If you remove any lines here or in your Makefile, make the change X * to localize.sh so you won't have to redo it for each news release. X * X * If TMAIL is undefined, the -M option will be disabled. X * X * By convention, the version of the software you are running is taken X * to be news_version below. X */ X X#define DAYS (60L*60L*24L) X#define WEEKS (7*DAYS) X/* Things that very well may require local configuration */ X#ifndef HOME X#define ROOTID 10 /* uid of person allowed to cancel anything */ X#endif X#define N_UMASK 002 /* mask for umask call, 022 for secure system */ X#define DFLTEXP 2*WEEKS /* default no. of seconds to expire in */ X#define HISTEXP 4*WEEKS /* default no. of seconds to forget in */ X#define DFLTSUB "general,all.announce" /* default subscription list */ X#define TMAIL "/usr/bin/Mail" /* Mail program that understands -T */ X#define ADMSUB "general,all.announce" /* Mandatory subscription list */ X#define PAGE "/usr/bin/more" /* Default pager */ X#define NOTIFY "usenet" /* Tell him about certain ctl messages */ X /* Default xmit command - remove -z if */ X#define DFTXMIT "uux - -r -z -gd %s!rnews < %s" /* your uux can't do it */ X#define UXMIT "uux -r -z -gd -c %s!rnews '<' %s" /* If uux -c is ok */ X#define DFTEDITOR "mined" /* Default editor, see also postnews. */ X/* #define UUPROG "euuname" /* omit for uuname, put in LIBDIR */ X#define MANUALLY /* Don't execute rmgroups, just notify. */ X/* #define NONEWGROUPS /* Don't create new groups, just notify.*/ X/* #define SPOOLNEWS /* Spool incoming rnews, don't process */ X/* #define SPOOLINEWS /* Spool local inews, don't process */ X/* #define LOCALNAME /* There is no full name database. */ X#define INTERNET /* Internet mail works locally */ X#define MYDOMAIN ".OZ" /* Local domain */ X/* #define CHEAP /* don't chown files to news */ X/* #define OLD /* Add extra headers for old neighbors */ X/* #define UNAME /* If uname call returns your nodename */ X/* #define GHNAME /* If gethostname call is available. */ X#define UUNAME "/etc/uucpname" /* If your nodename is stored in a file */ X#define V7MAIL /* Local mail format is V7 ("From ") */ X#define SORTACTIVE /* if you want news presented in the order of the .newsrc */ X#define ZAPNOTES /* if you want old style notes headers moved into the headers */ X#define DIGPAGE /* allow digestifying in vnews */ X/* #define DOXREFS /* Generate xref line for rn to use */ X#define MULTICAST /* If you want to be able to multicast news */ X/* #define BSD4_2 /* If you are running 4.2 or 4.3 BSD */ X/* #define BSD4_1C /* If you are running 4.1C BSD */ X/* #define LOCKF /* If you have the lockf() sys call */ X/* #define ALWAYSALIAS /* temporary kludge for conversion */ X/* #define SENDMAIL "/usr/bin/sendmail" /* command line to run "sendmail" if you have it */ X/* #define MMDF "/usr/mmdf/submit" /* command line to run mmdf if you have it */ X#define MYORG "Minix support BBS, NSW, Australia" /* My organization. Please */ X /* include your city (and state, and */ X /* country, if not obvious) in MYORG, */ X /* and please keep it short. */ X/* #define HIDDENNET "frooz" /* if you have a local network and want */ X /* The mail address to look like it came */ X /* from one machine */ X/* NOTE: The following two macros replace the use of HIDDENNET */ X/* #define GENERICPATH "frooz" /* If you are using a shared USENET/UUCP node */ X/* #define GENERICFROM "Frobozz.COM" /* If you want generic From:-addresses */ X/* #define NICENESS 4 /* does a nice(NICENESS) in rnews */ X/* #define FASCIST "all,!all.all" /* only permit posting to certain groups */ X /* see installation guide for details */ X#define SMALL_ADDRESS_SPACE /* If your machine can't address > 32767 */ X/* #define ORGDISTRIB "froozum" /* For organization wide control message handling */ X X/* Things you might want to change */ X#define NEWSRC ".newsrc" /* name of .newsrc file (in home dir) */ X#define LINES 512 /* maximum no. of lines in .newsrc */ X#define NEGCHAR '!' /* newsgroup negation character */ X#define DEADTIME 45 /* no. of seconds to wait on deadlock */ X#define FMETA '%' /* file meta-character for c option */ X#if defined(pdp11) || defined(SMALL_ADDRESS_SPACE) X# define BUFLEN 128 /* standard buffer size */ X#else X# define BUFLEN 256 /* standard buffer size */ X#endif X#define LBUFLEN 1024 /* big buffer size */ X#define SBUFLEN 32 /* small buffer size (for system names, etc) */ X#define LNCNT 14 /* Articles with > LNCNT lines go through pager */ X X/* Things you probably won't want to change */ X#define PATHLEN 512 /* length of longest source string */ X#define DATELEN 64 /* length of longest allowed date string */ X#define NAMELEN 128 /* length of longest possible message ID */ X#define SNLN 8 /* max significant characters in sysname */ X#define PROTO 'A' /* old protocol name */ X#define NETCHRS "!:@^%,"/* Punct. chars used for various networks */ X#define TRUE 1 /* boolean true */ X#define FALSE 0 /* boolean false */ X#define PERHAPS 2 /* indeterminate boolean value */ X#define NGDELIM ',' /* delimit character in news group line */ X END_OF_FILE if test 5776 -ne `wc -c <'defs.h'`; then echo shar: \"'defs.h'\" unpacked with wrong size! fi # end of 'defs.h' fi if test -f 'defs.dist' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'defs.dist'\" else echo shar: Extracting \"'defs.dist'\" \(5768 characters\) sed "s/^X//" >'defs.dist' <<'END_OF_FILE' X/* X * This software is Copyright (c) 1986 by Rick Adams. X * X * Permission is hereby granted to copy, reproduce, redistribute or X * otherwise use this software as long as: there is no monetary X * profit gained specifically from the use or reproduction or this X * software, it is not sold, rented, traded or otherwise marketed, and X * this copyright notice is included prominently in any copy X * made. X * X * The author make no claims as to the fitness or correctness of X * this software for any use whatsoever, and it is provided as is. X * Any use of this software is at the user's own risk. X * X */ X X/* @(#)defs.dist 2.58 4/10/87 */ X X/* X * defs.h - defines for news-related programs. X * X * If you remove any lines here or in your Makefile, make the change X * to localize.sh so you won't have to redo it for each news release. X * X * If TMAIL is undefined, the -M option will be disabled. X * X * By convention, the version of the software you are running is taken X * to be news_version below. X */ X X#define DAYS (60L*60L*24L) X#define WEEKS (7*DAYS) X/* Things that very well may require local configuration */ X#ifndef HOME X#define ROOTID 10 /* uid of person allowed to cancel anything */ X#endif X#define N_UMASK 000 /* mask for umask call, 022 for secure system */ X#define DFLTEXP 2*WEEKS /* default no. of seconds to expire in */ X#define HISTEXP 4*WEEKS /* default no. of seconds to forget in */ X#define DFLTSUB "general,all.announce" /* default subscription list */ X#define TMAIL "/usr/ucb/Mail" /* Mail program that understands -T */ X#define ADMSUB "general,all.announce" /* Mandatory subscription list */ X#define PAGE "/usr/ucb/more" /* Default pager */ X#define NOTIFY "usenet" /* Tell him about certain ctl messages */ X /* Default xmit command - remove -z if */ X#define DFTXMIT "uux - -r -z %s!rnews < %s" /* your uux can't do it */ X#define UXMIT "uux -r -z -c %s!rnews '<' %s" /* If uux -c is ok */ X#define DFTEDITOR "vi" /* Default editor, see also postnews. */ X/* #define UUPROG "euuname" /* omit for uuname, put in LIBDIR */ X#define MANUALLY /* Don't execute rmgroups, just notify. */ X/* #define NONEWGROUPS /* Don't create new groups, just notify.*/ X/* #define SPOOLNEWS /* Spool incoming rnews, don't process */ X/* #define SPOOLINEWS /* Spool local inews, don't process */ X/* #define LOCALNAME /* There is no full name database. */ X/* #define INTERNET /* Internet mail works locally */ X#define MYDOMAIN ".UUCP" /* Local domain */ X/* #define CHEAP /* don't chown files to news */ X/* #define OLD /* Add extra headers for old neighbors */ X/* #define UNAME /* If uname call returns your nodename */ X/* #define GHNAME /* If gethostname call is available. */ X/* #define UUNAME "/etc/uucpname" /* If your nodename is stored in a file */ X#define V7MAIL /* Local mail format is V7 ("From ") */ X#define SORTACTIVE /* if you want news presented in the order of the .newsrc */ X#define ZAPNOTES /* if you want old style notes headers moved into the headers */ X#define DIGPAGE /* allow digestifying in vnews */ X/* #define DOXREFS /* Generate xref line for rn to use */ X/* #define MULTICAST /* If you want to be able to multicast news */ X/* #define BSD4_2 /* If you are running 4.2 or 4.3 BSD */ X/* #define BSD4_1C /* If you are running 4.1C BSD */ X/* #define LOCKF /* If you have the lockf() sys call */ X/* #define ALWAYSALIAS /* temporary kludge for conversion */ X/* #define SENDMAIL "/usr/lib/sendmail" /* command line to run "sendmail" if you have it */ X/* #define MMDF "/usr/mmdf/submit" /* command line to run mmdf if you have it */ X#define MYORG "Frobozz Inc., St. Louis" /* My organization. Please */ X /* include your city (and state, and */ X /* country, if not obvious) in MYORG, */ X /* and please keep it short. */ X/* #define HIDDENNET "frooz" /* if you have a local network and want */ X /* The mail address to look like it came */ X /* from one machine */ X/* NOTE: The following two macros replace the use of HIDDENNET */ X/* #define GENERICPATH "frooz" /* If you are using a shared USENET/UUCP node */ X/* #define GENERICFROM "Frobozz.COM" /* If you want generic From:-addresses */ X/* #define NICENESS 4 /* does a nice(NICENESS) in rnews */ X/* #define FASCIST "all,!all.all" /* only permit posting to certain groups */ X /* see installation guide for details */ X/* #define SMALL_ADDRESS_SPACE /* If your machine can't address > 32767 */ X/* #define ORGDISTRIB "froozum" /* For organization wide control message handling */ X X/* Things you might want to change */ X#define NEWSRC ".newsrc" /* name of .newsrc file (in home dir) */ X#define LINES 512 /* maximum no. of lines in .newsrc */ X#define NEGCHAR '!' /* newsgroup negation character */ X#define DEADTIME 45 /* no. of seconds to wait on deadlock */ X#define FMETA '%' /* file meta-character for c option */ X#if defined(pdp11) || defined(SMALL_ADDRESS_SPACE) X# define BUFLEN 128 /* standard buffer size */ X#else X# define BUFLEN 256 /* standard buffer size */ X#endif X#define LBUFLEN 1024 /* big buffer size */ X#define SBUFLEN 32 /* small buffer size (for system names, etc) */ X#define LNCNT 14 /* Articles with > LNCNT lines go through pager */ X X/* Things you probably won't want to change */ X#define PATHLEN 512 /* length of longest source string */ X#define DATELEN 64 /* length of longest allowed date string */ X#define NAMELEN 128 /* length of longest possible message ID */ X#define SNLN 8 /* max significant characters in sysname */ X#define PROTO 'A' /* old protocol name */ X#define NETCHRS "!:@^%,"/* Punct. chars used for various networks */ X#define TRUE 1 /* boolean true */ X#define FALSE 0 /* boolean false */ X#define PERHAPS 2 /* indeterminate boolean value */ X#define NGDELIM ',' /* delimit character in news group line */ END_OF_FILE if test 5768 -ne `wc -c <'defs.dist'`; then echo shar: \"'defs.dist'\" unpacked with wrong size! fi # end of 'defs.dist' fi if test -f 'batch.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'batch.c'\" else echo shar: Extracting \"'batch.c'\" \(5484 characters\) sed "s/^X//" >'batch.c' <<'END_OF_FILE' X X/* X * This software is Copyright (c) 1985 by Rick Adams. X * X * Permission is hereby granted to copy, reproduce, redistribute or X * otherwise use this software as long as: there is no monetary X * profit gained specifically from the use or reproduction or this X * software, it is not sold, rented, traded or otherwise marketed, and X * this copyright notice is included prominently in any copy X * made. X * X * The author make no claims as to the fitness or correctness of X * this software for any use whatsoever, and it is provided as is. X * Any use of this software is at the user's own risk. X * X * Batch: program to batch a list of news articles into an unbatch script. X * Usage: /usr/lib/news/batch listfile [bytecount] X * where listfile is a file containing a list, one per line, of full X * path names of files containing articles, e.g. as produced by the F X * transmission option in the sys file. X * bytecount is the maximum number of bytes to output before exiting X * Output is placed on standard output. X * X * Intended usage: X * X * With the shellfile "sendbatch", with machine names as arguments: X * e.g X * sendbatch rlgvax seismo X * X * This would be invoked every hour or two from crontab. X * X */ X X#ifdef SCCSID Xstatic char *SccsId = "@(#)batch.c 1.18 12/16/86"; X#endif /* SCCSID */ X X#include <stdio.h> X#include <sys/types.h> X#include <sys/stat.h> X#include <errno.h> X#include "defs.h" X X#if defined(USG) || defined(BSD4_2) || defined(BSD4_1C) X#include <fcntl.h> X#endif X Xstruct stat sbuf; X Xextern int errno; Xextern char *sys_errlist[]; X Xmain(argc,argv) Xchar **argv; X{ X register FILE *fd, *nfd; X register int c; X register long n; X register char *cp; X char *fdstatus; X long maxbytes, nbytes; X long atol(); X char fname[512]; X char workfile[512]; X char *index(), *fgets(); X X if (argc < 2) { X fprintf(stderr, "Usage: batch listfile [bytecount]\n"); X exit(1); X } X X /* X * Rename real file to a work name to avoid race conditions. X * If workfile exists skip the rename in order X * to recover from a crash w/o losing anything. X */ X (void) strcpy(workfile, argv[1]); X (void) strcat(workfile, ".work"); X if (access(workfile, 0) < 0) { X if (access(argv[1], 0) < 0 && errno == ENOENT) X exit(0); /* no news */ X if (rename(argv[1], workfile) < 0) { X logerror("rename(%s,%s) %s", argv[1], workfile, X sys_errlist[errno]); X exit(1); X } X } X fd = fopen(workfile, "r"); X if (fd == NULL) { X logerror("fopen(%s,r) %s", workfile, sys_errlist[errno]); X exit(1); X } X X if (argc > 2) X maxbytes = atol(argv[2]); X else X maxbytes = 100000000L; /* backwards compatible */ X nbytes = 0; X while ((fdstatus = fgets(fname, sizeof fname, fd)) != NULL) { X cp = index(fname, '\n'); X if (cp) X *cp = '\0'; X nfd = fopen(fname, "r"); X if (nfd == NULL) { X perror(fname); X continue; X } X (void) fstat(fileno(nfd), &sbuf); X if (cp) X *cp = '\n'; X nbytes += sbuf.st_size; X if (nbytes > maxbytes && nbytes != sbuf.st_size) X break; X printf("#! rnews %ld\n", (long)sbuf.st_size); X /* guess length of #! rnews string */ X nbytes += 13; X n = 0; X while ((c = getc(nfd)) != EOF) { X putchar(c); X n++; X } X (void) fclose(nfd); X if (ferror(stdout)){ X logerror("stdout write %s", sys_errlist[errno]); X exit(1); X } X if (n != sbuf.st_size) { /* paranoia */ X logerror("%s, expected %ld bytes, got %ld", fname, X n, sbuf.st_size); X /* breaking out of this early will end up resyncing X the batch files (isn't serendipity wonderful?) */ X break; X } X } X if (fdstatus != NULL) { /* exceeded maxbytes */ X char tmpfile[512]; X X (void) umask(2); X (void) strcpy(tmpfile, argv[1]); X (void) strcat(tmpfile, ".tmp"); X nfd = fopen(tmpfile, "w"); X if (nfd == NULL) { X logerror("fopen(%s,w) %s", tmpfile, sys_errlist[errno]); X exit(1); X } X do { X fputs(fname, nfd); X } while (fgets(fname, sizeof fname, fd) != NULL); X if (ferror(nfd)) { X logerror("write(%s) %s", tmpfile, sys_errlist[errno]); X exit(1); X } X (void) fclose(nfd); X (void) fclose(fd); X /* will pick it up next time thru */ X if (rename(tmpfile, workfile) < 0) { X logerror("rename(%s,%s) %s", tmpfile, workfile, X sys_errlist[errno]); X exit(1); X } X } X else X (void) unlink(workfile); X exit(0); X} X X/* X * Log the given message, with printf strings and parameters allowed, X * on the log file, if it can be written. X */ X/* VARARGS1 */ Xlogerror(fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9) Xchar *fmt; Xlong a1, a2, a3, a4, a5, a6, a7, a8, a9; X{ X FILE *logfile; X char lfname[BUFLEN]; /* the log file */ X char bfr[BUFLEN]; X char *logtime, *ctime(); X time_t t; X X (void) time(&t); X logtime = ctime(&t); X logtime[16] = 0; X logtime += 4; X X#if defined(IHCC) || defined(HOME) X (void) sprintf(lfname, "%s/%s/errlog", logdir(HOME), LIBDIR); X#else X (void) sprintf(lfname, "%s/errlog", LIBDIR); X#endif X X (void) sprintf(bfr, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9); X fprintf(stderr, bfr); X if (access(lfname, 0) == 0 && (logfile = fopen(lfname, "a")) != NULL) { X#if defined(USG) || defined(BSD4_2) || defined(BSD4_1C) X int flags; X flags = fcntl(fileno(logfile), F_GETFL, 0); X (void) fcntl(fileno(logfile), F_SETFL, flags|O_APPEND); X#else /* v7 */ X (void) lseek(fileno(logfile), 0L, 2); X#endif /* v7 */ X fprintf(logfile, "%s\tbatch\t%s\n", logtime, bfr); X (void) fclose(logfile); X } X} X X#if !defined(BSD4_2) && !defined(BSD4_1C) Xrename(from, to) Xregister char *from, *to; X{ X (void) unlink(to); X if (link(from, to) < 0) X return -1; X X (void) unlink(from); X return 0; X} X#endif /* !BSD4_2 && !BSD4_1C */ END_OF_FILE if test 5484 -ne `wc -c <'batch.c'`; then echo shar: \"'batch.c'\" unpacked with wrong size! fi # end of 'batch.c' fi if test -f 'uurec.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'uurec.c'\" else echo shar: Extracting \"'uurec.c'\" \(3247 characters\) sed "s/^X//" >'uurec.c' <<'END_OF_FILE' X/* X * uurec - receive articles via /bin/mail. X */ X X#ifdef SCCSID Xstatic char *SccsId = "@(#)uurec.c 2.11 3/21/87"; X#endif /* SCCSID */ X X#include "defs.h" X X#include <stdio.h> X#include <ctype.h> X X/* X * Process a news article which has been shipped via /bin/mail. X */ X X#define FROM 01 X#define NLIN 02 X#define BLANK 03 X#define OTHER 04 X X#define SKIPPING 010 X#define READING 020 X X#define BFSZ 250 X X#define EOT '\004' X X#define A 01 X#define B 02 X X#ifdef debug X# define RNEWS "cat" X#endif Xextern char *strcat(), *strcpy(); Xextern char *frombreak(); Xextern FILE *popen(); X X/* ARGSUSED */ Xmain(argc, argv) Xint argc; Xchar **argv; X{ X char buf[BFSZ], fbuf[BFSZ]; X char bfr[BFSZ], *pbfr = bfr; X register char *p = NULL; X register FILE *pipe = stdout; X register int mode, frmflg, pathcnt, format; X char *index(); X X mode = SKIPPING; X frmflg = FALSE; X while (fgets(buf, BFSZ, stdin) != NULL) { X#ifdef debug X printf("%o\t%s", mode|type(buf), buf); X#endif X switch (mode | type(buf)) { X X case FROM | SKIPPING: X if (frmflg) X p = frombreak(p, buf); X else X p = fbuf; X frmflg = TRUE; X break; X X case FROM | READING: X if (!frmflg) { X frmflg = TRUE; X p = fbuf; X pclose(pipe); X } X p = frombreak(p, buf); X break; X X case NLIN | SKIPPING: X if ((isupper(buf[1]) && index(buf, ':')) || !strncmp(buf, "From ", 5)) X format = B; X else X format = A; X#ifdef debug X printf("format = %d\n", format); X#endif X mode = READING; X X case NLIN | READING: X if (frmflg) { X frmflg = FALSE; X --p; X while (p >= fbuf && *--p != '!') X ; X *++p = '\0'; X pathcnt = 0; X#ifdef IHCC X sprintf(pbfr, "%s/%s", logdir(HOME), RNEWS); X#else X pbfr = RNEWS; X#endif X if ((pipe = popen(pbfr, "w")) == NULL) { X perror("uurec: popen failed"); X exit(1); X } X } X if (format == A) { X if (++pathcnt == 3) X fputs(fbuf, pipe); X fputs(buf+1, pipe); X } else { X if (!pathcnt && (!strncmp(buf+1, "From: ", 6) || !strncmp(buf+1, "From ", 5))) { X pathcnt++; X fprintf(pipe, "From: %s", fbuf); X sscanf(buf, "%s %[^\n]", fbuf, fbuf); X fprintf(pipe, "%s\n", fbuf); X } else X fputs(buf+1, pipe); X } X break; X X case OTHER | SKIPPING: X break; X X case OTHER | READING: X pclose(pipe); X mode = SKIPPING; X } X } X if (pipe && pipe != stdout) X pclose(pipe); X exit(0); X} X Xtype(p) Xregister char *p; X{ X while (*p == ' ' || *p == '?') X ++p; X X if (*p == 'N') X return (NLIN); X X if (strncmp(p, ">From ", 6) == 0) X return (FROM); X X if (strncmp(p, "From ", 5) == 0) X return (FROM); X X return(OTHER); X} X X/* X * Get the system name out of a from line. X */ Xchar * Xfrombreak(buf, fbuf) Xregister char *buf, *fbuf; X{ X register char *p; X X /* break the line into tokens. */ X p = fbuf; X while (*++p != '\0') X switch (*p) { X case '\n': X case '\t': X case ' ': X *p = '\0'; X break; X case EOT: X goto garbled; X default:; X } X *++p = EOT; X *++p = '\0'; X X for (p=fbuf; *p != EOT || p[1] != '\0'; p += strlen(p)+1) { X if (strcmp(p, "forwarded") == 0) X return(buf); X if (strcmp(p, "remote") == 0) { X p += strlen(p)+1; X if (strcmp(p, "from") == 0) { X p += strlen(p)+1; X strcpy(buf, p); X strcat(buf, "!"); X return(buf+strlen(buf)); X } X } X } X garbled: X strcat(buf, "???!"); X return(buf+4); X} END_OF_FILE if test 3247 -ne `wc -c <'uurec.c'`; then echo shar: \"'uurec.c'\" unpacked with wrong size! fi # end of 'uurec.c' fi if test -f 'process.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'process.c'\" else echo shar: Extracting \"'process.c'\" \(3638 characters\) sed "s/^X//" >'process.c' <<'END_OF_FILE' X/* X * This software is Copyright (c) 1986 by Rick Adams. X * X * Permission is hereby granted to copy, reproduce, redistribute or X * otherwise use this software as long as: there is no monetary X * profit gained specifically from the use or reproduction or this X * software, it is not sold, rented, traded or otherwise marketed, and X * this copyright notice is included prominently in any copy X * made. X * X * The author make no claims as to the fitness or correctness of X * this software for any use whatsoever, and it is provided as is. X * Any use of this software is at the user's own risk. X * X * process - process options for readnews/vnews X */ X X#ifdef SCCSID Xstatic char *SccsId = "@(#)process.c 2.17 12/16/86"; X#endif /* SCCSID */ X X#include "rparams.h" X Xchar coptbuf[LBUFLEN], datebuf[LBUFLEN]; X X#define OPTION 0 /* pick up an option string */ X#define STRING 1 /* pick up a string of arguments */ X Xstruct optable *optpt, options[] = { /* Xoptlet filchar flag newstate oldmode newmode buf */ X'p', '\0', FALSE, OPTION, UNKNOWN, UNKNOWN,(char *)NULL, X't', '\0', FALSE, STRING, ANY, UNKNOWN,header.title, X'a', ' ', FALSE, STRING, ANY, UNKNOWN,datebuf, X'n', NGDELIM, FALSE, STRING, ANY, UNKNOWN,header.nbuf, X'c', ' ', FALSE, STRING, UNKNOWN, UNKNOWN,coptbuf, X'l', ' ', FALSE, OPTION, UNKNOWN, UNKNOWN,(char *)NULL, X'r', '\0', FALSE, OPTION, ANY, UNKNOWN,(char *)NULL, X's', NGDELIM, FALSE, STRING, ANY, UNKNOWN,header.nbuf, X'x', '\0', FALSE, OPTION, ANY, UNKNOWN,(char *)NULL, X'h', '\0', FALSE, OPTION, ANY, UNKNOWN,(char *)NULL, X#ifdef TMAIL X'M', '\0', FALSE, OPTION, UNKNOWN, MAIL, (char *)NULL, X#else /* !TMAIL */ X'\377', '\0', FALSE, OPTION, UNKNOWN, UNKNOWN,(char *)NULL, X#endif /* !TMAIL */ X'f', '\0', FALSE, OPTION, ANY, UNKNOWN,(char *)NULL, X'u', '\0', FALSE, OPTION, ANY, UNKNOWN,(char *)NULL, X'e', '\0', FALSE, OPTION, ANY, UNKNOWN,(char *)NULL, X'K', '\0', FALSE, OPTION, ANY, UNKNOWN,(char *)NULL, X'\0', '\0', 0, 0, 0, 0, (char *)NULL X}; X Xprocess(argc,argv) Xregister int argc; Xregister char **argv; X{ X register int state = STRING; X register char *ptr = header.nbuf; X char filchar = NGDELIM; X int len = LBUFLEN, tlen; X X /* loop once per arg. */ X X if (argc > 1 && **argv != '-') X nflag = TRUE; X X while (--argc) { X if (state == OPTION) { X if (**argv != '-') { X xerror("Bad option string \"%s\"", *argv); X } X while (*++*argv != '\0') { X for (optpt = options; optpt->optlet != '\0'; ++optpt) { X if (optpt->optlet == **argv) X goto found; X } X /* unknown option letter */ X#ifdef TMAIL X fprintf(stderr, "Usage: %s [ -a [ date ]] [ -n newsgroups ] [ -t titles ] [ -lprxhfuMK ]\n", Progname); X#else /* !TMAIL */ X fprintf(stderr, "Usage: %s [ -a [ date ]] [ -n newsgroups ] [ -t titles ] [ -lprxhfuK ]\n", Progname); X#endif /* !TMAIL */ X fprintf(stderr, "\t[ -c [ ``mailer'' ]]\n\n"); X fprintf(stderr, " %s -s\n", Progname); X exit(1); X X found:; X if (mode != UNKNOWN && (mode&optpt->oldmode) == 0) { X xerror("Bad %c option", **argv); X } X if (mode == UNKNOWN) X mode = optpt->newmode; X filchar = optpt->filchar; X optpt->flag = TRUE; X state = optpt->newstate; X ptr = optpt->buf; X len = LBUFLEN; X } X X argv++; /* done with this option arg. */ X X } else { X X /* X * Pick up a piece of a string and put it into X * the appropriate buffer. X */ X if (**argv == '-') { X state = OPTION; X argc++; /* uncount this arg. */ X continue; X } X X if ((tlen = strlen(*argv)) >= len) X xerror("Argument string too long"); X strcpy(ptr, *argv++); X ptr += tlen; X if (*(ptr-1) != filchar) X *ptr++ = filchar; X len -= tlen + 1; X *ptr = '\0'; X } X } X return; X} END_OF_FILE if test 3638 -ne `wc -c <'process.c'`; then echo shar: \"'process.c'\" unpacked with wrong size! fi # end of 'process.c' fi if test -f 'decode.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'decode.c'\" else echo shar: Extracting \"'decode.c'\" \(3365 characters\) sed "s/^X//" >'decode.c' <<'END_OF_FILE' X#include <stdio.h> X X#ifdef SCCSID Xstatic char *SccsId = "@(#)decode.c 1.3 5/15/85"; X#endif /* SCCSID */ X X/* X * This program is the inverse of encode X * X * It collects runs of 12 characters, combines pairs of those X * to form 6 13 bit numbers, extracts the top bit of each of X * those to make a 13th 6 bit character, and splits each of X * the remaining 6 12 bit numbers to form 12 6 bit ones. X * X * The strings of 6 bit numbers are collected into groups of X * 4 and converted into 3 8 bit characters. X * X * Now all that would be trivial, if we didn't need to worry X * about ending all this correctly. About 1/2 of the following X * program wouldn't be here if the ending didn't matter.... X */ X X/* X * the following pair of characters can never occur as a pair X * in legal input (since (90 * 91 + 90) > 2^13) - they are X * noticed at the beginning of a 12 char block, and serve to X * indicate that this block is the terminator. The character X * immediately following is the (expanded) terminator length. X */ X#define ENDMARK1 ((90*91 + 90) / 91) X#define ENDMARK2 ((90*91 + 90) % 91) X Xmain() X{ X register c; X register char *p; X register i; X register first = 1; X register cnt = 0; X int errcnt = 0; X char b12[12]; X char c12[12]; X X p = b12; X i = 12; X X while ((c = getchar()) != EOF) { X if (c < ' ' || c >= (' ' + 91)) { X if (errcnt++ == 0) X fprintf(stderr, "decode: Bad data\n"); X continue; X } X if (i == 10 && p[-1] == ENDMARK1 && p[-2] == ENDMARK2) { X cnt = c - ' '; X i = 12; X p -= 2; X continue; X } X *p++ = c - ' '; X if (--i == 0) { X if (p == &b12[12]) { X if (!first) X pack12(c12, 12, 0); X else X first = 0; X p = c12; X } else { X pack12(b12, 12, 0); X p = b12; X } X i = 12; X } X } X X if (p >= &b12[0] && p < &b12[12]) { X if (!first) X pack12(c12, 12, i == 12 ? cnt : 0); X } else X pack12(b12, 12, i == 12 ? cnt : 0); X X if (i != 12) { X if (p >= &b12[0] && p < &b12[12]) X pack12(b12, 12-i, cnt); X else X pack12(c12, 12-i, cnt); X } X X exit(0); X} X Xstatic char b4[4]; Xstatic int cnt = 0; X Xpack12(p, n, last) X register char *p; X register n; X int last; X{ X register i; X register char *q; X char b13[13]; X X { X register c; X register c13; X X q = b13; X c13 = 0; X X for (i = 0; i < n; i += 2) { X c = *p++ * 91; X c += *p++; X c13 <<= 1; X if (c & (1 << 12)) X c13 |= 1; X *q++ = (c >> 6) & 0x3f; X *q++ = c & 0x3f; X } X *q++ = c13; X if (last) X q = &b13[last]; X } X X p = b13; X n = q - p; X i = cnt; X q = &b4[cnt]; X X while (--n > 0) { X *q++ = *p++; X if (++i == 4) { X char b3[3]; X register char *b = b4; X X /* inline expansion of pack6bit, to save calls ... */ X X q = b3; X *q++ = (b[0] << 2) | ((b[1] >> 4) & 0x3); X *q++ = (b[1] << 4) | ((b[2] >> 2) & 0xf); X *q = (b[2] << 6) | (b[3] & 0x3f); X X q = b3; X while (--i > 0) X putchar(*q++); X X q = b4; X } X } X X *q++ = *p++; /* the last octet */ X ++i; X X if (last || i == 4) { X pack6bit(b4, i, last); X i = 0; X } X X cnt = i; X} X Xpack6bit(p, n, last) X register char *p; X register int n; X int last; X{ X register char *q; X register i = 3; X char b3[3]; X X if (last) { X i = p[n-1]; X if (i >= 3) { X fprintf(stderr, "Badly encoded file\n"); X i = 3; /* do the best we can */ X } X } X X q = b3; X *q++ = (p[0] << 2) | ((p[1] >> 4) & 0x3); X *q++ = (p[1] << 4) | ((p[2] >> 2) & 0xf); X *q = (p[2] << 6) | (p[3] & 0x3f); X X q = b3; X X while (--i >= 0) X putchar(*q++); X} END_OF_FILE if test 3365 -ne `wc -c <'decode.c'`; then echo shar: \"'decode.c'\" unpacked with wrong size! fi # end of 'decode.c' fi if test -f 'checkgroups.sh' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'checkgroups.sh'\" else echo shar: Extracting \"'checkgroups.sh'\" \(3677 characters\) sed "s/^X//" >'checkgroups.sh' <<'END_OF_FILE' X: check active file for missing or extra newsgroups X: '@(#)checkgroups 1.22 3/20/87' X Xif test ! -s LIBDIR/newsgroups Xthen X cp /dev/null LIBDIR/newsgroups Xfi X# Read first line of stdin. If of the form "-n group", then only check X# for the specified group. Otherwise, assume doing standard groups Xsed -e '/^[a-zA-Z-]*: /d' -e '/^$/d' -e '/^[#:]/d' | ( Xread line Xcase "${line}" in X-n*) X # Doing specific group. extract group name and preserve X # all of current newsgroups file except for that group. X # Then append entries for this group. X group=`echo "${line}" | sed -e 's/-n /^/' -e 's/$/\\\\./'` X egrep -v "${group}" LIBDIR/newsgroups > /tmp/$$a X cat /tmp/$$a - > LIBDIR/newsgroups X ;; X*) X # Get the distributions from the checkgroups message itself X # This allows sites to append their local groups to the distributed X # checkgroups message and prevents stray checkgroups from other sites X # from showing all the local groups as being bad groups. X # X echo "${line}" > /tmp/$$msg X cat >> /tmp/$$msg X cp /dev/null /tmp/$$b X sed -e "s;[ ].*;;" -e "s;\..*;;" -e "s;^!;;" /tmp/$$msg | sort -u | X while read dist X do X group=`cat /tmp/$$b` X group="${group}|^$dist\\." X echo "${group}" > /tmp/$$b X done X group=`cat /tmp/$$b` X egrep -v "${group}" LIBDIR/newsgroups > /tmp/$$a X cat /tmp/$$a > LIBDIR/newsgroups X sed -e "/^!/d" /tmp/$$msg >> LIBDIR/newsgroups X rm -f /tmp/$$b /tmp/$$msg X ;; Xesac X Xegrep "${group}" LIBDIR/active | sed 's/ .*//' | sort >/tmp/$$active Xegrep "${group}" LIBDIR/newsgroups | sed 's/ .*//' | sort >/tmp/$$newsgrps X Xcomm -13 /tmp/$$active /tmp/$$newsgrps >/tmp/$$missing Xcomm -23 /tmp/$$active /tmp/$$newsgrps >/tmp/$$remove X Xegrep "${group}" LIBDIR/active | sed -n "/m\$/s/ .*//p" | X sort > /tmp/$$amod.all Xegrep "${group}" LIBDIR/newsgroups | Xsed -n "/Moderated/s/[ ][ ]*.*//p" | sort > /tmp/$$ng.mod X Xcomm -12 /tmp/$$missing /tmp/$$ng.mod >/tmp/$$add.mod Xcomm -23 /tmp/$$missing /tmp/$$ng.mod >/tmp/$$add.unmod Xcat /tmp/$$add.mod /tmp/$$add.unmod >>/tmp/$$add X Xcomm -23 /tmp/$$amod.all /tmp/$$remove >/tmp/$$amod Xcomm -13 /tmp/$$ng.mod /tmp/$$amod >/tmp/$$ismod Xcomm -23 /tmp/$$ng.mod /tmp/$$amod >/tmp/$$nm.all Xcomm -23 /tmp/$$nm.all /tmp/$$add >/tmp/$$notmod X Xif test -s /tmp/$$remove Xthen X ( X echo "The following newsgroups are not valid and should be removed." X sed "s/^/ /" /tmp/$$remove X echo "" X echo "You can do this by executing the command:" X echo \ LIBDIR/rmgroup `cat /tmp/$$remove` X echo "" X ) 2>&1 >/tmp/$$out Xfi X Xif test -s /tmp/$$add Xthen X ( X echo "The following newsgroups were missing and should be added." X sed "s/^/ /" /tmp/$$add X echo "" X echo "You can do this by executing the command(s):" X for i in `cat /tmp/$$add.unmod` X do X echo 'LIBDIR/inews -C '$i' </dev/null' X done X for i in `cat /tmp/$$add.mod` X do X echo 'LIBDIR/inews -C '$i' moderated </dev/null' X done X echo "" X ) 2>&1 >>/tmp/$$out Xfi X Xif test -s /tmp/$$ismod Xthen X ( X echo "The following newsgroups are not moderated and are marked moderated." X sed "s/^/ /" /tmp/$$ismod X echo "" X echo "You can correct this by executing the command(s):" X for i in `cat /tmp/$$ismod` X do X echo 'LIBDIR/inews -C '$i' </dev/null' X done X echo "" X ) 2>&1 >>/tmp/$$out Xfi X Xif test -s /tmp/$$notmod Xthen X ( X echo "The following newsgroups are moderated and not marked so." X sed "s/^/ /" /tmp/$$notmod X echo "" X echo "You can correct this by executing the command(s):" X for i in `cat /tmp/$$notmod` X do X echo 'LIBDIR/inews -C '$i' moderated </dev/null' X done X echo "" X ) 2>&1 >>/tmp/$$out Xfi X Xif test -s /tmp/$$out Xthen X (echo "Subject: Problems with your active file" X echo "" X cat /tmp/$$out X ) | if test $# -gt 0 X then X mail $1 X else X cat X fi Xfi X) X Xrm -f /tmp/$$* X END_OF_FILE if test 3677 -ne `wc -c <'checkgroups.sh'`; then echo shar: \"'checkgroups.sh'\" unpacked with wrong size! fi # end of 'checkgroups.sh' fi if test -f 'uname.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'uname.c'\" else echo shar: Extracting \"'uname.c'\" \(2333 characters\) sed "s/^X//" >'uname.c' <<'END_OF_FILE' X/* X * This software is Copyright (c) 1986 by Rick Adams. X * X * Permission is hereby granted to copy, reproduce, redistribute or X * otherwise use this software as long as: there is no monetary X * profit gained specifically from the use or reproduction or this X * software, it is not sold, rented, traded or otherwise marketed, and X * this copyright notice is included prominently in any copy X * made. X * X * The author make no claims as to the fitness or correctness of X * this software for any use whatsoever, and it is provided as is. X * Any use of this software is at the user's own risk. X * X * This routine is compatible with the Unix T/S system call uname, X * which figures out the name of the local system. X * However, we do it by reading the file /usr/include/whoami.h. X * This avoids having to recompile uucp for each site and hence X * avoids having to distribute the source to uucp to people who X * have only binary licenses. X */ X X#ifdef SCCSID Xstatic char *SccsId = "@(#)uname.c 2.15 3/21/87"; X#endif /* SCCSID */ X X#include "params.h" X X#ifdef UNAME X# define DONE X#endif /* UNAME */ X X#ifdef GHNAME Xuname(uptr) Xstruct utsname *uptr; X{ X char *cp; X extern char *mydomain(); X gethostname(uptr->nodename, sizeof (uptr->nodename)); X cp = mydomain(); X if (*cp == '\0') /* get domain name from hostname */ X return; X cp = index(uptr->nodename, '.'); X if (cp) X *cp = '\0'; X} X# define DONE X#endif X X#ifdef UUNAME Xuname(uptr) Xstruct utsname *uptr; X{ X FILE *uucpf; X register char *p; X /* uucp name is stored UUNAME */ X X if (((uucpf = fopen(UUNAME, "r")) == NULL) || X fgets(uptr->nodename, sizeof (uptr->nodename), uucpf) == NULL) { X fprintf(stderr, "no sysname in %s\n", UUNAME); X return; X } X p = index(uptr->nodename, '\n'); X if (p) X *p = '\0'; X if (uucpf != NULL) X fclose(uucpf); X} X#define DONE X#endif /* UUNAME */ X X#ifndef DONE X#define HDRFILE "/usr/include/whoami.h" X Xuname(uptr) Xstruct utsname *uptr; X{ X char buf[BUFSIZ]; X FILE *fd; X X fd = fopen(HDRFILE, "r"); X if (fd == NULL) { X fprintf(stderr, "Cannot open %s\n", HDRFILE); X exit(1); X } X X for (;;) { /* each line in the file */ X if (fgets(buf, sizeof buf, fd) == NULL) { X fprintf(stderr, "no sysname in %s\n", HDRFILE); X fclose(fd); X exit(2); X } X if (sscanf(buf, "#define sysname \"%[^\"]\"", uptr->nodename) == 1) { X fclose(fd); X return; X } X } X} X#endif END_OF_FILE if test 2333 -ne `wc -c <'uname.c'`; then echo shar: \"'uname.c'\" unpacked with wrong size! fi # end of 'uname.c' fi if test -f 'rparams.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'rparams.h'\" else echo shar: Extracting \"'rparams.h'\" \(2146 characters\) sed "s/^X//" >'rparams.h' <<'END_OF_FILE' X/* X * rparams.h - parameters for readnews, rfuncs, and readr. X */ X X/* @(#)rparams.h 2.23 10/23/86 */ X X#include "params.h" X X/* flags for readnews */ X#define pflag options[0].flag X#define tflag options[1].flag X#define aflag options[2].flag X#define nflag options[3].flag X#define cflag options[4].flag X#define lflag options[5].flag X#define rflag options[6].flag X#define sflag options[7].flag X#define xflag options[8].flag X#define hflag options[9].flag X#define Mflag options[10].flag X#define fflag options[11].flag X#define uflag options[12].flag X#define eflag options[13].flag X#define Kflag options[14].flag X X#define NEXT 0 X#define SPEC 1 X X#define FORWARD 0 X#define BACKWARD 1 X X#define UNKNOWN 0001 /* possible modes for news program */ X#define MAIL 0004 X#define ANY 0007 X Xstruct optable { /* options table. */ X char optlet; /* option character. */ X char filchar; /* if to pickup string, fill character. */ X int flag; /* TRUE if have seen this opt. */ X int newstate; /* STRING if takes arg, else OPTION */ X int oldmode; /* OR of legal input modes. */ X int newmode; /* output mode. */ X char *buf; /* string buffer */ X}; X X/* external declarations specific to readnews */ Xextern char *infile, *outfile, *PAGER, *ALIASES; Xextern char *bitmap, *MAILER, *MAILPARSER; X X#ifndef ROOTID Xextern int ROOTID; X#endif X X#ifdef NOTIFY Xextern char *TELLME; X#endif X Xextern char filename[],coptbuf[],datebuf[],afline[]; Xextern char newsrc[],groupdir[],rcbuf[],*rcline[],*argvrc[]; Xextern int mode, ngrp, line, newrc(), readmode, news; Xextern long bit, obit, last, ngsize, minartno; Xextern FILE *rcfp,*actfp; Xextern time_t atime; Xextern struct optable *optpt, options[]; Xextern int actdirect, rcreadok, zapng; X X#ifndef lint X/* lint gets very mad about i-minartno, this is one way of shutting it up */ X/* macros */ X#define get(i) ((i<minartno)? 0 : (bitmap[(i-minartno) >> 3] & (1 << (i-minartno) % 8))) X#define set(i) if (i>=minartno) bitmap[(i-minartno) >> 3] |= (1 << (i-minartno) % 8);else X#define clear(i) if (i>=minartno) bitmap[(i-minartno) >> 3] &= ~(1 << (i-minartno) % 8);else X#endif /* !lint */ X X#define FCLOSE(fp) {if (fp != NULL) {fclose(fp);fp = NULL;}} END_OF_FILE if test 2146 -ne `wc -c <'rparams.h'`; then echo shar: \"'rparams.h'\" unpacked with wrong size! fi # end of 'rparams.h' fi echo shar: End of shell archive. exit 0 -- "Zeta Microcomputer Software" ACSnet: nick@ultima.cs.uts.oz UUCP: ...!uunet!munnari!ultima.cs.uts.oz!nick Fidonet: Nick Andrew on 3:713/602 (Zeta)
nick@ultima.cs.uts.oz (Nick Andrew) (12/07/89)
#! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of shell archive." # Contents: params.h ndir.c logdir.c fullname.c encode.c caesar.c # berknews.c vnews.help sendnews.c sendbatch.sh # Wrapped by nick@nswitgould on Thu Dec 7 22:43:07 1989 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'params.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'params.h'\" else echo shar: Extracting \"'params.h'\" \(2904 characters\) sed "s/^X//" >'params.h' <<'END_OF_FILE' X/* X * params.h - parameters for everyone. X */ X X/* @(#)params.h 2.23 4/6/87 */ X X#include <stdio.h> X#include <signal.h> X#include <sys/types.h> X#include <grp.h> X#include <pwd.h> X#include <sys/stat.h> X#include <ctype.h> X X#include "defs.h" X X#if defined(BSD4_2) || defined(BSD4_1C) X#include <sys/time.h> X#else /* sane */ X#include <time.h> X#endif /* sane */ X X#ifndef UNAME X/* X * 9 bytes is for compatibility with USG, in case you forget to define UNAME. X * 33 bytes in nodename because many sites have names longer than 8 chars. X */ X Xstruct utsname { X char sysname[9]; X char nodename[33]; X char release[9]; X char version[9]; X}; X#else X#include <sys/utsname.h> X#endif X X#ifndef USG X#include <sys/timeb.h> X#else Xstruct timeb X{ X time_t time; X unsigned short millitm; X short timezone; X short dstflag; X}; X#endif X X#include "header.h" X X/* line from SUBFILE */ Xstruct srec { X char s_name[2*BUFLEN]; /* system name */ X char *s_nosend; /* systems that inhibit sending */ X char s_nbuf[LBUFLEN]; /* system subscriptions */ X char s_flags[BUFLEN]; /* system flags */ X char s_xmit[LBUFLEN]; /* system xmit routine */ X}; X Xextern int uid, gid, duid, dgid; Xextern int savmask, SigTrap, mode, lockcount; Xextern struct hbuf header; Xextern char bfr[LBUFLEN], *username, *userhome; X Xextern char *SPOOL, *LIB, *BIN, *SUBFILE, *ACTIVE; Xextern char *LOCKFILE, *SEQFILE, *ARTFILE; Xextern char *news_version, *Progname; X X#ifdef NOTIFY Xextern char *TELLME; X#endif /* NOTIFY */ X Xextern char *LOCALSYSNAME, *LOCALPATHSYSNAME, *FROMSYSNAME, *PATHSYSNAME; X X#ifndef SHELL Xextern char *SHELL; X#endif /* !SHELL */ X X/* external function declarations */ Xextern FILE *xfopen(), *hread(); Xextern char *strcpy(), *strncpy(), *strcat(), *index(), *rindex(); Xextern char *ctime(), *mktemp(), *malloc(), *realloc(), *getenv(); Xextern char *arpadate(), *dirname(), *AllocCpy(), *strpbrk(); Xextern char *errmsg(); Xextern struct passwd *getpwnam(), *getpwuid(), *getpwent(); Xextern struct group *getgrnam(); Xextern time_t time(), getdate(), cgtdate(); Xextern int broadcast(), save(), newssave(), ushell(), onsig(); Xextern long atol(); Xextern struct tm *localtime(); X X#ifdef lint X/* This horrible gross kludge is the only way I know to X * convince lint that signal(SIGINT,SIG_IGN) is legal. It hates SIG_IGN. X */ X#ifdef SIG_IGN X#undef SIG_IGN X#endif /* SIG_IGN */ X#define SIG_IGN main Xextern int main(); X#endif /* lint */ X X#ifdef VMS X#define LINK(a,b) vmslink(a,b) X#define UNLINK(a) vmsdelete(a) XFILE *art_open(), *xart_open(); X#else X#define LINK(a,b) link(a,b) X#define UNLINK(a) unlink(a) X#define art_open fopen X#define xart_open xfopen X#endif /* !VMS */ X X/* Check for old naming scheme using HIDDENNET */ X#ifdef HIDDENNET X# ifndef GENERICFROM /* Ugly fix, only for use in pathinit.c */ X# define GENERICFROM "%s%0.0s%s", HIDDENNET X# define HIDDENNET_IN_LOCALSYSNAME X# endif X# ifndef GENERICPATH X# define GENERICPATH HIDDENNET X# endif X#endif END_OF_FILE if test 2904 -ne `wc -c <'params.h'`; then echo shar: \"'params.h'\" unpacked with wrong size! fi # end of 'params.h' fi if test -f 'ndir.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'ndir.c'\" else echo shar: Extracting \"'ndir.c'\" \(2564 characters\) sed "s/^X//" >'ndir.c' <<'END_OF_FILE' X#include "defs.h" X#if !defined(BSD4_2) && !defined(BSD4_1C) && !defined(HP9K5) X#ifndef MINIX X#include <sys/param.h> X#endif X#include "ndir.h" X X#ifdef SCCSID Xstatic char *SccsId = "@(#)ndir.c 1.11 3/20/87"; X#endif /* SCCSID */ X X/* X * support for Berkeley directory reading routine on a V7 file system X */ X Xextern char *malloc(); X X/* X * open a directory. X */ XDIR * Xopendir(name) Xchar *name; X{ X register DIR *dirp; X register int fd; X X if ((fd = open(name, 0)) == -1) X return NULL; X if ((dirp = (DIR *)malloc(sizeof(DIR))) == NULL) { X close (fd); X return NULL; X } X dirp->dd_fd = fd; X dirp->dd_loc = 0; X return dirp; X} X X/* X * read an old style directory entry and present it as a new one X */ X#ifdef pyr X/* Pyramid in the AT&T universe */ X#define ODIRSIZ 248 Xstruct olddirect { X long od_ino; X short od_fill1, od_fill2; X char od_name[ODIRSIZ]; X}; X#else /* V7 file system */ X#define ODIRSIZ 14 X Xstruct olddirect { X short od_ino; X char od_name[ODIRSIZ]; X}; X#endif /* !pyr */ X X/* X * get next entry in a directory. X */ Xstruct direct * Xreaddir(dirp) Xregister DIR *dirp; X{ X register struct olddirect *dp; X static struct direct dir; X X for (;;) { X if (dirp->dd_loc == 0) { X dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, X DIRBLKSIZ); X if (dirp->dd_size <= 0) X return NULL; X } X if (dirp->dd_loc >= dirp->dd_size) { X dirp->dd_loc = 0; X continue; X } X dp = (struct olddirect *)(dirp->dd_buf + dirp->dd_loc); X dirp->dd_loc += sizeof(struct olddirect); X if (dp->od_ino == 0) X continue; X dir.d_ino = dp->od_ino; X strncpy(dir.d_name, dp->od_name, ODIRSIZ); X dir.d_name[ODIRSIZ] = '\0'; /* insure null termination */ X dir.d_namlen = strlen(dir.d_name); X dir.d_reclen = DIRSIZ(&dir); X return (&dir); X } X} X X/* X * close a directory. X */ Xvoid Xclosedir(dirp) Xregister DIR *dirp; X{ X close(dirp->dd_fd); X dirp->dd_fd = -1; X dirp->dd_loc = 0; X free((char *)dirp); X} X X/* X * seek to an entry in a directory. X * Only values returned by "telldir" should be passed to seekdir. X */ Xvoid Xseekdir(dirp, loc) Xregister DIR *dirp; Xlong loc; X{ X long curloc, base, offset; X struct direct *dp; X long lseek(), telldir(); X X curloc = telldir(dirp); X if (loc == curloc) X return; X base = loc & ~(DIRBLKSIZ - 1); X offset = loc & (DIRBLKSIZ - 1); X (void) lseek(dirp->dd_fd, base, 0); X dirp->dd_loc = 0; X while (dirp->dd_loc < offset) { X dp = readdir(dirp); X if (dp == NULL) X return; X } X} X X/* X * return a pointer into a directory X */ Xlong Xtelldir(dirp) XDIR *dirp; X{ X return lseek(dirp->dd_fd, 0L, 1) - dirp->dd_size + dirp->dd_loc; X} X#endif /* !BSD4_2 && !BSD4_1C && !HP9K5 */ END_OF_FILE if test 2564 -ne `wc -c <'ndir.c'`; then echo shar: \"'ndir.c'\" unpacked with wrong size! fi # end of 'ndir.c' fi if test -f 'logdir.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'logdir.c'\" else echo shar: Extracting \"'logdir.c'\" \(2152 characters\) sed "s/^X//" >'logdir.c' <<'END_OF_FILE' X/* X * UNIX shell - logdir routine X * X * Joe Steffen X * Bell Telephone Laboratories X * X * This routine does not use the getpwent(3) library routine X * because the latter uses the stdio package. The allocation of X * storage in this package destroys the integrity of the shell's X * storage allocation. X * X * Modified 2/82 by DJ Molny X * X * This routine now implements name cacheing, so multiple requests X * for the same logdir do not result in multiple open/reads of X * /etc/passwd. If the previous request was successful and the name X * is the same as the last request, the same login directory is returned. X */ X#ifdef SCCSID Xstatic char *SccsId = "@(#)logdir.c 1.4 4/16/85"; X#endif /* SCCSID */ X X#define BUFSIZ 160 X Xstatic char line[BUFSIZ+1]; X Xchar * Xlogdir(name) Xchar *name; X{ X int pwf; X static char lastname[BUFSIZ+1]; X static char lastdir[BUFSIZ+1]; X register char *p; X register int i, j; X char *getenv(), *field(), *strcpy(); X X if (*lastdir && !strcmp(lastname,name)) /* djm */ X return(lastdir); X X strcpy(lastname, name); /* djm */ X strcpy(lastdir, ""); /* djm */ X X#ifdef IHCC X /* if the logname is exptools, see if $TOOLS is set */ X if (strcmp(name, "exptools") && X (p = getenv("TOOLS")) != 0 && *p != '\0') { X strcpy(lastdir, p); X return(lastdir); X } X#endif X X /* attempt to open the password file */ X if ((pwf = open("/etc/passwd", 0)) == -1) X return(0); X X /* find the matching password entry */ X do { X /* get the next line in the password file */ X i = read(pwf, line, BUFSIZ); X for (j = 0; j < i; j++) X if (line[j] == '\n') X break; X /* return a null pointer if the whole file has been read */ X if (j >= i) X return(0); X line[++j] = 0; /* terminate the line */ X lseek(pwf, (long) (j - i), 1); /* point at the next line */ X p = field(line); /* get the logname */ X } while (strcmp(name, line) != 0); X close(pwf); X X /* skip the intervening fields */ X p = field(p); X p = field(p); X p = field(p); X p = field(p); X X /* return the login directory */ X field(p); X strcpy(lastdir,p); /* djm */ X return(p); X} X Xstatic char * Xfield(p) Xregister char *p; X{ X while (*p && *p != ':') X ++p; X if (*p) *p++ = 0; X return(p); X} END_OF_FILE if test 2152 -ne `wc -c <'logdir.c'`; then echo shar: \"'logdir.c'\" unpacked with wrong size! fi # end of 'logdir.c' fi if test -f 'fullname.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'fullname.c'\" else echo shar: Extracting \"'fullname.c'\" \(2985 characters\) sed "s/^X//" >'fullname.c' <<'END_OF_FILE' X/* X * fullname.c - this file is made separate so that different local X * conventions can be applied. The stock version understands two X * conventions: X * X * (a) Berkeley finger: the gecos field in /etc/passwd begins with X * the full name, terminated with comma, semicolon, or end of X * field. & expands to the login name. X * (b) BTL RJE: the gecos field looks like X * : junk - full name ( junk : X * where the "junk -" is optional. X * X * If you have a different local convention, modify this file accordingly. X */ X X#ifdef SCCSID Xstatic char *SccsId = "@(#)fullname.c 1.11 9/16/86"; X#endif /* SCCSID */ X X#include "params.h" X X#ifndef LOCALNAME X/* X * Figure out who is sending the message and sign it. X * We attempt to look up the user in the gecos field of /etc/passwd. X */ Xchar * Xfullname(un) Xchar *un; X{ X static char inbuf[BUFLEN]; X struct passwd *pw; X X pw = getpwnam(un); X if (pw == NULL) X return un; X buildfname(pw->pw_gecos, un, inbuf); X if (inbuf[0] == 0) X return un; X return inbuf; X} X X#else X X/* X * Alternative version of fullname which asks the user for his full name. X * This is mainly suitable for systems that don't have a full name X * database somewhere. It puts the answer in $HOME/.name X */ Xchar * Xfullname(un) Xchar *un; X{ X static char inbuf[BUFLEN]; X char fbuf[BUFLEN]; X FILE *fd; X char *p, *index(), *getenv(); X int pid; X X if (!isatty(2)) X return un; X printf("What is your full name (for news article signatures): "); X fflush(stdout); X read(2, inbuf, sizeof inbuf); X if (inbuf[0] == 0) X return un; X p = index(inbuf, '\n'); X if (p) X *p = 0; X if ((p = getenv("HOME")) == NULL) { X fprintf(stderr, X "inews: no HOME environment variable - .name not written\n"); X return inbuf; X } X sprintf(fbuf, "%s/%s", p, ".name"); X if ((pid = vfork()) < 0) { X perror("inews"); X return inbuf; X } X else if (pid != 0) X while (wait((int *)0) != pid) X ; X else { X setuid(getuid()); /* become the user */ X if ((fd = fopen(fbuf, "w")) == NULL) X fprintf(stderr, "inews: can't create %s\n", fbuf); X else { X fprintf(fd, "%s\n", inbuf); X fclose(fd); X } X exit(0); X } X return inbuf; X} X#endif X X#ifndef LOCALNAME X/* X** BUILDFNAME -- build full name from gecos style entry. X** (routine lifted from sendmail) X** X** This routine interprets the strange entry that would appear X** in the GECOS field of the password file. X** X** Parameters: X** p -- name to build. X** login -- the login name of this user (for &). X** buf -- place to put the result. X** X** Returns: X** none. X** X** Side Effects: X** none. X*/ X Xbuildfname(p, login, buf) X register char *p; X char *login; X char *buf; X{ X register char *bp = buf; X X if (*p == '*') X p++; X while (*p != '\0' && *p != ',' && *p != ';' && *p != ':' && *p != '(') X { X if (*p == '-') { X bp = buf; X p++; X } X else if (*p == '&') X { X strcpy(bp, login); X if ((bp == buf || !isalpha(bp[-1])) && islower(*bp)) X *bp = toupper(*bp); X while (*bp != '\0') X bp++; X p++; X } X else X *bp++ = *p++; X } X *bp = '\0'; X} X#endif END_OF_FILE if test 2985 -ne `wc -c <'fullname.c'`; then echo shar: \"'fullname.c'\" unpacked with wrong size! fi # end of 'fullname.c' fi if test -f 'encode.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'encode.c'\" else echo shar: Extracting \"'encode.c'\" \(3062 characters\) sed "s/^X//" >'encode.c' <<'END_OF_FILE' X#include <stdio.h> X X#ifdef SCCSID Xstatic char *SccsId = "@(#)encode.c 1.3 5/15/85"; X#endif /* SCCSID */ X X/* X * Produce a 7 bit printable encoding of stdin on stdout. X * X * Encoding uses acsii chars from ' ' .. 'z' X * (040 .. 0172) (0x20 - 0x7a) inclusive X * X * Method is to expand 3 chars -> 4 6 bit ones. X * Then collect 13 6 bit chars, and spread the 13th over X * the preceding 12, so that each of the 12 chars is now X * 6.5 bits. These 2 6.5 bit chars are a little hard X * to represent on most common machines (one of these days X * sane hosts will have 1/2 bits just for this program) X * so we take a pair of them, and represent that in 13 bits. X * 13 bits (max value 8191) can be represented as X * A * 91 + B X * where A < 91, B < 91 (91^2 == 8281, so it fits!) X * X * Each of A and B is encoded as a character by adding 32 X * to make it printable (ie: 0x20). X * X * The termination conditions are foul beyond belief. Don't X * monkey with them! X * X * If you think its a fluke that 040 .. 0171 just happen to X * be the chars that Piet Beertema's uucp 'f' protocol transmits X * as single bytes, you're insane. 0172 chars are produced X * with lower frequency than any other (given random data) X * so the doubling that occurs with that we will just suffer. X * (A newer 'f' proto, sometime, will probably not use 0172) X */ X X/* X * the following pair of characters cannot legally occur X * in normal output (since 90*91 + 90 == 8280, which > 2^13) X * so we use them to indicate that the data that follows is the X * terminator. The character immediately following this X * pair is the length of the (expanded) terminator (which X * otherwise might be indeterminable) X */ X#define ENDMARK1 ((90*91 + 90) / 91 + ' ') X#define ENDMARK2 ((90*91 + 90) % 91 + ' ') X Xmain() X{ X register char *p; X register char *e; X register c; X char b3[3]; X X p = b3; X e = b3 + 3; X while ((c = getchar()) != EOF) { X *p++ = c; X if (p == e) { X encode(b3, 3); X p = b3; X } X } X encode(b3, p - b3); X flushout(); X exit(0); X} X Xstatic char b13[13]; Xstatic int cnt = 0; X Xencode(c, n) X register char *c; X int n; X{ X register char *p; X register i = cnt; X register j; X char b4[4]; X X p = b4; X X p[0] = (c[0] >> 2) & 0x3f; X p[1] = ((c[0] & 0x3) << 4) | ((c[1] >> 4) & 0xf); X p[2] = ((c[1] & 0xF) << 2) | ((c[2] >> 6) & 0x3); X if (n == 3) X p[3] = c[2] & 0x3f; X else X p[3] = n; X X c = &b13[i]; X for (j = 4; --j >= 0; i++) { X if (i == 13) { X dumpcode(b13, 13); X c = b13; X i = 0; X } X *c++ = *p++; X } X cnt = i; X} X Xflushout() X{ X putchar(ENDMARK1); X putchar(ENDMARK2); X putchar(cnt + ' '); X dumpcode(b13, cnt); X} X Xdumpcode(p, n) X register char *p; X register int n; X{ X register last; X register c; X X if (n == 13) X n--, last = p[12]; X else if (n & 1) X last = (1 << (6-1)); X else X last = 0; X X for ( ; n > 0; n -= 2) { X c = *p++ << 6; X c |= *p++; X if (last & (1 << (6-1))) X c |= (1 << 12); X last <<= 1; X X /* X * note: 91^2 > 2^13, 90^2 < 2^13, (91 + ' ') is printable X */ X X /* oh for a compiler that would only do one division... */ X putchar((c / 91) + ' '); X putchar((c % 91) + ' '); X } X} END_OF_FILE if test 3062 -ne `wc -c <'encode.c'`; then echo shar: \"'encode.c'\" unpacked with wrong size! fi # end of 'encode.c' fi if test -f 'caesar.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'caesar.c'\" else echo shar: Extracting \"'caesar.c'\" \(2376 characters\) sed "s/^X//" >'caesar.c' <<'END_OF_FILE' X/* X * program to to decrypt caesar(tm) cypher X * (caesar is a trademark of the roman empire) X * X * to compile: X * X * cc decrypt.c -lm -o decrypt.c X * X * usage: X * X * decrypt [n] < file X * X * where n is an optional forced rotation. X * X * authors: Stan King, John Eldridge, based on algorithm suggested by X * Bob Morris X * 29-Sep-82 X * X */ X X#ifdef SCCSID Xstatic char *SccsId = "@(#)caesar.c 1.7 4/16/85"; X#endif /* SCCSID */ X X#include <stdio.h> X#include <ctype.h> X#include <math.h> Xextern char *calloc(); X Xmain(argc, argv) Xint argc; Xchar *argv[]; X{ X /* letter frequencies (taken from some unix(tm) documentation) */ X /* (unix is a trademark of Bell Laboratories) */ X static double stdf[ 26 ] = X { X 7.97, 1.35, 3.61, 4.78, 12.37, 2.01, 1.46, 4.49, X 6.39, 0.04, 0.42, 3.81, 2.69, 5.92, 6.96, 2.91, X 0.08, 6.63, 8.77, 9.68, 2.62, 0.81, 1.88, 0.23, X 2.07, 0.06, X }; X int obs[26]; X int bufsize; X int c, i, try; X double dot, winnerdot; /* .. */ X int winner, forced = 0; X char *inbuf; X X bufsize = 0; X if( argc > 1 ) X sscanf( argv[1], "%d", &forced ); X if( forced == 0 ) X forced = -1000; X X inbuf = calloc( BUFSIZ, 1 ); X X /* adjust frequency table to weight low probs REAL low */ X for (i=0; i<26; i++) { X stdf[i] = log(stdf[i]) + log(26.0/100.0); X } X X /* Decode each line separately */ X for (;;) { X for (i=0; i<=25; obs[i++]=0) X ; X X /* get a sample of the text */ X for( i = 0; i < BUFSIZ; i++ ) { X if( (c = getchar()) == EOF ) { X exit(0); X } X inbuf[i] = c; X if (c == '\n') { X bufsize = i+1; X break; X } X if (islower(c)) X obs[c-'a'] += 1; X else if (isupper(c)) X obs[c-'A'] += 1; X } X X /* now "dot" the freqs with the observed letter freqs */ X /* and keep track of best fit */ X winner = 0; X for (try = 0; try<26; try+=13) { X dot = 0; X for ( i=0; i<26; i++ ) { X dot += obs[i] * stdf[ (i+try) % 26 ]; X } X /* initialize winning score */ X if( try == 0 ) X winnerdot = dot; X if( dot > winnerdot ) { X /* got a new winner! */ X winner = try; X winnerdot = dot; X } X } X X if (forced != -1000) X winner = forced; X X /* print out sample buffer */ X for( i = 0; i < bufsize; i++ ) X putchar( rotate( inbuf[i], winner ) ); X } X } X X Xstatic int Xrotate( c, perm ) Xchar c; Xint perm; X{ X if (isupper(c)) { X return 'A' + (c - 'A' + perm) % 26 ; X } X else if (islower(c)) { X return 'a' + (c-'a'+perm) % 26 ; X } X else return c; X} END_OF_FILE if test 2376 -ne `wc -c <'caesar.c'`; then echo shar: \"'caesar.c'\" unpacked with wrong size! fi # end of 'caesar.c' fi if test -f 'berknews.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'berknews.c'\" else echo shar: Extracting \"'berknews.c'\" \(2809 characters\) sed "s/^X//" >'berknews.c' <<'END_OF_FILE' X/* X * berknews - send news article via Berknet X * X * Synopsis: X * berknews [-o] [-n newsgroup] host_net_command machine remote_rnews X */ X X#ifdef SCCSID Xstatic char *SccsId = "@(#)berknews.c 2.5 4/16/85"; X#endif /* SCCSID */ X X#include <stdio.h> X#include <ctype.h> X#ifndef USG X#include <whoami.h> Xstruct utsname { X char Sysname[9]; X char nodename[33]; X char release[9]; X char version[9]; X}; X#else /* USG */ X#include <sys/utsname.h> X#endif /* USG */ X X Xstruct network { X char *uucpname; X char *berkname; X} berknet[] = { X/* UUCP Net Name BerkNet Name X ------------- ------------ */ X "ucbvax", "CSVAX", X "populi", "G", X "ucbarpa", "ARPAVAX", X "ucbcfo-c", "C", X "ucbopt", "ESVAX", X "ucbcad", "ucbcad", X "ucbcory", "Cory", X "ucb", "C70", X "ucbmathstat", "MathStat", X "ucbonyx", "Onyx", X "ucbkim", "Kim", X "ucbcfo-a", "A", X "ucbcfo-b", "B", X "ucbcfo-d", "D", X "ucbcfo-e", "E", X "ucbcfo-f", "F", X "ucbingvax", "IngVAX", X "ucbingres", "Ingres", X "ucbeecs40", "EECS40", X "ucbvlsi", "VLSI", X "ucbsrc", "SRC", X "ucbimage", "Image", X '\0', '\0' X}; X Xchar *index(); Xchar buffer[BUFSIZ]; Xint linecount; X XFILE *popen(); Xmain(argc, argv) Xint argc; Xchar **argv; X{ X FILE *out; X char sender[BUFSIZ],newsgroup[100]; X char *punct; X char sysn[20]; X int sysnl; X struct utsname ubuf; X X if (argc < 4) { X fprintf(stderr, "Too few arguments.\n"); X exit(1); X } X X#ifdef debug X printf("%s - -m%s %s\n", argv[1], argv[2], argv[3]); X sprintf(buffer, "cat"); X#else X sprintf(buffer, "%s - -m%s %s", argv[1], argv[2], argv[3]); X#endif X out = popen(buffer, "w"); X uname(&ubuf); X strcpy(sysn, ubuf.nodename); X strcat(sysn, "!"); X sysnl = strlen(sysn); X X while (fgets(buffer, sizeof buffer, stdin)) { X if (fromline()) { X punct = index(buffer, '!'); X if (punct == NULL) X printf("Bad from line: '%s'\n", buffer); X else { X *punct = ':'; /* berknet mail delimiter */ X if (!strncmp("From: ", buffer, 6)) X punct = &buffer[6]; X else if (!strncmp("From ",buffer,5)) X punct = &buffer[5]; X else X punct = buffer; X fiddle(punct); X } X } X fputs(buffer, out); X } X pclose(out); X exit(0); X} X Xfromline() { X if (!linecount && (!strncmp("From: ", buffer, 6) || !strncmp("From ", buffer, 5))) X return ++linecount; X return 0; X} X X/* X * make sure the host name is a correct berknet address, since the X * internal names are not the berknet host names. X */ Xfiddle(buf) Xchar *buf; X{ X char uucpname[100]; X register struct network *netptr; X char *rest; X X strcpy(uucpname, buf); X rest = index(uucpname, ':'); X *rest++ = 0; X#ifdef debug X printf("uucpname = '%s', buf = '%s', rest = '%s'\n", uucpname, buf, rest); X#endif X for (netptr = &berknet[0]; strcmp(netptr->uucpname, uucpname) && netptr->uucpname; netptr++) X ; X if (netptr->uucpname) X sprintf(buf, "%s:%s", netptr->berkname, rest); X else X sprintf(buf, "UNKNOWN:%s", rest); X} END_OF_FILE if test 2809 -ne `wc -c <'berknews.c'`; then echo shar: \"'berknews.c'\" unpacked with wrong size! fi # end of 'berknews.c' fi if test -f 'vnews.help' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'vnews.help'\" else echo shar: Extracting \"'vnews.help'\" \(1326 characters\) sed "s/^X//" >'vnews.help' <<'END_OF_FILE' XVnews commands: (each may be preceded by a non-negative count) X XCR Next page or article D Decrypt a rot 13 joke Xn Go to next article A Go to article numbered count Xe Mark current article as unread < Go to article with given ID X+ Go forwards count articles p Go to parent article X- Go to previous article ug Unsubscribe to this group X^B Go backwards count pages ^L Redraw screen X^N Go forward count lines v Print netnews version X^P Go backwards count lines q Quit X^D Go forward half a page x Quit without updating .newsrc X^U Go backwards half a page c Cancel the current article Xh Display article header H Display all article headers X! Escape to shell ? Display this message Xr Reply to article using editor K Mark rest of newsgroup read XR Reply--put current article in reply b Go back 1 article in same group XESC-r Reply directly using mailer m Move on to next item in a digest Xf Post a followup article s Save article in file XN Go to newsgroup (next is default) w Save without header Xl List unread articles in group L List all articles in group X X[Press ^L to see article again] END_OF_FILE if test 1326 -ne `wc -c <'vnews.help'`; then echo shar: \"'vnews.help'\" unpacked with wrong size! fi # end of 'vnews.help' fi if test -f 'sendnews.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'sendnews.c'\" else echo shar: Extracting \"'sendnews.c'\" \(1640 characters\) sed "s/^X//" >'sendnews.c' <<'END_OF_FILE' X/* X * sendnews - send news article by mail. X */ X X#ifdef SCCSID Xstatic char *SccsId = "@(#)sendnews.c 2.12 3/21/87"; X#endif /* SCCSID */ X X#include <stdio.h> X#include <ctype.h> X#include "defs.h" X Xchar buffer[BUFSIZ]; X Xint linecount, oflag = 0, aflag = 0, bflag = 0, toflag = 0; X Xextern FILE *popen(); X X/* ARGSUSED */ Xmain(argc, argv) Xchar **argv; X{ X register FILE *out; X char newsgroup[BUFSIZ]; X X while (**(++argv) == '-') { X if (*++*argv == 'o') X oflag++; X else if (**argv == 'a') X aflag++; X else if (**argv == 'b') X bflag++; X else if (**argv == 'n') X strcpy(newsgroup, *(++argv)); X } X if (aflag && bflag) { X fprintf(stderr, "'-a' and '-b' options mutually exclusive.\n"); X exit(1); X } X X#ifdef DEBUG X printf("/bin/mail %s\n", *argv); X sprintf(buffer, "cat"); X#else X#ifdef SENDMAIL X (void) sprintf(buffer, "%s -i -odq %s", SENDMAIL, *argv); X#else /* !SENDMAIL */ X (void) sprintf(buffer, "/bin/mail %s", *argv); X#endif /* !SENDMAIL */ X#endif X if ((out = popen(buffer, "w")) == NULL) { X perror(buffer); X exit(1); X } X X /* Standard mail prelude to make the formatters happy */ X fprintf(out, "Subject: network news article\n"); X fprintf(out, "To: %s\n\n", *argv); X X while (fgets(buffer, sizeof buffer, stdin)) { X if (*newsgroup && ngline()) { X if (oflag) X sprintf(buffer, "%s\n", newsgroup); X else X sprintf(buffer, "Newsgroups: %s\n", newsgroup); X } X putc('N', out); X fputs(buffer, out); X if (ferror(out)) X exit(1); X } X pclose(out); X exit(0); X} X Xngline() X{ X if (oflag) X return linecount == 2; X if (!toflag && (!strncmp("Newsgroups: ", buffer, 12) || X !strncmp("To: ",buffer, 4))) X return ++toflag; X return 0; X} END_OF_FILE if test 1640 -ne `wc -c <'sendnews.c'`; then echo shar: \"'sendnews.c'\" unpacked with wrong size! fi # end of 'sendnews.c' fi if test -f 'sendbatch.sh' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'sendbatch.sh'\" else echo shar: Extracting \"'sendbatch.sh'\" \(1231 characters\) sed "s/^X//" >'sendbatch.sh' <<'END_OF_FILE' X: '@(#)sendbatch.sh 1.10 9/23/86' X Xcflags= XLIM=50000 XCMD='LIBDIR/batch BATCHDIR/$rmt $BLIM' XECHO= XCOMP= XC7= XDOIHAVE= XRNEWS=rnews X Xfor rmt in $* Xdo X case $rmt in X -[bBC]*) cflags="$cflags $rmt"; continue;; X -s*) LIM=`expr "$rmt" : '-s\(.*\)'` X continue;; X -c7) COMP='| LIBDIR/compress $cflags' X C7='| LIBDIR/encode' X ECHO='echo "#! c7unbatch"' X continue;; X -c) COMP='| LIBDIR/compress $cflags' X ECHO='echo "#! cunbatch"' X continue;; X -o*) ECHO=`expr "$rmt" : '-o\(.*\)'` X RNEWS='cunbatch' X continue;; X -i*) DOIHAVE=`expr "$rmt" : '-i\(.*\)'` X if test -z "$DOIHAVE" X then X DOIHAVE=`uuname -l` X fi X continue;; X esac X X if test -n "$COMP" X then X BLIM=`expr $LIM \* 2` X else X BLIM=$LIM X fi X X : make sure $? is zero X while test $? -eq 0 -a \( -s BATCHDIR/$rmt -o -s BATCHDIR/$rmt.work -o \( -n "$DOIHAVE" -a -s BATCHDIR/$rmt.ihave \) \) X do X if test -n "$DOIHAVE" -a -s BATCHDIR/$rmt.ihave X then X mv BATCHDIR/$rmt.ihave BATCHDIR/$rmt.$$ X LIBDIR/inews -t "cmsg ihave $DOIHAVE" -n to.$rmt.ctl < \ X BATCHDIR/$rmt.$$ X rm BATCHDIR/$rmt.$$ X X else X (eval $ECHO; eval $CMD $COMP $C7) | X if test -s BATCHDIR/$rmt.cmd X then X BATCHDIR/$rmt.cmd X else X uux - UUXFLAGS $rmt!$RNEWS X fi X fi X done Xdone END_OF_FILE if test 1231 -ne `wc -c <'sendbatch.sh'`; then echo shar: \"'sendbatch.sh'\" unpacked with wrong size! fi # end of 'sendbatch.sh' fi echo shar: End of shell archive. exit 0 -- "Zeta Microcomputer Software" ACSnet: nick@ultima.cs.uts.oz UUCP: ...!uunet!munnari!ultima.cs.uts.oz!nick Fidonet: Nick Andrew on 3:713/602 (Zeta)
nick@ultima.cs.uts.oz (Nick Andrew) (12/07/89)
#! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of shell archive." # Contents: rextern.c ndir.c iextern.c help header.h rmgroup.sh # patchlevel.h iparams.h ftime.c # Wrapped by nick@nswitgould on Thu Dec 7 22:44:29 1989 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'rextern.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'rextern.c'\" else echo shar: Extracting \"'rextern.c'\" \(1456 characters\) sed "s/^X//" >'rextern.c' <<'END_OF_FILE' X/* X * rextern - external definitions for readnews X */ X X#ifdef SCCSID Xstatic char *SccsId = "@(#)rextern.c 2.17 11/21/86"; X#endif /* SCCSID */ X X/*LINTLIBRARY*/ X X#include "rparams.h" X Xint uid, gid; /* real user/group I.D. */ Xint duid, dgid; /* effective user/group I.D. */ Xint SigTrap; /* set if signal trapped */ Xint savmask; /* old umask */ X#ifdef MINIX X/* mode is external */ Xextern int mode; /* mode of news program */ X#else Xint mode; /* mode of news program */ X#endif X Xstruct hbuf header; /* general-use header structure */ Xchar bfr[LBUFLEN]; /* general-use scratch area */ X X#ifndef ROOTID Xint ROOTID; /* special users id # */ X#endif X Xchar *outfile = "/tmp/M1XXXXXX"; /* output file for -M and -c */ Xchar *infile = "/tmp/M2XXXXXX"; /* -T output from Mail */ Xint ngrp, line = -1; X Xchar filename[BUFLEN]; Xchar afline[BUFLEN]; XFILE *rcfp, *actfp; Xtime_t atime; Xchar newsrc[BUFLEN], groupdir[BUFLEN], *rcline[LINES], rcbuf[LBUFLEN]; Xchar *bitmap, *argvrc[LINES]; Xlong bit, obit, last; Xint readmode = NEXT; Xint news = 0; /* Was there any news to read */ Xint actdirect = FORWARD; /* read direction in ACTIVE file */ Xint rcreadok = FALSE; /* NEWSRC has been read OK */ Xint zapng = FALSE; /* ! out this newsgroup on next updaterc */ Xlong ngsize; /* max article # in this newsgroup */ Xlong minartno; /* min article # in this newsgroup */ X X#ifndef SHELL Xchar *SHELL; X#endif X X#ifndef MAILER Xchar *MAILER; X#endif X Xchar *PAGER = ""; END_OF_FILE if test 1456 -ne `wc -c <'rextern.c'`; then echo shar: \"'rextern.c'\" unpacked with wrong size! fi # end of 'rextern.c' fi if test -f 'ndir.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'ndir.c'\" else echo shar: Extracting \"'ndir.c'\" \(2564 characters\) sed "s/^X//" >'ndir.c' <<'END_OF_FILE' X#include "defs.h" X#if !defined(BSD4_2) && !defined(BSD4_1C) && !defined(HP9K5) X#ifndef MINIX X#include <sys/param.h> X#endif X#include "ndir.h" X X#ifdef SCCSID Xstatic char *SccsId = "@(#)ndir.c 1.11 3/20/87"; X#endif /* SCCSID */ X X/* X * support for Berkeley directory reading routine on a V7 file system X */ X Xextern char *malloc(); X X/* X * open a directory. X */ XDIR * Xopendir(name) Xchar *name; X{ X register DIR *dirp; X register int fd; X X if ((fd = open(name, 0)) == -1) X return NULL; X if ((dirp = (DIR *)malloc(sizeof(DIR))) == NULL) { X close (fd); X return NULL; X } X dirp->dd_fd = fd; X dirp->dd_loc = 0; X return dirp; X} X X/* X * read an old style directory entry and present it as a new one X */ X#ifdef pyr X/* Pyramid in the AT&T universe */ X#define ODIRSIZ 248 Xstruct olddirect { X long od_ino; X short od_fill1, od_fill2; X char od_name[ODIRSIZ]; X}; X#else /* V7 file system */ X#define ODIRSIZ 14 X Xstruct olddirect { X short od_ino; X char od_name[ODIRSIZ]; X}; X#endif /* !pyr */ X X/* X * get next entry in a directory. X */ Xstruct direct * Xreaddir(dirp) Xregister DIR *dirp; X{ X register struct olddirect *dp; X static struct direct dir; X X for (;;) { X if (dirp->dd_loc == 0) { X dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, X DIRBLKSIZ); X if (dirp->dd_size <= 0) X return NULL; X } X if (dirp->dd_loc >= dirp->dd_size) { X dirp->dd_loc = 0; X continue; X } X dp = (struct olddirect *)(dirp->dd_buf + dirp->dd_loc); X dirp->dd_loc += sizeof(struct olddirect); X if (dp->od_ino == 0) X continue; X dir.d_ino = dp->od_ino; X strncpy(dir.d_name, dp->od_name, ODIRSIZ); X dir.d_name[ODIRSIZ] = '\0'; /* insure null termination */ X dir.d_namlen = strlen(dir.d_name); X dir.d_reclen = DIRSIZ(&dir); X return (&dir); X } X} X X/* X * close a directory. X */ Xvoid Xclosedir(dirp) Xregister DIR *dirp; X{ X close(dirp->dd_fd); X dirp->dd_fd = -1; X dirp->dd_loc = 0; X free((char *)dirp); X} X X/* X * seek to an entry in a directory. X * Only values returned by "telldir" should be passed to seekdir. X */ Xvoid Xseekdir(dirp, loc) Xregister DIR *dirp; Xlong loc; X{ X long curloc, base, offset; X struct direct *dp; X long lseek(), telldir(); X X curloc = telldir(dirp); X if (loc == curloc) X return; X base = loc & ~(DIRBLKSIZ - 1); X offset = loc & (DIRBLKSIZ - 1); X (void) lseek(dirp->dd_fd, base, 0); X dirp->dd_loc = 0; X while (dirp->dd_loc < offset) { X dp = readdir(dirp); X if (dp == NULL) X return; X } X} X X/* X * return a pointer into a directory X */ Xlong Xtelldir(dirp) XDIR *dirp; X{ X return lseek(dirp->dd_fd, 0L, 1) - dirp->dd_size + dirp->dd_loc; X} X#endif /* !BSD4_2 && !BSD4_1C && !HP9K5 */ END_OF_FILE if test 2564 -ne `wc -c <'ndir.c'`; then echo shar: \"'ndir.c'\" unpacked with wrong size! fi # end of 'ndir.c' fi if test -f 'iextern.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'iextern.c'\" else echo shar: Extracting \"'iextern.c'\" \(1118 characters\) sed "s/^X//" >'iextern.c' <<'END_OF_FILE' X/* X * iextern - external definitions for inews. X */ X X#ifdef SCCSID Xstatic char *SccsId = "@(#)iextern.c 2.17 9/19/86"; X#endif /* SCCSID */ X X#include "iparams.h" X Xint uid, gid; /* real user/group I.D. */ Xint duid, dgid; /* effective user/group I.D. */ Xint SigTrap; /* set if signal trapped */ Xint savmask; /* old umask */ Xint mode; /* mode of news program */ Xstruct hbuf header; /* general-use header structure */ Xchar bfr[LBUFLEN]; /* general-use scratch area */ Xchar nbuf[LBUFLEN]; /* local newsgroup buffer */ Xchar filename[BUFLEN]; /* general-use file name */ Xchar not_here[SBUFLEN]; /* name of system not to xmit to */ X X#ifndef ROOTID Xint ROOTID; /* special users id # */ X#endif X Xchar *DFLTNG = "general"; /* default newsgroup */ XFILE *infp; /* input file-pointer */ XFILE *actfp; /* active newsgroups file pointer */ Xint tty; /* set if infp is a tty */ Xchar *PARTIAL = "dead.article"; /* place to save partial news */ Xchar *SHELL = "/bin/sh"; /* shell for inews to use */ Xint is_ctl; /* true for a control message */ Xchar is_mod[NAMELEN]; /* contains newsgroup if moderated */ END_OF_FILE if test 1118 -ne `wc -c <'iextern.c'`; then echo shar: \"'iextern.c'\" unpacked with wrong size! fi # end of 'iextern.c' fi if test -f 'help' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'help'\" else echo shar: Extracting \"'help'\" \(1149 characters\) sed "s/^X//" >'help' <<'END_OF_FILE' XCommand Meaning X Xy Yes. (Or just hit return.) Prints this article and goes on. Xn No. Goes on to next article without printing current one. Xd Digest. Breaks a digest article up into seperate articles. Xq Quit. Update .newsrc if -l or -x not used. XU Unsubscribe. You won't be shown this newsgroup anymore. Xc Cancel an article you posted. Xr Reply. Reply to article's author via mail. Xf [title] Submit a follow up article. XN [newsgroup] Go to next newsgroup or named newsgroup. Xs [file] Save. Article is appended to file (default is "Articles"). Xs |program Run program with article as standard input. Xe Erase. Forget that an article was read. Xh Print verbose header. Use H for extremely verbose header. X! Shell escape. X<number> Go to message #<number> in this newsgroup. X- Go back to last article. Xb Back up one article in the current group. XK Mark the rest of the articles in current group as read. Xx Exit. Don't update .newsrc. Xv Version. Print current news version number. Xl List unread articles in newsgroup. XL List all articles in newsgroup. Xc, f, r, e, h, and s can be followed by -'s to refer to the previous article END_OF_FILE if test 1149 -ne `wc -c <'help'`; then echo shar: \"'help'\" unpacked with wrong size! fi # end of 'help' fi if test -f 'header.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'header.h'\" else echo shar: Extracting \"'header.h'\" \(1239 characters\) sed "s/^X//" >'header.h' <<'END_OF_FILE' X/* X * header.h - Article header format X */ X X/* @(#)header.h 2.20 2/22/87 */ X X#define NUNREC 50 X X/* article header */ Xstruct hbuf { X char from[BUFLEN]; /* From: */ X char path[PATHLEN]; /* Path: */ X char nbuf[LBUFLEN]; /* Newsgroups: */ X char title[BUFLEN]; /* Subject: */ X char ident[BUFLEN]; /* Message-ID: */ X char replyto[BUFLEN]; /* Reply-To: */ X char followid[BUFLEN]; /* References: */ X char subdate[DATELEN]; /* Date: (submission) */ X time_t subtime; /* subdate in secs */ X char expdate[DATELEN]; /* Expires: */ X char ctlmsg[PATHLEN]; /* Control: */ X char sender[BUFLEN]; /* Sender: */ X char followto[BUFLEN]; /* Followup-to: */ X char distribution[BUFLEN]; /* Distribution: */ X char organization[BUFLEN]; /* Organization: */ X char numlines[8]; /* Lines: */ X int intnumlines; /* Integer version */ X char keywords[BUFLEN]; /* Keywords: */ X char summary[BUFLEN]; /* Summary: */ X char approved[BUFLEN]; /* Approved: */ X char nf_id[BUFLEN]; /* Nf-ID: */ X char nf_from[BUFLEN]; /* Nf-From: */ X#ifdef DOXREFS X char xref[BUFLEN]; /* Xref: */ X#endif /* DOXREFS */ X char *unrec[NUNREC]; /* unrecognized lines */ X}; X X#define hwrite(hp,fp) ihwrite(hp,fp,0) X#define lhwrite(hp,fp) ihwrite(hp,fp,1) X Xchar *oident(); END_OF_FILE if test 1239 -ne `wc -c <'header.h'`; then echo shar: \"'header.h'\" unpacked with wrong size! fi # end of 'header.h' fi if test -f 'rmgroup.sh' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'rmgroup.sh'\" else echo shar: Extracting \"'rmgroup.sh'\" \(832 characters\) sed "s/^X//" >'rmgroup.sh' <<'END_OF_FILE' X: '@(#)rmgroup.sh 1.8 12/16/86' Xfor group Xdo X qgrp="`echo $group | sed 's/\./\\\./g'`" X if X grep -s "^$qgrp " LIBDIR/active X then X echo "Removing newsgroup $group" X echo "/^$qgrp[ ]/d" >>/tmp/,edit$$ X dir=SPOOLDIR/"`echo $group | sed 's/\./\//g'`" X if test -d $dir X then X rm $dir/* >/dev/null 2>&1 X echo "rmdir $dir >/dev/null 2>&1" >>/tmp/,rmdir$$ X else X echo "$0: $dir: no spool directory" 2>&1 X fi X else X echo "$0: $group: no such newsgroup" 2>&1 X fi Xdone Xecho w >>/tmp/,edit$$ Xecho q >>/tmp/,edit$$ Xecho "Editing LIBDIR/active..." Xed - LIBDIR/active < /tmp/,edit$$ XFIXACTIVE Xecho "Editing LIBDIR/newsgroups..." Xed - LIBDIR/newsgroups < /tmp/,edit$$ Xecho "Removing directories..." Xif test -s /tmp/,rmdir$$ Xthen X sort +1r -o /tmp/,rmdir$$ /tmp/,rmdir$$ X . /tmp/,rmdir$$ Xfi Xrm -f /tmp/,edit$$ /tmp/,rmdir$$ Xexit 0 END_OF_FILE if test 832 -ne `wc -c <'rmgroup.sh'`; then echo shar: \"'rmgroup.sh'\" unpacked with wrong size! fi # end of 'rmgroup.sh' fi if test -f 'patchlevel.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'patchlevel.h'\" else echo shar: Extracting \"'patchlevel.h'\" \(62 characters\) sed "s/^X//" >'patchlevel.h' <<'END_OF_FILE' X#define PATCHLEVEL 8 X X#define NEWS_VERSION "B 2.11 4/10/87" END_OF_FILE if test 62 -ne `wc -c <'patchlevel.h'`; then echo shar: \"'patchlevel.h'\" unpacked with wrong size! fi # end of 'patchlevel.h' fi if test -f 'iparams.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'iparams.h'\" else echo shar: Extracting \"'iparams.h'\" \(577 characters\) sed "s/^X//" >'iparams.h' <<'END_OF_FILE' X/* X * iparams - parameters for inews. X */ X X/* @(#)iparams.h 2.17 11/21/86 */ X X#include "params.h" X#include <errno.h> Xextern int errno; X X/* external declarations specific to inews */ Xextern char nbuf[LBUFLEN], *ARTICLE, *INFILE, *ALIASES, *PARTIAL; X#ifndef ROOTID Xextern int ROOTID; X#endif X X#ifdef NOTIFY Xextern char *TELLME; X#endif /* NOTIFY */ X Xstruct msgtype { X char *m_name; X char *m_who_to; X int (*m_func)(); X}; X Xextern struct msgtype msgtype[]; X Xextern FILE *infp, *actfp; Xextern int tty, is_ctl; Xextern char filename[BUFLEN], is_mod[NAMELEN], not_here[SBUFLEN], *DFLTNG; END_OF_FILE if test 577 -ne `wc -c <'iparams.h'`; then echo shar: \"'iparams.h'\" unpacked with wrong size! fi # end of 'iparams.h' fi if test -f 'ftime.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'ftime.c'\" else echo shar: Extracting \"'ftime.c'\" \(506 characters\) sed "s/^X//" >'ftime.c' <<'END_OF_FILE' X#ifdef SCCSID Xstatic char *SccsId = "@(#)ftime.c 2.5 4/26/85"; X#endif /* SCSCID */ X X#include <sys/types.h> Xstruct timeb X{ X time_t time; X unsigned short millitm; X short timezone; X short dstflag; X}; X X#ifndef MINIX Xextern long timezone; Xextern int daylight; X#else X/* We are using dummies for these two variables */ Xlong timezone = 0L; Xint daylight = 0; X#endif MINIX X Xftime(tp) Xstruct timeb *tp; X{ X long t; X X time(&t); X tp->time = t; X tp->millitm = 0; X tp->timezone = timezone/60; X tp->dstflag = daylight; X} END_OF_FILE if test 506 -ne `wc -c <'ftime.c'`; then echo shar: \"'ftime.c'\" unpacked with wrong size! fi # end of 'ftime.c' fi echo shar: End of shell archive. exit 0 -- "Zeta Microcomputer Software" ACSnet: nick@ultima.cs.uts.oz UUCP: ...!uunet!munnari!ultima.cs.uts.oz!nick Fidonet: Nick Andrew on 3:713/602 (Zeta)
nick@ultima.cs.uts.oz (Nick Andrew) (12/21/89)
It was just pointed out to me (and most politely, if I do say so) that I missed posting one file in my recent News 2.11 posting. This file was ndir.h ... somehow I posted ndir.c twice. Additionally, for those without a Yacc, I have converted getdate.y into getdate.c using BSD Yacc and included that in this posting. There seems to have been a resounding lack of response from the newsgroup about these News postings. Is it just the Xmas cheer (and holidays), or are the postings not getting out? M E R R Y C H R I S T M A S T O A L L . . . Nick. #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of shell archive." # Contents: ndir.h getdate.c # Wrapped by nick@ultima on Thu Dec 21 23:19:46 1989 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'ndir.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'ndir.h'\" else echo shar: Extracting \"'ndir.h'\" \(1281 characters\) sed "s/^X//" >'ndir.h' <<'END_OF_FILE' X/* @(#)ndir.h 1.6 3/9/87 */ X#if defined(HP9K5) X/* He should have included it instead of this, but prevent confusion */ X#include <sys/ndir.h> X#else /* other */ X#ifndef DEV_BSIZE X#define DEV_BSIZE 512 X#endif X#define DIRBLKSIZ DEV_BSIZE X#define MAXNAMLEN 255 X Xstruct direct { X long d_ino; /* inode number of entry */ X short d_reclen; /* length of this record */ X short d_namlen; /* length of string in d_name */ X char d_name[MAXNAMLEN + 1]; /* name must be no longer than this */ X}; X X/* X * The DIRSIZ macro gives the minimum record length which will hold X * the directory entry. This requires the amount of space in struct direct X * without the d_name field, plus enough space for the name with a terminating X * null byte (dp->d_namlen+1), rounded up to a 4 byte boundary. X */ X X#ifdef DIRSIZ X#undef DIRSIZ X#endif /* DIRSIZ */ X#define DIRSIZ(dp) \ X ((sizeof (struct direct) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3)) X X/* X * Definitions for library routines operating on directories. X */ Xtypedef struct _dirdesc { X int dd_fd; X long dd_loc; X long dd_size; X char dd_buf[DIRBLKSIZ]; X} DIR; X#ifndef NULL X#define NULL 0 X#endif Xextern DIR *opendir(); Xextern struct direct *readdir(); Xextern void closedir(); X X#define rewinddir(dirp) seekdir((dirp), (long)0) X#endif /* other */ END_OF_FILE if test 1281 -ne `wc -c <'ndir.h'`; then echo shar: \"'ndir.h'\" unpacked with wrong size! fi # end of 'ndir.h' fi if test -f 'getdate.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'getdate.c'\" else echo shar: Extracting \"'getdate.c'\" \(19766 characters\) sed "s/^X//" >'getdate.c' <<'END_OF_FILE' X# define ID 257 X# define MONTH 258 X# define DAY 259 X# define MERIDIAN 260 X# define NUMBER 261 X# define UNIT 262 X# define MUNIT 263 X# define SUNIT 264 X# define ZONE 265 X# define DAYZONE 266 X# define AGO 267 X X# line 3 "getdate.y" X /* Originally from: Steven M. Bellovin (unc!smb) */ X /* Dept. of Computer Science */ X /* University of North Carolina at Chapel Hill */ X /* @(#)getdate.y 2.15 12/16/86 */ X X#include <sys/types.h> X#ifdef USG Xstruct timeb X{ X time_t time; X unsigned short millitm; X short timezone; X short dstflag; X}; X#else X#include <sys/timeb.h> X#endif X#include <ctype.h> X X#include "defs.h" X#if defined(BSD4_2) || defined (BSD4_1C) X#include <sys/time.h> X#else /* sane */ X#include <time.h> X#endif /* sane */ X X#define NULL 0 X#define daysec (24L*60L*60L) X static int timeflag, zoneflag, dateflag, dayflag, relflag; X static time_t relsec, relmonth; X static int hh, mm, ss, merid, daylight; X static int dayord, dayreq; X static int month, day, year; X static int ourzone; X#define AM 1 X#define PM 2 X#define DAYLIGHT 1 X#define STANDARD 2 X#define MAYBE 3 X#define yyclearin yychar = -1 X#define yyerrok yyerrflag = 0 Xextern int yychar; Xextern short yyerrflag; X#ifndef YYMAXDEPTH X#define YYMAXDEPTH 150 X#endif X#ifndef YYSTYPE X#define YYSTYPE int X#endif XYYSTYPE yylval, yyval; X# define YYERRCODE 256 X X# line 121 "getdate.y" X X Xstatic int mdays[12] = X {31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; X#define epoch 1970 X Xextern struct tm *localtime(); X Xtime_t Xdateconv(mm, dd, yy, h, m, s, mer, zone, dayflag) Xint mm, dd, yy, h, m, s, mer, zone, dayflag; X{ X time_t tod, jdate; X register int i; X time_t timeconv(); X X if (yy < 0) yy = -yy; X if (yy < 100) yy += 1900; X mdays[1] = 28 + (yy%4 == 0 && (yy%100 != 0 || yy%400 == 0)); X if (yy < epoch || yy > 1999 || mm < 1 || mm > 12 || X dd < 1 || dd > mdays[--mm]) return (-1); X jdate = dd-1; X for (i=0; i<mm; i++) jdate += mdays[i]; X for (i = epoch; i < yy; i++) jdate += 365 + (i%4 == 0); X jdate *= daysec; X jdate += zone * 60L; X if ((tod = timeconv(h, m, s, mer)) < 0) return (-1); X jdate += tod; X if (dayflag==DAYLIGHT || (dayflag==MAYBE&&localtime(&jdate)->tm_isdst)) X jdate += -1*60*60; X return (jdate); X} X Xtime_t Xdayconv(ord, day, now) Xint ord, day; time_t now; X{ X register struct tm *loctime; X time_t tod; X time_t daylcorr(); X X tod = now; X loctime = localtime(&tod); X tod += daysec * ((day - loctime->tm_wday + 7) % 7); X tod += 7*daysec*(ord<=0?ord:ord-1); X return daylcorr(tod, now); X} X Xtime_t Xtimeconv(hh, mm, ss, mer) Xregister int hh, mm, ss, mer; X{ X if (mm < 0 || mm > 59 || ss < 0 || ss > 59) return (-1); X switch (mer) { X case AM: if (hh < 1 || hh > 12) return(-1); X return (60L * ((hh%12)*60L + mm)+ss); X case PM: if (hh < 1 || hh > 12) return(-1); X return (60L * ((hh%12 +12)*60L + mm)+ss); X case 24: if (hh < 0 || hh > 23) return (-1); X return (60L * (hh*60L + mm)+ss); X default: return (-1); X } X} Xtime_t Xmonthadd(sdate, relmonth) Xtime_t sdate, relmonth; X{ X struct tm *ltime; X time_t dateconv(); X time_t daylcorr(); X int mm, yy; X X if (relmonth == 0) return 0; X ltime = localtime(&sdate); X mm = 12*ltime->tm_year + ltime->tm_mon + relmonth; X yy = mm/12; X mm = mm%12 + 1; X return daylcorr(dateconv(mm, ltime->tm_mday, yy, ltime->tm_hour, X ltime->tm_min, ltime->tm_sec, 24, ourzone, MAYBE), sdate); X} X Xtime_t Xdaylcorr(future, now) Xtime_t future, now; X{ X int fdayl, nowdayl; X X nowdayl = (localtime(&now)->tm_hour+1) % 24; X fdayl = (localtime(&future)->tm_hour+1) % 24; X return (future-now) + 60L*60L*(nowdayl-fdayl); X} X Xstatic char *lptr; X Xyylex() X{ X extern int yylval; X int sign; X register char c; X register char *p; X char idbuf[20]; X int pcnt; X X for (;;) { X while (isspace(*lptr)) X lptr++; X X if (isdigit(c = *lptr) || c == '-' || c == '+') { X if (c== '-' || c == '+') { X if (c=='-') sign = -1; X else sign = 1; X if (!isdigit(*++lptr)) { X /* yylval = sign; return (NUMBER); */ X return yylex(); /* skip the '-' sign */ X } X } else sign = 1; X yylval = 0; X while (isdigit(c = *lptr++)) X yylval = 10*yylval + c - '0'; X yylval *= sign; X lptr--; X return (NUMBER); X X } else if (isalpha(c)) { X p = idbuf; X while (isalpha(c = *lptr++) || c=='.') X *p++ = c; X *p = '\0'; X lptr--; X return (lookup(idbuf)); X } X X else if (c == '(') { X pcnt = 0; X do { X c = *lptr++; X if (c == '\0') return(c); X else if (c == '(') pcnt++; X else if (c == ')') pcnt--; X } while (pcnt > 0); X } X X else return (*lptr++); X } X} X Xstruct table { X char *name; X int type, value; X}; X Xstruct table mdtab[] = { X {"january", MONTH, 1}, X {"february", MONTH, 2}, X {"march", MONTH, 3}, X {"april", MONTH, 4}, X {"may", MONTH, 5}, X {"june", MONTH, 6}, X {"july", MONTH, 7}, X {"august", MONTH, 8}, X {"september", MONTH, 9}, X {"sept", MONTH, 9}, X {"october", MONTH, 10}, X {"november", MONTH, 11}, X {"december", MONTH, 12}, X X {"sunday", DAY, 0}, X {"monday", DAY, 1}, X {"tuesday", DAY, 2}, X {"tues", DAY, 2}, X {"wednesday", DAY, 3}, X {"wednes", DAY, 3}, X {"thursday", DAY, 4}, X {"thur", DAY, 4}, X {"thurs", DAY, 4}, X {"friday", DAY, 5}, X {"saturday", DAY, 6}, X {0, 0, 0}}; X X#define HRS *60 X#define HALFHR 30 Xstruct table mztab[] = { X {"a.m.", MERIDIAN, AM}, X {"am", MERIDIAN, AM}, X {"p.m.", MERIDIAN, PM}, X {"pm", MERIDIAN, PM}, X {"nst", ZONE, 3 HRS + HALFHR}, /* Newfoundland */ X {"n.s.t.", ZONE, 3 HRS + HALFHR}, X {"ast", ZONE, 4 HRS}, /* Atlantic */ X {"a.s.t.", ZONE, 4 HRS}, X {"adt", DAYZONE, 4 HRS}, X {"a.d.t.", DAYZONE, 4 HRS}, X {"est", ZONE, 5 HRS}, /* Eastern */ X {"e.s.t.", ZONE, 5 HRS}, X {"edt", DAYZONE, 5 HRS}, X {"e.d.t.", DAYZONE, 5 HRS}, X {"cst", ZONE, 6 HRS}, /* Central */ X {"c.s.t.", ZONE, 6 HRS}, X {"cdt", DAYZONE, 6 HRS}, X {"c.d.t.", DAYZONE, 6 HRS}, X {"mst", ZONE, 7 HRS}, /* Mountain */ X {"m.s.t.", ZONE, 7 HRS}, X {"mdt", DAYZONE, 7 HRS}, X {"m.d.t.", DAYZONE, 7 HRS}, X {"pst", ZONE, 8 HRS}, /* Pacific */ X {"p.s.t.", ZONE, 8 HRS}, X {"pdt", DAYZONE, 8 HRS}, X {"p.d.t.", DAYZONE, 8 HRS}, X {"yst", ZONE, 9 HRS}, /* Yukon */ X {"y.s.t.", ZONE, 9 HRS}, X {"ydt", DAYZONE, 9 HRS}, X {"y.d.t.", DAYZONE, 9 HRS}, X {"hst", ZONE, 10 HRS}, /* Hawaii */ X {"h.s.t.", ZONE, 10 HRS}, X {"hdt", DAYZONE, 10 HRS}, X {"h.d.t.", DAYZONE, 10 HRS}, X X {"gmt", ZONE, 0 HRS}, X {"g.m.t.", ZONE, 0 HRS}, X {"bst", DAYZONE, 0 HRS}, /* British Summer Time */ X {"b.s.t.", DAYZONE, 0 HRS}, X {"eet", ZONE, 0 HRS}, /* European Eastern Time */ X {"e.e.t.", ZONE, 0 HRS}, X {"eest", DAYZONE, 0 HRS}, /* European Eastern Summer Time */ X {"e.e.s.t.", DAYZONE, 0 HRS}, X {"met", ZONE, -1 HRS}, /* Middle European Time */ X {"m.e.t.", ZONE, -1 HRS}, X {"mest", DAYZONE, -1 HRS}, /* Middle European Summer Time */ X {"m.e.s.t.", DAYZONE, -1 HRS}, X {"wet", ZONE, -2 HRS }, /* Western European Time */ X {"w.e.t.", ZONE, -2 HRS }, X {"west", DAYZONE, -2 HRS}, /* Western European Summer Time */ X {"w.e.s.t.", DAYZONE, -2 HRS}, X X {"jst", ZONE, -9 HRS}, /* Japan Standard Time */ X {"j.s.t.", ZONE, -9 HRS}, /* Japan Standard Time */ X /* No daylight savings time */ X X {"aest", ZONE, -10 HRS}, /* Australian Eastern Time */ X {"a.e.s.t.", ZONE, -10 HRS}, X {"aesst", DAYZONE, -10 HRS}, /* Australian Eastern Summer Time */ X {"a.e.s.s.t.", DAYZONE, -10 HRS}, X {"acst", ZONE, -(9 HRS + HALFHR)}, /* Australian Central Time */ X {"a.c.s.t.", ZONE, -(9 HRS + HALFHR)}, X {"acsst", DAYZONE, -(9 HRS + HALFHR)}, /* Australian Central Summer */ X {"a.c.s.s.t.", DAYZONE, -(9 HRS + HALFHR)}, X {"awst", ZONE, -8 HRS}, /* Australian Western Time */ X {"a.w.s.t.", ZONE, -8 HRS}, /* (no daylight time there, I'm told */ X {0, 0, 0}}; X Xstruct table unittb[] = { X {"year", MUNIT, 12}, X {"month", MUNIT, 1}, X {"fortnight", UNIT, 14*24*60}, X {"week", UNIT, 7*24*60}, X {"day", UNIT, 1*24*60}, X {"hour", UNIT, 60}, X {"minute", UNIT, 1}, X {"min", UNIT, 1}, X {"second", SUNIT, 1}, X {"sec", SUNIT, 1}, X {0, 0, 0}}; X Xstruct table othertb[] = { X {"tomorrow", UNIT, 1*24*60}, X {"yesterday", UNIT, -1*24*60}, X {"today", UNIT, 0}, X {"now", UNIT, 0}, X {"last", NUMBER, -1}, X {"this", UNIT, 0}, X {"next", NUMBER, 2}, X {"first", NUMBER, 1}, X /* {"second", NUMBER, 2}, */ X {"third", NUMBER, 3}, X {"fourth", NUMBER, 4}, X {"fifth", NUMBER, 5}, X {"sixth", NUMBER, 6}, X {"seventh", NUMBER, 7}, X {"eigth", NUMBER, 8}, X {"ninth", NUMBER, 9}, X {"tenth", NUMBER, 10}, X {"eleventh", NUMBER, 11}, X {"twelfth", NUMBER, 12}, X {"ago", AGO, 1}, X {0, 0, 0}}; X Xstruct table milzone[] = { X {"a", ZONE, 1 HRS}, X {"b", ZONE, 2 HRS}, X {"c", ZONE, 3 HRS}, X {"d", ZONE, 4 HRS}, X {"e", ZONE, 5 HRS}, X {"f", ZONE, 6 HRS}, X {"g", ZONE, 7 HRS}, X {"h", ZONE, 8 HRS}, X {"i", ZONE, 9 HRS}, X {"k", ZONE, 10 HRS}, X {"l", ZONE, 11 HRS}, X {"m", ZONE, 12 HRS}, X {"n", ZONE, -1 HRS}, X {"o", ZONE, -2 HRS}, X {"p", ZONE, -3 HRS}, X {"q", ZONE, -4 HRS}, X {"r", ZONE, -5 HRS}, X {"s", ZONE, -6 HRS}, X {"t", ZONE, -7 HRS}, X {"u", ZONE, -8 HRS}, X {"v", ZONE, -9 HRS}, X {"w", ZONE, -10 HRS}, X {"x", ZONE, -11 HRS}, X {"y", ZONE, -12 HRS}, X {"z", ZONE, 0 HRS}, X {0, 0, 0}}; X Xlookup(id) Xchar *id; X{ X#define gotit (yylval=i->value, i->type) X X char idvar[128]; X register char *j, *k; X register struct table *i; X int abbrev; X X (void) strcpy(idvar, id); X j = idvar; X k = id - 1; X while (*++k) X *j++ = isupper(*k) ? tolower(*k) : *k; X *j = '\0'; X X if (strlen(idvar) == 3) X abbrev = 1; X else X if (strlen(idvar) == 4 && idvar[3] == '.') { X abbrev = 1; X idvar[3] = '\0'; X } X else X abbrev = 0; X X for (i = mdtab; i->name; i++) { X k = idvar; X for (j = i->name; *j++ == *k++;) { X if (abbrev && j == i->name+3) X return gotit; X if (j[-1] == 0) X return gotit; X } X } X X for (i = mztab; i->name; i++) X if (strcmp(i->name, idvar) == 0) X return gotit; X X for (i=mztab; i->name; i++) X if (strcmp(i->name, idvar) == 0) X return gotit; X X for (i=unittb; i->name; i++) X if (strcmp(i->name, idvar) == 0) X return gotit; X X if (idvar[strlen(idvar)-1] == 's') X idvar[strlen(idvar)-1] = '\0'; X X for (i=unittb; i->name; i++) X if (strcmp(i->name, idvar) == 0) X return gotit; X X for (i = othertb; i->name; i++) X if (strcmp(i->name, idvar) == 0) X return gotit; X X if (strlen(idvar) == 1 && isalpha(*idvar)) { X for (i = milzone; i->name; i++) X if (strcmp(i->name, idvar) == 0) X return gotit; X } X X return ID; X} X Xtime_t Xgetdate(p, now) Xchar *p; Xstruct timeb *now; X{ X#define mcheck(f) if (f>1) err++ X time_t monthadd(); X int err; X struct tm *lt; X struct timeb ftz; X X time_t sdate, tod; X X lptr = p; X if (now == ((struct timeb *) NULL)) { X now = &ftz; X ftime(&ftz); X } X lt = localtime(&now->time); X year = lt->tm_year; X month = lt->tm_mon+1; X day = lt->tm_mday; X relsec = 0; relmonth = 0; X timeflag=zoneflag=dateflag=dayflag=relflag=0; X ourzone = now->timezone; X daylight = MAYBE; X hh = mm = ss = 0; X merid = 24; X X if (err = yyparse()) return (-1); X X mcheck(timeflag); X mcheck(zoneflag); X mcheck(dateflag); X mcheck(dayflag); X X if (err) return (-1); X if (dateflag || timeflag || dayflag) { X sdate = dateconv(month,day,year,hh,mm,ss,merid,ourzone,daylight); X if (sdate < 0) return -1; X } X else { X sdate = now->time; X if (relflag == 0) X sdate -= (lt->tm_sec + lt->tm_min*60 + X lt->tm_hour*(60L*60L)); X } X X sdate += relsec; X sdate += monthadd(sdate, relmonth); X X if (dayflag && !dateflag) { X tod = dayconv(dayord, dayreq, sdate); X sdate += tod; X } X X return sdate; X} X Xyyerror(s) char *s; X{} Xshort yyexca[] ={ X-1, 1, X 0, -1, X -2, 0, X }; X# define YYNPROD 35 X# define YYLAST 220 Xshort yyact[]={ X X 12, 13, 21, 9, 14, 15, 16, 10, 11, 34, X 17, 39, 40, 19, 38, 37, 36, 30, 29, 28, X 26, 35, 31, 27, 8, 7, 6, 5, 4, 3, X 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, X 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, X 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, X 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, X 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, X 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, X 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, X 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, X 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, X 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, X 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, X 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, X 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, X 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, X 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, X 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, X 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, X 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, X 0, 32, 33, 22, 20, 18, 0, 23, 24, 25 }; Xshort yypact[]={ X X-1000,-258,-1000,-1000,-1000,-1000,-1000,-257,-1000, -45, X-1000,-1000,-241, -21,-1000,-1000,-1000,-1000,-1000,-242, X-1000,-243,-244,-1000,-1000,-1000, -22,-1000, -49, -26, X-1000,-245,-1000,-1000,-246,-247,-1000,-249,-1000,-1000, X-1000 }; Xshort yypgo[]={ X X 0, 31, 30, 29, 28, 27, 26, 25, 24 }; Xshort yyr1[]={ X X 0, 1, 1, 2, 2, 2, 2, 2, 2, 8, X 3, 3, 3, 3, 3, 3, 3, 4, 4, 6, X 6, 6, 5, 5, 5, 5, 5, 5, 7, 7, X 7, 7, 7, 7, 7 }; Xshort yyr2[]={ X X 0, 0, 2, 1, 1, 1, 1, 1, 1, 1, X 2, 3, 4, 4, 5, 6, 6, 1, 1, 1, X 2, 2, 3, 5, 2, 4, 2, 3, 2, 2, X 2, 1, 1, 1, 2 }; Xshort yychk[]={ X X-1000, -1, -2, -3, -4, -5, -6, -7, -8, 261, X 265, 266, 258, 259, 262, 263, 264, 267, 260, 58, X 259, 47, 258, 262, 263, 264, 261, 44, 261, 261, X 261, 44, 260, 261, 58, 47, 261, 261, 261, 260, X 261 }; Xshort yydef[]={ X X 1, -2, 2, 3, 4, 5, 6, 7, 8, 9, X 17, 18, 0, 19, 31, 32, 33, 34, 10, 0, X 21, 0, 26, 28, 29, 30, 24, 20, 11, 22, X 27, 0, 12, 13, 0, 0, 25, 14, 23, 15, X 16 }; X#ifndef lint Xstatic char yaccpar_sccsid[] = "@(#)yaccpar 1.6 88/02/08 SMI"; /* from UCB 4.1 83/02/11 */ X#endif X X# X# define YYFLAG -1000 X# define YYERROR goto yyerrlab X# define YYACCEPT return(0) X# define YYABORT return(1) X X/* parser for yacc output */ X X#ifdef YYDEBUG Xint yydebug = 0; /* 1 for debugging */ X#endif XYYSTYPE yyv[YYMAXDEPTH]; /* where the values are stored */ Xint yychar = -1; /* current input token number */ Xint yynerrs = 0; /* number of errors */ Xshort yyerrflag = 0; /* error recovery flag */ X Xyyparse() { X X short yys[YYMAXDEPTH]; X short yyj, yym; X register YYSTYPE *yypvt; X register short yystate, *yyps, yyn; X register YYSTYPE *yypv; X register short *yyxi; X X yystate = 0; X yychar = -1; X yynerrs = 0; X yyerrflag = 0; X yyps= &yys[-1]; X yypv= &yyv[-1]; X X yystack: /* put a state and value onto the stack */ X X#ifdef YYDEBUG X if( yydebug ) printf( "state %d, char 0%o\n", yystate, yychar ); X#endif X if( ++yyps>= &yys[YYMAXDEPTH] ) { yyerror( "yacc stack overflow" ); return(1); } X *yyps = yystate; X ++yypv; X *yypv = yyval; X X yynewstate: X X yyn = yypact[yystate]; X X if( yyn<= YYFLAG ) goto yydefault; /* simple state */ X X if( yychar<0 ) if( (yychar=yylex())<0 ) yychar=0; X if( (yyn += yychar)<0 || yyn >= YYLAST ) goto yydefault; X X if( yychk[ yyn=yyact[ yyn ] ] == yychar ){ /* valid shift */ X yychar = -1; X yyval = yylval; X yystate = yyn; X if( yyerrflag > 0 ) --yyerrflag; X goto yystack; X } X X yydefault: X /* default state action */ X X if( (yyn=yydef[yystate]) == -2 ) { X if( yychar<0 ) if( (yychar=yylex())<0 ) yychar = 0; X /* look through exception table */ X X for( yyxi=yyexca; (*yyxi!= (-1)) || (yyxi[1]!=yystate) ; yyxi += 2 ) ; /* VOID */ X X while( *(yyxi+=2) >= 0 ){ X if( *yyxi == yychar ) break; X } X if( (yyn = yyxi[1]) < 0 ) return(0); /* accept */ X } X X if( yyn == 0 ){ /* error */ X /* error ... attempt to resume parsing */ X X switch( yyerrflag ){ X X case 0: /* brand new error */ X X yyerror( "syntax error" ); X yyerrlab: X ++yynerrs; X X case 1: X case 2: /* incompletely recovered error ... try again */ X X yyerrflag = 3; X X /* find a state where "error" is a legal shift action */ X X while ( yyps >= yys ) { X yyn = yypact[*yyps] + YYERRCODE; X if( yyn>= 0 && yyn < YYLAST && yychk[yyact[yyn]] == YYERRCODE ){ X yystate = yyact[yyn]; /* simulate a shift of "error" */ X goto yystack; X } X yyn = yypact[*yyps]; X X /* the current yyps has no shift onn "error", pop stack */ X X#ifdef YYDEBUG X if( yydebug ) printf( "error recovery pops state %d, uncovers %d\n", *yyps, yyps[-1] ); X#endif X --yyps; X --yypv; X } X X /* there is no state on the stack with an error shift ... abort */ X X yyabort: X return(1); X X X case 3: /* no shift yet; clobber input char */ X X#ifdef YYDEBUG X if( yydebug ) printf( "error recovery discards char %d\n", yychar ); X#endif X X if( yychar == 0 ) goto yyabort; /* don't discard EOF, quit */ X yychar = -1; X goto yynewstate; /* try again in the same state */ X X } X X } X X /* reduction by production yyn */ X X#ifdef YYDEBUG X if( yydebug ) printf("reduce %d\n",yyn); X#endif X yyps -= yyr2[yyn]; X yypvt = yypv; X yypv -= yyr2[yyn]; X yyval = yypv[1]; X yym=yyn; X /* consult goto table to find next state */ X yyn = yyr1[yyn]; X yyj = yypgo[yyn] + *yyps + 1; X if( yyj>=YYLAST || yychk[ yystate = yyact[yyj] ] != -yyn ) yystate = yyact[yypgo[yyn]]; X switch(yym){ X Xcase 3: X# line 48 "getdate.y" X X {timeflag++;} break; Xcase 4: X# line 50 "getdate.y" X X {zoneflag++;} break; Xcase 5: X# line 52 "getdate.y" X X {dateflag++;} break; Xcase 6: X# line 54 "getdate.y" X X {dayflag++;} break; Xcase 7: X# line 56 "getdate.y" X X {relflag++;} break; Xcase 9: X# line 60 "getdate.y" X X {if (timeflag && dateflag && !relflag) year = yypvt[-0]; X else {timeflag++;hh = yypvt[-0]/100;mm = yypvt[-0]%100;ss = 0;merid = 24;}} break; Xcase 10: X# line 64 "getdate.y" X X {hh = yypvt[-1]; mm = 0; ss = 0; merid = yypvt[-0];} break; Xcase 11: X# line 66 "getdate.y" X X {hh = yypvt[-2]; mm = yypvt[-0]; merid = 24;} break; Xcase 12: X# line 68 "getdate.y" X X {hh = yypvt[-3]; mm = yypvt[-1]; merid = yypvt[-0];} break; Xcase 13: X# line 70 "getdate.y" X X {hh = yypvt[-3]; mm = yypvt[-1]; merid = 24; X daylight = STANDARD; ourzone = -(yypvt[-0]%100 + 60*(yypvt[-0]/100));} break; Xcase 14: X# line 73 "getdate.y" X X {hh = yypvt[-4]; mm = yypvt[-2]; ss = yypvt[-0]; merid = 24;} break; Xcase 15: X# line 75 "getdate.y" X X {hh = yypvt[-5]; mm = yypvt[-3]; ss = yypvt[-1]; merid = yypvt[-0];} break; Xcase 16: X# line 77 "getdate.y" X X {hh = yypvt[-5]; mm = yypvt[-3]; ss = yypvt[-1]; merid = 24; X daylight = STANDARD; ourzone = -(yypvt[-0]%100 + 60*(yypvt[-0]/100));} break; Xcase 17: X# line 81 "getdate.y" X X {ourzone = yypvt[-0]; daylight = STANDARD;} break; Xcase 18: X# line 83 "getdate.y" X X {ourzone = yypvt[-0]; daylight = DAYLIGHT;} break; Xcase 19: X# line 86 "getdate.y" X X {dayord = 1; dayreq = yypvt[-0];} break; Xcase 20: X# line 88 "getdate.y" X X {dayord = 1; dayreq = yypvt[-1];} break; Xcase 21: X# line 90 "getdate.y" X X {dayord = yypvt[-1]; dayreq = yypvt[-0];} break; Xcase 22: X# line 93 "getdate.y" X X {month = yypvt[-2]; day = yypvt[-0];} break; Xcase 23: X# line 95 "getdate.y" X X {month = yypvt[-4]; day = yypvt[-2]; year = yypvt[-0];} break; Xcase 24: X# line 97 "getdate.y" X X {month = yypvt[-1]; day = yypvt[-0];} break; Xcase 25: X# line 99 "getdate.y" X X {month = yypvt[-3]; day = yypvt[-2]; year = yypvt[-0];} break; Xcase 26: X# line 101 "getdate.y" X X {month = yypvt[-0]; day = yypvt[-1];} break; Xcase 27: X# line 103 "getdate.y" X X {month = yypvt[-1]; day = yypvt[-2]; year = yypvt[-0];} break; Xcase 28: X# line 107 "getdate.y" X X {relsec += 60L * yypvt[-1] * yypvt[-0];} break; Xcase 29: X# line 109 "getdate.y" X X {relmonth += yypvt[-1] * yypvt[-0];} break; Xcase 30: X# line 111 "getdate.y" X X {relsec += yypvt[-1];} break; Xcase 31: X# line 113 "getdate.y" X X {relsec += 60L * yypvt[-0];} break; Xcase 32: X# line 115 "getdate.y" X X {relmonth += yypvt[-0];} break; Xcase 33: X# line 117 "getdate.y" X X {relsec++;} break; Xcase 34: X# line 119 "getdate.y" X X {relsec = -relsec; relmonth = -relmonth;} break; X } X goto yystack; /* stack new state and value */ X X } END_OF_FILE if test 19766 -ne `wc -c <'getdate.c'`; then echo shar: \"'getdate.c'\" unpacked with wrong size! fi # end of 'getdate.c' fi echo shar: End of shell archive. exit 0 -- "Zeta Microcomputer Software" ACSnet: nick@ultima.cs.uts.oz UUCP: ...!uunet!munnari!ultima.cs.uts.oz!nick Fidonet: Nick Andrew on 3:713/602 (Zeta)