1: /*
   2: ** remote communication routines for NNTP/SMTP style communication.
   3: **
   4: **	sendcmd		- return TRUE on error.
   5: **
   6: **	readreply	- return reply code or FAIL for error;
   7: **				modifies buffer passed to it.
   8: **
   9: **	converse	- sendcmd() & readreply();
  10: **				return reply code or FAIL for error;
  11: **				modifies buffer passed to it.
  12: **
  13: **	hello		- establish connection with remote;
  14: **				check greeting code.
  15: **
  16: **	goodbye		- give QUIT command, and shut down connection.
  17: **
  18: **	sfgets		- safe fgets(); does fgets with TIMEOUT.
  19: **			  (N.B.: possibly unportable stdio macro ref in here)
  20: **
  21: **	rfgets		- remote fgets() (calls sfgets());
  22: **				does SMTP dot escaping and
  23: **				\r\n -> \n conversion.
  24: **
  25: **	sendfile	- send a file with SMTP dot escaping and
  26: **				\n -> \r\n conversion.
  27: **
  28: ** Erik E. Fair <fair@ucbarpa.berkeley.edu>
  29: */
  30: 
  31: #include "nntpxmit.h"
  32: #include <sys/types.h>
  33: #include <sys/socket.h>
  34: #include <errno.h>
  35: #include <stdio.h>
  36: #include <ctype.h>
  37: #include <setjmp.h>
  38: #include <signal.h>
  39: #ifdef SYSLOG
  40: #include <syslog.h>
  41: #endif
  42: #include "get_tcp_conn.h"
  43: #include "nntp.h"
  44: 
  45: static  jmp_buf SFGstack;
  46: FILE    *rmt_rd;
  47: FILE    *rmt_wr;
  48: char    *sfgets();
  49: char    *rfgets();
  50: 
  51: extern  int errno;
  52: extern  char    Debug;
  53: extern  char    *errmsg();
  54: extern  char    *strcpy();
  55: extern  void    log();
  56: 
  57: /*
  58: ** send cmd to remote, terminated with a CRLF.
  59: */
  60: sendcmd(cmd)
  61: char    *cmd;
  62: {
  63:     if (cmd == (char *)NULL)
  64:         return(TRUE);   /* error */
  65:     dprintf(stderr, ">>> %s\n", cmd);   /* DEBUG */
  66:     (void) fprintf(rmt_wr, "%s\r\n", cmd);
  67:     (void) fflush(rmt_wr);
  68:     return(ferror(rmt_wr));
  69: }
  70: 
  71: /*
  72: ** read a reply line from the remote server and return the code number
  73: ** as an integer, and the message in a buffer supplied by the caller.
  74: ** Returns FAIL if something went wrong.
  75: */
  76: readreply(buf, size)
  77: register char   *buf;
  78: int size;
  79: {
  80:     register char   *cp;
  81:     register int    len;
  82: 
  83:     if (buf == (char *)NULL || size <= 0)
  84:         return(FAIL);
  85: 
  86:     /*
  87: 	** make sure it's invalid, unless we say otherwise
  88: 	*/
  89:     buf[0] = '\0';
  90: 
  91:     /*
  92: 	** read one line from the remote
  93: 	*/
  94:     if (sfgets(buf, size, rmt_rd) == NULL)
  95:         return(FAIL);   /* error reading from remote */
  96: 
  97:     /*
  98: 	** Make sure that what the remote sent us had a CRLF at the end
  99: 	** of the line, and then null it out.
 100: 	*/
 101:     if ((len = strlen(buf)) > 2 && *(cp = &buf[len - 2]) == '\r' &&
 102:         *(cp + 1) == '\n')
 103:     {
 104:         *cp = '\0';
 105:     } else
 106:         return(FAIL);   /* error reading from remote */
 107: 
 108:     dprintf(stderr, "%s\n", buf);   /* DEBUG */
 109:     /*
 110: 	** Skip any non-digits leading the response code
 111: 	** and then convert the code from ascii to integer for
 112: 	** return from this routine.
 113: 	*/
 114:     cp = buf;
 115:     while(*cp != '\0' && isascii(*cp) && !isdigit(*cp))
 116:         cp++;   /* skip anything leading */
 117: 
 118:     if (*cp == '\0' || !isascii(*cp))
 119:         return(FAIL);   /* error reading from remote */
 120: 
 121:     return(atoi(cp));
 122: }
 123: 
 124: /*
 125: ** send a command to the remote, and wait for a response
 126: ** returns the response code, and the message in the buffer
 127: */
 128: converse(buf, size)
 129: char    *buf;
 130: int size;
 131: {
 132:     register int    resp;
 133: 
 134:     if (sendcmd(buf))
 135:         return(FAIL);   /* Ooops! Something went wrong in xmit */
 136:     /*
 137: 	** Skip the silly 100 series messages, since they're not the
 138: 	** final response we can expect
 139: 	*/
 140:     while((resp = readreply(buf, size)) >= 100 && resp < 200)
 141:         continue;
 142:     return(resp);
 143: }
 144: 
 145: /*
 146: ** Contact the remote server and set up the two global FILE pointers
 147: ** to that descriptor.
 148: **
 149: ** I can see the day when this routine will have 8 args:  one for
 150: ** hostname, and one for each of the seven ISO Reference Model layers
 151: ** for networking. A curse upon those involved with the ISO protocol
 152: ** effort: may they be forced to use the network that they will create,
 153: ** as opposed to something that works (like the Internet).
 154: */
 155: hello(host, transport)
 156: char    *host;
 157: int transport;
 158: { char  *service;
 159:     char    *rmode = "r";
 160:     char    *wmode = "w";
 161:     char    *e_fdopen = "fdopen(%d, \"%s\"): %s";
 162:     int socket0, socket1;   /* to me (bad pun) */
 163:     char    buf[BUFSIZ];
 164: 
 165:     switch(transport) {
 166:     case T_IP_TCP:
 167:         service = "nntp";
 168:         socket0 = get_tcp_conn(host, service);
 169:         break;
 170:     case T_DECNET:
 171: #ifdef DECNET
 172:         (void) signal(SIGPIPE, SIG_IGN);
 173:         service = "NNTP";
 174:         socket0 = dnet_conn(host, service, 0, 0, 0, 0, 0);
 175:         if (socket0 < 0) {
 176:             switch(errno) {
 177:             case EADDRNOTAVAIL:
 178:                 socket0 = NOHOST;
 179:                 break;
 180:             case ESRCH:
 181:                 socket0 = NOSERVICE;
 182:                 break;
 183:             }
 184:         }
 185:         break;
 186: #else
 187:         log(L_WARNING, "no DECNET support compiled in");
 188:         return(FAIL);
 189: #endif
 190:     case T_FD:
 191:         service = "with a smile";
 192:         socket0 = atoi(host);
 193:         break;
 194:     }
 195: 
 196:     if (socket0 < 0) {
 197:         switch(socket0) {
 198:         case NOHOST:
 199:             sprintf(buf, "%s host unknown", host);
 200:             log(L_WARNING, buf);
 201:             return(FAIL);
 202:         case NOSERVICE:
 203:             sprintf(buf, "%s service unknown: %s", host, service);
 204:             log(L_WARNING, buf);
 205:             return(FAIL);
 206:         case FAIL:
 207:             sprintf(buf, "%s hello: %s", host, errmsg(errno));
 208:             log(L_NOTICE, buf);
 209:             return(FAIL);
 210:         }
 211:     }
 212: 
 213:     if ((socket1 = dup(socket0)) < 0) {
 214:         sprintf(buf, "dup(%d): %s", socket0, errmsg(errno));
 215:         log(L_WARNING, buf);
 216:         (void) close(socket0);
 217:         return(FAIL);
 218:     }
 219: 
 220:     if ((rmt_rd = fdopen(socket0, rmode)) == (FILE *)NULL) {
 221:         sprintf(buf, e_fdopen, socket0, rmode);
 222:         log(L_WARNING, buf);
 223:         (void) close(socket0);
 224:         (void) close(socket1);
 225:         return(FAIL);
 226:     }
 227: 
 228:     if ((rmt_wr = fdopen(socket1, wmode)) == (FILE *)NULL) {
 229:         sprintf(buf, e_fdopen, socket1, wmode);
 230:         log(L_WARNING, buf);
 231:         (void) fclose(rmt_rd);
 232:         rmt_rd = (FILE *)NULL;
 233:         (void) close(socket1);
 234:         return(FAIL);
 235:     }
 236: 
 237:     switch(readreply(buf, sizeof(buf))) {
 238:     case OK_CANPOST:
 239:     case OK_NOPOST:
 240:         if (ferror(rmt_rd)) {
 241:             goodbye(DONT_WAIT);
 242:             return(FAIL);
 243:         }
 244:         break;
 245:     default:
 246:         if (buf[0] != '\0') {
 247:             char    err[BUFSIZ];
 248: 
 249:             sprintf(err, "%s greeted us with %s", host, buf);
 250:             log(L_NOTICE, err);
 251:         }
 252:         goodbye(DONT_WAIT);
 253:         return(FAIL);
 254:     }
 255:     return(NULL);
 256: }
 257: 
 258: /*
 259: ** Say goodbye to the nice remote server.
 260: **
 261: ** We trap SIGPIPE because the socket might already be gone.
 262: */
 263: goodbye(wait_for_reply)
 264: int wait_for_reply;
 265: {
 266:     register ifunp  pstate = signal(SIGPIPE, SIG_IGN);
 267: 
 268:     if (sendcmd("QUIT"))
 269:         wait_for_reply = FALSE; /* override, something's wrong. */
 270:     /*
 271: 	** I don't care what they say to me; this is just being polite.
 272: 	*/
 273:     if (wait_for_reply) {
 274:         char    buf[BUFSIZ];
 275: 
 276:         (void) readreply(buf, sizeof(buf));
 277:     }
 278:     (void) fclose(rmt_rd);
 279:     rmt_rd = (FILE *)NULL;
 280:     (void) fclose(rmt_wr);
 281:     rmt_wr = (FILE *)NULL;
 282:     if (pstate != (ifunp)(-1));
 283:         (void) signal(SIGPIPE, pstate);
 284: }
 285: 
 286: static
 287: to_sfgets()
 288: {
 289:     longjmp(SFGstack, 1);
 290: }
 291: 
 292: /*
 293: ** `Safe' fgets, ala sendmail. This fgets will timeout after some
 294: ** period of time, on the assumption that if the remote did not
 295: ** return, they're gone.
 296: ** WARNING: contains a possibly unportable reference to stdio
 297: ** error macros.
 298: */
 299: char *
 300: sfgets(buf, size, fp)
 301: char    *buf;
 302: int size;
 303: FILE    *fp;
 304: {
 305:     register char   *ret;
 306:     int esave;
 307: 
 308:     if (buf == (char *)NULL || size <= 0 || fp == (FILE *)NULL)
 309:         return((char *)NULL);
 310:     if (setjmp(SFGstack)) {
 311:         (void) alarm(0);        /* reset alarm clock */
 312:         (void) signal(SIGALRM, SIG_DFL);
 313: #ifdef apollo
 314:         fp->_flag |= _SIERR;
 315: #else
 316:         fp->_flag |= _IOERR;        /* set stdio error */
 317: #endif
 318: #ifndef ETIMEDOUT
 319:         errno = EPIPE;          /* USG doesn't have ETIMEDOUT */
 320: #else
 321:         errno = ETIMEDOUT;      /* connection timed out */
 322: #endif
 323:         return((char *)NULL);       /* bad read, remote time out */
 324:     }
 325:     (void) signal(SIGALRM, to_sfgets);
 326:     (void) alarm(TIMEOUT);
 327:     ret = fgets(buf, size, fp);
 328:     esave = errno;
 329:     (void) alarm(0);            /* reset alarm clock */
 330:     (void) signal(SIGALRM, SIG_DFL);    /* reset SIGALRM */
 331:     errno = esave;
 332:     return(ret);
 333: }
 334: 
 335: /*
 336: ** Remote fgets - converts CRLF to \n, and returns NULL on `.' EOF from
 337: ** the remote. Otherwise it returns its first argument, like fgets(3).
 338: */
 339: char *
 340: rfgets(buf, size, fp)
 341: char    *buf;
 342: int size;
 343: FILE    *fp;
 344: {
 345:     register char   *cp = buf;
 346:     register int    len;
 347: 
 348:     if (buf == (char *)NULL || size <= 0 || fp == (FILE *)NULL)
 349:         return((char *)NULL);
 350:     *cp = '\0';
 351:     if (sfgets(buf, size, fp) == (char *)NULL)
 352:         return((char *)NULL);
 353: 
 354:     /* <CRLF> => '\n' */
 355:     if ((len = strlen(buf)) > 2 && *(cp = &buf[len - 2]) == '\r') {
 356:         *cp++ = '\n';
 357:         *cp = '\0';
 358:     }
 359: 
 360:     /* ".\n" => EOF */
 361:     cp = buf;
 362:     if (*cp++ == '.' && *cp == '\n') {
 363:         return((char *)NULL);   /* EOF */
 364:     }
 365: 
 366:     /* Dot escaping */
 367:     if (buf[0] == '.')
 368:         (void) strcpy(&buf[0], &buf[1]);
 369:     return(buf);
 370: }
 371: 
 372: /*
 373: ** send the contents of an open file descriptor to the remote,
 374: ** with appropriate RFC822 filtering (e.g. CRLF line termination,
 375: ** and dot escaping). Return FALSE if something went wrong.
 376: */
 377: sendfile(fp)
 378: FILE    *fp;
 379: {
 380:     register int    c;
 381:     register FILE   *remote = rmt_wr;
 382:     register int    nl = TRUE;  /* assume we start on a new line */
 383: 
 384: /*
 385: ** I'm using putc() instead of fputc();
 386: ** why do a subroutine call when you don't have to?
 387: ** Besides, this ought to give the C preprocessor a work-out.
 388: */
 389: #define PUTC(c) if (putc(c, remote) == EOF) return(FALSE)
 390: 
 391:     if (fp == (FILE *)NULL)
 392:         return(FALSE);
 393: 
 394:     /*
 395: 	** the second test makes no sense to me,
 396: 	** but System V apparently needed it...
 397: 	*/
 398:     while((c = fgetc(fp)) != EOF && !feof(fp)) {
 399:         switch(c) {
 400:         case '\n':
 401:             PUTC('\r');     /* \n -> \r\n */
 402:             PUTC(c);
 403:             nl = TRUE;      /* for dot escaping */
 404:             break;
 405:         case '.':
 406:             if (nl) {
 407:                 PUTC(c);    /* add a dot */
 408:                 nl = FALSE;
 409:             }
 410:             PUTC(c);
 411:             break;
 412:         default:
 413:             PUTC(c);
 414:             nl = FALSE;
 415:             break;
 416:         }
 417:     }
 418:     if (!nl) {
 419:         PUTC('\r');
 420:         PUTC('\n');
 421:     }
 422:     return( !(sendcmd(".") || ferror(fp)) );
 423: }

Defined functions

converse defined in line 128; used 1 times
goodbye defined in line 263; used 7 times
hello defined in line 155; used 1 times
readreply defined in line 76; used 4 times
rfgets defined in line 339; used 1 times
  • in line 49
sendcmd defined in line 60; used 3 times
sendfile defined in line 377; used 1 times
sfgets defined in line 299; used 3 times
to_sfgets defined in line 286; used 1 times

Defined variables

SFGstack defined in line 45; used 2 times

Defined macros

PUTC defined in line 389; used 7 times
Last modified: 1988-01-12
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2001
Valid CSS Valid XHTML 1.0 Strict