/* * rnews for usenet newsgroups in usenet 1 message-per-file format */ #include "news.h" #include #include #include #include #include #include extern char *spool(); extern FILE *fopen(); extern char *getenv(); extern long ftell(); extern char *skipblanks(); int flit(); long messageid; char textline[200]; char *spoolid = 0; char *tempfile= 0; char *tmpdir; FILE *keyfile[10]; extern char backdate; /* when adding messages, date them according to */ /* their headers */ extern char makegroup; /* automagically generate newsgroups */ struct newsgroups *updated; main(argc,argv) char **argv; { register i; if (getcfg() == 0) exit(2); xchdir(NETDIR); tmpdir = getenv("TMP"); if (!tmpdir) tmpdir = ""; /* * avoid racing rnewses * * when multi is running, replace with a while loop to delay until * other rnewses are done. */ if ((i=creat("newslock", 0)) < 0) { fprintf(stderr, "can't create lock <%s\\newslock>\n", NETDIR); exit(99); } else close(i); catcher(flit); for (i=0; i<10; i++) keyfile[i] = NULL; while (argc > 1 && (argv[1][0] == '-' || argv[1][0] == '+')) { ++argv, --argc; switch (argv[0][1]) { case 'b': case 'B': backdate = (**argv == '+'); break; case 'm': case 'M': makegroup = (**argv == '+'); break; } } if (isatty(fileno(stdin))) { spoolid = spool(stdin); if (!freopen(stdin, spoolid, "r")) { fprintf(stderr, "cannot open %s\n", spoolid); flit(2); } } updated = getgroups("active"); gets(textline); rewind(stdin); if (strncmp("#!", textline, 2) == 0) unbatch(stdin); else handle(stdin); flit(0); } /* main */ panic(s) char *s; { fprintf(stderr, "rnews: %s\n", s); flit(255); } merge_update() /* * update the active file */ { FILE *from, *to; long old, new; char group[100]; char tempact[20]; register i; sprintf(tempact, "temp%u", getpid()); if ((to = fopen(tempact, "w")) == NULL) { fprintf(stderr, "can't creat active file!\n"); return; } if ((from = fopen("active", "r")) == 0) fprintf(stderr, "can't find old active file!\n"); for (i=0; icount; i++) fprintf(to, "%s: %06ld-%06ld\n", updated->list[i].groupname, updated->list[i].first, updated->list[i].last); fclose(to); unlink("active"); rename(tempact, "active"); } /* merge_update */ flit(status) { register i; if (spoolid) unlink(spoolid); if (tempfile) unlink(tempfile); for (i=0; i<10; i++) if (keyfile[i]) fclose(keyfile[i]); merge_update(); unlink("newslock"); exit(status); } /* flit */ char * spool(file) FILE *file; { static char what[80]; FILE *x; register char c; sprintf(what, "%s%srnews%u", tmpdir, *tmpdir ? "\\" : "", getpid()); if (x=fopen(what, "wb")) { while ((c=getchar()) != EOF) putc(c,x); fclose(x); return what; } else { fprintf(stderr, "Cannot creat %s\n", what); flit(2); } } char mesgfile[200]; FILE * getid(newsgroup) char *newsgroup; { register int i; register char *tngp; FILE *fd; char *strchr(); for (i = updated->count-1; i>=0; --i) if (strcmp(newsgroup, updated->list[i].groupname) == 0) { messageid = ++(updated->list[i].last); sprintf(mesgfile, "%s\\%ld", newsgroup, messageid); if (fd = fopen(mesgfile, "wb")) return fd; fprintf(stderr, "can't generate message #%s\n", mesgfile); return NULL; } if (makegroup) { /*printf("MAKEGROUP %s\n", newsgroup);*/ for (tngp=strchr(newsgroup, '\\'); tngp; tngp=strchr(1+tngp, '\\')) { *tngp = 0; if (xchdir(newsgroup) != 0 && mkdir(newsgroup) != 0) { fprintf(stderr, "can't mkdir %s\n", newsgroup); return NULL; } xchdir(NETDIR); *tngp = '\\'; } if (xchdir(newsgroup) != 0 && mkdir(newsgroup) != 0) { fprintf(stderr, "can't mkdir %s\n", newsgroup); return NULL; } xchdir(NETDIR); messageid = 1; sprintf(mesgfile, "%s\\1", newsgroup); /*printf("MESGFILE=%s\n", mesgfile);*/ if (fd = fopen(mesgfile, "wb")) { addgroup(&updated, newsgroup, messageid, messageid); return fd; } fprintf(stderr, "can't generate message #%s\n", mesgfile); } else fprintf(stderr, "no newsgroup <%s>\n", newsgroup); return NULL; fprintf(stderr, "no newsgroup <%s>\n", newsgroup); return NULL; } struct { struct _time fixtime; struct _date fixdate; } magic; int grokked; grokdate(string, tp, dp) char *string; register struct _time *tp; register struct _date *dp; { int dd, yr, hh, mm, ss; char mon[20]; register i; static char mons[12][4] = { "jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec" }; while (*string && !isdigit(*string)) ++string; if (sscanf(string, "%d %s %d %d:%d:%d", &dd, mon, &yr, &hh, &mm, &ss) < 6) return 0; strlwr(mon); for (i=0; i<12; i++) if (strncmp(mon, mons[i]) == 0) break; if (i == 12) return 0; if (yr < 1900) yr += 1900; tp->Tsec = ss/2; tp->Tmin = mm; tp->Thour= hh; dp->Dday = dd; dp->Dmonth = 1+i; dp->Dyear= yr-1980; return 1; } /* grokdate */ plunk(fd, where, path) FILE *fd; register char *where; char *path; { register inheader; FILE *msg; register char *p; if (msg=getid(where)) { rewind(fd); fprintf(msg, "Path: %s!%s\n", SITE, path); /* put Path: at top */ inheader = 1; while (fgets(textline, 200, fd)) { if (inheader) { if (textline[0] == '\n') inheader=0; else if (strnicmp(textline, "Path:",5) == 0) continue; } fputs(textline, msg); } fclose(msg); if (backdate && grokked) { sprintf(textline, "%s\\%ld", where, messageid); utime(textline, &magic); } return 1; } return 0; } /* plunk */ handle(fd) FILE *fd; { FILE *msg; char filename[128]; static char groups[300]; static char date[80]; static char mesgno[80]; static char path[400]; char *strtok(); register char *p=0, *q; register size; int written = 0; char *strchr(); memset(groups, 0, 300); memset(date, 0, 80); memset(mesgno, 0, 80); memset(path, 0, 400); while (specgets(textline, fd) && *textline) { if (*textline && strchr("\t ", *textline)) { if (p) strcat(p, textline); } else { if (strnicmp(textline, "Newsgroups:", 11) == 0) strcpy(p=groups, skipblanks(11+textline)); else if (strnicmp(textline, "Path:", 5) == 0) strcpy(p=path, skipblanks(5+textline)); else if (strnicmp(textline, "Date:", 5) == 0) strcpy(p=date, skipblanks(5+textline)); else if (strnicmp(textline, "Message-ID:", 11) == 0) strcpy(p=mesgno, skipblanks(11+textline)); else p = NULL; } } if (mesgno[0] == 0) { fprintf(stderr, "Missing message-id!\n"); return; } else if (p=strchr(mesgno, ' ')) *p = 0; if (indb(mesgno, date)) return; if (backdate && date[0]) grokked = grokdate(date, &magic.fixtime, &magic.fixdate); if (groups[0] == 0) { fprintf(stderr, "No newsgroups: line, message moved to junk\n"); plunk(fd, "junk", path); return; } if (feof(fd)) { fprintf(stderr, "null-bodied article!\n"); return; } for (p=strtok(groups, "\t ,"); p; p=strtok(NULL, "\t ,")) { strlwr(p); for (q=p; *q; ++q) if (*q == '.') *q = '\\'; if (plunk(fd, p, path)) { written = 1; advance(p, path, mesgfile); } } if (!written) plunk(fd, "junk", path); } /* handle */ unbatch(stream) FILE *stream; { long temp; register long size; FILE *x; register c; char command[40]; char tempf[200]; sprintf(tempf, "%s%srnews%d", tmpdir, tmpdir ? "\\" : "", getpid()); while (specgets(textline, stream)) { if (strncmp(textline, "#!", 2) != 0) { fprintf(stderr, "sync> %s\n", textline); continue; } if (sscanf(textline, "#! rnews %ld", &temp) != 1) { fprintf(stderr, "can't grok <%s>\n", textline); flit(6); } fprintf(stderr, "#! rnews %ld\n", temp); if ((x=fopen(tempf, "w+b")) == NULL) { fprintf(stderr, "can't open tempfile <%s>\n", tempf); flit(7); } tempfile = tempf; for (size=temp; size-- > 0 && (c=fgetc(stream)) != EOF; putc(c,x)) ; rewind(x); handle(x); fclose(x); unlink(tempf); tempfile = 0; } } /* unbatch */ hash(mesgno) register char *mesgno; { register char *p; char *strchr(); if ((p=strchr(mesgno, '@')) && p>mesgno && isdigit(p[-1])) return p[-1]-'0'; while (*mesgno && !isdigit(*mesgno)) ++mesgno; if (!*mesgno) return 0; while (isdigit(*mesgno)) ++mesgno; return mesgno[-1]-'0'; } /* hash */ indb(mesgno, date) register char *mesgno; char *date; { register size; static char temp[128]; register key; register FILE *x; long ftell(); key = hash(mesgno); if (keyfile[key] == NULL) { sprintf(temp, "%s\\%d", LOOPZAP, key); if ((keyfile[key] = fopen(temp, "r+b")) == NULL) { if ((keyfile[key] = fopen(temp, "w+b")) == NULL) { fprintf(stderr, "cannot access key file <%s>!\n", temp); return 1; } x = keyfile[key]; goto insert; } } x = keyfile[key]; rewind(x); size = strlen(mesgno); while (fgets(temp, 128, x)) { if (strncmp(temp, mesgno, size) == 0) return 1; } fseek(x, 0L, SEEK_END); insert: fprintf(x, "%s %s\n", mesgno, date); return 0; }