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