1: #include <stdio.h> 2: #include <ctype.h> 3: #include <setjmp.h> 4: #include <signal.h> 5: #include "get_tcp_conn.h" 6: #include "response_codes.h" 7: #include "nntpxmit.h" 8: 9: #define TRUE 1 10: #define FALSE 0 11: 12: static jmp_buf SFGstack; 13: FILE *rmt_rd; 14: FILE *rmt_wr; 15: char *sfgets(); 16: char *rfgets(); 17: 18: extern int errno; 19: extern char *pname; 20: extern char Debug; 21: extern char *errmsg(); 22: 23: /* 24: ** send cmd to remote, terminated with a CRLF. 25: */ 26: sendcmd(cmd) 27: char *cmd; 28: { 29: dprintf(stderr, "<<< %s\n", cmd); /* DEBUG */ 30: (void) fprintf(rmt_wr, "%s\r\n", cmd); 31: (void) fflush(rmt_wr); 32: return(ferror(rmt_wr)); 33: } 34: 35: /* 36: ** read a reply line from the remote server and return the code number 37: ** as an integer, and the message in a buffer supplied by the caller. 38: ** Returns FAIL if something went wrong. 39: */ 40: readreply(buf, size) 41: register char *buf; 42: int size; 43: { 44: register char *cp; 45: register int len; 46: 47: /* 48: ** make sure it's invalid, unless we say otherwise 49: */ 50: buf[0] = '\0'; 51: 52: /* 53: ** read one line from the remote 54: */ 55: if (sfgets(buf, size, rmt_rd) == NULL) 56: return(FAIL); /* error reading from remote */ 57: 58: /* 59: ** Make sure that what the remote sent us had a CRLF at the end 60: ** of the line, and then null it out. 61: */ 62: if ((len = strlen(buf)) > 2 && *(cp = &buf[len - 2]) == '\r' && 63: *(cp + 1) == '\n') 64: { 65: *cp = '\0'; 66: } else 67: return(FAIL); /* error reading from remote */ 68: 69: dprintf(stderr, ">>> %s\n", buf); /* DEBUG */ 70: /* 71: ** Skip any non-digits leading the response code 72: ** and then convert the code from ascii to integer for 73: ** return from this routine. 74: */ 75: cp = buf; 76: while(*cp != '\0' && isascii(*cp) && !isdigit(*cp)) 77: cp++; /* skip anything leading */ 78: 79: if (*cp == '\0' || !isascii(*cp)) 80: return(FAIL); /* error reading from remote */ 81: 82: return(atoi(cp)); 83: } 84: 85: /* 86: ** send a command to the remote, and wait for a response 87: ** returns the response code, and the message in the buffer 88: */ 89: converse(buf, size) 90: char *buf; 91: int size; 92: { 93: register int resp; 94: 95: if (sendcmd(buf)) 96: return(FAIL); /* Ooops! Something went wrong in xmit */ 97: /* 98: ** Skip the silly 100 series messages, since they're not the 99: ** final response we can expect 100: */ 101: while((resp = readreply(buf, size)) >= 100 && resp < 200) 102: continue; 103: return(resp); 104: } 105: 106: /* 107: ** Contact the remote server and set up the two global FILE pointers 108: ** to that socket. 109: */ 110: hello(host) 111: char *host; 112: { 113: int socket0, socket1; /* to me (bad pun) */ 114: static char *service = "nntp"; 115: char buf[BUFSIZ]; 116: 117: switch(socket0 = get_tcp_conn(host, service)) { 118: case NOHOST: 119: fprintf(stderr,"%s: no such host <%s>\n", pname, host); 120: return(FAIL); 121: case NOSERVICE: 122: fprintf(stderr,"%s: no such service <%s>\n", pname, service); 123: return(FAIL); 124: case FAIL: 125: fprintf(stderr,"%s: %s: %s\n", pname, host, errmsg(errno)); 126: return(FAIL); 127: } 128: 129: if ((socket1 = dup(socket0)) < 0) { 130: close(socket0); 131: fprintf(stderr,"%s: dup(2): %s\n", pname, errmsg(errno)); 132: return(FAIL); 133: } 134: 135: if ((rmt_rd = fdopen(socket0, "r")) == (FILE *)NULL) { 136: close(socket0); 137: close(socket1); 138: fprintf(stderr,"%s: fdopen(3): %s\n", pname, errmsg(errno)); 139: return(FAIL); 140: } 141: 142: if ((rmt_wr = fdopen(socket1, "w")) == (FILE *)NULL) { 143: fclose(rmt_rd); 144: rmt_rd = (FILE *)NULL; 145: close(socket1); 146: fprintf(stderr,"%s: fdopen(3): %s\n", pname, errmsg(errno)); 147: return(FAIL); 148: } 149: 150: switch(readreply(buf, sizeof(buf))) { 151: case OK_CANPOST: 152: case OK_NOPOST: 153: if (ferror(rmt_rd)) { 154: goodbye(DONT_WAIT); 155: return(FAIL); 156: } 157: break; 158: default: 159: if (buf[0] != '\0') 160: fprintf(stderr, "%s: %s\n", pname, buf); 161: goodbye(DONT_WAIT); 162: return(FAIL); 163: } 164: return(NULL); 165: } 166: 167: /* 168: ** Say goodbye to the nice remote server. 169: */ 170: goodbye(wait) 171: int wait; 172: { 173: if (sendcmd("QUIT")) 174: wait = FALSE; /* override, something's wrong. */ 175: /* 176: ** I don't care what they say to me; this is just being polite. 177: */ 178: if (wait) { 179: char buf[BUFSIZ]; 180: 181: (void) readreply(buf, sizeof(buf)); 182: } 183: (void) fclose(rmt_rd); 184: rmt_rd = (FILE *)NULL; 185: (void) fclose(rmt_wr); 186: rmt_wr = (FILE *)NULL; 187: } 188: 189: static 190: to_sfgets() 191: { 192: longjmp(SFGstack, 1); 193: } 194: 195: /* 196: ** `Safe' fgets, ala sendmail. This fgets will timeout after some 197: ** period of time, on the assumption that if the remote did not 198: ** return, they're gone. 199: ** WARNING: contains a possibly unportable reference to stdio 200: ** error macros. 201: */ 202: char * 203: sfgets(buf, size, fp) 204: char *buf; 205: int size; 206: FILE *fp; 207: { 208: register char *ret; 209: 210: if (setjmp(SFGstack)) { 211: alarm(0); /* reset alarm clock */ 212: signal(SIGALRM, SIG_DFL); /* reset SIGALRM */ 213: fp->_flag |= _IOERR; /* set stdio error */ 214: return(NULL); /* bad read, remote time out */ 215: } 216: signal(SIGALRM, to_sfgets); 217: alarm(TIMEOUT); 218: ret = fgets(buf, size, fp); 219: alarm(0); /* reset alarm clock */ 220: signal(SIGALRM, SIG_DFL); /* reset SIGALRM */ 221: return(ret); 222: } 223: 224: /* 225: ** Remote fgets - converts CRLF to \n, and returns NULL on `.' EOF from 226: ** the remote. Otherwise it returns its first argument, like fgets(3). 227: */ 228: char * 229: rfgets(buf, size, fp) 230: char *buf; 231: int size; 232: FILE *fp; 233: { 234: register char *cp = buf; 235: register int len; 236: 237: *cp = '\0'; 238: if (sfgets(buf, size, fp) == NULL) 239: return(NULL); 240: 241: /* <CRLF> => '\n' */ 242: if ((len = strlen(buf)) > 2 && *(cp = &buf[len - 2]) == '\r') { 243: *cp++ = '\n'; 244: *cp = '\0'; 245: } 246: 247: /* ".\n" => EOF */ 248: cp = buf; 249: if (*cp++ == '.' && *cp == '\n') { 250: return(NULL); /* EOF */ 251: } 252: 253: /* Dot escaping */ 254: if (buf[0] == '.') strcpy(&buf[0], &buf[1]); 255: return(buf); 256: } 257: 258: /* 259: ** send the contents of an open file descriptor to the remote, 260: ** with appropriate RFC822 filtering (e.g. CRLF line termination, 261: ** and dot escaping). Return FALSE if something went wrong. 262: */ 263: sendfile(fp) 264: FILE *fp; 265: { 266: register int c; 267: register int nl = TRUE; /* assume we start on a new line */ 268: 269: if (fp == (FILE *)NULL) 270: return(FALSE); 271: 272: while((c = fgetc(fp)) != EOF) { 273: switch(c) { 274: case '\n': 275: (void) fputc('\r', rmt_wr); /* \n -> \r\n */ 276: (void) fputc(c, rmt_wr); 277: nl = TRUE; /* for dot escaping */ 278: break; 279: case '.': 280: if (nl) { 281: (void) fputc(c, rmt_wr); /* add a dot */ 282: nl = FALSE; 283: } 284: (void) fputc(c, rmt_wr); 285: break; 286: default: 287: (void) fputc(c, rmt_wr); 288: nl = FALSE; 289: break; 290: } 291: } 292: if (!nl) { 293: (void) fputs("\r\n", rmt_wr); 294: } 295: (void) fputs(".\r\n", rmt_wr); /* <CRLF>.<CRLF> termination */ 296: (void) fflush(rmt_wr); 297: if (ferror(fp) || ferror(rmt_wr)) /* any errors? */ 298: return(FALSE); 299: return(TRUE); 300: }