0
|
1 /* ftpsbr.c - simple FTP client library (why doesn't BSD have one?!?) */
|
|
2
|
|
3 #ifndef lint
|
12
|
4 static char ident[] = "@(#)$Id: ftpsbr.c,v 1.2 2006/12/05 18:18:13 kono Exp $";
|
0
|
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 /* 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 /* */
|
|
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 /* */
|
|
68
|
|
69 #include <errno.h>
|
|
70 #if !defined(BSD44) && !defined(__GNU_LIBRARY__)
|
|
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 /* */
|
|
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 /* */
|
|
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 /* */
|
|
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 /* */
|
|
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 /* */
|
|
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 /* */
|
|
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 /* */
|
|
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 /* */
|
|
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 /* */
|
|
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
|