home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Professional / OS2PRO194.ISO / os2 / com / bbs / uupc / source / rnews / rnews.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-09-27  |  48.5 KB  |  1,415 lines

  1. /*--------------------------------------------------------------------*/
  2. /*    r n e w s . c                                                   */
  3. /*                                                                    */
  4. /*    Receive incoming news into the news directory.                  */
  5. /*                                                                    */
  6. /*    Written by Mike Lipsie; modified for UUPC/extended 1.11s by     */
  7. /*    Andrew H., Derbyshire.                                          */
  8. /*                                                                    */
  9. /*    Changes and Compilation Copyright (c) 1992 by Andrew H.         */
  10. /*    Derbyshire.  All rights reserved except as granted by the       */
  11. /*    general UUPC/extended license.                                  */
  12. /*                                                                    */
  13. /*    This package has been substantially modified.  It will now      */
  14. /*    copy compressed articles (assumed batches but they could be     */
  15. /*    single articles) to the CMPRSSED directory and it will          */
  16. /*    unbatch (if necessary) and deliver articles to their            */
  17. /*    appropriate newsgroup directories.  At the end, if the file     */
  18. /*    was compressed it will invoke a batch file which will           */
  19. /*    uncompress the file and then feed it back to rnews.             */
  20. /*                                                                    */
  21. /*    Appropriate is defined as                                       */
  22. /*                                                                    */
  23. /*       (a) the newsgroup is in the active file and                  */
  24. /*       (b) the directory name is the group name with all            */
  25. /*           the"."s replaced with "/"s and all of that under the     */
  26. /*           news directory.                                          */
  27. /*                                                                    */
  28. /*    Names are insured to be valid by ImportNewsGroup, which maps    */
  29. /*    invalid characters and truncates names as required.             */
  30. /*--------------------------------------------------------------------*/
  31.  
  32. /*--------------------------------------------------------------------*/
  33. /*                          RCS Information                           */
  34. /*--------------------------------------------------------------------*/
  35.  
  36. /*
  37.  *       $Id: rnews.c 1.17 1993/09/27 04:04:06 ahd Exp $
  38.  *
  39.  *       $Log: rnews.c $
  40.  * Revision 1.17  1993/09/27  04:04:06  ahd
  41.  * Reduce buffer sizes to avoid 16 bit stack over flows
  42.  *
  43.  * Revision 1.16  1993/09/24  03:43:27  ahd
  44.  * Double buffers to avoid crashes during Disney Stock Flame War
  45.  *
  46.  * Revision 1.15  1993/09/21  01:42:13  ahd
  47.  * Suppress changes to body of delivered news
  48.  *
  49.  * Revision 1.14  1993/09/20  04:41:54  ahd
  50.  * OS/2 2.x support
  51.  *
  52.  * Revision 1.13  1993/07/31  16:26:01  ahd
  53.  * Changes in support of Robert Denny's Windows support
  54.  *
  55.  * Revision 1.12  1993/07/22  23:19:50  ahd
  56.  * First pass for Robert Denny's Windows 3.x support changes
  57.  *
  58.  * Revision 1.11  1993/05/03  02:41:57  ahd
  59.  * Correct name of file to set into binary mode
  60.  *
  61.  * Revision 1.10  1993/04/19  13:16:20  ahd
  62.  * Binary mode for snews
  63.  *
  64.  * Revision 1.9  1993/04/17  13:40:39  ahd
  65.  * fix compile errors for snews fix
  66.  *
  67.  * Revision 1.8  1993/04/17  13:23:37  ahd
  68.  * make snews option more compatible with snews (which is brain dead)
  69.  *
  70.  * Revision 1.7  1993/04/16  12:55:36  dmwatt
  71.  * Bounds check group lengths
  72.  *
  73.  * Revision 1.5  1993/04/11  00:33:54  ahd
  74.  * Global edits for year, TEXT, etc.
  75.  *
  76.  * Revision 1.4  1993/03/24  01:57:30  ahd
  77.  * Corrections for short articles
  78.  * Corrections for articles claimed to be zero length
  79.  * Resync gracefully after incorrect length descriptor
  80.  *
  81.  * Revision 1.3  1993/03/06  23:04:54  ahd
  82.  * Do not delete open files
  83.  *
  84.  * Revision 1.2  1992/11/22  21:14:21  ahd
  85.  * Reformat selected sections of code
  86.  * Check for premature end of articles in batched news
  87.  *
  88.  */
  89.  
  90. static const char rcsid[] =
  91.          "$Id: rnews.c 1.17 1993/09/27 04:04:06 ahd Exp $";
  92.  
  93. /*--------------------------------------------------------------------*/
  94. /*                        System include files                        */
  95. /*--------------------------------------------------------------------*/
  96.  
  97. #include <stdio.h>
  98. #include <stdlib.h>
  99. #include <string.h>
  100. #include <ctype.h>
  101. #include <time.h>
  102. #include <fcntl.h>
  103. #include <io.h>
  104. #include <process.h>
  105.  
  106. /*--------------------------------------------------------------------*/
  107. /*                    UUPC/extended include files                     */
  108. /*--------------------------------------------------------------------*/
  109.  
  110. #include "lib.h"
  111. #include "active.h"
  112. #include "getopt.h"
  113. #include "getseq.h"
  114. #include "history.h"
  115. #include "hlib.h"
  116. #include "import.h"
  117. #include "importng.h"
  118. #include "logger.h"
  119. #include "timestmp.h"
  120.  
  121. #include "execute.h"
  122.  
  123. /*--------------------------------------------------------------------*/
  124. /*                           Global defines                           */
  125. /*--------------------------------------------------------------------*/
  126.  
  127. #define UNCOMPRESS "uncompre"
  128. #ifdef BIT32ENV
  129. #define DISNEY (BUFSIZ*2)
  130. #else
  131. #define DISNEY (BUFSIZ*4/3)
  132. #endif
  133.  
  134. /*--------------------------------------------------------------------*/
  135. /*                          Global variables                          */
  136. /*--------------------------------------------------------------------*/
  137.  
  138. currentfile();
  139.  
  140. extern struct grp *group_list;   /* List of all groups */
  141.  
  142. FILE *hfile = NULL;           /* History file */
  143. char history_date[12];        /* dd/mm/yyyy + null + 1 for no good reason */
  144.  
  145. /*--------------------------------------------------------------------*/
  146. /*                       Functions in this file                       */
  147. /*--------------------------------------------------------------------*/
  148.  
  149. static boolean deliver_article(char *art_fname);
  150.                               /* Distribute the article to the
  151.                                  proper newsgroups                   */
  152.  
  153. static void copy_file(FILE *f,
  154.             char *group,
  155.             char *xref);      /* Copy file (f) to newsgroup          */
  156.  
  157. static struct grp *find_newsgroup(const char *grp);
  158.                               /* Get the grp struct for the newsgroup */
  159.  
  160. static void get_snum(const char *group, char *snum);
  161.                                     /* Get (and format) the next article
  162.                                        number in group                     */
  163.  
  164. static void fixEOF( char *buf, int bytes );
  165.  
  166. static int Single( char *filename , FILE *stream );
  167.  
  168. static int Compressed( char *filename , FILE *in_stream );
  169.  
  170. static int Batched( char *filename, FILE *stream);
  171.  
  172. static void xmit_news( char *sysname, FILE *in_stream );
  173.  
  174. static int copy_snews( char *filename, FILE *stream );
  175.  
  176. /*--------------------------------------------------------------------*/
  177. /*    m a i n                                                         */
  178. /*                                                                    */
  179. /*    Main program                                                    */
  180. /*                                                                    */
  181. /*    Exit conditions                                                 */
  182. /*                                                                    */
  183. /*    0 - Success                                                     */
  184. /*    1 - System configuration failed                                 */
  185. /*    2 - Unable to open working file                                 */
  186. /*    4 - out of memory                                               */
  187. /*    5 - Unable to create history dbm file                           */
  188. /*    6 - Problem decompressing news batch                            */
  189. /*    7 - Unable to create cmprssed directory                         */
  190. /*--------------------------------------------------------------------*/
  191.  
  192. void main( int argc, char **argv)
  193. {
  194.  
  195.    struct tm *local_now;
  196.  
  197.    long now = time(nil(long));
  198.    FILE *f;
  199.    char in_filename[FILENAME_MAX];
  200.    char filename[FILENAME_MAX];
  201.    int c;
  202.    int status;
  203.  
  204. #if defined(__CORE__)
  205.    copywrong = strdup(copyright);
  206.    checkref(copywrong);
  207. #endif
  208.  
  209.    logfile = stderr;             // Prevent redirection of error
  210.                                  // messages during configuration
  211.  
  212.    banner( argv );
  213.  
  214.    if (!configure( B_NEWS ))
  215.       exit(1);    /* system configuration failed */
  216.  
  217.    openlog( NULL );           /* Begin logging to disk            */
  218.  
  219.    if (argc > 1)
  220.    {
  221.       int option;
  222.  
  223.     /*------------------------------------------------------------*/
  224.     /*                          parse arguments                   */
  225.     /*------------------------------------------------------------*/
  226.  
  227.        while ((option = getopt(argc, argv, "f:x:")) != EOF)
  228.        {
  229.            switch (option)
  230.            {
  231.                case 'f':
  232.                   strcpy(in_filename, optarg);
  233.                   f = freopen(in_filename, "r", stdin);
  234.                   if (f == NULL) {
  235.                      printerr( in_filename );
  236.                      panic();
  237.                   } else
  238.                      printmsg(2, "Opened %s as newsfile", in_filename);
  239.  
  240.                   break;
  241.  
  242.                case 'x':
  243.                   debuglevel = atoi(optarg);
  244.                   break;
  245.  
  246.                case '?':
  247.                   puts("\nUsage:\trnews [-f newsfile] [-x debug]");
  248.                   return;
  249.            } /* break */
  250.  
  251.        } /* while */
  252.     } /* if (argc > 1) */
  253.  
  254.    tzset();                   /* Set up time zone information  */
  255.    setmode(fileno(stdin), O_BINARY);   /* Don't die on control-Z, etc */
  256.  
  257. /*--------------------------------------------------------------------*/
  258. /*    If we are processing snews input, write it all out to the       */
  259. /*    news directory as one file and return gracefully.               */
  260. /*--------------------------------------------------------------------*/
  261.  
  262.    if ( bflag[F_SNEWS])
  263.    {
  264.       char *savetemp = E_tempdir;   /* Save the real temp directory  */
  265.  
  266.       if (bflag[F_HISTORY])
  267.       {
  268.          printmsg(0,
  269.                "rnews: Conflicting options snews and history specified!");
  270.          panic();
  271.       } /* else if */
  272.  
  273.  
  274.       E_tempdir = E_newsdir;        /* Generate this file in news    */
  275.       mktempname(filename, "ART");  /* Get the file name             */
  276.       E_tempdir = savetemp;         /* Restore true directory name   */
  277.       exit (copy_snews( filename, stdin ));
  278.                                     /* Dump news into NEWS directory */
  279.    }
  280.    else
  281.       mktempname(filename, "tmp");  /* Make normal temp name         */
  282.  
  283. /*--------------------------------------------------------------------*/
  284. /*             Load the active file and validate its data             */
  285. /*--------------------------------------------------------------------*/
  286.  
  287.    get_active();           /* Get sequence numbers for groups
  288.                               from active file                 */
  289.    validate_newsgroups();  /* Make sure all directories exist  */
  290.  
  291. /*--------------------------------------------------------------------*/
  292. /*                   Initialize history processing                    */
  293. /*--------------------------------------------------------------------*/
  294.  
  295.    local_now = localtime(&now);
  296.  
  297.    sprintf(history_date, "%2.2d/%2.2d/%4d",  local_now->tm_mday,
  298.                                  local_now->tm_mon+1,
  299.                                  local_now->tm_year+1900);
  300.  
  301. /*--------------------------------------------------------------------*/
  302. /*                 Open (or create) the history file                  */
  303. /*--------------------------------------------------------------------*/
  304.  
  305.    if ( bflag[F_HISTORY] )
  306.    {
  307.       if (history_exists())
  308.          hfile = open_history(history_date);
  309.       else
  310.          hfile = create_history(history_date);
  311.  
  312.       if (hfile == NULL)
  313.       {
  314.          printmsg(0, "Error %s history file", history_exists() ?
  315.             "opening" : "creating");
  316.             panic();
  317.       }
  318.  
  319.    } /* if */
  320.  
  321. /*--------------------------------------------------------------------*/
  322. /*    This loop copies the file to the NEWS directory.                */
  323. /*                                                                    */
  324. /*    A news article/batch either has a '#' character as its first    */
  325. /*    character or it does not.                                       */
  326. /*                                                                    */
  327. /*    If it does not it is a single (unbatched, uncompressed)         */
  328. /*    article.                                                        */
  329. /*                                                                    */
  330. /*    If the first character _is_ a '#', the first line is #!         */
  331. /*    cunbatch\n which means that it is a compressed batch; it        */
  332. /*    will be uncompressed and then re-fed to rnews or the first      */
  333. /*    line can be #! rnews nnn\n (where nnn is some number) which     */
  334. /*    means that the next nnn characters are an article and that      */
  335. /*    more might follow.                                              */
  336. /*                                                                    */
  337. /*    Due to a "feature" in the compressed batch, there may be        */
  338. /*    _no_ articles batched (an article destined for transmittal      */
  339. /*    is cancelled before being sent).                                */
  340. /*                                                                    */
  341. /*    Since this is a bit spread out, the various clauses of the      */
  342. /*    if statement will be marked with boxed 1, 2, or 3 (and a        */
  343. /*    brief explanation.                                              */
  344. /*--------------------------------------------------------------------*/
  345.  
  346. /*--------------------------------------------------------------------*/
  347. /*    Compressed files need to be read in BINARY mode so that         */
  348. /*    "magic" characters (like ^Z) don't upset it.  Batched files     */
  349. /*    need to be read in TEXT mode so that the character count is     */
  350. /*    correct.  The other case doesn't matter.                        */
  351. /*--------------------------------------------------------------------*/
  352.  
  353.    c = getc(stdin);
  354.    ungetc(c, stdin);
  355.  
  356.    if (c != '#') {
  357.  
  358.       /***********************************************/
  359.       /* 1  single (unbatched, uncompressed) article */
  360.       /***********************************************/
  361.  
  362.       status = Single(filename, stdin);
  363.  
  364.    }
  365.    else {
  366.  
  367.       char buf[BUFSIZ];
  368.       int fields = fscanf(stdin, "#! %s ", &buf);
  369.       if ((fields == 1) && (strcmp(buf, "cunbatch") == 0))
  370.       {
  371.  
  372.          /***********************************************/
  373.          /*  2  Compressed batch                        */
  374.          /***********************************************/
  375.  
  376.          status = Compressed(filename, stdin);
  377.  
  378.       }
  379.       else {
  380.  
  381.          /***********************************************/
  382.          /* 3  Uncompressed batch                       */
  383.          /***********************************************/
  384.  
  385.          status = Batched( filename, stdin );
  386.       } /* else */
  387.    } /* else */
  388.  
  389. /*--------------------------------------------------------------------*/
  390. /*                     Close open files and exit                      */
  391. /*--------------------------------------------------------------------*/
  392.  
  393.    put_active();
  394.  
  395.    if (hfile != NULL)
  396.       fclose(hfile);
  397.  
  398.    exit(status);
  399.  
  400. } /*main*/
  401.  
  402. /*--------------------------------------------------------------------*/
  403. /*    S i n g l e                                                     */
  404. /*                                                                    */
  405. /*    Deliver a single article to the proper news group(s)            */
  406. /*--------------------------------------------------------------------*/
  407.  
  408. static int Single( char *filename , FILE *stream )
  409. {
  410.    char tmp_fname[FILENAME_MAX];
  411.    FILE *tmpf;
  412.    char buf[BUFSIZ];
  413.    unsigned chars_read;
  414.    unsigned chars_written;
  415.  
  416.  
  417. /*--------------------------------------------------------------------*/
  418. /* Make a file name and then open the file to write the article into  */
  419. /*--------------------------------------------------------------------*/
  420.  
  421.    tmpf = FOPEN(filename, "w", BINARY_MODE);
  422.  
  423.    if ( tmpf == NULL )
  424.    {
  425.       printerr( tmp_fname );
  426.       panic();
  427.    }
  428.  
  429. /*--------------------------------------------------------------------*/
  430. /*              Now copy the input into our holding bin               */
  431. /*--------------------------------------------------------------------*/
  432.  
  433.    while ((chars_read = fread(buf,sizeof(char), BUFSIZ, stream)) != 0)
  434.    {
  435.  
  436.       chars_written = fwrite(buf, sizeof(char), chars_read, tmpf);
  437.       if (chars_written != chars_read)
  438.       {
  439.          printerr( filename );
  440.          printmsg(0, "rnews: Error writing single article to working file");
  441.          fclose( tmpf );
  442.          unlink( filename );
  443.          panic();
  444.       }
  445.    }
  446.  
  447. /*--------------------------------------------------------------------*/
  448. /*     Close the file, deliver the article, and return the caller     */
  449. /*--------------------------------------------------------------------*/
  450.  
  451.    fclose(tmpf);
  452.  
  453.    deliver_article(filename);
  454.    unlink( filename );
  455.    return 0;
  456.  
  457. } /* Single */
  458.  
  459. /*--------------------------------------------------------------------*/
  460. /*    C o m p r e s s e d                                             */
  461. /*                                                                    */
  462. /*    Decompress news                                                 */
  463. /*--------------------------------------------------------------------*/
  464.  
  465. static int Compressed( char *filename , FILE *in_stream )
  466. {
  467.  
  468.    FILE *work_stream;
  469.  
  470.    char zfile[FILENAME_MAX];
  471.    char unzfile[FILENAME_MAX];
  472.    char buf[BUFSIZ];
  473.  
  474.    boolean first_time = TRUE;
  475.    char *program, *args;
  476.    long cfile_size = 0L;
  477.    size_t chars_read, i;
  478.    int status = 0;
  479.    boolean needtemp = TRUE;
  480.  
  481.    char *sysname;             /* For reading systems to process   */
  482.  
  483. /*--------------------------------------------------------------------*/
  484. /*        Copy the compressed file to the "holding" directory         */
  485. /*--------------------------------------------------------------------*/
  486.  
  487.    fseek(in_stream, 0L, SEEK_SET);      /* Back to the beginning       */
  488.  
  489.  
  490.    while( needtemp )
  491.    {
  492.       mktempname( zfile , "Z" );          /* Generate "compressed" file
  493.                                           name                       */
  494.       strcpy( unzfile, zfile );
  495.       unzfile[ strlen(unzfile)-2 ] = '\0';
  496.  
  497.       if ( access( unzfile, 0 ))  /* Does the host file exist?       */
  498.          needtemp = FALSE;        /* No, we have a good pair         */
  499.       else
  500.          printmsg(0,"Had compressed name %s, found %s already exists!",
  501.                   zfile, unzfile );
  502.  
  503.    } /* while */
  504.  
  505. /*--------------------------------------------------------------------*/
  506. /*                 Open the file, with error recovery                 */
  507. /*--------------------------------------------------------------------*/
  508.  
  509.    if ((work_stream = FOPEN(zfile, "w", BINARY_MODE)) == nil(FILE))
  510.    {
  511.       printmsg(0, "Compressed: Can't open %s (%d)", zfile, errno);
  512.       printerr(zfile);
  513.       return 2;
  514.    }
  515.  
  516.    printmsg(2, "Compressed: Copy to %s for later processing", zfile);
  517.  
  518. /*--------------------------------------------------------------------*/
  519. /*                 Main loop to copy compressed file                  */
  520. /*--------------------------------------------------------------------*/
  521.  
  522.    while ((chars_read = fread(buf,sizeof(char), BUFSIZ, in_stream)) != 0)
  523.    {
  524.       char *t_buf = buf;
  525.       if (first_time)
  526.       {
  527.          t_buf += sizeof("#! cunbatch");
  528.  
  529.          first_time = FALSE;
  530.          chars_read -= (t_buf - buf);
  531.  
  532.          while ((*t_buf == ' ') || (*t_buf == '\n') || (*t_buf == '\r'))
  533.          {
  534.             t_buf++;
  535.             chars_read--;
  536.          } /* while */
  537.  
  538.       } /* if */
  539.  
  540.       i = fwrite(t_buf,sizeof(char),chars_read,work_stream);
  541.  
  542.       if (i != chars_read)
  543.       {
  544.          fclose( work_stream );
  545.          printerr( zfile );
  546.          unlink( zfile );     /* Kill the compressed input file      */
  547.          panic();
  548.       }
  549.  
  550.       cfile_size += (long)chars_read;
  551.    } /* while */
  552.  
  553.    fclose(work_stream);
  554.  
  555. /*--------------------------------------------------------------------*/
  556. /*             If the file is empty, delete it gracefully             */
  557. /*--------------------------------------------------------------------*/
  558.  
  559.    if (cfile_size == 3)
  560.    {
  561.       unlink(zfile); /* Get rid of null file */
  562.       printmsg(1, "Compressed: %s empty, deleted", zfile);
  563.       return status;
  564.    }
  565.    else
  566.       printmsg(2,"Compressed: Copy to %s complete, %ld characters",
  567.                zfile, cfile_size);
  568.  
  569. /*--------------------------------------------------------------------*/
  570. /*      Special hack for creating mirror images of the news feed      */
  571. /*--------------------------------------------------------------------*/
  572.  
  573.    sysname = getenv( "UUPCSHADOWS" );
  574.  
  575.    if ( sysname != NULL )
  576.    {
  577.       strcpy( buf, sysname);
  578.  
  579.       sysname = strtok( buf, WHITESPACE );
  580.  
  581.       while( sysname != NULL )
  582.       {
  583.          printmsg(1,"Compressed: Shadowing news to %s", sysname );
  584.          fseek(in_stream, 0L, SEEK_SET);      /* Back to the beginning       */
  585.          xmit_news( sysname, in_stream );
  586.          sysname = strtok( NULL, WHITESPACE );
  587.       }
  588.  
  589.    } /* if */
  590.  
  591. /*--------------------------------------------------------------------*/
  592. /*          Uncompress the article and feed it back to rnews          */
  593. /*--------------------------------------------------------------------*/
  594.  
  595.    if ( E_uncompress == NULL )
  596.    {
  597.       program = UNCOMPRESS;
  598.       args    = zfile;
  599.       printmsg(2,"Compressed: %s %s", program , args);
  600.    }
  601.    else {
  602.       sprintf( buf, E_uncompress, zfile, unzfile );
  603.       printmsg(2,"Compressed: %s", buf );
  604.  
  605.       program = strtok( buf, WHITESPACE );
  606.       args = strtok( NULL, "");
  607.  
  608.       if ( args != NULL )
  609.          while (isspace(*args))
  610.             args++;
  611.  
  612.    } /* else */
  613.  
  614.    status = execute( program, args, NULL, NULL, TRUE, FALSE);
  615.  
  616.    unlink( zfile );           /* Kill the compressed input file      */
  617.  
  618.    if (status != 0)
  619.    {
  620.       if (status == -1)
  621.       {
  622.           printmsg( 0, "Compress: spawn failed completely" );
  623.           printerr( program );
  624.       }
  625.       else
  626.           printmsg(0, "%s command failed (exit code %d)",
  627.                         UNCOMPRESS, status);
  628.       panic();
  629.    } /* if status != 0 */
  630.  
  631. /*--------------------------------------------------------------------*/
  632. /*            Now process the file as normal batched news             */
  633. /*--------------------------------------------------------------------*/
  634.  
  635.                               /* Create uncompressed output file name   */
  636.  
  637.    work_stream = FOPEN( unzfile, "r", BINARY_MODE);
  638.    if ( work_stream == NULL )
  639.    {
  640.       printerr( unzfile );
  641.       panic();
  642.    }
  643.  
  644.    status = Batched( filename, work_stream );
  645.  
  646. /*--------------------------------------------------------------------*/
  647. /*                   Clean up and return to caller                    */
  648. /*--------------------------------------------------------------------*/
  649.  
  650.    fclose( work_stream );
  651.    unlink( unzfile );
  652.  
  653.    return status;
  654.  
  655. } /* Compressed */
  656.  
  657. /*--------------------------------------------------------------------*/
  658. /*    B a t c h e d                                                   */
  659. /*                                                                    */
  660. /*    Handle batched, uncompressed news                               */
  661. /*--------------------------------------------------------------------*/
  662.  
  663. static int Batched( char *filename, FILE *stream)
  664. {
  665.  
  666.    char buf[BUFSIZ * 2];
  667.    int status = 0;
  668.    long article_size;
  669.    int articles = 0;
  670.    int ignored  = 0;
  671.    boolean gotsize = FALSE;
  672.    int chars_read;
  673.    int chars_written;
  674.  
  675. /*--------------------------------------------------------------------*/
  676. /*    This is an uncompressed batch.  Copy it to the working          */
  677. /*    directory and then distribute the individual articles.          */
  678. /*--------------------------------------------------------------------*/
  679.  
  680.    fseek(stream, 0L, SEEK_SET);        /* Back to the beginning       */
  681.  
  682.    while( ! feof( stream ) && ! ferror( stream ))
  683.    {
  684.       long article_left;
  685.       int  max_read = (long) sizeof buf;
  686.       long skipped_lines = 0;
  687.       long skipped_bytes = 0;
  688.       FILE *tmpf;
  689.  
  690.  /*--------------------------------------------------------------------*/
  691.  /*    Handle next article (articles are separated by the line         */
  692.  /*    indicating their size when they are batched.)                   */
  693.  /*--------------------------------------------------------------------*/
  694.  
  695.       while ( ! gotsize )
  696.       {
  697.          if (fgets( buf, sizeof buf, stream ) == NULL)
  698.             break;
  699.  
  700.          if ( equaln( "#! rnews", buf, 8) )
  701.          {
  702.             article_size = 0;
  703.             sscanf(buf, "#! rnews %ld \n", &article_size);
  704.             gotsize = TRUE;
  705.          }
  706.          else {
  707.             skipped_lines ++;
  708.             skipped_bytes += strlen( buf );
  709.          }
  710.       } /* while */
  711.  
  712.       if ( skipped_lines )
  713.          printmsg(0,
  714.                   "Batched: Skipped %ld bytes in %ld "
  715.                   "lines after article %d",
  716.                   skipped_bytes,
  717.                   skipped_lines,
  718.                   articles );
  719.  
  720. /*--------------------------------------------------------------------*/
  721. /*                          Trap end of file                          */
  722. /*--------------------------------------------------------------------*/
  723.  
  724.       if ( ! gotsize )
  725.       {
  726.          if ( ferror( stream ))
  727.             printerr( "stdin" );
  728.          break;
  729.       }
  730.  
  731.       article_left = article_size;
  732.       gotsize = FALSE;
  733.  
  734. /*--------------------------------------------------------------------*/
  735. /*                   Open up our next working file                    */
  736. /*--------------------------------------------------------------------*/
  737.  
  738.       tmpf = FOPEN(filename, "w", BINARY_MODE);
  739.       if ( tmpf == NULL )
  740.       {
  741.          printerr( filename );
  742.          panic();
  743.       }
  744.  
  745.  /*--------------------------------------------------------------------*/
  746.  /*   Copy this article to the temp file (except for the last block)   */
  747.  /*--------------------------------------------------------------------*/
  748.  
  749.       if ( article_size )
  750.       {
  751.          do {
  752.             if ( article_left < max_read )
  753.                max_read = (int) article_left;
  754.  
  755.             chars_read = fread(buf, sizeof(char), max_read, stream);
  756.  
  757.             if ( (chars_read < max_read) && ferror( stream ))
  758.             {
  759.                printerr("STDIN");
  760.                panic();
  761.             }
  762.  
  763.             if ( chars_read == 0)
  764.                break;
  765.  
  766.             fixEOF( buf , chars_read );
  767.  
  768.             chars_written = fwrite(buf, sizeof(char), chars_read, tmpf);
  769.             if (chars_read != chars_written)
  770.             {
  771.                printmsg(0,"Batched: Read %d bytes, only wrote %d bytes of article %d",
  772.                      chars_read, chars_written , articles + 1);
  773.                printerr(filename);
  774.             }
  775.  
  776.             article_left -= chars_read;
  777.  
  778.          } while (article_left > 0);
  779.  
  780.          if ( article_left )     // Premature EOF?
  781.             printmsg(0,"Batched: Unexpected EOF for article %d, "
  782.                      "read %ld bytes of expected %ld",
  783.                       articles + 1,
  784.                       article_size - article_left, article_size );
  785.  
  786.       } /* if */
  787.       else {
  788.  
  789.          long actual_size = 0;
  790.  
  791.          do {
  792.             if (fgets( buf, sizeof buf, stream ) == NULL)
  793.             {
  794.                if ( ferror( stream ))
  795.                   printerr( filename );
  796.                break;
  797.             }
  798.  
  799.             chars_read = strlen( buf );
  800.  
  801.             if ( equaln( "#! rnews", buf, 8) )
  802.             {
  803.                sscanf(buf, "#! rnews %ld \n", &article_size);
  804.                gotsize = TRUE;
  805.             }
  806.             else if ( chars_read > 0 )
  807.             {
  808.                actual_size += chars_read;
  809.  
  810.                chars_written = fwrite(buf,
  811.                                       sizeof(char),
  812.                                       chars_read,
  813.                                       tmpf);
  814.                if (chars_read != chars_written)
  815.                {
  816.                   printmsg(0,
  817.                        "Batched: Read %d bytes, only wrote %d bytes of article %d",
  818.                         chars_read, chars_written , articles + 1);
  819.                   printerr(filename);
  820.                }
  821.             } /* else */
  822.  
  823.          } while( ! gotsize );
  824.  
  825.          printmsg(2,"Batched: Article %d size %ld",
  826.                      articles + 1,
  827.                      actual_size );
  828.       } /* else */
  829.  
  830.  /*--------------------------------------------------------------------*/
  831.  /*      Close the file, deliver its contents, and get rid of it       */
  832.  /*--------------------------------------------------------------------*/
  833.  
  834.       fclose(tmpf);
  835.       if ( ! deliver_article(filename) )
  836.          ignored ++;
  837.       unlink( filename );
  838.       articles ++;
  839.  
  840.    } /* while */
  841.  
  842. /*--------------------------------------------------------------------*/
  843. /*                          Return to caller                          */
  844. /*--------------------------------------------------------------------*/
  845.  
  846.    if ( ignored )
  847.       printmsg(1,"Batched: Unbatched %d articles (discarded %d of these)",
  848.                articles , ignored);
  849.    else
  850.       printmsg(1,"Batched: Unbatched %d articles", articles );
  851.    return status;
  852.  
  853. } /* Batched */
  854.  
  855. /*--------------------------------------------------------------------*/
  856. /*    f i x E O F                                                     */
  857. /*                                                                    */
  858. /*    Zap Cntrl-Z characters in the input stream                      */
  859. /*--------------------------------------------------------------------*/
  860.  
  861. static void fixEOF( char *buf, int bytes )
  862. {
  863.    static warn = TRUE;
  864.  
  865.    while ( bytes-- )
  866.    {
  867.       if ( *buf == ('Z' - 'A'))
  868.       {
  869.          *buf = 'Z';
  870.          if ( warn )
  871.          {
  872.             printmsg(0,"Altered Cntl-Z to Z");
  873.             warn = FALSE;
  874.          } /* if */
  875.       } /* if */
  876.    } /* while */
  877.  
  878. } /* fixEOF */
  879.  
  880. /*--------------------------------------------------------------------*/
  881. /*    d e l i v e r _ a r t i c l e                                   */
  882. /*                                                                    */
  883. /*    Determine delivery of a posting                                 */
  884. /*--------------------------------------------------------------------*/
  885.  
  886. static boolean deliver_article(char *art_fname)
  887. {
  888.  
  889.    char groupy[MAXGRP];
  890.  
  891.    char *newsgroups = NULL;   /* The Newsgroups: line */
  892.    char *messageID  = NULL;   /* The Message-ID: line */
  893.  
  894.    char *gc_ptr;           /* Scratch pointers.  Mostly used to go */
  895.    char *gc_ptr1;              /*   down the list of newsgroups.      */
  896.  
  897.    FILE *tfile;            /* The article file */
  898.  
  899.    int n_hdrs;             /* Number of desired headers seen */
  900.    int b_xref;
  901.  
  902.    int line_len;
  903.  
  904.    char hist_record[DISNEY];  /* buffer for history file
  905.                                  (also used for article)             */
  906.    char groups[DISNEY];
  907.    char message_buf[DISNEY];
  908.    char snum[10];
  909.  
  910.    tfile = FOPEN(art_fname, "r", BINARY_MODE);
  911.    if ( tfile == NULL )
  912.    {
  913.       printerr( art_fname );
  914.       panic();
  915.    }
  916.  
  917. /*--------------------------------------------------------------------*/
  918. /*    Get fields necessary for distribution (Newsgroups:)  and the    */
  919. /*    history file (Message-ID:).  Also, if the article is going      */
  920. /*    to more than one newsgroup, flag the creation of Xref: fields.  */
  921. /*--------------------------------------------------------------------*/
  922.  
  923.    n_hdrs = b_xref = 0;
  924.    while (n_hdrs < 2)
  925.    {
  926.       /* Get the next line */
  927.       gc_ptr = fgets(hist_record, sizeof(hist_record), tfile);
  928.  
  929. /*--------------------------------------------------------------------*/
  930. /*                    Check for end of the headers                    */
  931. /*--------------------------------------------------------------------*/
  932.  
  933.       if ((gc_ptr == NULL) || (strlen(hist_record) == 1))
  934.       {
  935.          /* Ooops.  Missing Message-ID: or Newsgroups: */
  936.          if (messageID == NULL)
  937.             printmsg(0, "Article has no Message-ID:, discarded");
  938.          else {
  939.             if (newsgroups == NULL)
  940.             {
  941.                printmsg(0,
  942.                     "Article %s has no Newsgroups: line, discarded",
  943.                     messageID);
  944.             } /* if */
  945.             else
  946.                break;
  947.          } /* else */
  948.  
  949.          fclose(tfile);
  950.  
  951.          return FALSE;
  952.       } /* if ((gc_ptr == NULL) || (strlen(hist_record) == 1)) */
  953.  
  954.       line_len = strlen(hist_record);
  955.  
  956.       if (hist_record[line_len-1] == '\n')
  957.          hist_record[(line_len--)-1] = '\0';
  958.  
  959.       if (hist_record[line_len-1] == '\r')
  960.          hist_record[(line_len--)-1] = '\0';
  961.  
  962.       if (equalni(hist_record, "Newsgroups:", strlen("Newsgroups:")))
  963.       {
  964.          /* Handle Newsgroups: line*/
  965.          if (newsgroups == NULL)
  966.          {
  967.             gc_ptr += strlen("Newsgroups:") + 1;
  968.             newsgroups = strcpy(groups, gc_ptr);
  969.             newsgroups[strlen(newsgroups)+1] = '\0';  /* Guard char for rescan */
  970.             n_hdrs++;
  971.             b_xref = (strchr(newsgroups, ',') != NULL); /* more than 1 group */
  972.      }                     /* i.e. do we need to create a Xrefs: line ? */
  973.          else
  974.             printmsg(0, "Article has multiple Newsgroups: lines");
  975.       }
  976.       else if (equalni(hist_record, "Message-ID:", strlen("Message-ID:")))
  977.       {
  978.          /* Handle Message-ID: line */
  979.          if (messageID == NULL)
  980.          {
  981.             gc_ptr += strlen("Message-ID:") + 1;
  982.             messageID = message_buf;
  983.             messageID[0] = '\0';
  984.             if (*gc_ptr != '<') strcat(messageID, "<");
  985.                strcat(messageID, gc_ptr);
  986.             if (messageID[strlen(messageID)-1] != '>')
  987.                strcat(messageID,">");
  988.             n_hdrs++;
  989.          } /* if (messageID == NULL) */
  990.       }
  991.    }  /* while getting Newsgroups: and Message-ID: */
  992.  
  993. /*--------------------------------------------------------------------*/
  994. /*           Check whether article has been received before           */
  995. /*--------------------------------------------------------------------*/
  996.  
  997.    if ( bflag[ F_HISTORY ] )
  998.    {
  999.       if (is_in_history(hfile, messageID))
  1000.       {
  1001.          printmsg(2, "rnews: Duplicate article %s", messageID);
  1002.          fclose(tfile);
  1003.          return FALSE;
  1004.       }
  1005.  
  1006.       /* Start building the history record for this article */
  1007.       strcpy(hist_record, messageID);
  1008.       strcat(hist_record, " ");
  1009.       strcat(hist_record, history_date);
  1010.       strcat(hist_record, " ");
  1011.  
  1012.       gc_ptr1 = newsgroups;
  1013.       while ((gc_ptr = strchr(gc_ptr1, ',')) != NULL) {
  1014.          gc_ptr[0] = '\0';
  1015.          if (strlen(gc_ptr1) > MAXGRP - 1) { /* Bounds check the newsgroup len */
  1016.             printmsg(0, "rnews: newsgroup name too long -- %s", gc_ptr1);
  1017.             gc_ptr1 = gc_ptr + 1;
  1018.             continue; /* Punt the newsgroup history record */
  1019.          }
  1020.          strcpy(groupy, gc_ptr1);
  1021.          strcat(hist_record, groupy);
  1022.          strcat(hist_record, ":");
  1023.          gc_ptr1 = gc_ptr + 1;
  1024.          get_snum(groupy,snum);
  1025.          strcat(hist_record, snum);
  1026.            strcat(hist_record, ",");
  1027.       }
  1028.       strcpy(groupy, gc_ptr1);
  1029.       strcat(hist_record, groupy);
  1030.       strcat(hist_record, ":");
  1031.       get_snum(groupy,snum);
  1032.       strcat(hist_record, snum);
  1033.       strcat(hist_record, "\n");
  1034.  
  1035.       /* Restore the newsgroups line */
  1036.       while (newsgroups[strlen(newsgroups)+1] != '\0') {
  1037.          newsgroups[strlen(newsgroups)] = ',';
  1038.       }
  1039.  
  1040.       /* Post the history record */
  1041.       fseek(hfile, 0L, SEEK_END);
  1042.       fwrite(hist_record, sizeof(char), strlen(hist_record), hfile);
  1043.    } /* if ( bflag[ F_HISTORY ] ) */
  1044.  
  1045. /*--------------------------------------------------------------------*/
  1046. /*              Now build the Xref: line (if we need to)              */
  1047. /*--------------------------------------------------------------------*/
  1048.  
  1049.    if (b_xref) {
  1050.       strcpy(hist_record, "Xref: ");
  1051.       strcat(hist_record, E_nodename);
  1052.       strcat(hist_record, " ");
  1053.  
  1054.       gc_ptr1 = newsgroups;
  1055.       while ((gc_ptr = strchr(gc_ptr1, ',')) != NULL)
  1056.       {
  1057.          gc_ptr[0] = '\0';
  1058.          if (strlen(gc_ptr1) > MAXGRP - 1) { /* Bounds check the newsgroup len */
  1059.             printmsg(0, "rnews: newsgroup name too long -- %s", gc_ptr1);
  1060.             gc_ptr1 = gc_ptr + 1;
  1061.             continue; /* Punt the newsgroup history record */
  1062.          }
  1063.          strcpy(groupy, gc_ptr1);
  1064.          strcat(hist_record, groupy);
  1065.          strcat(hist_record, ":");
  1066.          gc_ptr1 = gc_ptr + 1;
  1067.          get_snum(groupy,snum);
  1068.          strcat(hist_record, snum);
  1069.          strcat(hist_record, " ");
  1070.       }
  1071.  
  1072.       strcpy(groupy, gc_ptr1);
  1073.       strcat(hist_record, groupy);
  1074.       strcat(hist_record, ":");
  1075.       get_snum(groupy,snum);
  1076.       strcat(hist_record, snum);
  1077.       strcat(hist_record, "\n");
  1078.  
  1079.         /* Restore the newsgroups line */
  1080.       while (newsgroups[strlen(newsgroups)+1] != '\0') {
  1081.          newsgroups[strlen(newsgroups)] = ',';
  1082.       }
  1083.  
  1084.     }
  1085.  
  1086. /*--------------------------------------------------------------------*/
  1087. /*       We now need to copy the file to each group in groupys        */
  1088. /*--------------------------------------------------------------------*/
  1089.  
  1090.    gc_ptr1 = newsgroups;
  1091.    while ((gc_ptr = strchr(gc_ptr1, ',')) != NULL)
  1092.    {
  1093.       gc_ptr[0] = '\0';
  1094.       strcpy(groupy, gc_ptr1);
  1095.       gc_ptr1 = gc_ptr + 1;
  1096.       copy_file(tfile, groupy, b_xref ? hist_record : NULL);
  1097.    }
  1098.  
  1099.    strcpy(groupy, gc_ptr1);
  1100.    copy_file(tfile, groupy, b_xref ? hist_record : NULL);
  1101.    fclose(tfile);
  1102.  
  1103.    return TRUE;
  1104. } /* deliver_article */
  1105.  
  1106. /*--------------------------------------------------------------------*/
  1107. /*    f i n d _ n e w s g r o u p                                     */
  1108. /*                                                                    */
  1109. /*    Locate a news group in our list                                 */
  1110. /*--------------------------------------------------------------------*/
  1111.  
  1112. static struct grp *find_newsgroup(const char *grp)
  1113. {
  1114.    struct grp *cur = group_list;
  1115.  
  1116.    while ((strcmp(grp,cur->grp_name) != 0)) {
  1117.       if (cur->grp_next != NULL) {
  1118.          cur = cur->grp_next;
  1119.       } else {
  1120.          return NULL;
  1121.       }
  1122.    }
  1123.  
  1124.    return cur;
  1125. }
  1126.  
  1127. /*--------------------------------------------------------------------*/
  1128. /*    c o p y _ f i l e                                               */
  1129. /*                                                                    */
  1130. /*    Write an article to it's final resting place                    */
  1131. /*--------------------------------------------------------------------*/
  1132.  
  1133. static void copy_file(FILE *input,
  1134.                       char *group,
  1135.                       char *xref)
  1136. {
  1137.    struct grp *cur;
  1138.    char filename[FILENAME_MAX];
  1139.    char buf[BUFSIZ];
  1140.    FILE *output;
  1141.    boolean header = TRUE;
  1142.  
  1143. /*--------------------------------------------------------------------*/
  1144. /*           Determine if the news has been already posted            */
  1145. /*--------------------------------------------------------------------*/
  1146.  
  1147.    cur = find_newsgroup(group);
  1148.    if (cur == NULL)
  1149.    {
  1150.       printmsg(3, "rnews: Article cross-posted to %s", group);
  1151.       return;
  1152.    }
  1153.  
  1154. /*--------------------------------------------------------------------*/
  1155. /*                       Now build a file name                        */
  1156. /*--------------------------------------------------------------------*/
  1157.  
  1158.    ImportNewsGroup( filename, cur->grp_name, cur->grp_high++);
  1159.  
  1160. /*--------------------------------------------------------------------*/
  1161. /*                 We have a file name, open the file                 */
  1162. /*--------------------------------------------------------------------*/
  1163.  
  1164.    printmsg(2, "rnews: Saving %s article in %s",
  1165.                cur->grp_name, filename);
  1166.  
  1167.    if ((output = FOPEN(filename, "w",TEXT_MODE)) == nil(FILE))
  1168.    {
  1169.       printerr( filename );
  1170.       printmsg(0, "rnews: Unable to save article");
  1171.       return;
  1172.    }
  1173.  
  1174.    rewind(input);
  1175.  
  1176.    if (xref) /* write new Xref: line first */
  1177.    {
  1178.       if (fputs(xref, output) == EOF)
  1179.       {
  1180.          printerr( filename );
  1181.          panic();
  1182.       }
  1183.    }
  1184.  
  1185.    while (fgets(buf, sizeof buf, input) != NULL)
  1186.    {
  1187.  
  1188.       if ( ! header )
  1189.          ;                 // No operation after end of header
  1190.       else if ( *buf == '\n' )
  1191.          header = FALSE;
  1192.       else if (equalni(buf, "Path:", strlen("Path:")))
  1193.       {
  1194.          fprintf(output, "Path: %s!%s", E_nodename,
  1195.                          buf + strlen("Path:") + 1);
  1196.          continue;
  1197.       }
  1198.       else if (equalni(buf, "Xref:", strlen("Xref:")))
  1199.          continue; /* skip possibly old Xref: line */
  1200.  
  1201.       if (fputs(buf, output) == EOF)
  1202.       {
  1203.          printerr( filename );
  1204.          panic();
  1205.       }
  1206.    } /* while */
  1207.  
  1208.    fclose(output);
  1209.  
  1210. } /* copy_file */
  1211.  
  1212. /*--------------------------------------------------------------------*/
  1213. /*    g e t _ s n u m                                                 */
  1214. /*                                                                    */
  1215. /*    Get highest article number of newsgroup                         */
  1216. /*--------------------------------------------------------------------*/
  1217.  
  1218. static void get_snum(const char *group, char *snum)
  1219. {
  1220.    struct grp *cur;
  1221.  
  1222.    strcpy(snum, "0");
  1223.    cur = find_newsgroup(group);
  1224.    if (cur == NULL)
  1225.    return;
  1226.  
  1227.    sprintf(snum, "%d", cur->grp_high);
  1228.  
  1229. } /* snum */
  1230.  
  1231. /*--------------------------------------------------------------------*/
  1232. /*    x m i t _ n e w s                                               */
  1233. /*                                                                    */
  1234. /*    A cruel hack to transmit news to other systems                  */
  1235. /*--------------------------------------------------------------------*/
  1236.  
  1237. static void xmit_news( char *sysname, FILE *in_stream )
  1238. {
  1239.    static char *spool_fmt = SPOOLFMT;              /* spool file name */
  1240.    static char *dataf_fmt = DATAFFMT;
  1241.    static char *send_cmd  = "S %s %s %s - %s 0666\n";
  1242.    static long seqno = 0;
  1243.    FILE *out_stream;          /* For writing out data                */
  1244.  
  1245.    char buf[BUFSIZ];
  1246.    unsigned len;
  1247.  
  1248.    char msfile[FILENAME_MAX]; /* MS-DOS format name of files         */
  1249.    char msname[22];           /* MS-DOS format w/o path name         */
  1250.  
  1251.    char tmfile[15];           /* Call file, UNIX format name         */
  1252.    char ixfile[15];           /* eXecute file for remote system,
  1253.                                 UNIX format name for local system   */
  1254.    char idfile[15];           /* Data file, UNIX format name         */
  1255.    char rdfile[15];           /* Data file name on remote system,
  1256.                                  UNIX format                         */
  1257.    char rxfile[15];           /* Remote system UNIX name of eXecute
  1258.                                  file                                */
  1259.    char *seq;
  1260.  
  1261. /*--------------------------------------------------------------------*/
  1262. /*          Create the UNIX format of the file names we need          */
  1263. /*--------------------------------------------------------------------*/
  1264.  
  1265.    seqno = getseq();
  1266.    seq = JobNumber( seqno );
  1267.  
  1268.    sprintf(tmfile, spool_fmt, 'C', sysname,  'd' , seq);
  1269.    sprintf(idfile, dataf_fmt, 'D', E_nodename , seq, 'd');
  1270.    sprintf(rdfile, dataf_fmt, 'D', E_nodename , seq, 'r');
  1271.    sprintf(ixfile, dataf_fmt, 'D', E_nodename , seq, 'e');
  1272.    sprintf(rxfile, dataf_fmt, 'X', E_nodename , seq, 'r');
  1273.  
  1274. /*--------------------------------------------------------------------*/
  1275. /*                     create remote X (xqt) file                     */
  1276. /*--------------------------------------------------------------------*/
  1277.  
  1278.    importpath( msname, ixfile, sysname);
  1279.    mkfilename( msfile, E_spooldir, msname);
  1280.  
  1281.    out_stream = FOPEN(msfile, "w", BINARY_MODE);
  1282.    if ( out_stream == NULL )
  1283.    {
  1284.       printmsg(0, "xmit_news: cannot open X file %s", msfile);
  1285.       printerr(msfile);
  1286.       return ;
  1287.    } /* if */
  1288.  
  1289.    if (setvbuf( out_stream, NULL, _IONBF, 0))
  1290.    {
  1291.       printmsg(0, "xmit_news: Cannot unbuffer file %s (%s).",
  1292.                   ixfile, msfile);
  1293.       printerr(msfile);
  1294.       panic();
  1295.    } /* if */
  1296.  
  1297.    fprintf(out_stream, "R %s %s\nU %s %s\nF %s\nI %s\nC rnews\n",
  1298.                "uucp", E_domain,
  1299.                "uucp", E_nodename,
  1300.                rdfile, rdfile);
  1301.    fclose(out_stream);
  1302.  
  1303. /*--------------------------------------------------------------------*/
  1304. /*  Create the data file with the mail to send to the remote system   */
  1305. /*--------------------------------------------------------------------*/
  1306.  
  1307.    importpath(msname, idfile, sysname);
  1308.    mkfilename( msfile, E_spooldir, msname);
  1309.  
  1310.    out_stream = FOPEN(msfile, "w", BINARY_MODE);
  1311.    if (out_stream == NULL )
  1312.    {
  1313.       printerr(msfile);
  1314.       printmsg(0,
  1315.                "xmit_news: Cannot open spool file \"%s\" for output",
  1316.                 msfile);
  1317.       return;
  1318.    }
  1319.  
  1320.    if (setvbuf( out_stream, NULL, _IONBF, 0))
  1321.    {
  1322.       printmsg(0, "xmit_news: Cannot unbuffer file %s (%s).",
  1323.                   idfile, msfile);
  1324.       printerr(msfile);
  1325.       panic();
  1326.    } /* if */
  1327.  
  1328. /*--------------------------------------------------------------------*/
  1329. /*                       Loop to copy the data                        */
  1330. /*--------------------------------------------------------------------*/
  1331.  
  1332.    while ( (len = fread( buf, 1, sizeof buf, in_stream)) != 0)
  1333.    {
  1334.       if (fwrite( buf, 1, len, out_stream ) != len)     /* I/O error?               */
  1335.       {
  1336.          printerr(msfile);
  1337.          fclose(out_stream);
  1338.          return;
  1339.       } /* if */
  1340.    } /* while */
  1341.  
  1342.    fclose( out_stream );
  1343.  
  1344. /*--------------------------------------------------------------------*/
  1345. /*                     create local C (call) file                     */
  1346. /*--------------------------------------------------------------------*/
  1347.  
  1348.    importpath( msname, tmfile, sysname);
  1349.    mkfilename( msfile, E_spooldir, msname);
  1350.  
  1351.    out_stream = FOPEN(msfile, "w",TEXT_MODE);
  1352.    if (out_stream == NULL)
  1353.    {
  1354.       printerr( msname );
  1355.       printmsg(0, "xmit_news: cannot open C file %s", msfile);
  1356.       return;
  1357.    }
  1358.  
  1359.    fprintf(out_stream, send_cmd, idfile, rdfile,
  1360.                   "uucp", idfile);
  1361.    fprintf(out_stream, send_cmd, ixfile, rxfile,
  1362.                   "uucp", ixfile);
  1363.    fclose(out_stream);
  1364.  
  1365. } /* xmit_news */
  1366.  
  1367. /*--------------------------------------------------------------------*/
  1368. /*    c o p y _ s n e w s                                             */
  1369. /*                                                                    */
  1370. /*    Process news destined for the simple news reader                */
  1371. /*--------------------------------------------------------------------*/
  1372.  
  1373. static int copy_snews( char *filename, FILE *stream )
  1374. {
  1375.    char buf[BUFSIZ];
  1376.    size_t len;
  1377.  
  1378.    FILE *out_stream = FOPEN(filename, "w", BINARY_MODE);
  1379.  
  1380.    if ( out_stream == NULL )
  1381.    {
  1382.       printerr(filename);
  1383.       panic();
  1384.    } /* if */
  1385.  
  1386.    if (setvbuf( out_stream, NULL, _IONBF, 0))
  1387.    {
  1388.       printmsg(0, "copy_snews: Cannot unbuffer file %s.", filename);
  1389.       printerr(filename);
  1390.       panic();
  1391.    } /* if */
  1392.  
  1393. /*--------------------------------------------------------------------*/
  1394. /*                          Perform the copy                          */
  1395. /*--------------------------------------------------------------------*/
  1396.  
  1397.    while ( (len = fread( buf, 1, sizeof buf, stream)) != 0)
  1398.    {
  1399.       if (fwrite( buf, 1, len, out_stream ) != len)     /* I/O error? */
  1400.       {
  1401.          printerr(filename);
  1402.          panic();
  1403.       } /* if */
  1404.    } /* while */
  1405.  
  1406. /*--------------------------------------------------------------------*/
  1407. /*                           Close the file                           */
  1408. /*--------------------------------------------------------------------*/
  1409.  
  1410.    fclose( out_stream );
  1411.    fclose( stream );
  1412.    return 0;
  1413.  
  1414. } /* copy_snews */
  1415.