home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
unix
/
volume19
/
cnews2
/
part13
< prev
next >
Wrap
Text File
|
1989-06-29
|
49KB
|
2,220 lines
Subject: v19i090: Cnews production release, Part13/19
Newsgroups: comp.sources.unix
Sender: sources
Approved: rsalz@uunet.UU.NET
Submitted-by: utzoo!henry
Posting-number: Volume 19, Issue 90
Archive-name: cnews2/part13
: ---CUT HERE---
echo 'nntpdiffs/src/misc.c':
sed 's/^X//' >'nntpdiffs/src/misc.c' <<'!'
X#ifndef lint
Xstatic char *sccsid = "@(#)misc.c 1.25 (Berkeley) 2/6/88";
X#endif
X
X#include "../common/conf.h"
X
X#include "common.h"
X
X/*
X * open_valid_art -- determine if a given article name is valid;
X * if it is, return a file pointer to the open article,
X * along with a unique id of the article.
X *
X * Parameters: "artname" is a string containing the
X * name of the article.
X * "id" is space for us to put the article
X * id in.
X *
X * Returns: File pointer to the open article if the
X * article is valid; NULL otherwise
X *
X * Side effects: None.
X */
X
XFILE *
Xopen_valid_art(artname, id)
X char *artname;
X char *id;
X{
X static int crnt_art_num;
X static char crnt_art_id[MAXBUFLEN];
X int fd;
X struct stat statbuf;
X
X if (art_fp != NULL) {
X if (crnt_art_num == atoi(artname)) {
X if (fseek(art_fp, (long) 0, 0) < 0)
X close_crnt();
X else {
X (void) strcpy(id, crnt_art_id);
X return (art_fp);
X }
X } else
X close_crnt();
X }
X
X art_fp = fopen(artname, "r");
X
X if (art_fp == NULL)
X return (NULL);
X
X fd = fileno(art_fp);
X
X if (fstat(fd, &statbuf) < 0) {
X close_crnt();
X return (NULL);
X }
X
X if ((statbuf.st_mode & S_IFREG) != S_IFREG) {
X close_crnt();
X return (NULL);
X }
X
X get_id(art_fp, id);
X (void) strcpy(crnt_art_id, id);
X crnt_art_num = atoi(artname);
X return (art_fp);
X}
X
X
X/*
X * gethistent -- return the path name of an article if it's
X * in the history file.
X *
X * Parameters: "msg_id" is the message ID of the
X * article, enclosed in <>'s.
X *
X * Returns: A char pointer to a static data area
X * containing the full pathname of the
X * article, or NULL if the message-id is not
X * in thef history file.
X *
X * Side effects: opens dbm database
X * (only once, keeps it open after that).
X */
X
X#ifndef NDBM
X# ifndef DBM
X# ifndef USGHIST
X# define USGHIST
X# endif not USGHIST
X# endif not DBM
X#endif not DBM
X
Xchar *
Xgethistent(msg_id)
X char *msg_id;
X{
X char line[MAXBUFLEN];
X char *tmp;
X register char *cp;
X long ltmp;
X static char path[MAXPATHLEN];
X#ifdef USGHIST
X char *histfile();
X register int len;
X#else not USGHIST
X#ifdef DBM
X static int dbopen = 0;
X datum fetch();
X#else not DBM
X static DBM *db = NULL; /* History file, dbm version */
X#endif DBM
X datum key, content;
X#endif USGHIST
X static FILE *hfp = NULL; /* history file, text version */
X
X#ifdef USGHIST
X hfp = fopen(histfile(msg_id), "r");
X if (hfp == NULL) {
X#ifdef SYSLOG
X syslog(LOG_ERR, "gethistent: histfile: %m");
X#endif SYSLOG
X return (NULL);
X }
X
X len = strlen(msg_id);
X while (fgets(line, sizeof (line), hfp))
X if (!strncasecmp(msg_id, line, len))
X break;
X
X if (feof(hfp)) {
X (void) fclose(hfp);
X return (NULL);
X }
X#else not USGHIST
X#ifdef DBM
X if (!dbopen) {
X if (dbminit(historyfile) < 0) {
X#ifdef SYSLOG
X syslog(LOG_ERR, "openartbyid: dbminit %s: %m",
X historyfile);
X#endif SYSLOG
X return (NULL);
X } else
X dbopen = 1;
X }
X#else /* ndbm */
X if (db == NULL) {
X db = dbm_open(historyfile, O_RDONLY, 0);
X if (db == NULL) {
X#ifdef SYSLOG
X syslog(LOG_ERR, "openartbyid: dbm_open %s: %m",
X historyfile);
X#endif SYSLOG
X return (NULL);
X }
X }
X#endif DBM
X
X key.dptr = msg_id;
X key.dsize = strlen(msg_id) + 1;
X
X#ifdef DBM
X content = fetch(key);
X#else /* ndbm */
X content = dbm_fetch(db, key);
X#endif DBM
X if (content.dptr == NULL)
X return (NULL);
X
X if (hfp == NULL) {
X hfp = fopen(historyfile, "r");
X if (hfp == NULL) {
X#ifdef SYSLOG
X syslog(LOG_ERR, "message: fopen %s: %m",
X historyfile);
X#endif SYSLOG
X return (NULL);
X }
X }
X
X bcopy(content.dptr, (char *)<mp, sizeof (long));
X if (fseek(hfp, ltmp, 0) < 0) {
X#ifdef SYSLOG
X syslog(LOG_ERR, "message: fseek: %m");
X#endif SYSLOG
X return (NULL);
X }
X
X (void) fgets(line, sizeof(line), hfp);
X#endif USGHIST
X
X if ((cp = index(line, '\n')) != NULL)
X *cp = '\0';
X cp = index(line, '\t');
X if (cp != NULL)
X cp = index(cp+1, '\t');
X if (cp == NULL) {
X#ifdef SYSLOG
X syslog(LOG_ERR,
X "message: malformed line in history file at %ld bytes, id %s",
X ltmp, msg_id);
X#endif SYSLOG
X return (NULL);
X }
X tmp = cp+1;
X
X if ((cp = index(tmp, ' ')) != NULL)
X *cp = '\0';
X
X while ((cp = index(tmp, '.')) != NULL)
X *cp = '/';
X
X (void) strcpy(path, spooldir);
X (void) strcat(path, "/");
X (void) strcat(path, tmp);
X
X return (path);
X}
X
X/*
X * openartbyid -- open an article by message-id.
X *
X * Arguments: "msg_id" is the message-id of the article
X * to open.
X *
X * Returns: File pointer to opened article, or NULL if
X * the article was not in the history file or
X * could not be opened.
X *
X * Side effects: Opens article.
X */
X
XFILE *
Xopenartbyid(msg_id)
X char *msg_id;
X{
X char *path;
X
X path = gethistent(msg_id);
X if (path != NULL)
X return (fopen(path, "r"));
X else
X return (NULL);
X}
X
X
X/*
X * check_ngperm -- check to see if they're allowed to see this
X * article by matching Newsgroups: and Distribution: line.
X *
X * Parameters: "fp" is the file pointer of this article.
X *
X * Returns: 0 if they're not allowed to see it.
X * 1 if they are.
X *
X * Side effects: None.
X */
X
Xcheck_ngperm(fp)
X register FILE *fp;
X{
X char buf[MAXBUFLEN];
X register char *cp;
X static char **ngarray;
X int ngcount;
X
X if (ngpermcount == 0)
X return (1);
X
X while (fgets(buf, sizeof (buf), fp) != NULL) {
X if (buf[0] == '\n') /* End of header */
X break;
X if (buf[0] != 'N' && buf[0] != 'n')
X continue;
X cp = index(buf, '\n');
X if (cp)
X *cp = '\0';
X cp = index(buf, ':');
X if (cp == NULL)
X continue;
X *cp = '\0';
X if (!strcasecmp(buf, "newsgroups")) {
X ngcount = get_nglist(&ngarray, cp+2);
X break;
X }
X }
X
X (void) rewind(fp);
X
X if (ngcount == 0) /* Either no newgroups or null entry */
X return (1);
X
X return (ngmatch(s1strneql, ALLBUT,
X ngpermlist, ngpermcount, ngarray, ngcount));
X}
X
X
X/*
X * spew -- spew out the contents of a file to stdout, doing
X * the necessary cr-lf additions at the end. Finish with
X * a "." on a line by itself, and an fflush(stdout).
X *
X * Parameters: "how" tells what part of the file we
X * want spewed:
X * ARTICLE The entire thing.
X * HEAD Just the first part.
X * BODY Just the second part.
X * "fp" is the open file to spew from.
X *
X * Returns: Nothing.
X *
X * Side effects: Changes current position in file.
X */
X
Xspew(fp, how)
X FILE *fp;
X int how;
X{
X char line[NNTP_STRLEN];
X register char *cp;
X
X#ifdef LOG
X ++arts_acsd;
X#endif
X
X if (how == STAT) {
X (void) fflush(stdout);
X return;
X }
X
X while (fgets(line, sizeof(line)-6, fp) != NULL && *line != '\n') {
X if (how == BODY) /* We need to skip this anyway */
X continue;
X cp = index(line, '\n');
X if (cp != NULL)
X *cp = '\0';
X if (*line == '.')
X putchar('.');
X putline(line);
X if (cp == NULL) {
X for (;;) {
X if ((fgets(line, sizeof(line)-6, fp) == NULL)
X || (index(line, '\n') != NULL))
X break;
X }
X }
X }
X
X if (how == HEAD) {
X putchar('.');
X putchar('\r');
X putchar('\n');
X (void) fflush(stdout);
X return;
X } else if (how == ARTICLE) {
X putchar('\r');
X putchar('\n');
X }
X
X while (fgets(line, sizeof(line)-6, fp) != NULL) {
X cp = index(line, '\n');
X if (cp != NULL)
X *cp = '\0';
X if (*line == '.')
X putchar('.');
X putline(line);
X
X if (cp == NULL) {
X for (;;) {
X if ((fgets(line, sizeof(line)-6, fp) == NULL)
X || (index(line, '\n') != NULL))
X break;
X }
X }
X }
X putchar('.');
X putchar('\r');
X putchar('\n');
X (void) fflush(stdout);
X}
X
X
X/*
X * get_id -- get the message id of the current article.
X *
X * Parameters: "art_fp" is a pointer to the open file.
X * "id" is space for the message ID.
X *
X * Returns: Nothing.
X *
X * Side effects: Seeks and rewinds on "art_fp".
X * Changes space pointed to by "id".
X */
X
Xget_id(art_fp, id)
X register FILE *art_fp;
X char *id;
X{
X char line[MAXBUFLEN];
X register char *cp;
X
X while (fgets(line, sizeof(line), art_fp) != NULL) {
X if (*line == '\n')
X break;
X if (*line == 'M' || *line == 'm') { /* "Message-ID" */
X if ((cp = index(line, ' ')) != NULL) {
X *cp = '\0';
X if (!strcasecmp(line, "Message-ID:")) {
X (void) strcpy(id, cp + 1);
X if ((cp = index(id, '\n')) != NULL)
X *cp = '\0';
X (void) rewind(art_fp);
X return;
X }
X }
X }
X }
X (void) rewind(art_fp);
X (void) strcpy(id, "<0>");
X}
X
X
X/*
X * close_crnt -- close the current article file pointer, if it's
X * open.
X *
X * Parameters: None.
X *
X * Returns: Nothing.
X *
X * Side effects: Closes "art_fp" if it's open; sets "art_fp" to NULL.
X */
X
Xclose_crnt()
X{
X if (art_fp != NULL)
X (void) fclose(art_fp);
X art_fp = NULL;
X}
X
X
X/*
X * findart -- find an article number in the article array.
X *
X * Parameters: "artname" is a string containing
X * the name of the article.
X *
X * Returns: An index into "art_array",
X * or -1 if "artname" isn't in "art_array".
X *
X * Side effects: None.
X *
X * Improvement: Replace this linear search with a binary one.
X */
X
Xfindart(artname)
X char *artname;
X{
X register int i, artnum;
X
X artnum = atoi(artname);
X
X for (i = 0; i < num_arts; ++i)
X if (art_array[i] == artnum)
X return(i);
X
X return (-1);
X}
X
X
X/*
X * get_distlist -- return a nicely set up array of distribution groups
X * along with a count, when given an NNTP-spec distribution list
X * in the form <dist1,dist2,...,distn>.
X *
X * Parameters: "array" is storage for our array,
X * set to point at some static data.
X * "list" is the NNTP distribution list.
X *
X * Returns: Number of distributions found.
X * -1 on error.
X *
X * Side effects: Changes static data area.
X */
X
Xget_distlist(array, list)
X char ***array;
X char *list;
X{
X char *cp;
X int distcount;
X static char **dist_list = (char **) NULL;
X
X if (list[0] != '<')
X return (-1);
X
X cp = index(list + 1, '>');
X if (cp != NULL)
X *cp = '\0';
X else
X return (-1);
X
X for (cp = list + 1; *cp != '\0'; ++cp)
X if (*cp == ',')
X *cp = ' ';
X distcount = parsit(list + 1, &dist_list);
X *array = dist_list;
X return (distcount);
X}
X
X
X/*
X * lower -- convert a character to lower case, if it's upper case.
X *
X * Parameters: "c" is the character to be
X * converted.
X *
X * Returns: "c" if the character is not
X * upper case, otherwise the lower
X * case eqivalent of "c".
X *
X * Side effects: None.
X */
X
Xchar
Xlower(c)
X register char c;
X{
X if (isascii(c) && isupper(c))
X c = c - 'A' + 'a';
X return (c);
X}
X
X
X/* the following is from news 2.11 */
X
X#ifdef USG
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[BUFSIZ];
X
X chr = findhfdigit(hline);
X sprintf(subfile, "%s.d/%c", HISTORY_FILE, 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}
Xbcopy(s, d, l)
X register char *s, *d;
X register int l;
X{
X while (l-- > 0)
X *d++ = *s++;
X}
X
Xbcmp(s1, s2, l)
X register char *s1, *s2;
X register int l;
X{
X if (l == 0)
X return (0);
X
X do
X if (*s1++ != *s2++)
X break;
X while (--l);
X
X return (l);
X}
X
Xbzero(p, l)
X register char *p;
X register int l;
X{
X while (l-- > 0)
X *p++ = 0;
X}
X
Xdup2(x,y)
Xint x,y;
X{
X close(y);
X return(fcntl(x, F_DUPFD,y ));
X}
X#endif USG
!
echo 'nntpdiffs/src/newnews.c':
sed 's/^X//' >'nntpdiffs/src/newnews.c' <<'!'
X#ifndef lint
Xstatic char *sccsid = "@(#)newnews.c 1.19 (Berkeley) 2/6/88";
X#endif
X
X#include "common.h"
X#include "time.h"
X
X#ifdef LOG
Xint nn_told = 0;
Xint nn_took = 0;
X#endif
X
X
X/*
X * NEWNEWS newsgroups date time ["GMT"] [<distributions>]
X *
X * Return the message-id's of any news articles past
X * a certain date and time, within the specified distributions.
X *
X */
X
Xnewnews(argc, argv)
X register int argc;
X char *argv[];
X{
X register char *cp, *ngp;
X char *key;
X char datebuf[32];
X char line[MAXBUFLEN];
X char **distlist, **histlist;
X static char **nglist;
X int distcount, ngcount, histcount;
X int all;
X FILE *fp;
X long date;
X long dtol();
X char *ltod();
X#ifdef USG
X FILE *tmplst;
X int i;
X char *tmpfile;
X#endif USG
X
X if (argc < 4) {
X printf("%d Usage: NEWNEWS newsgroups yymmdd hhmmss [\"GMT\"] [<distributions>].\r\n",
X ERR_CMDSYN);
X (void) fflush(stdout);
X return;
X }
X
X#ifdef LOG
X sprintf(line, "%s newnews %s %s %s %s %s",
X hostname,
X argv[1],
X argv[2],
X argv[3],
X (argc >= 5 && *argv[4] == 'G') ? "GMT" : "local",
X (argc >= 5 && *argv[argc-1] == '<') ? argv[argc-1] : "none");
X syslog(LOG_INFO, line);
X#endif
X
X all = (argv[1][0] == '*' && argv[1][1] == '\0');
X if (!all) {
X ngcount = get_nglist(&nglist, argv[1]);
X if (ngcount == 0) {
X printf("%d Bogus newsgroup specifier: %s\r\n",
X ERR_CMDSYN, argv[1]);
X (void) fflush(stdout);
X return;
X }
X }
X
X /* YYMMDD HHMMSS */
X if (strlen(argv[2]) != 6 || strlen(argv[3]) != 6) {
X printf("%d Date/time must be in form YYMMDD HHMMSS.\r\n",
X ERR_CMDSYN);
X (void) fflush(stdout);
X return;
X }
X
X (void) strcpy(datebuf, argv[2]);
X (void) strcat(datebuf, argv[3]);
X
X argc -= 4;
X argv += 4;
X
X /*
X * Flame on. The history file is not stored in GMT, but
X * in local time. So we have to convert GMT to local time
X * if we're given GMT, otherwise we need only chop off the
X * the seconds. Such braindamage.
X */
X
X key = datebuf; /* Unless they specify GMT */
X
X if (argc > 0) {
X if (!strcasecmp(*argv, "GMT")) { /* Which we handle here */
X date = dtol(datebuf);
X if (date < 0) {
X printf("%d Invalid date specification.\r\n",
X ERR_CMDSYN);
X (void) fflush(stdout);
X return;
X }
X date = gmt_to_local(date);
X key = ltod(date);
X ++argv;
X --argc;
X }
X }
X
X /* So, key now points to the local time, but we need to zap secs */
X
X key[10] = '\0';
X
X distcount = 0;
X if (argc > 0) {
X distcount = get_distlist(&distlist, *argv);
X if (distcount < 0) {
X printf("%d Bad distribution list: %s\r\n", ERR_CMDSYN,
X *argv);
X (void) fflush(stdout);
X return;
X }
X }
X
X#ifdef USG
X if ((tmpfile = mktemp("/tmp/listXXXXXX")) == NULL ||
X (tmplst = fopen(tmpfile, "w+")) == NULL) {
X printf("%d Cannot process history file.\r\n", ERR_FAULT);
X (void) fflush(stdout);
X return;
X }
X
X for (i = 0; i < 9; i++) {
X sprintf(historyfile, "%s.d/%d", HISTORY_FILE, i);
X#endif USG
X
X fp = fopen(historyfile, "r");
X if (fp == NULL) {
X#ifdef SYSLOG
X syslog(LOG_ERR, "newnews: fopen %s: %m", historyfile);
X#endif
X#ifndef USG
X printf("%d Cannot open history file.\r\n", ERR_FAULT);
X (void) fflush(stdout);
X return;
X#else USG
X continue;
X#endif USG
X }
X
X#ifndef USG
X printf("%d New news by message id follows.\r\n", OK_NEWNEWS);
X#endif not USG
X
X if (seekuntil(fp, key, line, sizeof (line)) < 0) {
X#ifndef USG
X printf(".\r\n");
X (void) fflush(stdout);
X#endif not USG
X (void) fclose(fp);
X#ifndef USG
X return;
X#else USG
X continue;
X#endif USG
X }
X
X/*
X * History file looks like:
X *
X * <1569@emory.UUCP> 01/22/86 09:19 net.micro.att/899 ucb.general/2545
X * ^--tab ^--tab ^--space ^sp\0
X * Sometimes the newsgroups are missing; we try to be robust and
X * ignore such bogosity. We tackle this by our usual parse routine,
X * and break the list of articles in the history file into an argv
X * array with one newsgroup per entry.
X */
X
X do {
X if ((cp = index(line, '\t')) == NULL)
X continue;
X
X if ((ngp = index(cp+1, '\t')) == NULL) /* 2nd tab */
X continue;
X ++ngp; /* Points at newsgroup list */
X if (*ngp == '\n')
X continue;
X histcount = get_histlist(&histlist, ngp);
X if (histcount == 0)
X continue;
X
X /*
X * For each newsgroup on this line in the history
X * file, check it against the newsgroup names we're given.
X * If it matches, then see if we're hacking distributions.
X * If so, open the file and match the distribution line.
X */
X
X if (!all)
X if (!ngmatch(restreql, 0, nglist, ngcount,
X histlist, histcount))
X continue;
X
X if (distcount)
X if (!distmatch(distlist, distcount, histlist, histcount))
X continue;
X
X *cp = '\0';
X#ifdef USG
X fputs(line, tmplst);
X fputc('\n', tmplst);
X#else not USG
X putline(line);
X#endif not USG
X#ifdef LOG
X nn_told++;
X#endif
X } while (fgets(line, sizeof(line), fp) != NULL);
X
X#ifndef USG
X putchar('.');
X putchar('\r');
X putchar('\n');
X (void) fflush(stdout);
X#endif
X (void) fclose(fp);
X#ifdef USG
X }
X printf("%d New news by message id follows.\r\n", OK_NEWNEWS);
X rewind(tmplst);
X while (fgets(line, sizeof(line), tmplst) != NULL)
X putline(line);
X putchar('.');
X putchar('\r');
X putchar('\n');
X (void) fflush(stdout);
X (void) fclose(tmplst);
X (void) unlink(tmpfile);
X#endif USG
X}
X
X
X/*
X * seekuntil -- seek through the history file looking for
X * a line with date "key". Get that line, and return.
X *
X * Parameters: "fp" is the active file.
X * "key" is the date, in form YYMMDDHHMM (no SS)
X * "line" is storage for the first line we find.
X *
X * Returns: -1 on error, 0 otherwise.
X *
X * Side effects: Seeks in history file, modifies line.
X */
X
Xseekuntil(fp, akey, line, linesize)
X FILE *fp;
X char *akey;
X char *line;
X int linesize;
X{
X char datetime[32];
X register int c;
X register long top, bot, mid;
X extern long dtol();
X char key[30];
X
X (void) sprintf(key, "%ld", dtol(akey)); /* akey -> time_t in ascii */
X bot = 0;
X (void) fseek(fp, 0L, 2);
X top = ftell(fp);
X for(;;) {
X mid = (top+bot)/2;
X (void) fseek(fp, mid, 0);
X do {
X c = getc(fp);
X mid++;
X } while (c != EOF && c!='\n');
X if (!getword(fp, datetime, line, linesize)) {
X return (-1);
X }
X switch (compare(key, datetime)) {
X case -2:
X case -1:
X case 0:
X if (top <= mid)
X break;
X top = mid;
X continue;
X case 1:
X case 2:
X bot = mid;
X continue;
X }
X break;
X }
X (void) fseek(fp, bot, 0);
X while(ftell(fp) < top) {
X if (!getword(fp, datetime, line, linesize)) {
X return (-1);
X }
X switch(compare(key, datetime)) {
X case -2:
X case -1:
X case 0:
X break;
X case 1:
X case 2:
X continue;
X }
X break;
X }
X
X return (0);
X}
X
X
Xcompare(s, t)
X register char *s, *t;
X{
X for (; *s == *t; s++, t++)
X if (*s == 0)
X return(0);
X return (*s == 0 ? -1:
X *t == 0 ? 1:
X *s < *t ? -2:
X 2);
X}
X
X
X/*
X * C news version of getword.
X */
Xgetword(fp, w, line, linesize)
X FILE *fp;
X register char *w;
X char *line;
X int linesize;
X{
X register char *cp;
X extern char *index();
X
X if (fgets(line, linesize, fp) == NULL)
X return (0);
X w[0] = '\0'; /* in case of bad format */
X if (cp = index(line, '\t')) { /* find 2nd field */
X register char *endp;
X
X *cp++ = '\0';
X endp = index(cp, '~'); /* end of date-received */
X if (endp == NULL)
X endp = index(cp, '\t'); /* end of expiry */
X if (endp != NULL) {
X (void) strncpy(w, cp, endp - cp);
X w[endp - cp] = '\0';
X }
X }
X return (1);
X}
X
X
X/*
X * distmatch -- see if a file matches a set of distributions.
X * We have to do this by (yech!) opening the file, finding
X * the Distribution: line, if it has one, and seeing if the
X * things match.
X *
X * Parameters: "distlist" is the distribution list
X * we want.
X * "distcount" is the count of distributions in it.
X * "grouplist" is the list of groups (articles)
X * for this line of the history file. Note that
X * this isn't quite a filename.
X * "groupcount" is the count of groups in it.
X *
X * Returns: 1 if the article is in the given distribution.
X * 0 otherwise.
X */
X
Xdistmatch(distlist, distcount, grouplist, groupcount)
X char *distlist[];
X int distcount;
X char *grouplist[];
X int groupcount;
X{
X register char c;
X register char *cp;
X register FILE *fp;
X register int i, j;
X char buf[MAXBUFLEN];
X
X (void) strcpy(buf, spooldir);
X (void) strcat(buf, "/");
X (void) strcat(buf, grouplist[0]);
X
X for (cp = buf; *cp; cp++)
X if (*cp == '.')
X *cp = '/';
X
X fp = fopen(buf, "r");
X if (fp == NULL) {
X#ifdef SYSLOG
X syslog(LOG_ERR, "distmatch: fopen %s: %m", buf);
X#endif
X return (0);
X }
X
X while (fgets(buf, sizeof (buf), fp) != NULL) {
X if ((c = buf[0]) == '\n') /* End of header */
X break;
X if (c != 'd' && c != 'D')
X continue;
X cp = index(cp + 1, '\n');
X if (cp)
X *cp = '\0';
X cp = index(buf, ':');
X if (cp == NULL)
X continue;
X *cp = '\0';
X if (!strcasecmp(buf, "distribution")) {
X for (i = 0; i < distcount; ++i) {
X if (!strcasecmp(cp + 2, distlist[i])) {
X (void) fclose(fp);
X return (1);
X }
X }
X (void) fclose(fp);
X return (0);
X }
X }
X
X (void) fclose(fp);
X
X /*
X * We've finished the header with no distribution field.
X * So we'll assume that the distribution is the characters
X * up to the first dot in the newsgroup name.
X */
X
X for (i = 0; i < groupcount; i++) {
X cp = index(grouplist[i], '.');
X if (cp)
X *cp = '\0';
X for (j = 0; j < distcount; j++)
X if (!strcasecmp(grouplist[i], distlist[j]))
X return (1);
X }
X
X return (0);
X}
X
X
X/*
X * get_histlist -- return a nicely set up array of newsgroups
X * (actually, net.foo.bar/article_num) along with a count.
X *
X * Parameters: "array" is storage for our array,
X * set to point at some static data.
X * "list" is the history file newsgroup list.
X *
X * Returns: Number of group specs found.
X *
X * Side effects: Changes static data area.
X */
X
Xget_histlist(array, list)
X char ***array;
X char *list;
X{
X register int histcount;
X register char *cp;
X static char **hist_list = (char **) NULL;
X
X cp = index(list, '\n');
X if (cp)
X *cp-- = '\0';
X histcount = parsit(list, &hist_list);
X *array = hist_list;
X return (histcount);
X}
X
X
X/*
X * get_nglist -- return a nicely set up array of newsgroups
X * along with a count, when given an NNTP-spec newsgroup list
X * in the form ng1,ng2,ng...
X *
X * Parameters: "array" is storage for our array,
X * set to point at some static data.
X * "list" is the NNTP newsgroup list.
X *
X * Returns: Number of group specs found.
X *
X * Side effects: Changes static data area.
X */
X
Xget_nglist(array, list)
X char ***array;
X char *list;
X{
X register char *cp;
X register int ngcount;
X
X for (cp = list; *cp != '\0'; ++cp)
X if (*cp == ',')
X *cp = ' ';
X
X ngcount = parsit(list, array);
X
X return (ngcount);
X}
!
echo 'nntpdiffs/src/serve.c':
sed 's/^X//' >'nntpdiffs/src/serve.c' <<'!'
X#ifndef lint
Xstatic char *sccsid = "@(#)serve.c 1.29 (Berkeley) 2/6/88";
X#endif
X
X/*
X * Main server routine
X */
X
X#include "common.h"
X#include <signal.h>
X#ifdef USG
X#include <sys/times.h>
X#else
X#include <sys/time.h>
X#endif
X
X#ifdef LOG
X# ifndef USG
X# include <sys/resource.h>
X# endif not USG
X#endif
X
Xextern int ahbs(), group(), help(), ihave();
Xextern int list(), newgroups(), newnews(), nextlast(), post();
Xextern int slave(), stat(), xhdr();
X
Xstatic struct cmdent {
X char *cmd_name;
X int (*cmd_fctn)();
X} cmdtbl[] = {
X "article", ahbs,
X "body", ahbs,
X "group", group,
X "head", ahbs,
X "help", help,
X "ihave", ihave,
X "last", nextlast,
X "list", list,
X "newgroups", newgroups,
X "newnews", newnews,
X "next", nextlast,
X "post", post,
X "slave", slave,
X "stat", ahbs,
X#ifdef XHDR
X "xhdr", xhdr,
X#endif XHDR
X};
X#define NUMCMDS (sizeof(cmdtbl) / sizeof(struct cmdent))
X
X
X/*
X * serve -- given a connection on stdin/stdout, serve
X * a client, executing commands until the client
X * says goodbye.
X *
X * Parameters: None.
X *
X * Returns: Exits.
X *
X * Side effects: Talks to client, does a lot of
X * stuff.
X */
X
Xserve()
X{
X char line[NNTP_STRLEN];
X char host[MAXHOSTNAMELEN];
X char gdbuf[MAXBUFLEN];
X char **argp;
X char *timeptr, *cp;
X int argnum, i;
X double Tstart, Tfinish;
X double user, sys;
X#ifdef USG
X time_t start, finish;
X#else not USG
X struct timeval start, finish;
X#endif not USG
X extern char *ctime();
X#ifdef POSTER
X struct passwd *pp;
X#endif
X#ifdef LOG
X# ifdef USG
X struct tms cpu;
X# else not USG
X struct rusage me, kids;
X# endif not USG
X# ifdef TIMEOUT
X void timeout();
X# endif
X
X grps_acsd = arts_acsd = 0;
X#endif
X
X /* Not all systems pass fd's 1 and 2 from inetd */
X
X (void) close(1);
X (void) close(2);
X (void) dup(0);
X (void) dup(0);
X
X /* If we're ALONE, then we've already opened syslog */
X
X#ifndef ALONE
X# ifdef SYSLOG
X# ifdef BSD_42
X openlog("nntpd", LOG_PID);
X# else
X openlog("nntpd", LOG_PID, SYSLOG);
X# endif
X# endif
X#endif
X
X#ifdef ALONE
X#ifndef USG
X (void) signal(SIGCHLD, SIG_IGN);
X#endif not USG
X#endif
X
X /* Ignore SIGPIPE, since we'll see closed connections with read */
X
X (void) signal(SIGPIPE, SIG_IGN);
X
X /* Get permissions and see if we can talk to this client */
X
X host_access(&canread, &canpost, &canxfer, gdbuf);
X
X if (gethostname(host, sizeof(host)) < 0)
X (void) strcpy(host, "Amnesiac");
X
X if (!canread && !canxfer) {
X printf("%d %s NNTP server can't talk to you. Goodbye.\r\n",
X ERR_ACCESS, host);
X (void) fflush(stdout);
X#ifdef LOG
X syslog(LOG_INFO, "%s refused connection", hostname);
X#endif
X exit(1);
X }
X
X /* If we can talk, proceed with initialization */
X
X ngpermcount = get_nglist(&ngpermlist, gdbuf);
X
X#ifdef POSTER
X pp = getpwnam(POSTER);
X if (pp != NULL) {
X uid_poster = pp->pw_uid;
X gid_poster = pp->pw_gid;
X } else
X#endif
X uid_poster = gid_poster = 0;
X
X#ifndef FASTFORK
X num_groups = 0;
X num_groups = read_groups(); /* Read in the active file */
X#else
X signal(SIGALRM, SIG_IGN); /* Children don't deal with */
X /* these things */
X#endif
X
X art_fp = NULL;
X argp = (char **) NULL; /* for first time */
X
X#ifdef USG
X (void) time(&start);
X Tstart = (double) start;
X timeptr = ctime(&start);
X#else not USG
X (void) gettimeofday(&start, (struct timezone *)NULL);
X Tstart = (double) start.tv_sec - ((double)start.tv_usec)/1000000.0;
X timeptr = ctime(&start.tv_sec);
X#endif not USG
X if ((cp = index(timeptr, '\n')) != NULL)
X *cp = '\0';
X else
X timeptr = "Unknown date";
X
X printf("%d %s NNTP server version %s ready at %s (%s).\r\n",
X canpost ? OK_CANPOST : OK_NOPOST,
X host, nntp_version,
X timeptr,
X canpost ? "posting ok" : "no posting");
X (void) fflush(stdout);
X
X /*
X * Now get commands one at a time and execute the
X * appropriate routine to deal with them.
X */
X
X#ifdef TIMEOUT
X (void) signal(SIGALRM, timeout);
X (void) alarm(TIMEOUT);
X#endif TIMEOUT
X
X while (fgets(line, sizeof(line), stdin) != NULL) {
X#ifdef TIMEOUT
X (void) alarm(0);
X#endif TIMEOUT
X
X cp = index(line, '\r'); /* Zap CR-LF */
X if (cp != NULL)
X *cp = '\0';
X else {
X cp = index(line, '\n');
X if (cp != NULL)
X *cp = '\0';
X }
X
X if ((argnum = parsit(line, &argp)) == 0)
X continue; /* Null command */
X else {
X for (i = 0; i < NUMCMDS; ++i)
X if (!strcasecmp(cmdtbl[i].cmd_name, argp[0]))
X break;
X if (i < NUMCMDS)
X (*cmdtbl[i].cmd_fctn)(argnum, argp);
X else {
X if (!strcasecmp(argp[0], "quit"))
X break;
X#ifdef LOG
X syslog(LOG_INFO, "%s unrecognized %s",
X hostname,
X line);
X#endif
X printf("%d Command unrecognized.\r\n",
X ERR_COMMAND);
X (void) fflush(stdout);
X }
X }
X#ifdef TIMEOUT
X (void) alarm(TIMEOUT);
X#endif TIMEOUT
X }
X
X printf("%d %s closing connection. Goodbye.\r\n", OK_GOODBYE, host);
X (void) fflush(stdout);
X#ifndef UNBATCHED_INPUT
X {
X char errbuf[2 * NNTP_STRLEN];
X
X enqpartbatch(CONT_XFER, ERR_XFERFAIL, errbuf);
X }
X#endif
X
X
X#ifdef LOG
X if (ferror(stdout))
X syslog(LOG_ERR, "%s disconnect: %m", hostname);
X
X#ifdef USG
X (void) time(&finish);
X Tfinish = (double) finish;
X
X#ifndef HZ
X#define HZ 60.0 /* typical system clock ticks - param.h */
X#endif not HZ
X
X (void) times(&cpu);
X user = (double)(cpu.tms_utime + cpu.tms_cutime) / HZ;
X sys = (double)(cpu.tms_stime + cpu.tms_cstime) / HZ;
X#else not USG
X (void) gettimeofday(&finish, (struct timezone *)NULL);
X Tfinish = (double) finish.tv_sec - ((double)finish.tv_usec)/1000000.0;
X
X (void) getrusage(RUSAGE_SELF, &me);
X (void) getrusage(RUSAGE_CHILDREN, &kids);
X
X user = (double) me.ru_utime.tv_sec + me.ru_utime.tv_usec/1000000.0 +
X kids.ru_utime.tv_sec + kids.ru_utime.tv_usec/1000000.0;
X sys = (double) me.ru_stime.tv_sec + me.ru_stime.tv_usec/1000000.0 +
X kids.ru_stime.tv_sec + kids.ru_stime.tv_usec/1000000.0;
X#endif not USG
X if (grps_acsd)
X syslog(LOG_INFO, "%s exit %d articles %d groups",
X hostname, arts_acsd, grps_acsd);
X if (nn_told)
X syslog(LOG_INFO, "%s newnews_stats told %d took %d",
X hostname, nn_told, nn_took);
X if (ih_accepted || ih_rejected || ih_failed)
X syslog(LOG_INFO,
X "%s ihave_stats accepted %d rejected %d failed %d",
X hostname,
X ih_accepted,
X ih_rejected,
X ih_failed);
X (void) sprintf(line, "user %.1f system %.1f elapsed %.1f",
X user, sys, Tfinish - Tstart);
X syslog(LOG_INFO, "%s times %s", hostname, line);
X#endif LOG
X
X#ifdef PROFILE
X profile();
X#endif
X exit(0);
X}
X
X
X#ifdef TIMEOUT
X/*
X * No activity for TIMEOUT seconds, so print an error message
X * and close the connection.
X */
X
Xvoid
Xtimeout()
X{
X printf("%d Timeout after %d seconds, closing connection.\r\n",
X ERR_FAULT, TIMEOUT);
X (void) fflush(stdout);
X
X#ifdef LOG
X syslog(LOG_ERR, "%s timeout", hostname);
X#endif LOG
X
X exit(1);
X}
X#endif TIMEOUT
!
echo 'nntpdiffs/src.allnew/batch.c':
sed 's/^X//' >'nntpdiffs/src.allnew/batch.c' <<'!'
X/*
X * rnews - setuid-news fake rnews for nntp: appends article to a batch with
X * a fixed name under in.coming. if batch is too big or old, rename
X * batch to be an input candidate and kick off a newsrun to process
X * the batch. the batch file is locked during appending.
X * Cooperates with C news input subsystem.
X * newsboot must be told to run partial batches left at a crash.
X */
X#include "../common/conf.h"
X#include "common.h"
X#include <signal.h>
X
X#define TOOBIG 300000L /* batch > TOOBIG bytes, kick rnews */
X#define TOOOLD (5*60) /* batch > TOOOLD seconds old, kick rnews */
X#define COPYSIZE 8192 /* bytes to copy at one time */
X#define MAXDIGITS 25 /* lg(maxlongint) + epsilon */
X#define MAXSTR 1024
X
X#define INDIR artfile("in.coming")
X#define BATCHFILE artfile("in.coming/nntp.XXXXXX")
X#define NEWSRUN binfile("input/newsrun")
X
X#define YES 1
X#define NO 0
X
X/* imports */
Xextern time_t time();
Xextern char *malloc(), *mktemp(), *index(), *rindex();
X
X/* forwards */
Xstatic char *artfile(), *binfile(), *strsave();
Xstatic void error(), warning();
Xstatic int xfer_timeout();
X
X/* private data */
Xstatic char tempfile[256];
Xstatic int xfer_lines, old_xfer_lines;
X
Xstatic char art[COPYSIZE]; /* entire article, if it fits */
Xstatic char *endart = art; /* points just past end of article */
Xstatic int incore = YES;
X
Xstatic struct batch_file {
X char *name;
X FILE *file;
X char isopen;
X time_t start; /* time of creation */
X off_t size; /* current size */
X} btch = { NULL, NULL, NO, 0, 0 };
X
Xchar *progname = "nntpd";
X
X#ifndef lint
Xstatic char *sccsid = "@(#)batch.c 1.5 (Toronto) 31/4/89";
X#endif
X
X/*
X * stash stdin (up to ".") on the end of the batch input file.
X * kick newsrun if the batch is non-empty and too big or too old.
X *
X * Parameters:
X * "cont_code" is the response code to transmit on successful startup.
X * "err_code" is the response code to transmit when something goes wrong.
X *
X * Returns: -1 on non-zero return from child, 0 on error before fork/exec, 1 else.
X * Side effects: Creates and removes temporary file; accepts input from client.
X * Can time out if XFER_TIMEOUT is defined.
X */
Xint
Xbatch_input_article(cont_code, err_code, errbuf)
Xint cont_code, err_code;
Xchar *errbuf;
X{
X int status = 1; /* okay status */
X
X /* protect locking */
X signal(SIGINT, SIG_IGN);
X signal(SIGQUIT, SIG_IGN);
X signal(SIGHUP, SIG_IGN);
X
X if (btch.name == NULL) {
X /* BATCHFILE may trigger unprivileged() */
X btch.name = mktemp(strsave(BATCHFILE));
X }
X if (btch.name == NULL)
X return 0;
X#ifdef notdef
X (void) setgid(getegid());
X (void) setuid(geteuid());
X#endif
X tempfile[0] = '\0';
X if (!cpstdin(cont_code, err_code, errbuf)) /* may create tempfile */
X return 0;
X#ifdef POSTER
X (void) chown(tempfile, uid_poster, gid_poster);
X#endif
X status = appbatch();
X if (tempfile[0] != '\0')
X (void) unlink(tempfile);
X if (status == 1 && oktorunbatch())
X status = enqueue(cont_code, err_code, errbuf);
X return status;
X}
X
Xint /* boolean */
Xoktorunbatch()
X{
X struct stat stbuf;
X
X if (!btch.isopen || fstat(fileno(btch.file), &stbuf) < 0)
X return NO;
X btch.size = stbuf.st_size;
X return btch.size > TOOBIG ||
X btch.size > 0 && time((time_t *)NULL) - btch.start > TOOOLD;
X}
X
X/*
X * Copy standard input (up to a "." line) to art, if it fits,
X * else to a temporary file.
X */
X/* ARGSUSED errbuf */
Xstatic int /* boolean: got article ok? */
Xcpstdin(cont_code, err_code, errbuf)
Xint cont_code, err_code;
Xchar *errbuf;
X{
X register FILE *tfp = NULL;
X register char *cp, *realline;
X char line[NNTP_STRLEN];
X int toobig = NO;
X int (*otimeout)();
X
X /* TODO: is this right? used to open here, with errors here */
X printf("%d Ok\r\n", cont_code);
X (void) fflush(stdout);
X
X xfer_lines = old_xfer_lines = 0;
X incore = YES;
X art[0] = '\0';
X endart = art;
X#ifdef XFER_TIMEOUT
X otimeout = signal(SIGALRM, xfer_timeout);
X (void) alarm(XFER_TIMEOUT);
X#endif
X while (fgets(line, sizeof line, stdin) != NULL) {
X xfer_lines++;
X if ((cp = rindex(line, '\r')) != NULL ||
X (cp = rindex(line, '\n')) != NULL)
X *cp = '\0'; /* nuke CRLF */
X if (line[0] == '.' && line[1] == '\0')
X break; /* article end: exit */
X /* remove hidden dot if present */
X realline = (line[0] == '.'? line+1: line);
X if (toobig) { /* straight to disk */
X (void) fputs(realline, tfp);
X (void) putc('\n', tfp);
X } else {
X int len = strlen(realline);
X
X /*
X * Does art have room to append realline + \n\0?
X * If not, open temp file and dump art & realline there.
X */
X if (sizeof art - (endart - art) < len + 1 + 1) {
X (void) strcpy(tempfile, "/tmp/rpostXXXXXX");
X (void) mktemp(tempfile);
X tfp = fopen(tempfile, "w");
X if (tfp == NULL) {
X printf("%d Cannot create temporary file.\r\n",
X err_code);
X (void) fflush(stdout);
X return 0;
X }
X#ifdef OK_IN_MIDDLE_OKAY
X else {
X printf("%d Ok\r\n", cont_code);
X (void) fflush(stdout);
X }
X#endif
X (void) fwrite(art, 1, endart - art, tfp);
X toobig = YES;
X incore = NO;
X art[0] = '\0';
X endart = art;
X (void) fputs(realline, tfp);
X (void) putc('\n', tfp);
X } else {
X /* fits: append realline\n to art at endart */
X (void) strcpy(endart, realline);
X endart += len;
X *endart++ = '\n';
X *endart = '\0';
X }
X }
X }
X if (tfp != NULL)
X (void) fclose(tfp);
X#ifdef XFER_TIMEOUT
X (void) alarm(0);
X (void) signal(SIGALRM, otimeout);
X#endif
X
X /* See if the connection got closed somehow... */
X if (line[0] != '.' && line[1] != '\0') {
X if (tempfile[0] != '\0')
X (void) unlink(tempfile);
X#ifdef LOG
X syslog(LOG_ERR, "%s spawn: EOF before period on line by itself",
X hostname);
X#else
X syslog(LOG_ERR, "spawn: EOF before period on line by itself");
X#endif
X return 0;
X }
X return 1;
X}
X
Xstatic int
Xxfer_timeout()
X{
X#ifdef XFER_TIMEOUT
X if (old_xfer_lines < xfer_lines) {
X old_xfer_lines = xfer_lines;
X (void) alarm(XFER_TIMEOUT);
X return;
X }
X /* Timed out. */
X printf("%d timeout after %d seconds, closing connection.\r\n",
X ERR_FAULT, XFER_TIMEOUT);
X fflush(stdout);
X#ifdef LOG
X syslog(LOG_ERR, "%s transfer_timeout", hostname);
X#endif LOG
X (void) unlink(tempfile);
X exit(1);
X#endif XFER_TIMEOUT
X}
X
X/*
X * Append "#! rnews count" and art (or tempfile) to batch file, locking assumed.
X * If batch file is too big or too old (but not empty), feed it to newsrun.
X */
Xstatic int /* same as batch_input_article */
Xappbatch()
X{
X register FILE *tfp = NULL;
X register int bytes = 0;
X int status = 1; /* okay status */
X long size = 0;
X char artbuf[COPYSIZE];
X struct stat stbuf;
X
X if (btch.file == NULL) {
X btch.file = fopen(btch.name, "a");
X if (btch.file == NULL)
X return 0;
X btch.isopen = YES;
X btch.size = 0;
X btch.start = time(&btch.start);
X }
X
X /* find article size and write the article */
X if (incore)
X size = endart - art;
X else {
X tfp = fopen(tempfile, "r");
X if (tfp == NULL)
X return 0;
X if (fstat(fileno(tfp), &stbuf) >= 0)
X size = stbuf.st_size;
X }
X (void) fprintf(btch.file, "#! rnews %ld\n", size);
X
X /* copy the article to the batch file */
X if (incore)
X (void) fwrite(art, 1, endart - art, btch.file);
X else {
X while ((bytes = fread(artbuf, 1, sizeof artbuf, tfp)) > 0)
X if (fwrite(artbuf, 1, bytes, btch.file) != bytes) {
X warning("can't write %s", btch.name);
X status = 0; /* hmm, #! count is off */
X break;
X }
X (void) fclose(tfp);
X }
X if (fflush(btch.file) == EOF) {
X warning("can't write %s", btch.name);
X status = 0;
X }
X return status;
X}
X
X/*
X * Enqueue any partial batch. Called before exit.
X */
Xenqpartbatch(cont_code, err_code, errbuf)
Xint cont_code, err_code;
Xchar *errbuf;
X{
X struct stat stbuf;
X
X if (btch.isopen && fstat(fileno(btch.file), &stbuf) >= 0) {
X if (btch.size > 0)
X enqueue(cont_code, err_code, errbuf);
X else {
X (void) fclose(btch.file);
X btch.file = NULL;
X btch.isopen = NO;
X (void) unlink(btch.name); /* remove empty batch */
X }
X }
X}
X
X/*
X * insert the batch file into the input subsystem queue by renaming
X * it to an all-numeric name, then kick newsrun to process it.
X * locks btch.name as appropriate.
X */
Xstatic int /* same as batch_input_article */
Xenqueue(cont_code, err_code, errbuf)
Xint cont_code, err_code;
Xchar *errbuf;
X{
X time_t now;
X int pid, wpid, status, fd, exitstat;
X char permname[MAXDIGITS], *number = permname, *newsrun;
X struct stat stbuf;
X
X (void) fclose(btch.file);
X btch.file = NULL;
X btch.isopen = NO;
X btch.start = 0;
X btch.size = 0;
X
X (void) fflush(stdout);
X (void) fflush(stderr);
X pid = fork();
X if (pid == -1) {
X warning("can't fork", "");
X return 0;
X } else if (pid != 0) { /* parent */
X while ((wpid = wait(&status)) != -1 && wpid != pid)
X ;
X exitstat = (status>>8)&0377;
X if (exitstat != 0) {
X syslog(LOG_ERR, "%s: enqueue returned exit status 0%o",
X progname, exitstat);
X strcpy(errbuf, "enqueue failed to run newsrun\n");
X }
X return exitstat != 0? -1 :1;
X }
X
X /* child: must exit */
X for (fd = 3; fd < 20; fd++)
X (void) close(fd);
X if (chdir(INDIR) < 0) {
X syslog(LOG_ERR, "%s: chdir(%s) failed", progname, INDIR);
X nerror("can't change directory to %s", INDIR);
X }
X
X /* rename btch.name to a number so newsrun will see it */
X sprintf(number, "%ld", (long)time(&now));
X while (link(btch.name, permname) < 0) {
X if (stat(btch.name, &stbuf) < 0)
X break;
X sleep(2);
X sprintf(number, "%ld", (long)time(&now));
X }
X if (unlink(btch.name) < 0)
X vanished(btch.name);
X
X signal(SIGINT, SIG_IGN);
X signal(SIGQUIT, SIG_IGN);
X signal(SIGHUP, SIG_IGN);
X (void) fflush(stdout);
X (void) fflush(stderr);
X newsrun = strsave(NEWSRUN);
X if (newsrun == NULL)
X newsrun = "/usr/lib/newsbin/input/newsrun";
X execl(newsrun, newsrun, (char *)NULL);
X syslog(LOG_ERR, "%s: can't run %s", progname, newsrun);
X error("attempt to run %s failed!", newsrun);
X exit(1);
X /* NOTREACHED */
X}
X
Xvanished(s) /* grieve for s, nerror [exit] */
Xchar *s;
X{
X syslog(LOG_ERR, "%s: %s vanished underfoot!", progname, s);
X nerror("%s vanished underfoot!", s); /* unlocks, exits */
X}
X
Xstatic
Xnerror(fmt, s) /* error, unused to be with unlock */
Xchar *fmt, *s;
X{
X error(fmt, s);
X}
X
X/* C news library starts here */
X
X/*
X * error - print best error message possible and exit
X */
Xstatic void warning();
X
Xstatic void
Xerror(s1, s2)
Xchar *s1;
Xchar *s2;
X{
X warning(s1, s2);
X exit(1);
X}
X
X/*
X * warning - print best error message possible and clear errno
X */
Xextern int errno, sys_nerr;
Xextern char *sys_errlist[];
Xextern char *progname;
Xextern char *getenv();
X
Xstatic void
Xwarning(s1, s2)
Xchar *s1;
Xchar *s2;
X{
X char *cmdname;
X
X (void) fflush(stdout); /* hack */
X cmdname = getenv("CMDNAME");
X if (cmdname != NULL && *cmdname != '\0')
X fprintf(stderr, "%s:", cmdname); /* No space after :. */
X if (progname != NULL)
X fprintf(stderr, "%s: ", progname);
X fprintf(stderr, s1, s2);
X if (errno > 0 && errno < sys_nerr)
X fprintf(stderr, " (%s)", sys_errlist[errno]);
X fprintf(stderr, "\n");
X errno = 0;
X}
X
Xvoid
Xunprivileged()
X{
X (void) setgid(getgid());
X (void) setuid(getuid());
X}
X
Xstatic char *
Xartfile(s)
Xchar *s;
X{
X static char name[MAXSTR];
X
X strcpy(name, "/usr/spool/news/");
X strcat(name, s);
X return name;
X}
X
Xstatic char *
Xbinfile(s)
Xchar *s;
X{
X static char name[MAXSTR];
X
X strcpy(name, "/usr/lib/newsbin/");
X strcat(name, s);
X return name;
X}
X
X#ifdef notdef
Xstatic char *
Xctlfile(s)
Xchar *s;
X{
X static char name[MAXSTR];
X
X strcpy(name, "/usr/lib/news/");
X strcat(name, s);
X return name;
X}
X#endif
X
Xstatic char *
Xstrsave(s)
Xregister char *s;
X{
X register char *news = malloc((unsigned)(strlen(s) + 1));
X
X if (news != NULL)
X strcpy(news, s);
X return news;
X}
X
X#ifndef SYSLOG
X/* VARARGS 2 */
Xstatic
Xsyslog(level, fmt)
Xint level;
Xchar *fmt;
X{
X}
X#endif
X
!
echo 'nntpdiffs/cdiff.1.5.0':
sed 's/^X//' >'nntpdiffs/cdiff.1.5.0' <<'!'
XCommon subdirectories: ../nntp.1.5.0/common and ./common
XCommon subdirectories: ../nntp.1.5.0/doc and ./doc
XCommon subdirectories: ../nntp.1.5.0/inews and ./inews
XOnly in .: nntp.1.5.C.diff
XCommon subdirectories: ../nntp.1.5.0/rrnpatches and ./rrnpatches
XCommon subdirectories: ../nntp.1.5.0/server and ./server
XCommon subdirectories: ../nntp.1.5.0/support and ./support
XCommon subdirectories: ../nntp.1.5.0/xfer and ./xfer
XCommon subdirectories: ../nntp.1.5.0/xmit and ./xmit
Xdiff -r -c ../nntp.1.5.0/server/Makefile ./server/Makefile
X*** ../nntp.1.5.0/server/Makefile Fri Feb 26 02:47:58 1988
X--- ./server/Makefile Tue Jun 6 23:15:49 1989
X***************
X*** 3,8 ****
X--- 3,9 ----
X #
X
X SRVROBJ = main.o serve.o access.o access_inet.o access_dnet.o active.o \
X+ batch.o \
X ahbs.o globals.o group.o help.o ihave.o list.o misc.o netaux.o \
X newgroups.o newnews.o nextlast.o ngmatch.o post.o parsit.o scandir.o \
X slave.o spawn.o strcasecmp.o subnet.o time.o xhdr.o fakesyslog.o \
X***************
X*** 9,14 ****
X--- 10,16 ----
X ../common/version.o
X
X SRVRSRC = main.c serve.c access.c access_inet.c access_dnet.c active.c \
X+ batch.c \
X ahbs.c globals.c group.c help.c ihave.c list.c misc.c netaux.c \
X newgroups.c newnews.c nextlast.c ngmatch.c post.c parsit.c scandir.c \
X slave.c spawn.c strcasecmp.c subnet.c time.c xhdr.c fakesyslog.c \
X***************
X*** 19,25 ****
X SRCS = ${SRVRSRC}
X
X # -ldbm here if you've #define'ed DBM in ../common/conf.h
X! LIBS =
X
X CFLAGS = -O
X
X--- 21,27 ----
X SRCS = ${SRVRSRC}
X
X # -ldbm here if you've #define'ed DBM in ../common/conf.h
X! LIBS = -ldbm
X
X CFLAGS = -O
X
XOnly in ./server: batch.c
Xdiff -r -c ../nntp.1.5.0/server/ihave.c ./server/ihave.c
X*** ../nntp.1.5.0/server/ihave.c Tue Jan 12 02:53:11 1988
X--- ./server/ihave.c Tue Jun 6 23:15:52 1989
X***************
X*** 43,49 ****
X return;
X }
X
X! retcode = spawn(rnews, "rnews", (char *) 0, CONT_XFER, ERR_XFERFAIL, errbuf);
X if (retcode <= 0)
X printf("%d %s\r\n", ERR_XFERFAIL, errbuf);
X else if (retcode > 0)
X--- 43,55 ----
X return;
X }
X
X! #ifdef UNBATCHED_INPUT
X! retcode = spawn(rnews, "rnews", (char *) 0, CONT_XFER,
X! ERR_XFERFAIL, errbuf);
X! #else
X! /* C news input hook */
X! retcode = batch_input_article(CONT_XFER, ERR_XFERFAIL, errbuf);
X! #endif
X if (retcode <= 0)
X printf("%d %s\r\n", ERR_XFERFAIL, errbuf);
X else if (retcode > 0)
Xdiff -r -c ../nntp.1.5.0/server/misc.c ./server/misc.c
X*** ../nntp.1.5.0/server/misc.c Sun Feb 7 01:29:33 1988
X--- ./server/misc.c Tue Jun 6 23:15:54 1989
X***************
X*** 82,88 ****
X *
X * Side effects: opens dbm database
X * (only once, keeps it open after that).
X- * Converts "msg_id" to lower case.
X */
X
X #ifndef NDBM
X--- 82,87 ----
X***************
X*** 115,124 ****
X datum key, content;
X #endif USGHIST
X static FILE *hfp = NULL; /* history file, text version */
X-
X- for (cp = msg_id; *cp != '\0'; ++cp)
X- if (isupper(*cp))
X- *cp = tolower(*cp);
X
X #ifdef USGHIST
X hfp = fopen(histfile(msg_id), "r");
X--- 114,119 ----
Xdiff -r -c ../nntp.1.5.0/server/newnews.c ./server/newnews.c
X*** ../nntp.1.5.0/server/newnews.c Sat Feb 6 20:29:07 1988
X--- ./server/newnews.c Tue Jun 6 23:15:57 1989
X***************
X*** 255,263 ****
X * Side effects: Seeks in history file, modifies line.
X */
X
X! seekuntil(fp, key, line, linesize)
X FILE *fp;
X! char *key;
X char *line;
X int linesize;
X {
X--- 255,263 ----
X * Side effects: Seeks in history file, modifies line.
X */
X
X! seekuntil(fp, akey, line, linesize)
X FILE *fp;
X! char *akey;
X char *line;
X int linesize;
X {
X***************
X*** 264,270 ****
X--- 264,273 ----
X char datetime[32];
X register int c;
X register long top, bot, mid;
X+ extern long dtol();
X+ char key[30];
X
X+ (void) sprintf(key, "%ld", dtol(akey)); /* akey -> time_t in ascii */
X bot = 0;
X (void) fseek(fp, 0L, 2);
X top = ftell(fp);
X***************
X*** 327,332 ****
X--- 330,338 ----
X }
X
X
X+ /*
X+ * C news version of getword.
X+ */
X getword(fp, w, line, linesize)
X FILE *fp;
X register char *w;
X***************
X*** 334,369 ****
X int linesize;
X {
X register char *cp;
X
X if (fgets(line, linesize, fp) == NULL)
X return (0);
X! if (cp = index(line, '\t')) {
X! /*
X! * The following gross hack is present because the history file date
X! * format is braindamaged. They like "mm/dd/yy hh:mm", which is useless
X! * for relative comparisons of dates using something like atoi() or
X! * strcmp. So, this changes their format into yymmddhhmm. Sigh.
X! *
X! * 12345678901234 ("x" for cp[x])
X! * mm/dd/yy hh:mm (their lousy representation)
X! * yymmddhhmm (our good one)
X! * 0123456789 ("x" for w[x])
X! */
X! *cp = '\0';
X! (void) strncpy(w, cp+1, 15);
X! w[0] = cp[7]; /* Years */
X! w[1] = cp[8];
X! w[2] = cp[1]; /* Months */
X! w[3] = cp[2];
X! w[4] = cp[4]; /* Days */
X! w[5] = cp[5];
X! w[6] = cp[10]; /* Hours */
X! w[7] = cp[11];
X! w[8] = cp[13]; /* Minutes */
X! w[9] = cp[14];
X! w[10] = '\0';
X! } else
X! w[0] = '\0';
X return (1);
X }
X
X--- 340,362 ----
X int linesize;
X {
X register char *cp;
X+ extern char *index();
X
X if (fgets(line, linesize, fp) == NULL)
X return (0);
X! w[0] = '\0'; /* in case of bad format */
X! if (cp = index(line, '\t')) { /* find 2nd field */
X! register char *endp;
X!
X! *cp++ = '\0';
X! endp = index(cp, '~'); /* end of date-received */
X! if (endp == NULL)
X! endp = index(cp, '\t'); /* end of expiry */
X! if (endp != NULL) {
X! (void) strncpy(w, cp, endp - cp);
X! w[endp - cp] = '\0';
X! }
X! }
X return (1);
X }
X
Xdiff -r -c ../nntp.1.5.0/server/serve.c ./server/serve.c
X*** ../nntp.1.5.0/server/serve.c Thu Feb 25 22:49:21 1988
X--- ./server/serve.c Tue Jun 6 23:16:00 1989
X***************
X*** 237,244 ****
X--- 237,251 ----
X
X printf("%d %s closing connection. Goodbye.\r\n", OK_GOODBYE, host);
X (void) fflush(stdout);
X+ #ifndef UNBATCHED_INPUT
X+ {
X+ char errbuf[2 * NNTP_STRLEN];
X
X+ enqpartbatch(CONT_XFER, ERR_XFERFAIL, errbuf);
X+ }
X+ #endif
X
X+
X #ifdef LOG
X if (ferror(stdout))
X syslog(LOG_ERR, "%s disconnect: %m", hostname);
X***************
X*** 287,293 ****
X #ifdef PROFILE
X profile();
X #endif
X-
X exit(0);
X }
X
X--- 294,299 ----
!
echo done