Sync with trunk head.
[reactos.git] / base / applications / network / ftp / main.c
1 /*
2 * Copyright (c) 1985, 1989 Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are permitted
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley. The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16 */
17
18 #ifndef lint
19 char copyright[] =
20 "@(#) Copyright (c) 1985, 1989 Regents of the University of California.\n\
21 All rights reserved.\n";
22 #endif /* not lint */
23
24 #ifndef lint
25 static char sccsid[] = "@(#)main.c based on 5.13 (Berkeley) 3/14/89";
26 #endif /* not lint */
27
28 /*
29 * FTP User Program -- Command Interface.
30 */
31 #ifndef _WIN32
32 #include <netdb.h>
33 #include <sys/socket.h>
34 #include <sys/ioctl.h>
35 #include <arpa/ftp.h>
36 #include <errno.h>
37 #include <pwd.h>
38 #endif
39 #include "ftp_var.h"
40 #include "prototypes.h"
41 #include <sys/types.h>
42
43 #include <io.h>
44 #include <fcntl.h>
45
46 #include <signal.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <ctype.h>
50
51
52 #if defined(sun) && !defined(FD_SET)
53 typedef int uid_t;
54 #endif
55
56 uid_t getuid();
57 void intr();
58 void lostpeer();
59 char *getlogin();
60
61 short portnum;
62
63 char home[128];
64 char *globerr;
65 int autologin;
66
67
68
69 /* Lot's of options... */
70 /*
71 * Options and other state info.
72 */
73 int trace; /* trace packets exchanged */
74 int hash; /* print # for each buffer transferred */
75 //int sendport; /* use PORT cmd for each data connection */
76 int verbose; /* print messages coming back from server */
77 int connected; /* connected to server */
78 int fromatty; /* input is from a terminal */
79 int interactive; /* interactively prompt on m* cmds */
80 int debug; /* debugging level */
81 int bell; /* ring bell on cmd completion */
82 int doglob; /* glob local file names */
83 int proxy; /* proxy server connection active */
84 int passivemode;
85 int proxflag; /* proxy connection exists */
86 int sunique; /* store files on server with unique name */
87 int runique; /* store local files with unique name */
88 int mcase; /* map upper to lower case for mget names */
89 int ntflag; /* use ntin ntout tables for name translation */
90 int mapflag; /* use mapin mapout templates on file names */
91 int code; /* return/reply code for ftp command */
92 int crflag; /* if 1, strip car. rets. on ascii gets */
93 char pasv[64]; /* passive port for proxy data connection */
94 char *altarg; /* argv[1] with no shell-like preprocessing */
95 char ntin[17]; /* input translation table */
96 char ntout[17]; /* output translation table */
97 // #include <sys/param.h>
98 char mapin[MAXPATHLEN]; /* input map template */
99 char mapout[MAXPATHLEN]; /* output map template */
100 char typename[32]; /* name of file transfer type */
101 int type; /* file transfer type */
102 char structname[32]; /* name of file transfer structure */
103 int stru; /* file transfer structure */
104 char formname[32]; /* name of file transfer format */
105 int form; /* file transfer format */
106 char modename[32]; /* name of file transfer mode */
107 int mode; /* file transfer mode */
108 char bytename[32]; /* local byte size in ascii */
109 int bytesize; /* local byte size in binary */
110
111 jmp_buf toplevel; /* non-local goto stuff for cmd scanner */
112
113 char line[200]; /* input line buffer */
114 char *stringbase; /* current scan point in line buffer */
115 char argbuf[200]; /* argument storage buffer */
116 char *argbase; /* current storage point in arg buffer */
117 int margc; /* count of arguments on input line */
118 const char *margv[20]; /* args parsed from input line */
119 int cpend; /* flag: if != 0, then pending server reply */
120 int mflag; /* flag: if != 0, then active multi command */
121
122 int options; /* used during socket creation */
123
124 int macnum; /* number of defined macros */
125 struct macel macros[16];
126 char macbuf[4096];
127
128 /*
129 * Need to start a listen on the data channel
130 * before we send the command, otherwise the
131 * server's connect may fail.
132 */
133 int sendport = -1;
134
135 static const char *slurpstring();
136
137
138 int main(int argc, const char *argv[])
139 {
140 const char *cp;
141 int top;
142 #if 0
143 char homedir[MAXPATHLEN];
144 #endif
145
146 int err;
147 WORD wVerReq;
148
149 WSADATA WSAData;
150 struct servent *sp; /* service spec for tcp/ftp */
151
152 /* Disable output buffering, for the benefit of Emacs. */
153 //setbuf(stdout, NULL);
154
155 _fmode = O_BINARY; // This causes an error somewhere.
156
157 wVerReq = MAKEWORD(1,1);
158
159 err = WSAStartup(wVerReq, &WSAData);
160 if (err != 0)
161 {
162 fprintf(stderr, "Could not initialize Windows socket interface.");
163 exit(1);
164 }
165
166 sp = getservbyname("ftp", "tcp");
167 if (sp == 0) {
168 fprintf(stderr, "ftp: ftp/tcp: unknown service\n");
169 exit(1);
170 }
171
172 portnum = sp->s_port;
173
174
175 doglob = 1;
176 interactive = 1;
177 autologin = 1;
178 argc--, argv++;
179 while (argc > 0 && **argv == '-') {
180 for (cp = *argv + 1; *cp; cp++)
181 switch (*cp) {
182
183 case 'd':
184 options |= SO_DEBUG;
185 debug++;
186 break;
187
188 case 'v':
189 verbose++;
190 break;
191
192 case 't':
193 trace++;
194 break;
195
196 case 'i':
197 interactive = 0;
198 break;
199
200 case 'n':
201 autologin = 0;
202 break;
203
204 case 'g':
205 doglob = 0;
206 break;
207
208 default:
209 fprintf(stdout,
210 "ftp: %c: unknown option\n", *cp);
211 exit(1);
212 }
213 argc--, argv++;
214 }
215 // fromatty = isatty(fileno(stdin));
216 fromatty = 1; // Strengthen this test
217 /*
218 * Set up defaults for FTP.
219 */
220 (void) strcpy(typename, "ascii"), type = TYPE_A;
221 (void) strcpy(formname, "non-print"), form = FORM_N;
222 (void) strcpy(modename, "stream"), mode = MODE_S;
223 (void) strcpy(structname, "file"), stru = STRU_F;
224 (void) strcpy(bytename, "8"), bytesize = 8;
225 if (fromatty)
226 verbose++;
227 cpend = 0; /* no pending replies */
228 proxy = 0; /* proxy not active */
229 passivemode = 1; /* passive mode *is* active */
230 crflag = 1; /* strip c.r. on ascii gets */
231 /*
232 * Set up the home directory in case we're globbing.
233 */
234 #if 0
235 cp = getlogin();
236 if (cp != NULL) {
237 pw = getpwnam(cp);
238 }
239 if (pw == NULL)
240 pw = getpwuid(getuid());
241 if (pw != NULL) {
242 home = homedir;
243 (void) strcpy(home, pw->pw_dir);
244 }
245 #endif
246 strcpy(home, "C:/");
247 if (argc > 0) {
248 if (setjmp(toplevel))
249 exit(0);
250 // (void) signal(SIGINT, intr);
251 // (void) signal(SIGPIPE, lostpeer);
252 setpeer(argc + 1, argv - 1);
253 }
254 top = setjmp(toplevel) == 0;
255 if (top) {
256 // (void) signal(SIGINT, intr);
257 // (void) signal(SIGPIPE, lostpeer);
258 }
259 for (;;) {
260 cmdscanner(top);
261 top = 1;
262 }
263 }
264
265 void
266 intr()
267 {
268
269 longjmp(toplevel, 1);
270 }
271
272 void lostpeer(void)
273 {
274 extern int cout;
275 extern int data;
276
277 if (connected) {
278 if (cout) {
279 closesocket(cout);
280 cout = 0;
281 }
282 if (data >= 0) {
283 (void) shutdown(data, 1+1);
284 (void) close(data);
285 data = -1;
286 }
287 connected = 0;
288 }
289 pswitch(1);
290 if (connected) {
291 if (cout) {
292 closesocket(cout);
293 cout = 0;
294 }
295 connected = 0;
296 }
297 proxflag = 0;
298 pswitch(0);
299 }
300
301 /*char *
302 tail(filename)
303 char *filename;
304 {
305 register char *s;
306
307 while (*filename) {
308 s = rindex(filename, '/');
309 if (s == NULL)
310 break;
311 if (s[1])
312 return (s + 1);
313 *s = '\0';
314 }
315 return (filename);
316 }
317 */
318 /*
319 * Command parser.
320 */
321 void cmdscanner(top)
322 int top;
323 {
324 register struct cmd *c;
325
326 if (!top)
327 (void) putchar('\n');
328 for (;;) {
329 (void) fflush(stdout);
330 if (fromatty) {
331 printf("ftp> ");
332 (void) fflush(stdout);
333 }
334 if (gets(line) == 0) {
335 if (feof(stdin) || ferror(stdin))
336 quit();
337 break;
338 }
339 if (line[0] == 0)
340 break;
341 makeargv();
342 if (margc == 0) {
343 continue;
344 }
345 c = getcmd(margv[0]);
346 if (c == (struct cmd *)-1) {
347 printf("?Ambiguous command\n");
348 continue;
349 }
350 if (c == 0) {
351 printf("?Invalid command\n");
352 continue;
353 }
354 if (c->c_conn && !connected) {
355 printf ("Not connected.\n");
356 continue;
357 }
358 (*c->c_handler)(margc, margv);
359 if (bell && c->c_bell)
360 (void) putchar('\007');
361 if (c->c_handler != help)
362 break;
363 }
364 (void) fflush(stdout);
365 // (void) signal(SIGINT, intr);
366 // (void) signal(SIGPIPE, lostpeer);
367 }
368
369 struct cmd *
370 getcmd(name)
371 const char *name;
372 {
373 extern struct cmd cmdtab[];
374 const char *p, *q;
375 struct cmd *c, *found;
376 int nmatches, longest;
377
378 longest = 0;
379 nmatches = 0;
380 found = 0;
381 for (c = cmdtab; (p = c->c_name); c++) {
382 for (q = name; *q == *p++; q++)
383 if (*q == 0) /* exact match? */
384 return (c);
385 if (!*q) { /* the name was a prefix */
386 if (q - name > longest) {
387 longest = q - name;
388 nmatches = 1;
389 found = c;
390 } else if (q - name == longest)
391 nmatches++;
392 }
393 }
394 if (nmatches > 1)
395 return ((struct cmd *)-1);
396 return (found);
397 }
398
399 /*
400 * Slice a string up into argc/argv.
401 */
402
403 int slrflag;
404
405 void makeargv()
406 {
407 const char **argp;
408
409 margc = 0;
410 argp = margv;
411 stringbase = line; /* scan from first of buffer */
412 argbase = argbuf; /* store from first of buffer */
413 slrflag = 0;
414 while ((*argp++ = slurpstring()))
415 margc++;
416 }
417
418 /*
419 * Parse string into argbuf;
420 * implemented with FSM to
421 * handle quoting and strings
422 */
423 static const char *
424 slurpstring()
425 {
426 int got_one = 0;
427 register char *sb = stringbase;
428 register char *ap = argbase;
429 char *tmp = argbase; /* will return this if token found */
430
431 if (*sb == '!' || *sb == '$') { /* recognize ! as a token for shell */
432 switch (slrflag) { /* and $ as token for macro invoke */
433 case 0:
434 slrflag++;
435 stringbase++;
436 return ((*sb == '!') ? "!" : "$");
437 /* NOTREACHED */
438 case 1:
439 slrflag++;
440 altarg = stringbase;
441 break;
442 default:
443 break;
444 }
445 }
446
447 S0:
448 switch (*sb) {
449
450 case '\0':
451 goto OUT1;
452
453 case ' ':
454 case '\t':
455 sb++; goto S0;
456
457 default:
458 switch (slrflag) {
459 case 0:
460 slrflag++;
461 break;
462 case 1:
463 slrflag++;
464 altarg = sb;
465 break;
466 default:
467 break;
468 }
469 goto S1;
470 }
471
472 S1:
473 switch (*sb) {
474
475 case ' ':
476 case '\t':
477 case '\0':
478 goto OUT1; /* end of token */
479
480 case '\\':
481 sb++; goto S2; /* slurp next character */
482
483 case '"':
484 sb++; goto S3; /* slurp quoted string */
485
486 default:
487 *ap++ = *sb++; /* add character to token */
488 got_one = 1;
489 goto S1;
490 }
491
492 S2:
493 switch (*sb) {
494
495 case '\0':
496 goto OUT1;
497
498 default:
499 *ap++ = *sb++;
500 got_one = 1;
501 goto S1;
502 }
503
504 S3:
505 switch (*sb) {
506
507 case '\0':
508 goto OUT1;
509
510 case '"':
511 sb++; goto S1;
512
513 default:
514 *ap++ = *sb++;
515 got_one = 1;
516 goto S3;
517 }
518
519 OUT1:
520 if (got_one)
521 *ap++ = '\0';
522 argbase = ap; /* update storage pointer */
523 stringbase = sb; /* update scan pointer */
524 if (got_one) {
525 return(tmp);
526 }
527 switch (slrflag) {
528 case 0:
529 slrflag++;
530 break;
531 case 1:
532 slrflag++;
533 altarg = (char *) 0;
534 break;
535 default:
536 break;
537 }
538 return((char *)0);
539 }
540
541 #define HELPINDENT (sizeof ("directory"))
542
543 /*
544 * Help command.
545 * Call each command handler with argc == 0 and argv[0] == name.
546 */
547 void help(argc, argv)
548 int argc;
549 char *argv[];
550 {
551 extern struct cmd cmdtab[];
552 struct cmd *c;
553
554 if (argc == 1) {
555 register int i, j, w, k;
556 int columns, width = 0, lines;
557 extern int NCMDS;
558
559 printf("Commands may be abbreviated. Commands are:\n\n");
560 for (c = cmdtab; c < &cmdtab[NCMDS]; c++) {
561 int len = strlen(c->c_name);
562
563 if (len > width)
564 width = len;
565 }
566 width = (width + 8) &~ 7;
567 columns = 80 / width;
568 if (columns == 0)
569 columns = 1;
570 lines = (NCMDS + columns - 1) / columns;
571 for (i = 0; i < lines; i++) {
572 for (j = 0; j < columns; j++) {
573 c = cmdtab + j * lines + i;
574 if (c->c_name && (!proxy || c->c_proxy)) {
575 printf("%s", c->c_name);
576 }
577 else if (c->c_name) {
578 for (k=0; k < (int) strlen(c->c_name); k++) {
579 (void) putchar(' ');
580 }
581 }
582 if (c + lines >= &cmdtab[NCMDS]) {
583 printf("\n");
584 break;
585 }
586 w = strlen(c->c_name);
587 while (w < width) {
588 w = (w + 8) &~ 7;
589 (void) putchar('\t');
590 }
591 }
592 }
593 (void) fflush(stdout);
594 return;
595 }
596 while (--argc > 0) {
597 register char *arg;
598 arg = *++argv;
599 c = getcmd(arg);
600 if (c == (struct cmd *)-1)
601 printf("?Ambiguous help command %s\n", arg);
602 else if (c == (struct cmd *)0)
603 printf("?Invalid help command %s\n", arg);
604 else
605 printf("%-*s\t%s\n", (int)HELPINDENT,
606 c->c_name, c->c_help);
607 }
608 (void) fflush(stdout);
609 }