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 . 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"] [] 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\"] [].\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 X#ifdef USG X#include X#else X#include X#endif X X#ifdef LOG X# ifndef USG X# include 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 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