a0e7a23e6a3d51fed3f1c0870cd07559e7e438e1
[reactos.git] / reactos / apps / utils / net / 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 #if !defined(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 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
125
126 int main(int argc, char *argv[])
127 {
128 register char *cp;
129 int top;
130 #if 0
131 char homedir[MAXPATHLEN];
132 #endif
133
134 int err;
135 WORD wVerReq;
136
137 WSADATA WSAData;
138 struct servent *sp; /* service spec for tcp/ftp */
139
140 /* Disable output buffering, for the benefit of Emacs. */
141 //setbuf(stdout, NULL);
142
143 _fmode = O_BINARY; // This causes an error somewhere.
144
145 wVerReq = MAKEWORD(1,1);
146
147 err = WSAStartup(wVerReq, &WSAData);
148 if (err != 0)
149 {
150 fprintf(stderr, "Could not initialize Windows socket interface.");
151 exit(1);
152 }
153
154 sp = getservbyname("ftp", "tcp");
155 if (sp == 0) {
156 fprintf(stderr, "ftp: ftp/tcp: unknown service\n");
157 exit(1);
158 }
159
160 portnum = sp->s_port;
161
162
163 doglob = 1;
164 interactive = 1;
165 autologin = 1;
166 argc--, argv++;
167 while (argc > 0 && **argv == '-') {
168 for (cp = *argv + 1; *cp; cp++)
169 switch (*cp) {
170
171 case 'd':
172 options |= SO_DEBUG;
173 debug++;
174 break;
175
176 case 'v':
177 verbose++;
178 break;
179
180 case 't':
181 trace++;
182 break;
183
184 case 'i':
185 interactive = 0;
186 break;
187
188 case 'n':
189 autologin = 0;
190 break;
191
192 case 'g':
193 doglob = 0;
194 break;
195
196 default:
197 fprintf(stdout,
198 "ftp: %c: unknown option\n", *cp);
199 exit(1);
200 }
201 argc--, argv++;
202 }
203 // fromatty = isatty(fileno(stdin));
204 fromatty = 1; // Strengthen this test
205 /*
206 * Set up defaults for FTP.
207 */
208 (void) strcpy(typename, "ascii"), type = TYPE_A;
209 (void) strcpy(formname, "non-print"), form = FORM_N;
210 (void) strcpy(modename, "stream"), mode = MODE_S;
211 (void) strcpy(structname, "file"), stru = STRU_F;
212 (void) strcpy(bytename, "8"), bytesize = 8;
213 if (fromatty)
214 verbose++;
215 cpend = 0; /* no pending replies */
216 proxy = 0; /* proxy not active */
217 passivemode = 1; /* passive mode *is* active */
218 crflag = 1; /* strip c.r. on ascii gets */
219 /*
220 * Set up the home directory in case we're globbing.
221 */
222 #if 0
223 cp = getlogin();
224 if (cp != NULL) {
225 pw = getpwnam(cp);
226 }
227 if (pw == NULL)
228 pw = getpwuid(getuid());
229 if (pw != NULL) {
230 home = homedir;
231 (void) strcpy(home, pw->pw_dir);
232 }
233 #endif
234 strcpy(home, "C:/");
235 if (argc > 0) {
236 if (setjmp(toplevel))
237 exit(0);
238 // (void) signal(SIGINT, intr);
239 // (void) signal(SIGPIPE, lostpeer);
240 setpeer(argc + 1, argv - 1);
241 }
242 top = setjmp(toplevel) == 0;
243 if (top) {
244 // (void) signal(SIGINT, intr);
245 // (void) signal(SIGPIPE, lostpeer);
246 }
247 for (;;) {
248 cmdscanner(top);
249 top = 1;
250 }
251 }
252
253 void
254 intr()
255 {
256
257 longjmp(toplevel, 1);
258 }
259
260 void lostpeer(void)
261 {
262 extern int cout;
263 extern int data;
264
265 if (connected) {
266 if (cout != (int) NULL) {
267 closesocket(cout);
268 cout = (int) NULL;
269 }
270 if (data >= 0) {
271 (void) shutdown(data, 1+1);
272 (void) close(data);
273 data = -1;
274 }
275 connected = 0;
276 }
277 pswitch(1);
278 if (connected) {
279 if (cout != (int)NULL) {
280 closesocket(cout);
281 cout = (int) NULL;
282 }
283 connected = 0;
284 }
285 proxflag = 0;
286 pswitch(0);
287 }
288
289 /*char *
290 tail(filename)
291 char *filename;
292 {
293 register char *s;
294
295 while (*filename) {
296 s = rindex(filename, '/');
297 if (s == NULL)
298 break;
299 if (s[1])
300 return (s + 1);
301 *s = '\0';
302 }
303 return (filename);
304 }
305 */
306 /*
307 * Command parser.
308 */
309 void cmdscanner(top)
310 int top;
311 {
312 register struct cmd *c;
313 struct cmd *getcmd();
314 extern int help();
315
316 if (!top)
317 (void) putchar('\n');
318 for (;;) {
319 (void) fflush(stdout);
320 if (fromatty) {
321 printf("ftp> ");
322 (void) fflush(stdout);
323 }
324 if (gets(line) == 0) {
325 if (feof(stdin) || ferror(stdin))
326 quit();
327 break;
328 }
329 if (line[0] == 0)
330 break;
331 makeargv();
332 if (margc == 0) {
333 continue;
334 }
335 c = getcmd(margv[0]);
336 if (c == (struct cmd *)-1) {
337 printf("?Ambiguous command\n");
338 continue;
339 }
340 if (c == 0) {
341 printf("?Invalid command\n");
342 continue;
343 }
344 if (c->c_conn && !connected) {
345 printf ("Not connected.\n");
346 continue;
347 }
348 (*c->c_handler)(margc, margv);
349 if (bell && c->c_bell)
350 (void) putchar('\007');
351 if (c->c_handler != help)
352 break;
353 }
354 (void) fflush(stdout);
355 // (void) signal(SIGINT, intr);
356 // (void) signal(SIGPIPE, lostpeer);
357 }
358
359 struct cmd *
360 getcmd(name)
361 register char *name;
362 {
363 extern struct cmd cmdtab[];
364 register char *p, *q;
365 register struct cmd *c, *found;
366 register int nmatches, longest;
367
368 longest = 0;
369 nmatches = 0;
370 found = 0;
371 for (c = cmdtab; (p = c->c_name); c++) {
372 for (q = name; *q == *p++; q++)
373 if (*q == 0) /* exact match? */
374 return (c);
375 if (!*q) { /* the name was a prefix */
376 if (q - name > longest) {
377 longest = q - name;
378 nmatches = 1;
379 found = c;
380 } else if (q - name == longest)
381 nmatches++;
382 }
383 }
384 if (nmatches > 1)
385 return ((struct cmd *)-1);
386 return (found);
387 }
388
389 /*
390 * Slice a string up into argc/argv.
391 */
392
393 int slrflag;
394
395 void makeargv()
396 {
397 char **argp;
398 char *slurpstring();
399
400 margc = 0;
401 argp = margv;
402 stringbase = line; /* scan from first of buffer */
403 argbase = argbuf; /* store from first of buffer */
404 slrflag = 0;
405 while ((*argp++ = slurpstring()))
406 margc++;
407 }
408
409 /*
410 * Parse string into argbuf;
411 * implemented with FSM to
412 * handle quoting and strings
413 */
414 char *
415 slurpstring()
416 {
417 int got_one = 0;
418 register char *sb = stringbase;
419 register char *ap = argbase;
420 char *tmp = argbase; /* will return this if token found */
421
422 if (*sb == '!' || *sb == '$') { /* recognize ! as a token for shell */
423 switch (slrflag) { /* and $ as token for macro invoke */
424 case 0:
425 slrflag++;
426 stringbase++;
427 return ((*sb == '!') ? "!" : "$");
428 /* NOTREACHED */
429 case 1:
430 slrflag++;
431 altarg = stringbase;
432 break;
433 default:
434 break;
435 }
436 }
437
438 S0:
439 switch (*sb) {
440
441 case '\0':
442 goto OUT1;
443
444 case ' ':
445 case '\t':
446 sb++; goto S0;
447
448 default:
449 switch (slrflag) {
450 case 0:
451 slrflag++;
452 break;
453 case 1:
454 slrflag++;
455 altarg = sb;
456 break;
457 default:
458 break;
459 }
460 goto S1;
461 }
462
463 S1:
464 switch (*sb) {
465
466 case ' ':
467 case '\t':
468 case '\0':
469 goto OUT1; /* end of token */
470
471 case '\\':
472 sb++; goto S2; /* slurp next character */
473
474 case '"':
475 sb++; goto S3; /* slurp quoted string */
476
477 default:
478 *ap++ = *sb++; /* add character to token */
479 got_one = 1;
480 goto S1;
481 }
482
483 S2:
484 switch (*sb) {
485
486 case '\0':
487 goto OUT1;
488
489 default:
490 *ap++ = *sb++;
491 got_one = 1;
492 goto S1;
493 }
494
495 S3:
496 switch (*sb) {
497
498 case '\0':
499 goto OUT1;
500
501 case '"':
502 sb++; goto S1;
503
504 default:
505 *ap++ = *sb++;
506 got_one = 1;
507 goto S3;
508 }
509
510 OUT1:
511 if (got_one)
512 *ap++ = '\0';
513 argbase = ap; /* update storage pointer */
514 stringbase = sb; /* update scan pointer */
515 if (got_one) {
516 return(tmp);
517 }
518 switch (slrflag) {
519 case 0:
520 slrflag++;
521 break;
522 case 1:
523 slrflag++;
524 altarg = (char *) 0;
525 break;
526 default:
527 break;
528 }
529 return((char *)0);
530 }
531
532 #define HELPINDENT (sizeof ("directory"))
533
534 /*
535 * Help command.
536 * Call each command handler with argc == 0 and argv[0] == name.
537 */
538 int help(argc, argv)
539 int argc;
540 char *argv[];
541 {
542 extern struct cmd cmdtab[];
543 register struct cmd *c;
544
545 if (argc == 1) {
546 register int i, j, w, k;
547 int columns, width = 0, lines;
548 extern int NCMDS;
549
550 printf("Commands may be abbreviated. Commands are:\n\n");
551 for (c = cmdtab; c < &cmdtab[NCMDS]; c++) {
552 int len = strlen(c->c_name);
553
554 if (len > width)
555 width = len;
556 }
557 width = (width + 8) &~ 7;
558 columns = 80 / width;
559 if (columns == 0)
560 columns = 1;
561 lines = (NCMDS + columns - 1) / columns;
562 for (i = 0; i < lines; i++) {
563 for (j = 0; j < columns; j++) {
564 c = cmdtab + j * lines + i;
565 if (c->c_name && (!proxy || c->c_proxy)) {
566 printf("%s", c->c_name);
567 }
568 else if (c->c_name) {
569 for (k=0; k < (int) strlen(c->c_name); k++) {
570 (void) putchar(' ');
571 }
572 }
573 if (c + lines >= &cmdtab[NCMDS]) {
574 printf("\n");
575 break;
576 }
577 w = strlen(c->c_name);
578 while (w < width) {
579 w = (w + 8) &~ 7;
580 (void) putchar('\t');
581 }
582 }
583 }
584 (void) fflush(stdout);
585 return 0;
586 }
587 while (--argc > 0) {
588 register char *arg;
589 arg = *++argv;
590 c = getcmd(arg);
591 if (c == (struct cmd *)-1)
592 printf("?Ambiguous help command %s\n", arg);
593 else if (c == (struct cmd *)0)
594 printf("?Invalid help command %s\n", arg);
595 else
596 printf("%-*s\t%s\n", HELPINDENT,
597 c->c_name, c->c_help);
598 }
599 (void) fflush(stdout);
600 return 0;
601 }