home *** CD-ROM | disk | FTP | other *** search
- /*--------------------------------------------------------------------*/
- /* 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.17 1993/09/27 04:04:06 ahd Exp $
- *
- * $Log: rnews.c $
- * Revision 1.17 1993/09/27 04:04:06 ahd
- * Reduce buffer sizes to avoid 16 bit stack over flows
- *
- * Revision 1.16 1993/09/24 03:43:27 ahd
- * Double buffers to avoid crashes during Disney Stock Flame War
- *
- * Revision 1.15 1993/09/21 01:42:13 ahd
- * Suppress changes to body of delivered news
- *
- * Revision 1.14 1993/09/20 04:41:54 ahd
- * OS/2 2.x support
- *
- * Revision 1.13 1993/07/31 16:26:01 ahd
- * Changes in support of Robert Denny's Windows support
- *
- * Revision 1.12 1993/07/22 23:19:50 ahd
- * First pass for Robert Denny's Windows 3.x support changes
- *
- * Revision 1.11 1993/05/03 02:41:57 ahd
- * Correct name of file to set into binary mode
- *
- * Revision 1.10 1993/04/19 13:16:20 ahd
- * Binary mode for snews
- *
- * 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.17 1993/09/27 04:04:06 ahd Exp $";
-
- /*--------------------------------------------------------------------*/
- /* System include files */
- /*--------------------------------------------------------------------*/
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <ctype.h>
- #include <time.h>
- #include <fcntl.h>
- #include <io.h>
- #include <process.h>
-
- /*--------------------------------------------------------------------*/
- /* 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"
-
- #include "execute.h"
-
- /*--------------------------------------------------------------------*/
- /* Global defines */
- /*--------------------------------------------------------------------*/
-
- #define UNCOMPRESS "uncompre"
- #ifdef BIT32ENV
- #define DISNEY (BUFSIZ*2)
- #else
- #define DISNEY (BUFSIZ*4/3)
- #endif
-
- /*--------------------------------------------------------------------*/
- /* 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 */
-
- /*--------------------------------------------------------------------*/
- /* 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
-
- logfile = stderr; // Prevent redirection of error
- // messages during configuration
-
- 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 */
- setmode(fileno(stdin), O_BINARY); /* Don't die on control-Z, etc */
-
- /*--------------------------------------------------------------------*/
- /* 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 (hfile == NULL)
- {
- printmsg(0, "Error %s history file", history_exists() ?
- "opening" : "creating");
- panic();
- }
-
- } /* 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 */
- /*--------------------------------------------------------------------*/
-
- 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 );
- unlink( zfile ); /* Kill the compressed input file */
- 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++;
-
- } /* else */
-
- status = execute( program, args, NULL, NULL, TRUE, FALSE);
-
- 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. */
- /*--------------------------------------------------------------------*/
-
- 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[DISNEY]; /* buffer for history file
- (also used for article) */
- char groups[DISNEY];
- char message_buf[DISNEY];
- 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;
- boolean header = TRUE;
-
- /*--------------------------------------------------------------------*/
- /* 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 ( ! header )
- ; // No operation after end of header
- else if ( *buf == '\n' )
- header = FALSE;
- else 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 */
-