Change __signed to signed.
[dragonfly.git] / crypto / kerberosIV / appl / ftp / ftp / main.c
1 /*
2  * Copyright (c) 1985, 1989, 1993, 1994
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by the University of
16  *      California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
34 /*
35  * FTP User Program -- Command Interface.
36  */
37
38 #include "ftp_locl.h"
39 RCSID("$Id: main.c,v 1.27.2.1 2000/10/10 13:01:50 assar Exp $");
40
41 int
42 main(int argc, char **argv)
43 {
44         int ch, top;
45         struct passwd *pw = NULL;
46         char homedir[MaxPathLen];
47         struct servent *sp;
48
49         set_progname(argv[0]);
50
51         sp = getservbyname("ftp", "tcp");
52         if (sp == 0)
53                 errx(1, "ftp/tcp: unknown service");
54         doglob = 1;
55         interactive = 1;
56         autologin = 1;
57         passivemode = 0; /* passive mode not active */
58
59         while ((ch = getopt(argc, argv, "dginptv")) != -1) {
60                 switch (ch) {
61                 case 'd':
62                         options |= SO_DEBUG;
63                         debug++;
64                         break;
65                         
66                 case 'g':
67                         doglob = 0;
68                         break;
69
70                 case 'i':
71                         interactive = 0;
72                         break;
73
74                 case 'n':
75                         autologin = 0;
76                         break;
77
78                 case 'p':
79                         passivemode = 1;
80                         break;
81                 case 't':
82                         trace++;
83                         break;
84
85                 case 'v':
86                         verbose++;
87                         break;
88
89                 default:
90                     fprintf(stderr,
91                             "usage: ftp [-dginptv] [host [port]]\n");
92                     exit(1);
93                 }
94         }
95         argc -= optind;
96         argv += optind;
97
98         fromatty = isatty(fileno(stdin));
99         if (fromatty)
100                 verbose++;
101         cpend = 0;      /* no pending replies */
102         proxy = 0;      /* proxy not active */
103         crflag = 1;     /* strip c.r. on ascii gets */
104         sendport = -1;  /* not using ports */
105         /*
106          * Set up the home directory in case we're globbing.
107          */
108         pw = k_getpwuid(getuid());
109         if (pw != NULL) {
110                 strlcpy(homedir, pw->pw_dir, sizeof(homedir));
111                 home = homedir;
112         }
113         if (argc > 0) {
114             char *xargv[5];
115             
116             if (setjmp(toplevel))
117                 exit(0);
118             signal(SIGINT, intr);
119             signal(SIGPIPE, lostpeer);
120             xargv[0] = (char*)__progname;
121             xargv[1] = argv[0];
122             xargv[2] = argv[1];
123             xargv[3] = argv[2];
124             xargv[4] = NULL;
125             setpeer(argc+1, xargv);
126         }
127         if(setjmp(toplevel) == 0)
128             top = 1;
129         else
130             top = 0;
131         if (top) {
132             signal(SIGINT, intr);
133             signal(SIGPIPE, lostpeer);
134         }
135         for (;;) {
136             cmdscanner(top);
137             top = 1;
138         }
139 }
140
141 void
142 intr(int sig)
143 {
144
145         longjmp(toplevel, 1);
146 }
147
148 #ifndef SHUT_RDWR
149 #define SHUT_RDWR 2
150 #endif
151
152 RETSIGTYPE
153 lostpeer(int sig)
154 {
155
156     if (connected) {
157         if (cout != NULL) {
158             shutdown(fileno(cout), SHUT_RDWR);
159             fclose(cout);
160             cout = NULL;
161         }
162         if (data >= 0) {
163             shutdown(data, SHUT_RDWR);
164             close(data);
165             data = -1;
166         }
167         connected = 0;
168     }
169     pswitch(1);
170     if (connected) {
171         if (cout != NULL) {
172             shutdown(fileno(cout), SHUT_RDWR);
173             fclose(cout);
174             cout = NULL;
175         }
176         connected = 0;
177     }
178     proxflag = 0;
179     pswitch(0);
180     sec_end();
181     SIGRETURN(0);
182 }
183
184 /*
185 char *
186 tail(filename)
187         char *filename;
188 {
189         char *s;
190         
191         while (*filename) {
192                 s = strrchr(filename, '/');
193                 if (s == NULL)
194                         break;
195                 if (s[1])
196                         return (s + 1);
197                 *s = '\0';
198         }
199         return (filename);
200 }
201 */
202
203 #ifndef HAVE_READLINE
204
205 static char *
206 readline(char *prompt)
207 {
208     char buf[BUFSIZ];
209     printf ("%s", prompt);
210     fflush (stdout);
211     if(fgets(buf, sizeof(buf), stdin) == NULL)
212         return NULL;
213     if (buf[strlen(buf) - 1] == '\n')
214         buf[strlen(buf) - 1] = '\0';
215     return strdup(buf);
216 }
217
218 static void
219 add_history(char *p)
220 {
221 }
222
223 #else
224
225 /* These should not really be here */
226
227 char *readline(char *);
228 void add_history(char *);
229
230 #endif
231
232 /*
233  * Command parser.
234  */
235 void
236 cmdscanner(int top)
237 {
238     struct cmd *c;
239     int l;
240
241     if (!top)
242         putchar('\n');
243     for (;;) {
244         if (fromatty) {
245             char *p;
246             p = readline("ftp> ");
247             if(p == NULL) {
248                 printf("\n");
249                 quit(0, 0);
250             }
251             strlcpy(line, p, sizeof(line));
252             add_history(p);
253             free(p);
254         } else{
255             if (fgets(line, sizeof line, stdin) == NULL)
256                 quit(0, 0);
257         }
258         /* XXX will break on long lines */
259         l = strlen(line);
260         if (l == 0)
261             break;
262         if (line[--l] == '\n') {
263             if (l == 0)
264                 break;
265             line[l] = '\0';
266         } else if (l == sizeof(line) - 2) {
267             printf("sorry, input line too long\n");
268             while ((l = getchar()) != '\n' && l != EOF)
269                 /* void */;
270             break;
271         } /* else it was a line without a newline */
272         makeargv();
273         if (margc == 0) {
274             continue;
275         }
276         c = getcmd(margv[0]);
277         if (c == (struct cmd *)-1) {
278             printf("?Ambiguous command\n");
279             continue;
280         }
281         if (c == 0) {
282             printf("?Invalid command\n");
283             continue;
284         }
285         if (c->c_conn && !connected) {
286             printf("Not connected.\n");
287             continue;
288         }
289         (*c->c_handler)(margc, margv);
290         if (bell && c->c_bell)
291             putchar('\007');
292         if (c->c_handler != help)
293             break;
294     }
295     signal(SIGINT, intr);
296     signal(SIGPIPE, lostpeer);
297 }
298
299 struct cmd *
300 getcmd(char *name)
301 {
302         char *p, *q;
303         struct cmd *c, *found;
304         int nmatches, longest;
305
306         longest = 0;
307         nmatches = 0;
308         found = 0;
309         for (c = cmdtab; (p = c->c_name); c++) {
310                 for (q = name; *q == *p++; q++)
311                         if (*q == 0)            /* exact match? */
312                                 return (c);
313                 if (!*q) {                      /* the name was a prefix */
314                         if (q - name > longest) {
315                                 longest = q - name;
316                                 nmatches = 1;
317                                 found = c;
318                         } else if (q - name == longest)
319                                 nmatches++;
320                 }
321         }
322         if (nmatches > 1)
323                 return ((struct cmd *)-1);
324         return (found);
325 }
326
327 /*
328  * Slice a string up into argc/argv.
329  */
330
331 int slrflag;
332
333 void
334 makeargv(void)
335 {
336         char **argp;
337
338         argp = margv;
339         stringbase = line;              /* scan from first of buffer */
340         argbase = argbuf;               /* store from first of buffer */
341         slrflag = 0;
342         for (margc = 0; ; margc++) {
343                 /* Expand array if necessary */
344                 if (margc == margvlen) {
345                         int i;
346
347                         margv = (margvlen == 0)
348                                 ? (char **)malloc(20 * sizeof(char *))
349                                 : (char **)realloc(margv,
350                                         (margvlen + 20)*sizeof(char *));
351                         if (margv == NULL)
352                                 errx(1, "cannot realloc argv array");
353                         for(i = margvlen; i < margvlen + 20; ++i)
354                                 margv[i] = NULL;
355                         margvlen += 20;
356                         argp = margv + margc;
357                 }
358
359                 if ((*argp++ = slurpstring()) == NULL)
360                         break;
361         }
362
363 }
364
365 /*
366  * Parse string into argbuf;
367  * implemented with FSM to
368  * handle quoting and strings
369  */
370 char *
371 slurpstring(void)
372 {
373         int got_one = 0;
374         char *sb = stringbase;
375         char *ap = argbase;
376         char *tmp = argbase;            /* will return this if token found */
377
378         if (*sb == '!' || *sb == '$') { /* recognize ! as a token for shell */
379                 switch (slrflag) {      /* and $ as token for macro invoke */
380                         case 0:
381                                 slrflag++;
382                                 stringbase++;
383                                 return ((*sb == '!') ? "!" : "$");
384                                 /* NOTREACHED */
385                         case 1:
386                                 slrflag++;
387                                 altarg = stringbase;
388                                 break;
389                         default:
390                                 break;
391                 }
392         }
393
394 S0:
395         switch (*sb) {
396
397         case '\0':
398                 goto OUT;
399
400         case ' ':
401         case '\t':
402                 sb++; goto S0;
403
404         default:
405                 switch (slrflag) {
406                         case 0:
407                                 slrflag++;
408                                 break;
409                         case 1:
410                                 slrflag++;
411                                 altarg = sb;
412                                 break;
413                         default:
414                                 break;
415                 }
416                 goto S1;
417         }
418
419 S1:
420         switch (*sb) {
421
422         case ' ':
423         case '\t':
424         case '\0':
425                 goto OUT;       /* end of token */
426
427         case '\\':
428                 sb++; goto S2;  /* slurp next character */
429
430         case '"':
431                 sb++; goto S3;  /* slurp quoted string */
432
433         default:
434                 *ap++ = *sb++;  /* add character to token */
435                 got_one = 1;
436                 goto S1;
437         }
438
439 S2:
440         switch (*sb) {
441
442         case '\0':
443                 goto OUT;
444
445         default:
446                 *ap++ = *sb++;
447                 got_one = 1;
448                 goto S1;
449         }
450
451 S3:
452         switch (*sb) {
453
454         case '\0':
455                 goto OUT;
456
457         case '"':
458                 sb++; goto S1;
459
460         default:
461                 *ap++ = *sb++;
462                 got_one = 1;
463                 goto S3;
464         }
465
466 OUT:
467         if (got_one)
468                 *ap++ = '\0';
469         argbase = ap;                   /* update storage pointer */
470         stringbase = sb;                /* update scan pointer */
471         if (got_one) {
472                 return (tmp);
473         }
474         switch (slrflag) {
475                 case 0:
476                         slrflag++;
477                         break;
478                 case 1:
479                         slrflag++;
480                         altarg = (char *) 0;
481                         break;
482                 default:
483                         break;
484         }
485         return NULL;
486 }
487
488 #define HELPINDENT ((int) sizeof ("directory"))
489
490 /*
491  * Help command.
492  * Call each command handler with argc == 0 and argv[0] == name.
493  */
494 void
495 help(int argc, char **argv)
496 {
497         struct cmd *c;
498
499         if (argc == 1) {
500                 int i, j, w, k;
501                 int columns, width = 0, lines;
502
503                 printf("Commands may be abbreviated.  Commands are:\n\n");
504                 for (c = cmdtab; c < &cmdtab[NCMDS]; c++) {
505                         int len = strlen(c->c_name);
506
507                         if (len > width)
508                                 width = len;
509                 }
510                 width = (width + 8) &~ 7;
511                 columns = 80 / width;
512                 if (columns == 0)
513                         columns = 1;
514                 lines = (NCMDS + columns - 1) / columns;
515                 for (i = 0; i < lines; i++) {
516                         for (j = 0; j < columns; j++) {
517                                 c = cmdtab + j * lines + i;
518                                 if (c->c_name && (!proxy || c->c_proxy)) {
519                                         printf("%s", c->c_name);
520                                 }
521                                 else if (c->c_name) {
522                                         for (k=0; k < strlen(c->c_name); k++) {
523                                                 putchar(' ');
524                                         }
525                                 }
526                                 if (c + lines >= &cmdtab[NCMDS]) {
527                                         printf("\n");
528                                         break;
529                                 }
530                                 w = strlen(c->c_name);
531                                 while (w < width) {
532                                         w = (w + 8) &~ 7;
533                                         putchar('\t');
534                                 }
535                         }
536                 }
537                 return;
538         }
539         while (--argc > 0) {
540                 char *arg;
541                 arg = *++argv;
542                 c = getcmd(arg);
543                 if (c == (struct cmd *)-1)
544                         printf("?Ambiguous help command %s\n", arg);
545                 else if (c == (struct cmd *)0)
546                         printf("?Invalid help command %s\n", arg);
547                 else
548                         printf("%-*s\t%s\n", HELPINDENT,
549                                 c->c_name, c->c_help);
550         }
551 }