]> diplodocus.org Git - nmh/blob - docs/historical/mh-6.8.5/uip/ftpsbr.c
sbr/mts.c: Delete mmdlm2; use same-valued mmdlm1 instead.
[nmh] / docs / historical / mh-6.8.5 / uip / ftpsbr.c
1 /* ftpsbr.c - simple FTP client library (why doesn't BSD have one?!?) */
2
3 #ifndef lint
4 static char ident[] = "@(#)$Id: ftpsbr.c,v 1.13 1993/08/25 17:25:27 jromine Exp $";
5 #endif
6
7 #include "../h/mh.h"
8 #include "../h/mhn.h"
9 #ifdef FTP
10 #include <ctype.h>
11 #ifdef SVR4
12 #undef NULLVP /* stdio.h */
13 #endif
14 #include <stdio.h>
15 #include <arpa/ftp.h>
16 #ifdef __STDC__
17 #include <stdarg.h>
18 #else
19 #include <varargs.h>
20 #endif
21
22 #ifdef __STDC__
23 static int command(int arg1, ...);
24 #else
25 static int command();
26 #endif
27
28 static int ftp_quit(), ftp_read(), initconn(),
29 dataconn(), _command(), getreply();
30
31 /* \f DATA */
32
33 #define v_debug debugsw
34 #define v_verbose verbosw
35
36
37 static int ftp_fd = NOTOK;
38 static int data_fd = NOTOK;
39
40 static int v_noise;
41
42 extern int v_debug;
43 extern int v_verbose;
44
45 /* \f */
46
47 #if defined(SYS5) && defined(AUX)
48 #define u_short ushort
49 #define u_long ulong
50 #endif
51
52 #include <sys/types.h>
53 #include <sys/socket.h>
54 #include <netinet/in.h>
55 #include <netdb.h>
56
57 #if defined(BIND) && !defined(h_addr)
58 #define h_addr h_addr_list[0]
59 #endif
60
61 #define inaddr_copy(hp,sin) \
62 bcopy ((hp) -> h_addr, (char *) &((sin) -> sin_addr), (hp) -> h_length)
63
64
65 struct hostent *gethostbystring ();
66
67 /* \f */
68
69 extern int errno;
70 #ifndef BSD44
71 extern int sys_nerr;
72 extern char *sys_errlist[];
73 #endif
74
75
76 #define start_tcp_client(sock,priv) \
77 socket (AF_INET, SOCK_STREAM, 0)
78
79 #define join_tcp_server(fd, sock) \
80 connect ((fd), (struct sockaddr *) (sock), sizeof *(sock))
81
82
83 /* ARGSUSED */
84
85 static int start_tcp_server (sock, backlog, opt1, opt2)
86 struct sockaddr_in *sock;
87 int backlog,
88 opt1,
89 opt2;
90 {
91 int eindex,
92 sd;
93
94 if ((sd = socket (AF_INET, SOCK_STREAM, 0)) == NOTOK)
95 return NOTOK;
96
97 if (bind (sd, (struct sockaddr *) sock, sizeof *sock) == NOTOK) {
98 eindex = errno;
99 (void) close (sd);
100 errno = eindex;
101 }
102 else
103 (void) listen (sd, backlog);
104
105 return sd;
106 }
107
108 static int __len__;
109 #define join_tcp_client(fd,sock) \
110 accept ((fd), (struct sockaddr *) (sock), \
111 (__len__ = sizeof *(sock), &__len__))
112
113
114 #define read_tcp_socket read
115 #define write_tcp_socket write
116 #define close_tcp_socket close
117
118 /* \f */
119
120 static void _asprintf (bp, what, ap) /* fmt, args, ... */
121 register char *bp;
122 char *what;
123 va_list ap;
124 {
125 register int eindex;
126 char *fmt;
127
128 eindex = errno;
129
130 *bp = '\0';
131 fmt = va_arg (ap, char *);
132
133 if (fmt) {
134 #ifndef VSPRINTF
135 struct _iobuf iob;
136 #endif
137
138 #ifndef VSPRINTF
139 #ifdef pyr
140 bzero ((char *) &iob, sizeof iob);
141 iob._file = _NFILE;
142 #endif
143 iob._flag = _IOWRT | _IOSTRG;
144 #if !defined(vax) && !defined(pyr) && !defined(sequent)
145 iob._ptr = (unsigned char *) bp;
146 #else
147 iob._ptr = bp;
148 #endif
149 iob._cnt = BUFSIZ;
150 _doprnt (fmt, ap, &iob);
151 (void) putc ('\0', &iob);
152 #else
153 (void) vsprintf (bp, fmt, ap);
154 #endif
155 bp += strlen (bp);
156
157 }
158
159 if (what) {
160 if (*what) {
161 (void) sprintf (bp, " %s: ", what);
162 bp += strlen (bp);
163 }
164 if (0 < eindex && eindex < sys_nerr)
165 (void) strcpy (bp, sys_errlist[eindex]);
166 else
167 (void) sprintf (bp, "Error %d", eindex);
168 bp += strlen (bp);
169 }
170
171 errno = eindex;
172 }
173
174 /* \f */
175
176 int ftp_get (host, user, password, cwd, remote, local, ascii, stayopen)
177 char *host,
178 *user,
179 *password,
180 *cwd,
181 *remote,
182 *local;
183 int ascii,
184 stayopen;
185 {
186 return ftp_trans (host, user, password, cwd, remote, local, "RETR", ascii,
187 stayopen);
188 }
189
190 /* \f */
191
192 int ftp_trans (host, user, password, cwd, remote, local, cmd, ascii,
193 stayopen)
194 char *host,
195 *user,
196 *password,
197 *cwd,
198 *remote,
199 *local,
200 *cmd;
201 int ascii,
202 stayopen;
203 {
204 int result;
205
206 if (stayopen <= 0) {
207 result = ftp_quit ();
208 if (host == NULL)
209 return result;
210 }
211
212 if (ftp_fd == NOTOK) {
213 struct sockaddr_in in_socket;
214 register struct hostent *hp;
215 register struct servent *sp;
216
217 if ((sp = getservbyname ("ftp", "tcp")) == NULL) {
218 fprintf (stderr, "tcp/ftp: unknown service");
219 return NOTOK;
220 }
221 if ((hp = gethostbystring (host)) == NULL) {
222 fprintf (stderr, "%s: unknown host\n", host);
223 return NOTOK;
224 }
225 in_socket.sin_family = hp -> h_addrtype;
226 inaddr_copy (hp, &in_socket);
227 in_socket.sin_port = sp -> s_port;
228
229 if ((ftp_fd = start_tcp_client ((struct sockaddr_in *) NULL, 0))
230 == NOTOK) {
231 perror (host);
232 return NOTOK;
233 }
234 if (join_tcp_server (ftp_fd, &in_socket) == NOTOK) {
235 perror (host);
236 (void) close_tcp_socket (ftp_fd), ftp_fd = NOTOK;
237 return NOTOK;
238 }
239 (void) getreply (1, 0);
240
241 if (v_verbose) {
242 fprintf (stdout, "Connected to %s\n", host);
243 (void) fflush (stdout);
244 }
245
246 if (user) {
247 if ((result = command (0, "USER %s", user)) == CONTINUE)
248 result = command (1, "PASS %s", password);
249 if (result != COMPLETE) {
250 result = NOTOK;
251 goto out;
252 }
253 }
254
255 if (remote == NULL)
256 return OK;
257 }
258
259 if (cwd && ((result = command (0, "CWD %s", cwd)) != COMPLETE
260 && result != CONTINUE)) {
261 result = NOTOK;
262 goto out;
263 }
264
265 if (command (1, ascii ? "TYPE A" : "TYPE I") != COMPLETE) {
266 result = NOTOK;
267 goto out;
268 }
269
270 result = ftp_read (remote, local, cmd, ascii);
271
272 out: ;
273 if (result != OK || !stayopen)
274 (void) ftp_quit ();
275
276 return result;
277 }
278
279 /* \f */
280
281 static int ftp_quit ()
282 {
283 int n;
284
285 if (ftp_fd == NOTOK)
286 return OK;
287
288 n = command (1, "QUIT");
289
290 (void) close_tcp_socket (ftp_fd), ftp_fd = NOTOK;
291
292 return (n == 0 || n == COMPLETE ? OK : NOTOK);
293 }
294
295 /* \f */
296
297 static int ftp_read (remote, local, cmd, ascii)
298 char *remote,
299 *local,
300 *cmd;
301 int ascii;
302 {
303 int istdio = 0,
304 istore;
305 register int cc;
306 int expectingreply = 0;
307 char buffer[BUFSIZ];
308 FILE *fp = NULL;
309
310 if (initconn () == NOTOK)
311 goto bad;
312
313 v_noise = v_verbose;
314 if (command (-1, *remote ? "%s %s" : "%s", cmd, remote) != PRELIM)
315 goto bad;
316
317 expectingreply++;
318 if (dataconn () == NOTOK) {
319 bad: ;
320 if (fp && !istdio)
321 (void) fclose (fp);
322 if (data_fd != NOTOK)
323 (void) close_tcp_socket (data_fd), data_fd = NOTOK;
324 if (expectingreply)
325 (void) getreply (-2, 0);
326
327 return NOTOK;
328 }
329
330 istore = !strcmp (cmd, "STOR");
331
332 if (istdio = !strcmp (local, "-"))
333 fp = istore ? stdin : stdout;
334 else
335 if ((fp = fopen (local, istore ? "r" : "w")) == NULL) {
336 perror (local);
337 goto bad;
338 }
339
340 if (istore) {
341 if (ascii) {
342 int c;
343 FILE *out;
344
345 if (!(out = fdopen (data_fd, "w"))) {
346 perror ("fdopen");
347 goto bad;
348 }
349
350 while ((c = getc (fp)) != EOF) {
351 if (c == '\n')
352 (void) putc ('\r', out);
353 if (putc (c, out) == EOF) {
354 perror ("putc");
355 (void) fclose (out);
356 data_fd = NOTOK;
357 goto bad;
358 }
359 }
360
361 (void) fclose (out);
362 data_fd = NOTOK;
363 }
364 else {
365 while ((cc = fread (buffer, sizeof *buffer, sizeof buffer, fp)) >0)
366 if (write_tcp_socket (data_fd, buffer, cc) != cc) {
367 perror ("write_tcp_socket");
368 goto bad;
369 }
370
371 (void) close_tcp_socket (data_fd), data_fd = NOTOK;
372 }
373 }
374 else {
375 if (ascii) {
376 int c;
377 FILE *in;
378
379 if (!(in = fdopen (data_fd, "r"))) {
380 perror ("fdopen");
381 goto bad;
382 }
383
384 while ((c = getc (in)) != EOF) {
385 if (c == '\r')
386 switch (c = getc (in)) {
387 case EOF:
388 case '\0':
389 c = '\r';
390 break;
391
392 case '\n':
393 break;
394
395 default:
396 (void) putc ('\r', fp);
397 break;
398 }
399
400 if (putc (c, fp) == EOF) {
401 perror ("putc");
402 (void) fclose (in);
403 data_fd = NOTOK;
404 goto bad;
405 }
406 }
407
408 (void) fclose (in);
409 data_fd = NOTOK;
410 }
411 else {
412 while ((cc = read_tcp_socket (data_fd, buffer, sizeof buffer)) > 0)
413 if (fwrite (buffer, sizeof *buffer, cc, fp) == 0) {
414 perror ("fwrite");
415 goto bad;
416 }
417 if (cc < 0) {
418 perror ("read_tcp_socket");
419 goto bad;
420 }
421
422 (void) close_tcp_socket (data_fd), data_fd = NOTOK;
423 }
424 }
425
426 if (!istdio)
427 (void) fclose (fp);
428
429 v_noise = v_verbose;
430 return (getreply (1, 0) == COMPLETE ? OK : NOTOK);
431 }
432
433 /* \f */
434
435 static int initconn ()
436 {
437 int len;
438 register char *a,
439 *p;
440 struct sockaddr_in in_socket;
441
442 if (getsockname (ftp_fd, (struct sockaddr *) &in_socket,
443 (len = sizeof in_socket, &len)) == NOTOK) {
444 perror ("getsockname");
445 return NOTOK;
446 }
447 in_socket.sin_port = 0;
448 if ((data_fd = start_tcp_server (&in_socket, 1, 0, 0)) == NOTOK) {
449 perror ("start_tcp_server");
450 return NOTOK;
451 }
452
453 if (getsockname (data_fd, (struct sockaddr *) &in_socket,
454 (len = sizeof in_socket, &len)) == NOTOK) {
455 perror ("getsockname");
456 return NOTOK;
457 }
458
459 a = (char *) &in_socket.sin_addr;
460 p = (char *) &in_socket.sin_port;
461
462 #define UC(b) (((int) b) & 0xff)
463 if (command (1, "PORT %d,%d,%d,%d,%d,%d",
464 UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
465 UC(p[0]), UC(p[1])) == COMPLETE)
466 return OK;
467
468 return NOTOK;
469 }
470
471 /* \f */
472
473 static int dataconn ()
474 {
475 int fd;
476 struct sockaddr_in in_socket;
477
478 if ((fd = join_tcp_client (data_fd, &in_socket)) == NOTOK) {
479 perror ("join_tcp_client");
480 return NOTOK;
481 }
482 (void) close_tcp_socket (data_fd);
483 data_fd = fd;
484
485 return OK;
486 }
487
488 /* \f */
489
490 #ifndef lint
491 #ifdef __STDC__
492 static int command (int arg1, ...)
493 {
494 int val;
495 va_list ap;
496
497 va_start (ap, arg1);
498
499 val = _command (arg1, ap);
500
501 va_end (ap);
502
503 return val;
504 }
505 #else
506 static int command (va_alist)
507 va_dcl
508 {
509 int val;
510 va_list ap;
511
512 va_start (ap);
513
514 val = va_arg (ap, int);
515 val = _command (val, ap);
516
517 va_end (ap);
518
519 return val;
520 }
521 #endif
522
523 static int _command (complete, ap)
524 int complete;
525 va_list ap;
526 {
527 int len;
528 char buffer[BUFSIZ];
529
530 if (ftp_fd == NOTOK)
531 return NOTOK;
532
533 _asprintf (buffer, NULLCP, ap);
534 if (v_debug)
535 fprintf (stderr, "<--- %s\n", buffer);
536
537 (void) strcat (buffer, "\r\n");
538 len = strlen (buffer);
539
540 if (write_tcp_socket (ftp_fd, buffer, len) != len) {
541 perror ("write_tcp_socket");
542 return NOTOK;
543 }
544
545 return (getreply (complete, !strcmp (buffer, "QUIT")));
546 }
547 #else
548 /* VARARGS2 */
549
550 static int command (complete, fmt)
551 int complete;
552 char *fmt;
553 {
554 return command (complete, fmt);
555 }
556 #endif
557
558 /* \f */
559
560 static int getreply (complete, expecteof)
561 int complete,
562 expecteof;
563 {
564 for (;;) {
565 register int code,
566 dig,
567 n;
568 int continuation;
569 register char *bp;
570 char buffer[BUFSIZ];
571
572 code = dig = n = continuation = 0;
573 bp = buffer;
574
575 for (;;) {
576 char c;
577
578 if (read_tcp_socket (ftp_fd, &c, 1) < 1) {
579 if (expecteof)
580 return OK;
581
582 perror ("read_tcp_socket");
583 return DONE;
584 }
585 if (c == '\n')
586 break;
587 *bp++ = c != '\r' ? c : '\0';
588
589 dig++;
590 if (dig < 4) {
591 if (isdigit(c))
592 code = code * 10 + (c - '0');
593 else /* XXX: naughty FTP... */
594 if (isspace (c))
595 continuation++;
596 }
597 else
598 if (dig == 4 && c == '-')
599 continuation++;
600 if (n == 0)
601 n = c;
602 }
603
604 if (v_debug)
605 fprintf (stderr, "---> %s\n", buffer);
606 if (continuation)
607 continue;
608
609 n -= '0';
610
611 if (v_noise) {
612 fprintf (stdout, "%s\n", buffer);
613 (void) fflush (stdout);
614 v_noise = 0;
615 }
616 else
617 if ((complete == -1 && n != PRELIM)
618 || (complete == 0 && n != CONTINUE && n != COMPLETE)
619 || (complete == 1 && n != COMPLETE))
620 fprintf (stderr, "%s\n", buffer);
621
622 return n;
623 }
624 }
625 #endif