|
|
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.