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