|
|
1.1 ! root 1: /* ! 2: * NNTP client routines. ! 3: */ ! 4: ! 5: #ifndef lint ! 6: static char *sccsid = "@(#)clientlib.c 1.5 (Berkeley) 10/15/87"; ! 7: #endif ! 8: ! 9: #include <stdio.h> ! 10: #include <sys/types.h> ! 11: #include <sys/socket.h> ! 12: #include <netinet/in.h> ! 13: #include <netdb.h> ! 14: ! 15: #if defined(AF_DECnet) && defined(ultrix) ! 16: # ifndef DECNET ! 17: # define DECNET ! 18: # endif ! 19: #endif ! 20: ! 21: #ifdef DECNET ! 22: #include <netdnet/dn.h> ! 23: #include <netdnet/dnetdb.h> ! 24: #endif ! 25: ! 26: #include "response_codes.h" ! 27: ! 28: FILE *ser_rd_fp = NULL; ! 29: FILE *ser_wr_fp = NULL; ! 30: ! 31: /* ! 32: * getserverbyfile Get the name of a server from a named file. ! 33: * Handle white space and comments. ! 34: * Use NNTPSERVER environment variable if set. ! 35: * ! 36: * Parameters: "file" is the name of the file to read. ! 37: * ! 38: * Returns: Pointer to static data area containing the ! 39: * first non-ws/comment line in the file. ! 40: * NULL on error (or lack of entry in file). ! 41: * ! 42: * Side effects: None. ! 43: */ ! 44: ! 45: char * ! 46: getserverbyfile(file) ! 47: char *file; ! 48: { ! 49: register FILE *fp; ! 50: register char *cp; ! 51: static char buf[256]; ! 52: char *index(); ! 53: char *getenv(); ! 54: ! 55: if (cp = getenv("NNTPSERVER")) { ! 56: (void) strcpy(buf, cp); ! 57: return (buf); ! 58: } ! 59: ! 60: if (file == NULL) ! 61: return (NULL); ! 62: ! 63: fp = fopen(file, "r"); ! 64: if (fp == NULL) ! 65: return (NULL); ! 66: ! 67: while (fgets(buf, sizeof (buf), fp) != NULL) { ! 68: if (*buf == '\n' || *buf == '#') ! 69: continue; ! 70: cp = index(buf, '\n'); ! 71: if (cp) ! 72: *cp = '\0'; ! 73: (void) fclose(fp); ! 74: return (buf); ! 75: } ! 76: ! 77: (void) fclose(fp); ! 78: return (NULL); /* No entry */ ! 79: } ! 80: ! 81: ! 82: /* ! 83: * server_init Get a connection to the remote news server. ! 84: * ! 85: * Parameters: "machine" is the machine to connect to. ! 86: * ! 87: * Returns: -1 on error ! 88: * server's initial response code on success. ! 89: * ! 90: * Side effects: Connects to server. ! 91: * "ser_rd_fp" and "ser_wr_fp" are fp's ! 92: * for reading and writing to server. ! 93: */ ! 94: ! 95: server_init(machine) ! 96: char *machine; ! 97: { ! 98: int sockt_rd, sockt_wr; ! 99: char line[256]; ! 100: char *cp; ! 101: char *index(); ! 102: ! 103: #ifdef DECNET ! 104: cp = index(machine, ':'); ! 105: ! 106: if (cp && cp[1] == ':') { ! 107: *cp = '\0'; ! 108: sockt_rd = get_dnet_socket(machine); ! 109: } else ! 110: sockt_rd = get_tcp_socket(machine); ! 111: #else ! 112: sockt_rd = get_tcp_socket(machine); ! 113: #endif ! 114: ! 115: if (sockt_rd < 0) ! 116: return (-1); ! 117: ! 118: /* ! 119: * Now we'll make file pointers (i.e., buffered I/O) out of ! 120: * the socket file descriptor. Note that we can't just ! 121: * open a fp for reading and writing -- we have to open ! 122: * up two separate fp's, one for reading, one for writing. ! 123: */ ! 124: ! 125: if ((ser_rd_fp = fdopen(sockt_rd, "r")) == NULL) { ! 126: perror("server_init: fdopen #1"); ! 127: return (-1); ! 128: } ! 129: ! 130: sockt_wr = dup(sockt_rd); ! 131: if ((ser_wr_fp = fdopen(sockt_wr, "w")) == NULL) { ! 132: perror("server_init: fdopen #2"); ! 133: ser_rd_fp = NULL; /* from above */ ! 134: return (-1); ! 135: } ! 136: ! 137: /* Now get the server's signon message */ ! 138: ! 139: (void) get_server(line, sizeof(line)); ! 140: return (atoi(line)); ! 141: } ! 142: ! 143: ! 144: /* ! 145: * get_tcp_socket -- get us a socket connected to the news server. ! 146: * ! 147: * Parameters: "machine" is the machine the server is running on. ! 148: * ! 149: * Returns: Socket connected to the news server if ! 150: * all is ok, else -1 on error. ! 151: * ! 152: * Side effects: Connects to server. ! 153: * ! 154: * Errors: Printed via perror. ! 155: */ ! 156: ! 157: get_tcp_socket(machine) ! 158: char *machine; ! 159: { ! 160: int s, x = 0; ! 161: register char **cp; ! 162: struct sockaddr_in sin; ! 163: struct servent *getservbyname(), *sp; ! 164: struct hostent *gethostbyname(), *hp; ! 165: ! 166: if ((sp = getservbyname("nntp", "tcp")) == NULL) { ! 167: fprintf(stderr, "nntp/tcp: Unknown service.\n"); ! 168: return (-1); ! 169: } ! 170: ! 171: if ((hp = gethostbyname(machine)) == NULL) { ! 172: fprintf(stderr, "%s: Unknown host.\n", machine); ! 173: return (-1); ! 174: } ! 175: ! 176: bzero((char *) &sin, sizeof(sin)); ! 177: sin.sin_family = hp->h_addrtype; ! 178: sin.sin_port = sp->s_port; ! 179: ! 180: /* ! 181: * The following is kinda gross. The name server under 4.3 ! 182: * returns a list of addresses, each of which should be tried ! 183: * in turn if the previous one fails. However, 4.2 hostent ! 184: * structure doesn't have this list of addresses. ! 185: * Under 4.3, h_addr is a #define to h_addr_list[0]. ! 186: * We use this to figure out whether to include the NS specific ! 187: * code... ! 188: */ ! 189: ! 190: #ifdef h_addr ! 191: ! 192: /* get a socket and initiate connection -- use multiple addresses */ ! 193: ! 194: for (cp = hp->h_addr_list; cp && *cp; cp++) { ! 195: s = socket(hp->h_addrtype, SOCK_STREAM, 0); ! 196: if (s < 0) { ! 197: perror("socket"); ! 198: return (-1); ! 199: } ! 200: bcopy(*cp, (char *)&sin.sin_addr, hp->h_length); ! 201: ! 202: if (x < 0) ! 203: fprintf(stderr, "trying %s\n", inet_ntoa(sin.sin_addr)); ! 204: x = connect(s, (struct sockaddr *)&sin, sizeof (sin)); ! 205: if (x == 0) ! 206: break; ! 207: fprintf(stderr, "connection to %s: ", inet_ntoa(sin.sin_addr)); ! 208: perror(""); ! 209: (void) close(s); ! 210: } ! 211: if (x < 0) { ! 212: fprintf(stderr, "giving up...\n"); ! 213: return (-1); ! 214: } ! 215: #else /* no name server */ ! 216: ! 217: if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { /* Get the socket */ ! 218: perror("socket"); ! 219: return (-1); ! 220: } ! 221: ! 222: /* And then connect */ ! 223: ! 224: bcopy(hp->h_addr, (char *) &sin.sin_addr, hp->h_length); ! 225: if (connect(s, (struct sockaddr *) &sin, sizeof(sin)) < 0) { ! 226: perror("connect"); ! 227: (void) close(s); ! 228: return (-1); ! 229: } ! 230: ! 231: #endif ! 232: ! 233: return (s); ! 234: } ! 235: ! 236: #ifdef DECNET ! 237: /* ! 238: * get_dnet_socket -- get us a socket connected to the news server. ! 239: * ! 240: * Parameters: "machine" is the machine the server is running on. ! 241: * ! 242: * Returns: Socket connected to the news server if ! 243: * all is ok, else -1 on error. ! 244: * ! 245: * Side effects: Connects to server. ! 246: * ! 247: * Errors: Printed via nerror. ! 248: */ ! 249: ! 250: get_dnet_socket(machine) ! 251: char *machine; ! 252: { ! 253: int s, area, node; ! 254: struct sockaddr_dn sdn; ! 255: struct nodeent *getnodebyname(), *np; ! 256: ! 257: bzero((char *) &sdn, sizeof(sdn)); ! 258: ! 259: switch (s = sscanf( machine, "%d%*[.]%d", &area, &node )) { ! 260: case 1: ! 261: node = area; ! 262: area = 0; ! 263: case 2: ! 264: node += area*1024; ! 265: sdn.sdn_add.a_len = 2; ! 266: sdn.sdn_family = AF_DECnet; ! 267: sdn.sdn_add.a_addr[0] = node % 256; ! 268: sdn.sdn_add.a_addr[1] = node / 256; ! 269: break; ! 270: default: ! 271: if ((np = getnodebyname(machine)) == NULL) { ! 272: fprintf(stderr, ! 273: "%s: Unknown host.\n", machine); ! 274: return (-1); ! 275: } else { ! 276: bcopy(np->n_addr, ! 277: (char *) sdn.sdn_add.a_addr, ! 278: np->n_length); ! 279: sdn.sdn_add.a_len = np->n_length; ! 280: sdn.sdn_family = np->n_addrtype; ! 281: } ! 282: break; ! 283: } ! 284: sdn.sdn_objnum = 0; ! 285: sdn.sdn_flags = 0; ! 286: sdn.sdn_objnamel = strlen("NNTP"); ! 287: bcopy("NNTP", &sdn.sdn_objname[0], sdn.sdn_objnamel); ! 288: ! 289: if ((s = socket(AF_DECnet, SOCK_STREAM, 0)) < 0) { ! 290: nerror("socket"); ! 291: return (-1); ! 292: } ! 293: ! 294: /* And then connect */ ! 295: ! 296: if (connect(s, (struct sockaddr *) &sdn, sizeof(sdn)) < 0) { ! 297: nerror("connect"); ! 298: close(s); ! 299: return (-1); ! 300: } ! 301: ! 302: return (s); ! 303: } ! 304: #endif ! 305: ! 306: ! 307: ! 308: /* ! 309: * handle_server_response ! 310: * ! 311: * Print some informative messages based on the server's initial ! 312: * response code. This is here so inews, rn, etc. can share ! 313: * the code. ! 314: * ! 315: * Parameters: "response" is the response code which the ! 316: * server sent us, presumably from "server_init", ! 317: * above. ! 318: * "server" is the news server we got the ! 319: * response code from. ! 320: * ! 321: * Returns: -1 if the error is fatal (and we should exit). ! 322: * 0 otherwise. ! 323: * ! 324: * Side effects: None. ! 325: */ ! 326: ! 327: handle_server_response(response, server) ! 328: int response; ! 329: char *server; ! 330: { ! 331: switch (response) { ! 332: case OK_NOPOST: /* fall through */ ! 333: printf( ! 334: "NOTE: This machine does not have permission to post articles.\n"); ! 335: printf( ! 336: " Please don't waste your time trying.\n\n"); ! 337: ! 338: case OK_CANPOST: ! 339: return (0); ! 340: break; ! 341: ! 342: case ERR_ACCESS: ! 343: printf( ! 344: "This machine does not have permission to use the %s news server.\n", ! 345: server); ! 346: return (-1); ! 347: break; ! 348: ! 349: default: ! 350: printf("Unexpected response code from %s news server: %d\n", ! 351: server, response); ! 352: return (-1); ! 353: break; ! 354: } ! 355: /*NOTREACHED*/ ! 356: } ! 357: ! 358: ! 359: /* ! 360: * put_server -- send a line of text to the server, terminating it ! 361: * with CR and LF, as per ARPA standard. ! 362: * ! 363: * Parameters: "string" is the string to be sent to the ! 364: * server. ! 365: * ! 366: * Returns: Nothing. ! 367: * ! 368: * Side effects: Talks to the server. ! 369: * ! 370: * Note: This routine flushes the buffer each time ! 371: * it is called. For large transmissions ! 372: * (i.e., posting news) don't use it. Instead, ! 373: * do the fprintf's yourself, and then a final ! 374: * fflush. ! 375: */ ! 376: ! 377: void ! 378: put_server(string) ! 379: char *string; ! 380: { ! 381: #ifdef DEBUG ! 382: fprintf(stderr, ">>> %s\n", string); ! 383: #endif ! 384: fprintf(ser_wr_fp, "%s\r\n", string); ! 385: (void) fflush(ser_wr_fp); ! 386: } ! 387: ! 388: ! 389: /* ! 390: * get_server -- get a line of text from the server. Strips ! 391: * CR's and LF's. ! 392: * ! 393: * Parameters: "string" has the buffer space for the ! 394: * line received. ! 395: * "size" is the size of the buffer. ! 396: * ! 397: * Returns: -1 on error, 0 otherwise. ! 398: * ! 399: * Side effects: Talks to server, changes contents of "string". ! 400: */ ! 401: ! 402: get_server(string, size) ! 403: char *string; ! 404: int size; ! 405: { ! 406: register char *cp; ! 407: char *index(); ! 408: ! 409: if (fgets(string, size, ser_rd_fp) == NULL) ! 410: return (-1); ! 411: ! 412: if ((cp = index(string, '\r')) != NULL) ! 413: *cp = '\0'; ! 414: else if ((cp = index(string, '\n')) != NULL) ! 415: *cp = '\0'; ! 416: #ifdef DEBUG ! 417: fprintf(stderr, "<<< %s\n", string); ! 418: #endif ! 419: ! 420: return (0); ! 421: } ! 422: ! 423: ! 424: /* ! 425: * close_server -- close the connection to the server, after sending ! 426: * the "quit" command. ! 427: * ! 428: * Parameters: None. ! 429: * ! 430: * Returns: Nothing. ! 431: * ! 432: * Side effects: Closes the connection with the server. ! 433: * You can't use "put_server" or "get_server" ! 434: * after this routine is called. ! 435: */ ! 436: ! 437: void ! 438: close_server() ! 439: { ! 440: char ser_line[256]; ! 441: ! 442: if (ser_wr_fp == NULL || ser_rd_fp == NULL) ! 443: return; ! 444: ! 445: put_server("QUIT"); ! 446: (void) get_server(ser_line, sizeof(ser_line)); ! 447: ! 448: (void) fclose(ser_wr_fp); ! 449: (void) fclose(ser_rd_fp); ! 450: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.