Path: utzoo!utgpu!jarvis.csri.toronto.edu!mailrus!shadooby!samsung!munnari.oz.au!basser!ultima!nick From: nick@ultima.cs.uts.oz (Nick Andrew) Newsgroups: comp.os.minix Subject: News for Minix (part 5 of 12) Keywords: news Message-ID: <16747@ultima.cs.uts.oz> Date: 7 Dec 89 11:52:32 GMT Organization: Comp Sci, NSWIT, Australia Lines: 2291 #! /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 '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 ... X * or X * ihave X * with s in message body. X * X * The other system is telling you it has article , 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 ... X * or X * sendme X * with s in message body. X * The other system wants me to send out article . 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 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 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 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 \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 X#else X#include "ndir.h" X#endif /* !BSD4_2 && !BSD4_1C */ X#include X#include 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)