home *** CD-ROM | disk | FTP | other *** search
/ Unix System Administration Handbook 1997 October / usah_oct97.iso / news / cnews.tar / contrib / snntp / snntp.c < prev    next >
C/C++ Source or Header  |  1994-08-28  |  6KB  |  268 lines

  1. /*
  2.  * snntp, mark 2 - transmit news articles via NNTP
  3.  *
  4.  * snntp site <batch >newbatch 2>log
  5.  *
  6.  * exit stati:    0: normal, newbatch lists any unsent articles
  7.  *        1: didn't send a single article to site; throw away newbatch
  8.  *        other: something horrid happened
  9.  *
  10.  * batch is in C News "n" format (relative-file message-id)
  11.  */
  12.  
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #include <signal.h>
  17. #include <setjmp.h>
  18.  
  19. #include "fgetfln.h"
  20. #include "ipc.h"
  21. #include "config.h"
  22.  
  23. #define    STREQ(a, b)    (*(a) == *(b) && strcmp((a), (b)) == 0)
  24.  
  25. #define YES 1
  26. #define NO 0
  27.  
  28. #define EX_OK 0
  29. #define EX_NOSEND 1
  30. #define EX_OTHER 2
  31.  
  32. /* max. sec.s to send one article (consider SLIP link) */
  33. #define MAXARTTIME (20*60)
  34.  
  35. #define SENDLATER (-1)        /* ``count'' to indicate `try again later' */
  36.  
  37. /* imports */
  38. extern int optind;
  39. extern char *optarg;
  40.  
  41. /* exports */
  42. char *progname = "";
  43. int debug;
  44. int hooting = NO;
  45.  
  46. /* privates */
  47.  
  48. jmp_buf errbuf;
  49.  
  50. /* ARGSUSED */
  51. static
  52. spring(sig)
  53. int sig;
  54. {
  55.     signal(sig, spring);
  56.     longjmp(errbuf, 1);
  57.     /* NOTREACHED */
  58. }
  59.  
  60. /*
  61.  * main - parse arguments and handle options
  62.  */
  63. main(argc, argv)
  64. int argc;
  65. char *argv[];
  66. {
  67.     int c, errflg = 0;
  68.  
  69.     if (argc > 0)
  70.         progname = argv[0];
  71.     while ((c = getopt(argc, argv, "dv")) != EOF)
  72.         switch (c) {
  73.         case 'd':
  74.             ++debug;
  75.             break;
  76.         case 'v':
  77.             hooting = YES;
  78.             break;
  79.         default:
  80.             errflg++;
  81.             break;
  82.         }
  83.     if (errflg || optind != argc - 1) {
  84.         (void) fprintf(stderr, "usage: %s [-dv] site\n", progname);
  85.         exit(2);
  86.     }
  87.     cd(fullartfile((char *)NULL));        /* move to spool directory */
  88.     if (setjmp(errbuf) != 0) {
  89.         fprintf(stderr,
  90.             "%s: i/o error or timeout on network connection\n",
  91.             progname);
  92.         exit(EX_OTHER);
  93.     }
  94.     signal(SIGPIPE, spring);    /* in case the remote shuts down */
  95.     signal(SIGALRM, spring);
  96.     exit(sendsite(argv[optind]));
  97.     /* NOTREACHED */
  98. }
  99.  
  100. int                    /* response code or -1 on error */
  101. getresp(netfp)                /* read nntp response code line */
  102. FILE *netfp;
  103. {
  104.     int respcode = -1;        /* assume protocol error */
  105.     char resp[1024];
  106.  
  107.     (void) fseek(netfp, 0L, 1);    /* allow i/o reversal */
  108.     resp[0] = 'x';
  109.     while (tgets(resp, sizeof resp, netfp) != EOF && resp[0] == '1')
  110.         ;            /* ignore 1xx informational msgs */
  111.     if (isascii(resp[0]) && isdigit(resp[0]))
  112.         respcode = atoi(resp);
  113.     return respcode;
  114. }
  115.  
  116. /*
  117.  * sendfile - send articles named on stdin (in "n" format) to site.
  118.  * names of articles wanted but not sent are copied to stdout.
  119.  */
  120. int                    /* exit status */
  121. sendsite(site)
  122. char *site;
  123. {
  124.     register char *line, *sp, *msgid;
  125.     register int count;
  126.     int net, filessent = 0, respcode;
  127.     char *ipcname, *file;
  128.     FILE *netfp;
  129.  
  130.     ipcname = ipcpath(site, "tcp", "nntp");
  131.     net = ipcopen(ipcname, "heavy");
  132.     if (net < 0) {
  133.         fprintf(stderr, "%s: can't dial %s (%s)\n",
  134.             progname, ipcname, errstr);
  135.         return EX_OTHER;
  136.     }
  137.     netfp = fdopen(net, "r+");
  138.     if (netfp == NULL) {
  139.         fprintf(stderr, "%s: can't fdopen network connection\n",
  140.             progname);
  141.         return EX_OTHER;
  142.     }
  143.     respcode = getresp(netfp);
  144.     if (respcode != 200 && respcode != 201) {
  145.         fprintf(stderr, "%s: got %d, not 200 nor 201 greeting\n",
  146.             progname, respcode);
  147.         return EX_OTHER;        /* protocol error */
  148.     }
  149.     while ((line = fgetln(stdin)) != NULL) {
  150.         trim(line);
  151.         sp = strchr(line, ' ');
  152.         if (sp == NULL)
  153.             continue;        /* malformed input */
  154.         *sp = '\0';
  155.         file = line;
  156.         msgid = sp + 1;
  157.         count = sendart(netfp, file, msgid);
  158.         if (count == SENDLATER) {
  159.             /* try sending again later */
  160.             (void) printf("%s %s\n", file, msgid);
  161.             count = 0;        /* no article was sent */
  162.         }
  163.         filessent += count;
  164.     }
  165.     if (setjmp(errbuf) != 0) {
  166.         fprintf(stderr, "%s: i/o error on network connection\n",
  167.             progname);
  168.         exit(EX_OTHER);
  169.     }
  170.     (void) fseek(netfp, 0L, 1);        /* allow i/o reversal */
  171.     (void) tputs("quit\n", netfp);
  172.     if (fclose(netfp) == EOF) {
  173.         fprintf(stderr, "%s: i/o error on network connection\n",
  174.             progname);
  175.         exit(EX_OTHER);
  176.     }
  177.     return filessent == 0? EX_NOSEND: EX_OK;
  178. }
  179.  
  180. int                /* count of files sent; SENDLATER to retry */
  181. sendart(netfp, file, msgid)
  182. FILE *netfp;
  183. char *file, *msgid;
  184. {
  185.     int count = 0, art;
  186.     static int netlive = YES;
  187.  
  188.     if (!netlive)
  189.         return SENDLATER;    /* don't even try, no point */
  190.     art = open(file, 0);
  191.     if (art < 0)
  192.         return count;        /* missing or unreadable: don't copy */
  193.  
  194.     if (setjmp(errbuf) != 0) {    /* protocol time-out? */
  195.         fprintf(stderr,
  196.             "%s: i/o error or timeout on network connection\n",
  197.             progname);
  198.         netlive = NO;        /* communication has broken down */
  199.         count = SENDLATER;
  200.     } else {
  201.         (void) alarm(MAXARTTIME);
  202.         count = netsend(netfp, art, msgid); /* may longjmp on signal */
  203.     }
  204.     (void) alarm(0);        /* stop timing protocol transactions */
  205.     (void) close(art);
  206.     return count;
  207. }
  208.  
  209. int                /* count of files sent; SENDLATER to retry */
  210. netsend(netfp, art, msgid)
  211. FILE *netfp;
  212. int art;
  213. char *msgid;
  214. {
  215.     char buff[8192+1];
  216.     int respcode, bytes, lastc = '\n';
  217.  
  218.     (void) fseek(netfp, 0L, 1);        /* allow i/o reversal */
  219.     (void) tputs("ihave ", netfp);
  220.     (void) tputs(msgid, netfp);
  221.     (void) tputs("\n", netfp);
  222.  
  223.     respcode = getresp(netfp);
  224.     if (respcode == 435)
  225.         return 0;            /* got it; don't send */
  226.     else if (respcode != 335) {
  227.         fprintf(stderr, "%s: got %d, not 335 nor 435 for %s\n",
  228.             progname, respcode, msgid);
  229.         return SENDLATER;        /* protocol error */
  230.     } else {
  231.         /* 335: haven't got it, please send */
  232.         (void) fseek(netfp, 0L, 1);    /* allow i/o reversal */
  233.         while ((bytes = read(art, buff, sizeof buff-1)) > 0) {
  234.             buff[bytes] = '\0';
  235.             lastc = buff[bytes-1];
  236.             if (tputs(buff, netfp) == EOF) {
  237.                 lastc = 'x';
  238.                 break;
  239.             }
  240.         }
  241.         if (lastc != '\n')
  242.             (void) tputs("\n", netfp);
  243.         (void) putc('.', netfp);    /* prevent dot hiding */
  244.         (void) tputs("\n", netfp);
  245.  
  246.         respcode = getresp(netfp);
  247.         if (ferror(netfp)) {
  248.             fprintf(stderr, "%s: i/o error on network connection\n",
  249.                 progname);
  250.             return SENDLATER;
  251.         }
  252.         if (respcode == 235)
  253.             return 1;        /* success: got it okay */
  254.         else if (respcode == 437)
  255.             return 1;  /* success: got it, rejected, don't resend */
  256.         else if (respcode == 436) {
  257.             fprintf(stderr, "%s: transfer of %s failed\n", progname,
  258.                 msgid);
  259.             return SENDLATER;
  260.         } else {
  261.             fprintf(stderr,
  262.                 "%s: got %d, not 235 nor 436 nor 437 for %s\n",
  263.                 progname, respcode, msgid);
  264.             return SENDLATER;    /* protocol error */
  265.         }
  266.     }
  267. }
  268.