/* SNEWS 2.0 rnews - quick and dirty news toss, no feeding of other sites Copyright (C) 1991 John McCombs, Christchurch, NEW ZEALAND john@ahuriri.gen.nz PO Box 2708, Christchurch, NEW ZEALAND This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 1, as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. See the file COPYING, which contains a copy of the GNU General Public License. Derived from unbatch.c by Kai Uwe Rommel USAGE: rnews -x when debug>9 means verbose, tell what we are doing */ #include "defs.h" #include "rnews.h" unsigned _stklen = 16384; INFO my_stuff; char iobuf[IOBUFSIZE]; int verbose, slave; int pidc, pidr; extern char _far *_pgmptr; /*------------------------------- main --------------------------------*/ void main(int argc, char *argv[]) { int arg; FILE *tmp_file; slave = (strcmp(argv[0], "slave") == 0); if (argc > 1 && strncmp(argv[1], "-x", 2) == 0) { verbose = (atoi(argv[1] + 2) >= 9); argc--; argv++; } if (verbose && !slave) fprintf(stderr, "RNEWS: (%s)\n", VERSION); if (!load_stuff()) { fprintf(stderr, "Couldn't read rc info\n"); exit(1); } load_active_file(); open_hist_file(); free_ng(); if (argc == 1) { if (isatty(0)) { if (!verbose) fprintf(stderr, "RNEWS: (%s)\n", VERSION); fprintf(stderr, "\nusage: rnews [-v] [file ...]\n"); exit(1); } setmode(fileno(stdin), O_BINARY); tmp_file = fdopen(dup(fileno(stdin)), "rb"); decode_batch(tmp_file, ""); } else for (arg = 1; arg < argc; arg++) if ((tmp_file = fopen(argv[arg], "rb")) != NULL) { decode_batch(tmp_file, argv[arg]); fclose(tmp_file); } close_hist_file(); close_active_file(); exit(0); } /*--------------------------- unpack the batch ------------------------*/ void write_logentry(char *line) { static FILE *logfile; char buf[256]; if (logfile == NULL) { strcpy(buf, my_stuff.spool_dir); strcat(buf, "rnews.log"); logfile = fopen(buf, "a"); } if (logfile) { _strdate(buf); buf[5] = '-'; _strtime(buf + 6); buf[11] = 0; fprintf(logfile, "%s %s\n", buf, line); } } long save_message(LINE *spool, char *newsgroups, char *subject, char *msg_id) { /* * For each newsgroup * - open the text file * - save the file pointer * - append the message to it * - close the file * - open the index file * - save the file pointer and the subject line */ char buf[512], nglist[256], log[1024], *group, *p; FILE *out_file = NULL; LINE *help; ACTIVE *gp; long where; time_t t; int saved = FALSE; long lines = 0, bytes = 0, cross = 0; for (help = spool; help; help = help->next) { lines++; bytes += strlen(help->data); } for (p = subject; *p && isspace(*p); p++); strcpy(buf, "("); strcat(buf, p); if (buf[strlen(buf) - 1] == '\n') buf[strlen(buf) - 1] = 0; buf[19] = 0; strcat(buf,")"); if (verbose) sprintf(log, "%4ld %6ld %-20.20s to:", lines, bytes, buf); time(&t); nglist[0] = 0; p = strtok(newsgroups, " \r\n,:"); p = strtok(NULL, " \r\n,:"); while (p != NULL) { group = p; p = strtok(NULL, " \r\n,:"); gp = find_news_group(group); if (stricmp(gp->group, "junk") == 0 && (p != NULL || saved)) continue; if (verbose) { strcat(log, " "); strcat(log, gp->group); } out_file = open_out_file(group); where = ftell(out_file); help = spool; setvbuf(out_file, iobuf, _IOFBF, IOBUFSIZE); for (help = spool; help != NULL; help = help->next) fputs(help->data, out_file); fprintf(out_file, "\n@@@@END\n"); fclose(out_file); out_file = open_index_file(group); fprintf(out_file,"%08ld %08ld %09ld %s", where, gp->hi_num, t, subject); fclose(out_file); if (saved) cross++; else saved = TRUE; if ( nglist[0] ) strcat(nglist, ","); strcat(nglist, group); } if (verbose) { write_logentry(log); fprintf(stderr, "%s\n", log); } while (spool) { help = spool; spool = spool->next; free(help->data); free(help); } add_hist_record(msg_id, nglist); return cross; } void toss(FILE *tmp_file) { /* * Toss it into the appropriate files. */ LINE *spool = NULL, *help; char buf[512], buf2[512], *p; char newsgroups[256], subject[256], msg_id[256]; int in_header, control; long lines = 0, articles = 0, cross = 0, bytes = 0; strcpy(msg_id, ""); strcpy(subject, "-- no subject --\n"); strcpy(newsgroups, ""); in_header = TRUE; control = FALSE; /* read the file */ while (fgets(buf, 511, tmp_file) != NULL) { if (strstr(buf, "#! rnews") != NULL) { if (control) strcpy(newsgroups, "Newsgroups: control"); /* kludge */ if (spool != NULL) { cross += save_message(spool, newsgroups, subject, msg_id); articles++; } strcpy(subject, "-- no subject --\n"); in_header = TRUE; control = FALSE; spool = NULL; } else { /* flag the end of the header */ if (strcmp(buf, "\n") == 0) in_header = FALSE; /* save the newsgroups line */ if (in_header) { if (strnicmp(buf,"Message-ID:",11) == 0) { strcpy(buf2, buf); p = strtok(buf2, " \t\r\n"); p = strtok(NULL, " \t\r\n"); strcpy(msg_id, p); } if (strnicmp(buf,"Newsgroups:",11) == 0) strcpy(newsgroups,buf); if (strnicmp(buf,"Subject:",8) == 0) strcpy(subject, buf+8); if (strnicmp(buf,"Control:",8) == 0) control = TRUE; /* add our system name to the path list */ if (strnicmp(buf, "Path:", 5) == 0) { p = strtok(buf, " \t"); p = strtok(NULL, " \t"); strcpy(buf2, p); sprintf(buf, "Path: %s!%s", my_stuff.my_site, buf2); } } if (spool == NULL) spool = help = (LINE *) xmalloc(sizeof(LINE)); else { help->next = (LINE *) xmalloc(sizeof(LINE)); help = help->next; } help->next = NULL; help->data = (char *) xmalloc(strlen(buf) + 1); strcpy(help->data, buf); lines++; bytes += strlen(buf); } } /* process the last one */ if (control) strcpy(newsgroups, "Newsgroups: control"); /* kludge */ if (spool != NULL) { cross += save_message(spool, newsgroups, subject, msg_id); articles++; } sprintf(buf, "Delivered %ld articles, %ld crossposts, %ld lines, %ldk bytes.", articles, cross, lines, (bytes + 512) / 1024); write_logentry(buf); fprintf(stderr, "rnews: %s\n", buf); } /*--------------------------- unpack the batch ------------------------*/ FILE *create_pipe(char *compressor) { int pipe1[2], pipe2[2], oldout; _pipe(pipe1, 4096, O_BINARY); _pipe(pipe2, 4096, O_BINARY); noinherit(pipe1[1]); noinherit(pipe2[0]); oldout = dup(1); close(0); dup2(pipe1[0], 0); close(pipe1[0]); close(1); dup2(pipe2[1], 1); close(pipe2[1]); pidc = spawnlp(P_NOWAIT, compressor, compressor, "-d", NULL); close(0); dup2(pipe2[0], 0); close(pipe2[0]); close(1); dup2(oldout, 1); close(oldout); pidr = spawnlp(P_NOWAIT, _pgmptr, "slave", verbose ? "-x9" : NULL, NULL); close(0); return fdopen(pipe1[1], "wb"); } void close_pipe(FILE *stream) { fclose(stream); cwait(NULL, pidc, WAIT_CHILD); cwait(NULL, pidr, WAIT_CHILD); } void decode_batch(FILE *in_file, char *fn) { /* * take the batch, strip off the !cunbatch, and feed the file to * uncompress, the opened uncompressed file is returned */ FILE *out_file; int res, header; char buf[1024], *compressor; long pos; short magic; if (fgets(buf, sizeof(buf), in_file) == NULL) { fprintf(stderr, "batch %s is inexplicably too small\n", fn); return; } if (memcmp(buf, "#! rnews ", 9) == 0) { if (verbose) fprintf(stderr, "Unpacking %s ...\n", fn); toss(in_file); return; } if (memcmp(buf, "#! cunbatch\n", 12) == 0) header = TRUE; else if (memcmp(buf, "#! funbatch\n", 12) == 0) header = TRUE; else header = FALSE; if (header) fread(&magic, 1, sizeof(short), in_file); else memcpy(&magic, buf, sizeof(short)); if (magic == COMPRESS) compressor = "compress"; else if (magic == FREEZE) compressor = "freeze"; else { fprintf(stderr, "batch %s has unknown compression type\n", fn); return; } out_file = create_pipe(compressor); if (out_file == NULL) { fprintf(stderr, "Cannot create pipe for %s.\n", fn); return; } if (verbose) fprintf(stderr,"Piping compressed %s to '%s -d' and slave 'rnews' ...\n", fn, compressor); if (header) fwrite(&magic, 1, sizeof(short), out_file); else fputs(buf, out_file); while ((res = fread(buf, 1, 1024, in_file)) > 0) fwrite(buf, 1, res, out_file); close_pipe(out_file); }