/*--------------------------------------------------------------------*/ /* r n e w s . c */ /* */ /* Receive incoming news into the news directory. */ /* */ /* Written by Mike Lipsie; modified for UUPC/extended 1.11s by */ /* Andrew H., Derbyshire. */ /* */ /* Changes and Compilation Copyright (c) 1992 by Andrew H. */ /* Derbyshire. All rights reserved except as granted by the */ /* general UUPC/extended license. */ /* */ /* This package has been substantially modified. It will now */ /* copy compressed articles (assumed batches but they could be */ /* single articles) to the CMPRSSED directory and it will */ /* unbatch (if necessary) and deliver articles to their */ /* appropriate newsgroup directories. At the end, if the file */ /* was compressed it will invoke a batch file which will */ /* uncompress the file and then feed it back to rnews. */ /* */ /* Appropriate is defined as */ /* */ /* (a) the newsgroup is in the active file and */ /* (b) the directory name is the group name with all */ /* the"."s replaced with "/"s and all of that under the */ /* news directory. */ /* */ /* Names are insured to be valid by ImportNewsGroup, which maps */ /* invalid characters and truncates names as required. */ /*--------------------------------------------------------------------*/ /*--------------------------------------------------------------------*/ /* RCS Information */ /*--------------------------------------------------------------------*/ /* * $Id: RNEWS.C 1.9 1993/04/17 13:40:39 ahd Exp $ * * $Log: RNEWS.C $ * Revision 1.9 1993/04/17 13:40:39 ahd * fix compile errors for snews fix * * Revision 1.8 1993/04/17 13:23:37 ahd * make snews option more compatible with snews (which is brain dead) * * Revision 1.7 1993/04/16 12:55:36 dmwatt * Bounds check group lengths * * Revision 1.5 1993/04/11 00:33:54 ahd * Global edits for year, TEXT, etc. * * Revision 1.4 1993/03/24 01:57:30 ahd * Corrections for short articles * Corrections for articles claimed to be zero length * Resync gracefully after incorrect length descriptor * * Revision 1.3 1993/03/06 23:04:54 ahd * Do not delete open files * * Revision 1.2 1992/11/22 21:14:21 ahd * Reformat selected sections of code * Check for premature end of articles in batched news * */ static const char rcsid[] = "$Id: RNEWS.C 1.9 1993/04/17 13:40:39 ahd Exp $"; /*--------------------------------------------------------------------*/ /* System include files */ /*--------------------------------------------------------------------*/ #include #include #include #include #include #include #include #include /*--------------------------------------------------------------------*/ /* UUPC/extended include files */ /*--------------------------------------------------------------------*/ #include "lib.h" #include "active.h" #include "getopt.h" #include "getseq.h" #include "history.h" #include "hlib.h" #include "import.h" #include "importng.h" #include "logger.h" #include "timestmp.h" /*--------------------------------------------------------------------*/ /* Global defines */ /*--------------------------------------------------------------------*/ #define UNCOMPRESS "uncompre" /*--------------------------------------------------------------------*/ /* Global variables */ /*--------------------------------------------------------------------*/ currentfile(); extern struct grp *group_list; /* List of all groups */ FILE *hfile = NULL; /* History file */ char history_date[12]; /* dd/mm/yyyy + null + 1 for no good reason */ char hbuff[BUFSIZ]; /*--------------------------------------------------------------------*/ /* Functions in this file */ /*--------------------------------------------------------------------*/ static boolean deliver_article(char *art_fname); /* Distribute the article to the proper newsgroups */ static void copy_file(FILE *f, char *group, char *xref); /* Copy file (f) to newsgroup */ static struct grp *find_newsgroup(const char *grp); /* Get the grp struct for the newsgroup */ static void get_snum(const char *group, char *snum); /* Get (and format) the next article number in group */ static void fixEOF( char *buf, int bytes ); static int Single( char *filename , FILE *stream ); static int Compressed( char *filename , FILE *in_stream ); static int Batched( char *filename, FILE *stream); static void xmit_news( char *sysname, FILE *in_stream ); static int copy_snews( char *filename, FILE *stream ); /*--------------------------------------------------------------------*/ /* m a i n */ /* */ /* Main program */ /* */ /* Exit conditions */ /* */ /* 0 - Success */ /* 1 - System configuration failed */ /* 2 - Unable to open working file */ /* 4 - out of memory */ /* 5 - Unable to create history dbm file */ /* 6 - Problem decompressing news batch */ /* 7 - Unable to create cmprssed directory */ /*--------------------------------------------------------------------*/ void main( int argc, char **argv) { struct tm *local_now; long now = time(nil(long)); FILE *f; char in_filename[FILENAME_MAX]; char filename[FILENAME_MAX]; int c; int status; #if defined(__CORE__) copywrong = strdup(copyright); checkref(copywrong); #endif banner( argv ); if (!configure( B_NEWS )) exit(1); /* system configuration failed */ openlog( NULL ); /* Begin logging to disk */ if (argc > 1) { int option; /*------------------------------------------------------------*/ /* parse arguments */ /*------------------------------------------------------------*/ while ((option = getopt(argc, argv, "f:x:")) != EOF) { switch (option) { case 'f': strcpy(in_filename, optarg); f = freopen(in_filename, "r", stdin); if (f == NULL) { printerr( in_filename ); panic(); } else printmsg(2, "Opened %s as newsfile", in_filename); break; case 'x': debuglevel = atoi(optarg); break; case '?': puts("\nUsage:\trnews [-f newsfile] [-x debug]"); return; } /* break */ } /* while */ } /* if (argc > 1) */ tzset(); /* Set up time zone information */ /*--------------------------------------------------------------------*/ /* If we are processing snews input, write it all out to the */ /* news directory as one file and return gracefully. */ /*--------------------------------------------------------------------*/ if ( bflag[F_SNEWS]) { char *savetemp = E_tempdir; /* Save the real temp directory */ if (bflag[F_HISTORY]) { printmsg(0, "rnews: Conflicting options snews and history specified!"); panic(); } /* else if */ E_tempdir = E_newsdir; /* Generate this file in news */ mktempname(filename, "ART"); /* Get the file name */ E_tempdir = savetemp; /* Restore true directory name */ exit (copy_snews( filename, stdin )); /* Dump news into NEWS directory */ } else mktempname(filename, "tmp"); /* Make normal temp name */ /*--------------------------------------------------------------------*/ /* Load the active file and validate its data */ /*--------------------------------------------------------------------*/ get_active(); /* Get sequence numbers for groups from active file */ validate_newsgroups(); /* Make sure all directories exist */ /*--------------------------------------------------------------------*/ /* Initialize history processing */ /*--------------------------------------------------------------------*/ local_now = localtime(&now); sprintf(history_date, "%2.2d/%2.2d/%4d", local_now->tm_mday, local_now->tm_mon+1, local_now->tm_year+1900); /*--------------------------------------------------------------------*/ /* Open (or create) the history file */ /*--------------------------------------------------------------------*/ if ( bflag[F_HISTORY] ) { if (history_exists()) hfile = open_history(history_date); else hfile = create_history(history_date); } /* if */ /*--------------------------------------------------------------------*/ /* This loop copies the file to the NEWS directory. */ /* */ /* A news article/batch either has a '#' character as its first */ /* character or it does not. */ /* */ /* If it does not it is a single (unbatched, uncompressed) */ /* article. */ /* */ /* If the first character _is_ a '#', the first line is #! */ /* cunbatch\n which means that it is a compressed batch; it */ /* will be uncompressed and then re-fed to rnews or the first */ /* line can be #! rnews nnn\n (where nnn is some number) which */ /* means that the next nnn characters are an article and that */ /* more might follow. */ /* */ /* Due to a "feature" in the compressed batch, there may be */ /* _no_ articles batched (an article destined for transmittal */ /* is cancelled before being sent). */ /* */ /* Since this is a bit spread out, the various clauses of the */ /* if statement will be marked with boxed 1, 2, or 3 (and a */ /* brief explanation. */ /*--------------------------------------------------------------------*/ /*--------------------------------------------------------------------*/ /* Compressed files need to be read in BINARY mode so that */ /* "magic" characters (like ^Z) don't upset it. Batched files */ /* need to be read in TEXT mode so that the character count is */ /* correct. The other case doesn't matter. */ /*--------------------------------------------------------------------*/ c = getc(stdin); ungetc(c, stdin); if (c != '#') { /***********************************************/ /* 1 single (unbatched, uncompressed) article */ /***********************************************/ status = Single(filename, stdin); } else { char buf[BUFSIZ]; int fields = fscanf(stdin, "#! %s ", &buf); if ((fields == 1) && (strcmp(buf, "cunbatch") == 0)) { /***********************************************/ /* 2 Compressed batch */ /***********************************************/ status = Compressed(filename, stdin); } else { /***********************************************/ /* 3 Uncompressed batch */ /***********************************************/ status = Batched( filename, stdin ); } /* else */ } /* else */ /*--------------------------------------------------------------------*/ /* Close open files and exit */ /*--------------------------------------------------------------------*/ put_active(); if (hfile != NULL) fclose(hfile); exit(status); } /*main*/ /*--------------------------------------------------------------------*/ /* S i n g l e */ /* */ /* Deliver a single article to the proper news group(s) */ /*--------------------------------------------------------------------*/ static int Single( char *filename , FILE *stream ) { char tmp_fname[FILENAME_MAX]; FILE *tmpf; char buf[BUFSIZ]; unsigned chars_read; unsigned chars_written; /*--------------------------------------------------------------------*/ /* Make a file name and then open the file to write the article into */ /*--------------------------------------------------------------------*/ tmpf = FOPEN(filename, "w", BINARY_MODE); if ( tmpf == NULL ) { printerr( tmp_fname ); panic(); } /*--------------------------------------------------------------------*/ /* Now copy the input into our holding bin */ /*--------------------------------------------------------------------*/ while ((chars_read = fread(buf,sizeof(char), BUFSIZ, stream)) != 0) { chars_written = fwrite(buf, sizeof(char), chars_read, tmpf); if (chars_written != chars_read) { printerr( filename ); printmsg(0, "rnews: Error writing single article to working file"); fclose( tmpf ); unlink( filename ); panic(); } } /*--------------------------------------------------------------------*/ /* Close the file, deliver the article, and return the caller */ /*--------------------------------------------------------------------*/ fclose(tmpf); deliver_article(filename); unlink( filename ); return 0; } /* Single */ /*--------------------------------------------------------------------*/ /* C o m p r e s s e d */ /* */ /* Decompress news */ /*--------------------------------------------------------------------*/ static int Compressed( char *filename , FILE *in_stream ) { FILE *work_stream; char zfile[FILENAME_MAX]; char unzfile[FILENAME_MAX]; char buf[BUFSIZ]; boolean first_time = TRUE; char *program, *args; long cfile_size = 0L; size_t chars_read, i; int status = 0; boolean needtemp = TRUE; char *sysname; /* For reading systems to process */ /*--------------------------------------------------------------------*/ /* Copy the compressed file to the "holding" directory */ /*--------------------------------------------------------------------*/ setmode(fileno(in_stream), O_BINARY);/* Don't die on control-Z, etc */ fseek(in_stream, 0L, SEEK_SET); /* Back to the beginning */ while( needtemp ) { mktempname( zfile , "Z" ); /* Generate "compressed" file name */ strcpy( unzfile, zfile ); unzfile[ strlen(unzfile)-2 ] = '\0'; if ( access( unzfile, 0 )) /* Does the host file exist? */ needtemp = FALSE; /* No, we have a good pair */ else printmsg(0,"Had compressed name %s, found %s already exists!", zfile, unzfile ); } /* while */ /*--------------------------------------------------------------------*/ /* Open the file, with error recovery */ /*--------------------------------------------------------------------*/ if ((work_stream = FOPEN(zfile, "w", BINARY_MODE)) == nil(FILE)) { printmsg(0, "Compressed: Can't open %s (%d)", zfile, errno); printerr(zfile); return 2; } printmsg(2, "Compressed: Copy to %s for later processing", zfile); /*--------------------------------------------------------------------*/ /* Main loop to copy compressed file */ /*--------------------------------------------------------------------*/ while ((chars_read = fread(buf,sizeof(char), BUFSIZ, in_stream)) != 0) { char *t_buf = buf; if (first_time) { t_buf += sizeof("#! cunbatch"); first_time = FALSE; chars_read -= (t_buf - buf); while ((*t_buf == ' ') || (*t_buf == '\n') || (*t_buf == '\r')) { t_buf++; chars_read--; } /* while */ } /* if */ i = fwrite(t_buf,sizeof(char),chars_read,work_stream); if (i != chars_read) { fclose( work_stream ); printerr( zfile ); panic(); } cfile_size += (long)chars_read; } /* while */ fclose(work_stream); /*--------------------------------------------------------------------*/ /* If the file is empty, delete it gracefully */ /*--------------------------------------------------------------------*/ if (cfile_size == 3) { unlink(zfile); /* Get rid of null file */ printmsg(1, "Compressed: %s empty, deleted", zfile); return status; } else printmsg(2,"Compressed: Copy to %s complete, %ld characters", zfile, cfile_size); /*--------------------------------------------------------------------*/ /* Special hack for creating mirror images of the news feed */ /*--------------------------------------------------------------------*/ sysname = getenv( "UUPCSHADOWS" ); if ( sysname != NULL ) { strcpy( buf, sysname); sysname = strtok( buf, WHITESPACE ); while( sysname != NULL ) { printmsg(1,"Compressed: Shadowing news to %s", sysname ); fseek(in_stream, 0L, SEEK_SET); /* Back to the beginning */ xmit_news( sysname, in_stream ); sysname = strtok( NULL, WHITESPACE ); } } /* if */ /*--------------------------------------------------------------------*/ /* Uncompress the article and feed it back to rnews */ /*--------------------------------------------------------------------*/ if ( E_uncompress == NULL ) { program = UNCOMPRESS; args = zfile; printmsg(2,"Compressed: %s %s", program , args); } else { sprintf( buf, E_uncompress, zfile, unzfile ); printmsg(2,"Compressed: %s", buf ); program = strtok( buf, WHITESPACE ); args = strtok( NULL, ""); if ( args != NULL ) while (isspace(*args)) args++; } status = spawnlp(P_WAIT, program, program, args, NULL); unlink( zfile ); /* Kill the compressed input file */ if (status != 0) { if (status == -1) { printmsg( 0, "Compress: spawn failed completely" ); printerr( program ); } else printmsg(0, "%s command failed (exit code %d)", UNCOMPRESS, status); panic(); } /* if status != 0 */ /*--------------------------------------------------------------------*/ /* Now process the file as normal batched news */ /*--------------------------------------------------------------------*/ /* Create uncompressed output file name */ work_stream = FOPEN( unzfile, "r", BINARY_MODE); if ( work_stream == NULL ) { printerr( unzfile ); panic(); } status = Batched( filename, work_stream ); /*--------------------------------------------------------------------*/ /* Clean up and return to caller */ /*--------------------------------------------------------------------*/ fclose( work_stream ); unlink( unzfile ); return status; } /* Compressed */ /*--------------------------------------------------------------------*/ /* B a t c h e d */ /* */ /* Handle batched, uncompressed news */ /*--------------------------------------------------------------------*/ static int Batched( char *filename, FILE *stream) { char buf[BUFSIZ * 2]; int status = 0; long article_size; int articles = 0; int ignored = 0; boolean gotsize = FALSE; int chars_read; int chars_written; /*--------------------------------------------------------------------*/ /* This is an uncompressed batch. Copy it to the working */ /* directory and then distribute the individual articles. */ /*--------------------------------------------------------------------*/ setmode(fileno(stream), O_BINARY ); /* Don't die on Cntrl Z, etc. */ fseek(stream, 0L, SEEK_SET); /* Back to the beginning */ while( ! feof( stream ) && ! ferror( stream )) { long article_left; int max_read = (long) sizeof buf; long skipped_lines = 0; long skipped_bytes = 0; FILE *tmpf; /*--------------------------------------------------------------------*/ /* Handle next article (articles are separated by the line */ /* indicating their size when they are batched.) */ /*--------------------------------------------------------------------*/ while ( ! gotsize ) { if (fgets( buf, sizeof buf, stream ) == NULL) break; if ( equaln( "#! rnews", buf, 8) ) { article_size = 0; sscanf(buf, "#! rnews %ld \n", &article_size); gotsize = TRUE; } else { skipped_lines ++; skipped_bytes += strlen( buf ); } } /* while */ if ( skipped_lines ) printmsg(0, "Batched: Skipped %ld bytes in %ld " "lines after article %d", skipped_bytes, skipped_lines, articles ); /*--------------------------------------------------------------------*/ /* Trap end of file */ /*--------------------------------------------------------------------*/ if ( ! gotsize ) { if ( ferror( stream )) printerr( "stdin" ); break; } article_left = article_size; gotsize = FALSE; /*--------------------------------------------------------------------*/ /* Open up our next working file */ /*--------------------------------------------------------------------*/ tmpf = FOPEN(filename, "w", BINARY_MODE); if ( tmpf == NULL ) { printerr( filename ); panic(); } /*--------------------------------------------------------------------*/ /* Copy this article to the temp file (except for the last block) */ /*--------------------------------------------------------------------*/ if ( article_size ) { do { if ( article_left < max_read ) max_read = (int) article_left; chars_read = fread(buf, sizeof(char), max_read, stream); if ( (chars_read < max_read) && ferror( stream )) { printerr("STDIN"); panic(); } if ( chars_read == 0) break; fixEOF( buf , chars_read ); chars_written = fwrite(buf, sizeof(char), chars_read, tmpf); if (chars_read != chars_written) { printmsg(0,"Batched: Read %d bytes, only wrote %d bytes of article %d", chars_read, chars_written , articles + 1); printerr(filename); } article_left -= chars_read; } while (article_left > 0); if ( article_left ) // Premature EOF? printmsg(0,"Batched: Unexpected EOF for article %d, " "read %ld bytes of expected %ld", articles + 1, article_size - article_left, article_size ); } /* if */ else { long actual_size = 0; do { if (fgets( buf, sizeof buf, stream ) == NULL) { if ( ferror( stream )) printerr( filename ); break; } chars_read = strlen( buf ); if ( equaln( "#! rnews", buf, 8) ) { sscanf(buf, "#! rnews %ld \n", &article_size); gotsize = TRUE; } else if ( chars_read > 0 ) { actual_size += chars_read; chars_written = fwrite(buf, sizeof(char), chars_read, tmpf); if (chars_read != chars_written) { printmsg(0, "Batched: Read %d bytes, only wrote %d bytes of article %d", chars_read, chars_written , articles + 1); printerr(filename); } } /* else */ } while( ! gotsize ); printmsg(2,"Batched: Article %d size %ld", articles + 1, actual_size ); } /* else */ /*--------------------------------------------------------------------*/ /* Close the file, deliver its contents, and get rid of it */ /*--------------------------------------------------------------------*/ fclose(tmpf); if ( ! deliver_article(filename) ) ignored ++; unlink( filename ); articles ++; } /* while */ /*--------------------------------------------------------------------*/ /* Return to caller */ /*--------------------------------------------------------------------*/ if ( ignored ) printmsg(1,"Batched: Unbatched %d articles (discarded %d of these)", articles , ignored); else printmsg(1,"Batched: Unbatched %d articles", articles ); return status; } /* Batched */ /*--------------------------------------------------------------------*/ /* f i x E O F */ /* */ /* Zap Cntrl-Z characters in the input stream */ /*--------------------------------------------------------------------*/ static void fixEOF( char *buf, int bytes ) { static warn = TRUE; while ( bytes-- ) { if ( *buf == ('Z' - 'A')) { *buf = 'Z'; if ( warn ) { printmsg(0,"Altered Cntl-Z to Z"); warn = FALSE; } /* if */ } /* if */ } /* while */ } /* fixEOF */ /*--------------------------------------------------------------------*/ /* d e l i v e r _ a r t i c l e */ /* */ /* Determine delivery of a posting */ /*--------------------------------------------------------------------*/ static boolean deliver_article(char *art_fname) { char groupy[MAXGRP]; char *newsgroups = NULL; /* The Newsgroups: line */ char *messageID = NULL; /* The Message-ID: line */ char *gc_ptr; /* Scratch pointers. Mostly used to go */ char *gc_ptr1; /* down the list of newsgroups. */ FILE *tfile; /* The article file */ int n_hdrs; /* Number of desired headers seen */ int b_xref; int line_len; char hist_record[BUFSIZ]; /* buffer for history file (also used for article) */ char groups[BUFSIZ]; char message_buf[BUFSIZ]; char snum[10]; tfile = FOPEN(art_fname, "r", BINARY_MODE); if ( tfile == NULL ) { printerr( art_fname ); panic(); } /*--------------------------------------------------------------------*/ /* Get fields necessary for distribution (Newsgroups:) and the */ /* history file (Message-ID:). Also, if the article is going */ /* to more than one newsgroup, flag the creation of Xref: fields. */ /*--------------------------------------------------------------------*/ n_hdrs = b_xref = 0; while (n_hdrs < 2) { /* Get the next line */ gc_ptr = fgets(hist_record, sizeof(hist_record), tfile); /*--------------------------------------------------------------------*/ /* Check for end of the headers */ /*--------------------------------------------------------------------*/ if ((gc_ptr == NULL) || (strlen(hist_record) == 1)) { /* Ooops. Missing Message-ID: or Newsgroups: */ if (messageID == NULL) printmsg(0, "Article has no Message-ID:, discarded"); else { if (newsgroups == NULL) { printmsg(0, "Article %s has no Newsgroups: line, discarded", messageID); } /* if */ else break; } /* else */ fclose(tfile); return FALSE; } /* if ((gc_ptr == NULL) || (strlen(hist_record) == 1)) */ line_len = strlen(hist_record); if (hist_record[line_len-1] == '\n') hist_record[(line_len--)-1] = '\0'; if (hist_record[line_len-1] == '\r') hist_record[(line_len--)-1] = '\0'; if (equalni(hist_record, "Newsgroups:", strlen("Newsgroups:"))) { /* Handle Newsgroups: line*/ if (newsgroups == NULL) { gc_ptr += strlen("Newsgroups:") + 1; newsgroups = strcpy(groups, gc_ptr); newsgroups[strlen(newsgroups)+1] = '\0'; /* Guard char for rescan */ n_hdrs++; b_xref = (strchr(newsgroups, ',') != NULL); /* more than 1 group */ } /* i.e. do we need to create a Xrefs: line ? */ else printmsg(0, "Article has multiple Newsgroups: lines"); } else if (equalni(hist_record, "Message-ID:", strlen("Message-ID:"))) { /* Handle Message-ID: line */ if (messageID == NULL) { gc_ptr += strlen("Message-ID:") + 1; messageID = message_buf; messageID[0] = '\0'; if (*gc_ptr != '<') strcat(messageID, "<"); strcat(messageID, gc_ptr); if (messageID[strlen(messageID)-1] != '>') strcat(messageID,">"); n_hdrs++; } /* if (messageID == NULL) */ } } /* while getting Newsgroups: and Message-ID: */ /*--------------------------------------------------------------------*/ /* Check whether article has been received before */ /*--------------------------------------------------------------------*/ if ( bflag[ F_HISTORY ] ) { if (is_in_history(hfile, messageID)) { printmsg(2, "rnews: Duplicate article %s", messageID); fclose(tfile); return FALSE; } /* Start building the history record for this article */ strcpy(hist_record, messageID); strcat(hist_record, " "); strcat(hist_record, history_date); strcat(hist_record, " "); gc_ptr1 = newsgroups; while ((gc_ptr = strchr(gc_ptr1, ',')) != NULL) { gc_ptr[0] = '\0'; if (strlen(gc_ptr1) > MAXGRP - 1) { /* Bounds check the newsgroup len */ printmsg(0, "rnews: newsgroup name too long -- %s", gc_ptr1); gc_ptr1 = gc_ptr + 1; continue; /* Punt the newsgroup history record */ } strcpy(groupy, gc_ptr1); strcat(hist_record, groupy); strcat(hist_record, ":"); gc_ptr1 = gc_ptr + 1; get_snum(groupy,snum); strcat(hist_record, snum); strcat(hist_record, ","); } strcpy(groupy, gc_ptr1); strcat(hist_record, groupy); strcat(hist_record, ":"); get_snum(groupy,snum); strcat(hist_record, snum); strcat(hist_record, "\n"); /* Restore the newsgroups line */ while (newsgroups[strlen(newsgroups)+1] != '\0') { newsgroups[strlen(newsgroups)] = ','; } /* Post the history record */ fseek(hfile, 0L, SEEK_END); fwrite(hist_record, sizeof(char), strlen(hist_record), hfile); } /* if ( bflag[ F_HISTORY ] ) */ /*--------------------------------------------------------------------*/ /* Now build the Xref: line (if we need to) */ /*--------------------------------------------------------------------*/ if (b_xref) { strcpy(hist_record, "Xref: "); strcat(hist_record, E_nodename); strcat(hist_record, " "); gc_ptr1 = newsgroups; while ((gc_ptr = strchr(gc_ptr1, ',')) != NULL) { gc_ptr[0] = '\0'; if (strlen(gc_ptr1) > MAXGRP - 1) { /* Bounds check the newsgroup len */ printmsg(0, "rnews: newsgroup name too long -- %s", gc_ptr1); gc_ptr1 = gc_ptr + 1; continue; /* Punt the newsgroup history record */ } strcpy(groupy, gc_ptr1); strcat(hist_record, groupy); strcat(hist_record, ":"); gc_ptr1 = gc_ptr + 1; get_snum(groupy,snum); strcat(hist_record, snum); strcat(hist_record, " "); } strcpy(groupy, gc_ptr1); strcat(hist_record, groupy); strcat(hist_record, ":"); get_snum(groupy,snum); strcat(hist_record, snum); strcat(hist_record, "\n"); /* Restore the newsgroups line */ while (newsgroups[strlen(newsgroups)+1] != '\0') { newsgroups[strlen(newsgroups)] = ','; } } /*--------------------------------------------------------------------*/ /* We now need to copy the file to each group in groupys */ /*--------------------------------------------------------------------*/ gc_ptr1 = newsgroups; while ((gc_ptr = strchr(gc_ptr1, ',')) != NULL) { gc_ptr[0] = '\0'; strcpy(groupy, gc_ptr1); gc_ptr1 = gc_ptr + 1; copy_file(tfile, groupy, b_xref ? hist_record : NULL); } strcpy(groupy, gc_ptr1); copy_file(tfile, groupy, b_xref ? hist_record : NULL); fclose(tfile); return TRUE; } /* deliver_article */ /*--------------------------------------------------------------------*/ /* f i n d _ n e w s g r o u p */ /* */ /* Locate a news group in our list */ /*--------------------------------------------------------------------*/ static struct grp *find_newsgroup(const char *grp) { struct grp *cur = group_list; while ((strcmp(grp,cur->grp_name) != 0)) { if (cur->grp_next != NULL) { cur = cur->grp_next; } else { return NULL; } } return cur; } /*--------------------------------------------------------------------*/ /* c o p y _ f i l e */ /* */ /* Write an article to it's final resting place */ /*--------------------------------------------------------------------*/ static void copy_file(FILE *input, char *group, char *xref) { struct grp *cur; char filename[FILENAME_MAX]; char buf[BUFSIZ]; FILE *output; /*--------------------------------------------------------------------*/ /* Determine if the news has been already posted */ /*--------------------------------------------------------------------*/ cur = find_newsgroup(group); if (cur == NULL) { printmsg(3, "rnews: Article cross-posted to %s", group); return; } /*--------------------------------------------------------------------*/ /* Now build a file name */ /*--------------------------------------------------------------------*/ ImportNewsGroup( filename, cur->grp_name, cur->grp_high++); /*--------------------------------------------------------------------*/ /* We have a file name, open the file */ /*--------------------------------------------------------------------*/ printmsg(2, "rnews: Saving %s article in %s", cur->grp_name, filename); if ((output = FOPEN(filename, "w",TEXT_MODE)) == nil(FILE)) { printerr( filename ); printmsg(0, "rnews: Unable to save article"); return; } rewind(input); if (xref) /* write new Xref: line first */ { if (fputs(xref, output) == EOF) { printerr( filename ); panic(); } } while (fgets(buf, sizeof buf, input) != NULL) { if (equalni(buf, "Path:", strlen("Path:"))) { fprintf(output, "Path: %s!%s", E_nodename, buf + strlen("Path:") + 1); continue; } else if (equalni(buf, "Xref:", strlen("Xref:"))) continue; /* skip possibly old Xref: line */ if (fputs(buf, output) == EOF) { printerr( filename ); panic(); } } /* while */ fclose(output); } /* copy_file */ /*--------------------------------------------------------------------*/ /* g e t _ s n u m */ /* */ /* Get highest article number of newsgroup */ /*--------------------------------------------------------------------*/ static void get_snum(const char *group, char *snum) { struct grp *cur; strcpy(snum, "0"); cur = find_newsgroup(group); if (cur == NULL) return; sprintf(snum, "%d", cur->grp_high); } /* snum */ /*--------------------------------------------------------------------*/ /* x m i t _ n e w s */ /* */ /* A cruel hack to transmit news to other systems */ /*--------------------------------------------------------------------*/ static void xmit_news( char *sysname, FILE *in_stream ) { static char *spool_fmt = SPOOLFMT; /* spool file name */ static char *dataf_fmt = DATAFFMT; static char *send_cmd = "S %s %s %s - %s 0666\n"; static long seqno = 0; FILE *out_stream; /* For writing out data */ char buf[BUFSIZ]; unsigned len; char msfile[FILENAME_MAX]; /* MS-DOS format name of files */ char msname[22]; /* MS-DOS format w/o path name */ char tmfile[15]; /* Call file, UNIX format name */ char ixfile[15]; /* eXecute file for remote system, UNIX format name for local system */ char idfile[15]; /* Data file, UNIX format name */ char rdfile[15]; /* Data file name on remote system, UNIX format */ char rxfile[15]; /* Remote system UNIX name of eXecute file */ char *seq; /*--------------------------------------------------------------------*/ /* Create the UNIX format of the file names we need */ /*--------------------------------------------------------------------*/ seqno = getseq(); seq = JobNumber( seqno ); sprintf(tmfile, spool_fmt, 'C', sysname, 'd' , seq); sprintf(idfile, dataf_fmt, 'D', E_nodename , seq, 'd'); sprintf(rdfile, dataf_fmt, 'D', E_nodename , seq, 'r'); sprintf(ixfile, dataf_fmt, 'D', E_nodename , seq, 'e'); sprintf(rxfile, dataf_fmt, 'X', E_nodename , seq, 'r'); /*--------------------------------------------------------------------*/ /* create remote X (xqt) file */ /*--------------------------------------------------------------------*/ importpath( msname, ixfile, sysname); mkfilename( msfile, E_spooldir, msname); out_stream = FOPEN(msfile, "w", BINARY_MODE); if ( out_stream == NULL ) { printmsg(0, "xmit_news: cannot open X file %s", msfile); printerr(msfile); return ; } /* if */ if (setvbuf( out_stream, NULL, _IONBF, 0)) { printmsg(0, "xmit_news: Cannot unbuffer file %s (%s).", ixfile, msfile); printerr(msfile); panic(); } /* if */ fprintf(out_stream, "R %s %s\nU %s %s\nF %s\nI %s\nC rnews\n", "uucp", E_domain, "uucp", E_nodename, rdfile, rdfile); fclose(out_stream); /*--------------------------------------------------------------------*/ /* Create the data file with the mail to send to the remote system */ /*--------------------------------------------------------------------*/ importpath(msname, idfile, sysname); mkfilename( msfile, E_spooldir, msname); out_stream = FOPEN(msfile, "w", BINARY_MODE); if (out_stream == NULL ) { printerr(msfile); printmsg(0, "xmit_news: Cannot open spool file \"%s\" for output", msfile); return; } if (setvbuf( out_stream, NULL, _IONBF, 0)) { printmsg(0, "xmit_news: Cannot unbuffer file %s (%s).", idfile, msfile); printerr(msfile); panic(); } /* if */ /*--------------------------------------------------------------------*/ /* Loop to copy the data */ /*--------------------------------------------------------------------*/ while ( (len = fread( buf, 1, sizeof buf, in_stream)) != 0) { if (fwrite( buf, 1, len, out_stream ) != len) /* I/O error? */ { printerr(msfile); fclose(out_stream); return; } /* if */ } /* while */ fclose( out_stream ); /*--------------------------------------------------------------------*/ /* create local C (call) file */ /*--------------------------------------------------------------------*/ importpath( msname, tmfile, sysname); mkfilename( msfile, E_spooldir, msname); out_stream = FOPEN(msfile, "w",TEXT_MODE); if (out_stream == NULL) { printerr( msname ); printmsg(0, "xmit_news: cannot open C file %s", msfile); return; } fprintf(out_stream, send_cmd, idfile, rdfile, "uucp", idfile); fprintf(out_stream, send_cmd, ixfile, rxfile, "uucp", ixfile); fclose(out_stream); } /* xmit_news */ /*--------------------------------------------------------------------*/ /* c o p y _ s n e w s */ /* */ /* Process news destined for the simple news reader */ /*--------------------------------------------------------------------*/ static int copy_snews( char *filename, FILE *stream ) { char buf[BUFSIZ]; size_t len; FILE *out_stream = FOPEN(filename, "w", BINARY_MODE); if ( out_stream == NULL ) { printerr(filename); panic(); } /* if */ if (setvbuf( out_stream, NULL, _IONBF, 0)) { printmsg(0, "copy_snews: Cannot unbuffer file %s.", filename); printerr(filename); panic(); } /* if */ /*--------------------------------------------------------------------*/ /* Perform the copy */ /*--------------------------------------------------------------------*/ while ( (len = fread( buf, 1, sizeof buf, stream)) != 0) { if (fwrite( buf, 1, len, out_stream ) != len) /* I/O error? */ { printerr(filename); panic(); } /* if */ } /* while */ /*--------------------------------------------------------------------*/ /* Close the file */ /*--------------------------------------------------------------------*/ fclose( out_stream ); fclose( stream ); return 0; } /* copy_snews */