# 2.11BSD#431 - /usr/src/new/nntp/xmit/remote.c

##### Functions

    converse          X
    goodbye           X
    hello             X
    readreply         X
    rfgets            X
    sendcmd           X
    sendfile          X
    sfgets            X

##### Macros

    PUTC              X

       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

- in /usr/src/new/nntp/xmit/nntpxmit.c line 770

goodbye defined in line 263; used 7 times

- in line 241, 252
- in /usr/src/new/nntp/xmit/nntpxmit.c line 416, 424, 437, 825, 1038

hello defined in line 155; used 1 times

- in /usr/src/new/nntp/xmit/nntpxmit.c line 393

readreply defined in line 76; used 4 times

- in line 140, 237, 276
- in /usr/src/new/nntp/xmit/nntpxmit.c line 474

rfgets defined in line 339; used 1 times

- in line 49

sendcmd defined in line 60; used 3 times

- in line 134, 268, 422

sendfile defined in line 377; used 1 times

- in /usr/src/new/nntp/xmit/nntpxmit.c line 464

sfgets defined in line 299; used 3 times

- in line 48, 94, 351

to_sfgets defined in line 286; used 1 times

- in line 325

#### Defined variables

SFGstack defined in line 45; used 2 times

- in line 289, 310

#### Defined macros

PUTC defined in line 389; used 7 times

- in line 401-413(5), 419-420(2)

Last modified: 1988-01-12 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 1852 |