1: /*
   2: ** nntpxmit - transmit netnews articles across the internet with nntp
   3: **
   4: ** This program is for transmitting netnews between sites that offer the
   5: ** NNTP service, internet style.  Ideally, there are two forms of
   6: ** transmission that can be used in this environment, since the
   7: ** communication is interactive (and relatively immediate, when compared
   8: ** with UUCP).  They are:  passive poll (what have you gotten lately?) and
   9: ** active send (I have `x', do you want it?).  The USENET as a whole
  10: ** uniformly uses active send, and where the communication is batched
  11: ** (e.g. UUCP, or electronic mail) the software sends without even asking,
  12: ** unless it can determine that the article has already been to some site.
  13: **
  14: ** It turns out that when you implement passive poll, you have to be
  15: ** *very* careful about what you (the server) tell the client, because
  16: ** something that you might wish to restrict distribution of (either
  17: ** internal newsgroups, or material posted in the international groups in
  18: ** local distributions) will otherwise leak out.  It is the case that if
  19: ** the server doesn't tell the client that article `x' is there, the
  20: ** client won't ask for it.  If the server tells about an article which
  21: ** would otherwise stay within some restricted distribution, the onus is
  22: ** then on the client to figure out that the article is not appropriate to
  23: ** post on its local system.  Of course, at that point, we have already
  24: ** wasted the network bandwidth in transferring the article...
  25: **
  26: ** This is a roundabout way of saying that this program only implements
  27: ** active send.  There will have to be once-over done on the NNTP spec
  28: ** before passive poll goes in, because of the problems that I have cited.
  29: **
  30: ** Erik E. Fair	<ucbvax!fair>, Oct 14, 1985
  31: */
  32: 
  33: #include <stdio.h>
  34: #include <sys/types.h>
  35: #include <sys/file.h>
  36: #include <syslog.h>
  37: #include <sysexits.h>
  38: #include "defs.h"
  39: #include "header.h"
  40: #include "response_codes.h"
  41: #include "nntpxmit.h"
  42: 
  43: char    *pname;
  44: char    Debug = FALSE;
  45: char    Do_Stats = TRUE;
  46: char    *USAGE = "USAGE: nntpxmit [-s] hostname:file [hostname:file ...]";
  47: FILE    *getfp();
  48: 
  49: struct Stats {
  50:     u_long  offered;
  51:     u_long  accepted;
  52:     u_long  rejected;
  53:     u_long  failed;
  54: } Stats = {0L, 0L, 0L, 0L};
  55: 
  56: extern  int errno;
  57: extern  char    *rindex();
  58: extern  char    *index();
  59: extern  char    *errmsg();
  60: 
  61: main(ac,av)
  62: int ac;
  63: char    *av[];
  64: {
  65:     register int    i;
  66:     char    *host, *file;
  67: 
  68:     pname = ((pname = rindex(av[0],'/')) ? pname + 1 : av[0]);
  69: 
  70:     if (ac < 2) {
  71:         fprintf(stderr,"%s: %s\n", pname, USAGE);
  72:         exit(EX_USAGE);
  73:     }
  74: 
  75:     /* note that 4.2 BSD openlog has only two args */
  76:     (void) openlog(pname, LOG_PID, LOG_LOCAL7);
  77: 
  78:     for(i = 1; i < ac; i++) {
  79:         if (av[i][0] == '-') {
  80:             switch(av[i][1]) {
  81:             case 's':
  82:                 Do_Stats = FALSE;
  83:                 break;
  84:             case 'd':
  85:                 Debug++;
  86:                 break;
  87:             default:
  88:                 fprintf(stderr,"%s: no such option: -%c\n",
  89:                     pname, av[i][1]);
  90:                 fprintf(stderr,"%s: %s\n", pname, USAGE);
  91:                 exit(EX_USAGE);
  92:             }
  93:             continue;
  94:         }
  95: 
  96:         /*
  97: 		** OK, it wasn't an option, therefore it must be a
  98: 		** hostname, filename pair.
  99: 		*/
 100:         host = av[i];
 101:         if ((file = index(host, ':')) != (char *)NULL) {
 102:             *file++ = '\0';
 103:         } else {
 104:             fprintf(stderr,"%s: illegal hostname:file pair: <%s>\n",
 105:                 pname, host);
 106:             continue;
 107:         }
 108: 
 109:         bzero(&Stats, sizeof(Stats));
 110:         if (sendnews(host, file) && Do_Stats) {
 111:             syslog(LOG_INFO,
 112:                 "%s stats %d offered %d accepted %d rejected %d failed\n",
 113:                 host, Stats.offered, Stats.accepted, Stats.rejected, Stats.failed);
 114:         }
 115:     }
 116:     exit(EX_OK);
 117: }
 118: 
 119: /*
 120: ** Given a hostname to connect to, and a file of filenames (which contain
 121: ** netnews articles), send those articles to the named host using NNTP.
 122: */
 123: sendnews(host, file)
 124: char    *host, *file;
 125: {
 126:     register int    code;
 127:     register FILE   *filefile = fopen(file, "r");
 128:     register FILE   *fp;
 129:     char    buf[BUFSIZ];
 130: 
 131:     /*
 132: 	** if no news to send, return
 133: 	*/
 134:     if (filefile == (FILE *)NULL) {
 135:         dprintf(stderr, "%s: %s: %s\n", pname, file, errmsg(errno));
 136:         return(FALSE);
 137:     }
 138: 
 139:     if (hello(host) == FAIL) {
 140:         fclose(filefile);
 141:         return(FALSE);
 142:     }
 143: 
 144:     while((fp = getfp(filefile)) != (FILE *)NULL) {
 145:         switch(code = ihave(fp)) {
 146:         case CONT_XFER:
 147:             if (!sendfile(fp)) {
 148:                 fprintf(stderr, "%s: %s: article transmission failed.\n", pname, host);
 149:                 if (Do_Stats) Stats.failed++;
 150:                 fclose(filefile);
 151:                 fclose(fp);
 152:                 goodbye(DONT_WAIT);
 153:                 return(TRUE);
 154:             }
 155:             fclose(fp);
 156:             /*
 157: 			** Here I read the reply from the remote about the
 158: 			** transferred article, and I throw it away. I
 159: 			** should probably try and record the article
 160: 			** filename and append it back to the batchfile
 161: 			** again in the name of reliability, but that's
 162: 			** messy, and it's easier to assume that the guy
 163: 			** will have redundant feeds.
 164: 			*/
 165:             code = readreply(buf, sizeof(buf));
 166:             if (Do_Stats && code != OK_XFERED) Stats.failed++;
 167:             break;
 168:         case ERR_GOTIT:
 169:             fclose(fp);
 170:             break;
 171:         default:
 172:             fprintf(stderr,"%s: %s gave an improper response to IHAVE: %d\n", pname, host, code);
 173:             fclose(filefile);
 174:             fclose(fp);
 175:             goodbye(DONT_WAIT);
 176:             return(TRUE);
 177:         }
 178:     }
 179:     fclose(filefile);
 180:     if (unlink(file) < 0) {
 181:         fprintf(stderr,"%s: unable to unlink(%s): %s\n", pname, file, errmsg(errno));
 182:     }
 183:     goodbye(WAIT);
 184:     return(TRUE);
 185: }
 186: 
 187: /*
 188: ** Read the header of a netnews article, snatch the message-id therefrom,
 189: ** and ask the remote if they have that one already.
 190: */
 191: ihave(fp)
 192: FILE    *fp;
 193: {
 194:     struct hbuf header;
 195:     char    scr[LBUFLEN];
 196: 
 197:     bzero(&header, sizeof(header));
 198:     if (rfc822read(&header, fp, scr)) {
 199:         register int    code;
 200:         char    buf[BUFSIZ];
 201: 
 202:         /*
 203: 		** If an article shows up without a message-id,
 204: 		** we scream bloody murder. That's one in
 205: 		** the `can't ever happen' category.
 206: 		*/
 207:         if (header.ident[0] == '\0') {
 208:             fprintf(stderr, "%s: article w/o message-id!\n", pname);
 209:             return(ERR_GOTIT);
 210:         }
 211:         sprintf(buf, "IHAVE %s", header.ident);
 212:         if (Do_Stats) Stats.offered++;
 213: 
 214:         switch(code = converse(buf, sizeof(buf))) {
 215:         case CONT_XFER:
 216:             if (Do_Stats) Stats.accepted++;
 217:             rewind(fp);
 218:             return(code);
 219:         default:
 220:             if (Do_Stats) Stats.rejected++;
 221:             return(code);
 222:         }
 223:     }
 224:     /*
 225: 	** something botched locally with the article
 226: 	** so we don't send it, but we don't break off
 227: 	** communications with the remote either.
 228: 	*/
 229:     return(ERR_GOTIT);
 230: }
 231: 
 232: /*
 233: ** Given that fp points to an open file containing filenames,
 234: ** open and return a file pointer to the next filename in the file.
 235: ** Don't you love indirection?
 236: */
 237: FILE *
 238: getfp(fp)
 239: FILE    *fp;
 240: {
 241:     register FILE   *newfp = NULL;
 242:     register char   *cp;
 243:     char    filename[BUFSIZ];
 244: 
 245:     while(newfp == NULL) {
 246:         if (fgets(filename, sizeof(filename), fp) == NULL)
 247:             return(NULL);       /* EOF, tell caller */
 248: 
 249:         /* zap \n char */
 250:         if (*(cp = &filename[strlen(filename) - 1]) == '\n')
 251:             *cp = '\0';
 252: 
 253:         if ((newfp = fopen(filename, "r")) == NULL)
 254:             perror(filename);   /* tell 'em why it failed */
 255:     }
 256:     dprintf(stderr, "FILE: %s\n", filename);    /* DEBUG */
 257:     return(newfp);
 258: }

Defined functions

getfp defined in line 237; used 2 times
ihave defined in line 191; used 1 times
main defined in line 61; never used
sendnews defined in line 123; used 1 times

Defined variables

Debug defined in line 44; used 1 times
  • in line 85
Do_Stats defined in line 45; used 7 times
Stats defined in line 54; used 11 times
USAGE defined in line 46; used 2 times
pname defined in line 43; used 20 times

Defined struct's

Stats defined in line 49; never used
Last modified: 1986-03-21
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1495
Valid CSS Valid XHTML 1.0 Strict