Add heimdal-0.6.3
[dragonfly.git] / crypto / heimdal-0.6.3 / appl / ftp / ftp / cmds.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 Routines.
36  */
37
38 #include "ftp_locl.h"
39 RCSID("$Id: cmds.c,v 1.44 2001/08/05 06:39:14 assar Exp $");
40
41 typedef void (*sighand)(int);
42
43 jmp_buf jabort;
44 char   *mname;
45 char   *home = "/";
46
47 /*
48  * `Another' gets another argument, and stores the new argc and argv.
49  * It reverts to the top level (via main.c's intr()) on EOF/error.
50  *
51  * Returns false if no new arguments have been added.
52  */
53 int
54 another(int *pargc, char ***pargv, char *prompt)
55 {
56         int len = strlen(line), ret;
57
58         if (len >= sizeof(line) - 3) {
59                 printf("sorry, arguments too long\n");
60                 intr(0);
61         }
62         printf("(%s) ", prompt);
63         line[len++] = ' ';
64         if (fgets(&line[len], sizeof(line) - len, stdin) == NULL)
65                 intr(0);
66         len += strlen(&line[len]);
67         if (len > 0 && line[len - 1] == '\n')
68                 line[len - 1] = '\0';
69         makeargv();
70         ret = margc > *pargc;
71         *pargc = margc;
72         *pargv = margv;
73         return (ret);
74 }
75
76 /*
77  * Connect to peer server and
78  * auto-login, if possible.
79  */
80 void
81 setpeer(int argc, char **argv)
82 {
83         char *host;
84         u_short port;
85         struct servent *sp;
86
87         if (connected) {
88                 printf("Already connected to %s, use close first.\n",
89                         hostname);
90                 code = -1;
91                 return;
92         }
93         if (argc < 2)
94                 another(&argc, &argv, "to");
95         if (argc < 2 || argc > 3) {
96                 printf("usage: %s host-name [port]\n", argv[0]);
97                 code = -1;
98                 return;
99         }
100         sp = getservbyname("ftp", "tcp");
101         if (sp == NULL)
102                 errx(1, "You bastard. You removed ftp/tcp from services");
103         port = sp->s_port;
104         if (argc > 2) {
105                 sp = getservbyname(argv[2], "tcp");
106                 if (sp != NULL) {
107                         port = sp->s_port;
108                 } else {
109                         char *ep;
110
111                         port = strtol(argv[2], &ep, 0);
112                         if (argv[2] == ep) {
113                                 printf("%s: bad port number-- %s\n",
114                                        argv[1], argv[2]);
115                                 printf ("usage: %s host-name [port]\n",
116                                         argv[0]);
117                                 code = -1;
118                                 return;
119                         }
120                         port = htons(port);
121                 }
122         }
123         host = hookup(argv[1], port);
124         if (host) {
125                 int overbose;
126
127                 connected = 1;
128                 /*
129                  * Set up defaults for FTP.
130                  */
131                 strlcpy(typename, "ascii", sizeof(typename));
132                 type = TYPE_A;
133                 curtype = TYPE_A;
134                 strlcpy(formname, "non-print", sizeof(formname));
135                 form = FORM_N;
136                 strlcpy(modename, "stream", sizeof(modename));
137                 mode = MODE_S;
138                 strlcpy(structname, "file", sizeof(structname));
139                 stru = STRU_F;
140                 strlcpy(bytename, "8", sizeof(bytename));
141                 bytesize = 8;
142                 if (autologin)
143                         login(argv[1]);
144
145 #if (defined(unix) || defined(__unix__) || defined(__unix) || defined(_AIX) || defined(_CRAY) || defined(__NetBSD__)) && NBBY == 8
146 /*
147  * this ifdef is to keep someone form "porting" this to an incompatible
148  * system and not checking this out. This way they have to think about it.
149  */
150                 overbose = verbose;
151                 if (debug == 0)
152                         verbose = -1;
153                 if (command("SYST") == COMPLETE && overbose) {
154                         char *cp, c;
155                         cp = strchr(reply_string+4, ' ');
156                         if (cp == NULL)
157                                 cp = strchr(reply_string+4, '\r');
158                         if (cp) {
159                                 if (cp[-1] == '.')
160                                         cp--;
161                                 c = *cp;
162                                 *cp = '\0';
163                         }
164
165                         printf("Remote system type is %s.\n",
166                                 reply_string+4);
167                         if (cp)
168                                 *cp = c;
169                 }
170                 if (!strncmp(reply_string, "215 UNIX Type: L8", 17)) {
171                         if (proxy)
172                                 unix_proxy = 1;
173                         else
174                                 unix_server = 1;
175                         /*
176                          * Set type to 0 (not specified by user),
177                          * meaning binary by default, but don't bother
178                          * telling server.  We can use binary
179                          * for text files unless changed by the user.
180                          */
181                         type = 0;
182                         strlcpy(typename, "binary", sizeof(typename));
183                         if (overbose)
184                             printf("Using %s mode to transfer files.\n",
185                                 typename);
186                 } else {
187                         if (proxy)
188                                 unix_proxy = 0;
189                         else
190                                 unix_server = 0;
191                         if (overbose && 
192                             !strncmp(reply_string, "215 TOPS20", 10))
193                                 printf(
194 "Remember to set tenex mode when transfering binary files from this machine.\n");
195                 }
196                 verbose = overbose;
197 #endif /* unix */
198         }
199 }
200
201 struct  types {
202         char    *t_name;
203         char    *t_mode;
204         int     t_type;
205         char    *t_arg;
206 } types[] = {
207         { "ascii",      "A",    TYPE_A, 0 },
208         { "binary",     "I",    TYPE_I, 0 },
209         { "image",      "I",    TYPE_I, 0 },
210         { "ebcdic",     "E",    TYPE_E, 0 },
211         { "tenex",      "L",    TYPE_L, bytename },
212         { NULL }
213 };
214
215 /*
216  * Set transfer type.
217  */
218 void
219 settype(int argc, char **argv)
220 {
221         struct types *p;
222         int comret;
223
224         if (argc > 2) {
225                 char *sep;
226
227                 printf("usage: %s [", argv[0]);
228                 sep = " ";
229                 for (p = types; p->t_name; p++) {
230                         printf("%s%s", sep, p->t_name);
231                         sep = " | ";
232                 }
233                 printf(" ]\n");
234                 code = -1;
235                 return;
236         }
237         if (argc < 2) {
238                 printf("Using %s mode to transfer files.\n", typename);
239                 code = 0;
240                 return;
241         }
242         for (p = types; p->t_name; p++)
243                 if (strcmp(argv[1], p->t_name) == 0)
244                         break;
245         if (p->t_name == 0) {
246                 printf("%s: unknown mode\n", argv[1]);
247                 code = -1;
248                 return;
249         }
250         if ((p->t_arg != NULL) && (*(p->t_arg) != '\0'))
251                 comret = command ("TYPE %s %s", p->t_mode, p->t_arg);
252         else
253                 comret = command("TYPE %s", p->t_mode);
254         if (comret == COMPLETE) {
255                 strlcpy(typename, p->t_name, sizeof(typename));
256                 curtype = type = p->t_type;
257         }
258 }
259
260 /*
261  * Internal form of settype; changes current type in use with server
262  * without changing our notion of the type for data transfers.
263  * Used to change to and from ascii for listings.
264  */
265 void
266 changetype(int newtype, int show)
267 {
268         struct types *p;
269         int comret, oldverbose = verbose;
270
271         if (newtype == 0)
272                 newtype = TYPE_I;
273         if (newtype == curtype)
274                 return;
275         if (debug == 0 && show == 0)
276                 verbose = 0;
277         for (p = types; p->t_name; p++)
278                 if (newtype == p->t_type)
279                         break;
280         if (p->t_name == 0) {
281                 printf("ftp: internal error: unknown type %d\n", newtype);
282                 return;
283         }
284         if (newtype == TYPE_L && bytename[0] != '\0')
285                 comret = command("TYPE %s %s", p->t_mode, bytename);
286         else
287                 comret = command("TYPE %s", p->t_mode);
288         if (comret == COMPLETE)
289                 curtype = newtype;
290         verbose = oldverbose;
291 }
292
293 char *stype[] = {
294         "type",
295         "",
296         0
297 };
298
299 /*
300  * Set binary transfer type.
301  */
302 /*VARARGS*/
303 void
304 setbinary(int argc, char **argv)
305 {
306
307         stype[1] = "binary";
308         settype(2, stype);
309 }
310
311 /*
312  * Set ascii transfer type.
313  */
314 /*VARARGS*/
315 void
316 setascii(int argc, char **argv)
317 {
318
319         stype[1] = "ascii";
320         settype(2, stype);
321 }
322
323 /*
324  * Set tenex transfer type.
325  */
326 /*VARARGS*/
327 void
328 settenex(int argc, char **argv)
329 {
330
331         stype[1] = "tenex";
332         settype(2, stype);
333 }
334
335 /*
336  * Set file transfer mode.
337  */
338 /*ARGSUSED*/
339 void
340 setftmode(int argc, char **argv)
341 {
342
343         printf("We only support %s mode, sorry.\n", modename);
344         code = -1;
345 }
346
347 /*
348  * Set file transfer format.
349  */
350 /*ARGSUSED*/
351 void
352 setform(int argc, char **argv)
353 {
354
355         printf("We only support %s format, sorry.\n", formname);
356         code = -1;
357 }
358
359 /*
360  * Set file transfer structure.
361  */
362 /*ARGSUSED*/
363 void
364 setstruct(int argc, char **argv)
365 {
366
367         printf("We only support %s structure, sorry.\n", structname);
368         code = -1;
369 }
370
371 /*
372  * Send a single file.
373  */
374 void
375 put(int argc, char **argv)
376 {
377         char *cmd;
378         int loc = 0;
379         char *oldargv1, *oldargv2;
380
381         if (argc == 2) {
382                 argc++;
383                 argv[2] = argv[1];
384                 loc++;
385         }
386         if (argc < 2 && !another(&argc, &argv, "local-file"))
387                 goto usage;
388         if (argc < 3 && !another(&argc, &argv, "remote-file")) {
389 usage:
390                 printf("usage: %s local-file remote-file\n", argv[0]);
391                 code = -1;
392                 return;
393         }
394         oldargv1 = argv[1];
395         oldargv2 = argv[2];
396         if (!globulize(&argv[1])) {
397                 code = -1;
398                 return;
399         }
400         /*
401          * If "globulize" modifies argv[1], and argv[2] is a copy of
402          * the old argv[1], make it a copy of the new argv[1].
403          */
404         if (argv[1] != oldargv1 && argv[2] == oldargv1) {
405                 argv[2] = argv[1];
406         }
407         cmd = (argv[0][0] == 'a') ? "APPE" : ((sunique) ? "STOU" : "STOR");
408         if (loc && ntflag) {
409                 argv[2] = dotrans(argv[2]);
410         }
411         if (loc && mapflag) {
412                 argv[2] = domap(argv[2]);
413         }
414         sendrequest(cmd, argv[1], argv[2],
415                     curtype == TYPE_I ? "rb" : "r",
416                     argv[1] != oldargv1 || argv[2] != oldargv2);
417 }
418
419 /* ARGSUSED */
420 static RETSIGTYPE
421 mabort(int signo)
422 {
423         int ointer;
424
425         printf("\n");
426         fflush(stdout);
427         if (mflag && fromatty) {
428                 ointer = interactive;
429                 interactive = 1;
430                 if (confirm("Continue with", mname)) {
431                         interactive = ointer;
432                         longjmp(jabort,0);
433                 }
434                 interactive = ointer;
435         }
436         mflag = 0;
437         longjmp(jabort,0);
438 }
439
440 /*
441  * Send multiple files.
442  */
443 void
444 mput(int argc, char **argv)
445 {
446     int i;
447     RETSIGTYPE (*oldintr)(int);
448     int ointer;
449     char *tp;
450
451     if (argc < 2 && !another(&argc, &argv, "local-files")) {
452         printf("usage: %s local-files\n", argv[0]);
453         code = -1;
454         return;
455     }
456     mname = argv[0];
457     mflag = 1;
458     oldintr = signal(SIGINT, mabort);
459     setjmp(jabort);
460     if (proxy) {
461         char *cp, *tp2, tmpbuf[MaxPathLen];
462
463         while ((cp = remglob(argv,0)) != NULL) {
464             if (*cp == 0) {
465                 mflag = 0;
466                 continue;
467             }
468             if (mflag && confirm(argv[0], cp)) {
469                 tp = cp;
470                 if (mcase) {
471                     while (*tp && !islower((unsigned char)*tp)) {
472                         tp++;
473                     }
474                     if (!*tp) {
475                         tp = cp;
476                         tp2 = tmpbuf;
477                         while ((*tp2 = *tp) != '\0') {
478                             if (isupper((unsigned char)*tp2)) {
479                                 *tp2 = 'a' + *tp2 - 'A';
480                             }
481                             tp++;
482                             tp2++;
483                         }
484                     }
485                     tp = tmpbuf;
486                 }
487                 if (ntflag) {
488                     tp = dotrans(tp);
489                 }
490                 if (mapflag) {
491                     tp = domap(tp);
492                 }
493                 sendrequest((sunique) ? "STOU" : "STOR",
494                             cp, tp,
495                             curtype == TYPE_I ? "rb" : "r",
496                             cp != tp || !interactive);
497                 if (!mflag && fromatty) {
498                     ointer = interactive;
499                     interactive = 1;
500                     if (confirm("Continue with","mput")) {
501                         mflag++;
502                     }
503                     interactive = ointer;
504                 }
505             }
506         }
507         signal(SIGINT, oldintr);
508         mflag = 0;
509         return;
510     }
511     for (i = 1; i < argc; i++) {
512         char **cpp;
513         glob_t gl;
514         int flags;
515
516         if (!doglob) {
517             if (mflag && confirm(argv[0], argv[i])) {
518                 tp = (ntflag) ? dotrans(argv[i]) : argv[i];
519                 tp = (mapflag) ? domap(tp) : tp;
520                 sendrequest((sunique) ? "STOU" : "STOR",
521                             argv[i],
522                             curtype == TYPE_I ? "rb" : "r",
523                             tp, tp != argv[i] || !interactive);
524                 if (!mflag && fromatty) {
525                     ointer = interactive;
526                     interactive = 1;
527                     if (confirm("Continue with","mput")) {
528                         mflag++;
529                     }
530                     interactive = ointer;
531                 }
532             }
533             continue;
534         }
535
536         memset(&gl, 0, sizeof(gl));
537         flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE;
538         if (glob(argv[i], flags, NULL, &gl) || gl.gl_pathc == 0) {
539             warnx("%s: not found", argv[i]);
540             globfree(&gl);
541             continue;
542         }
543         for (cpp = gl.gl_pathv; cpp && *cpp != NULL; cpp++) {
544             if (mflag && confirm(argv[0], *cpp)) {
545                 tp = (ntflag) ? dotrans(*cpp) : *cpp;
546                 tp = (mapflag) ? domap(tp) : tp;
547                 sendrequest((sunique) ? "STOU" : "STOR",
548                             *cpp, tp,
549                             curtype == TYPE_I ? "rb" : "r",
550                             *cpp != tp || !interactive);
551                 if (!mflag && fromatty) {
552                     ointer = interactive;
553                     interactive = 1;
554                     if (confirm("Continue with","mput")) {
555                         mflag++;
556                     }
557                     interactive = ointer;
558                 }
559             }
560         }
561         globfree(&gl);
562     }
563     signal(SIGINT, oldintr);
564     mflag = 0;
565 }
566
567 void
568 reget(int argc, char **argv)
569 {
570     getit(argc, argv, 1, curtype == TYPE_I ? "r+wb" : "r+w");
571 }
572
573 void
574 get(int argc, char **argv)
575 {
576     char *mode;
577
578     if (restart_point) {
579         if (curtype == TYPE_I)
580             mode = "r+wb";
581         else
582             mode = "r+w";
583     } else {
584         if (curtype == TYPE_I)
585             mode = "wb";
586         else
587             mode = "w";
588     }
589
590     getit(argc, argv, 0, mode);
591 }
592
593 /*
594  * Receive one file.
595  */
596 int
597 getit(int argc, char **argv, int restartit, char *mode)
598 {
599         int loc = 0;
600         int local_given = 1;
601         char *oldargv1, *oldargv2;
602
603         if (argc == 2) {
604                 argc++;
605                 local_given = 0;
606                 argv[2] = argv[1];
607                 loc++;
608         }
609         if ((argc < 2 && !another(&argc, &argv, "remote-file")) ||
610             (argc < 3 && !another(&argc, &argv, "local-file"))) {
611                 printf("usage: %s remote-file [ local-file ]\n", argv[0]);
612                 code = -1;
613                 return (0);
614         }
615         oldargv1 = argv[1];
616         oldargv2 = argv[2];
617         if (!globulize(&argv[2])) {
618                 code = -1;
619                 return (0);
620         }
621         if (loc && mcase) {
622                 char *tp = argv[1], *tp2, tmpbuf[MaxPathLen];
623
624                 while (*tp && !islower((unsigned char)*tp)) {
625                         tp++;
626                 }
627                 if (!*tp) {
628                         tp = argv[2];
629                         tp2 = tmpbuf;
630                         while ((*tp2 = *tp) != '\0') {
631                                 if (isupper((unsigned char)*tp2)) {
632                                         *tp2 = 'a' + *tp2 - 'A';
633                                 }
634                                 tp++;
635                                 tp2++;
636                         }
637                         argv[2] = tmpbuf;
638                 }
639         }
640         if (loc && ntflag)
641                 argv[2] = dotrans(argv[2]);
642         if (loc && mapflag)
643                 argv[2] = domap(argv[2]);
644         if (restartit) {
645                 struct stat stbuf;
646                 int ret;
647
648                 ret = stat(argv[2], &stbuf);
649                 if (restartit == 1) {
650                         if (ret < 0) {
651                                 warn("local: %s", argv[2]);
652                                 return (0);
653                         }
654                         restart_point = stbuf.st_size;
655                 } else if (ret == 0) {
656                         int overbose;
657                         int cmdret;
658                         int yy, mo, day, hour, min, sec;
659                         struct tm *tm;
660                         time_t mtime = stbuf.st_mtime;
661
662                         overbose = verbose;
663                         if (debug == 0)
664                                 verbose = -1;
665                         cmdret = command("MDTM %s", argv[1]);
666                         verbose = overbose;
667                         if (cmdret != COMPLETE) {
668                                 printf("%s\n", reply_string);
669                                 return (0);
670                         }
671                         if (sscanf(reply_string,
672                                    "%*s %04d%02d%02d%02d%02d%02d",
673                                    &yy, &mo, &day, &hour, &min, &sec)
674                             != 6) {
675                                 printf ("bad MDTM result\n");
676                                 return (0);
677                         }
678
679                         tm = gmtime(&mtime);
680                         tm->tm_mon++;
681                         tm->tm_year += 1900;
682
683                         if ((tm->tm_year > yy) ||
684                             (tm->tm_year == yy && 
685                              tm->tm_mon > mo) ||
686                             (tm->tm_mon == mo && 
687                              tm->tm_mday > day) ||
688                             (tm->tm_mday == day && 
689                              tm->tm_hour > hour) ||
690                             (tm->tm_hour == hour && 
691                              tm->tm_min > min) ||
692                             (tm->tm_min == min && 
693                              tm->tm_sec > sec))
694                                 return (1);
695                 }
696         }
697
698         recvrequest("RETR", argv[2], argv[1], mode,
699                     argv[1] != oldargv1 || argv[2] != oldargv2, local_given);
700         restart_point = 0;
701         return (0);
702 }
703
704 static int
705 suspicious_filename(const char *fn)
706 {
707     return strstr(fn, "../") != NULL || *fn == '/';
708 }
709
710 /*
711  * Get multiple files.
712  */
713 void
714 mget(int argc, char **argv)
715 {
716         sighand oldintr;
717         int ch, ointer;
718         char *cp, *tp, *tp2, tmpbuf[MaxPathLen];
719
720         if (argc < 2 && !another(&argc, &argv, "remote-files")) {
721                 printf("usage: %s remote-files\n", argv[0]);
722                 code = -1;
723                 return;
724         }
725         mname = argv[0];
726         mflag = 1;
727         oldintr = signal(SIGINT, mabort);
728         setjmp(jabort);
729         while ((cp = remglob(argv,proxy)) != NULL) {
730                 if (*cp == '\0') {
731                         mflag = 0;
732                         continue;
733                 }
734                 if (mflag && suspicious_filename(cp))
735                     printf("*** Suspicious filename: %s\n", cp);
736                 if (mflag && confirm(argv[0], cp)) {
737                         tp = cp;
738                         if (mcase) {
739                                 for (tp2 = tmpbuf; (ch = *tp++);)
740                                         *tp2++ = tolower(ch);
741                                 *tp2 = '\0';
742                                 tp = tmpbuf;
743                         }
744                         if (ntflag) {
745                                 tp = dotrans(tp);
746                         }
747                         if (mapflag) {
748                                 tp = domap(tp);
749                         }
750                         recvrequest("RETR", tp, cp,
751                                     curtype == TYPE_I ? "wb" : "w",
752                                     tp != cp || !interactive, 0);
753                         if (!mflag && fromatty) {
754                                 ointer = interactive;
755                                 interactive = 1;
756                                 if (confirm("Continue with","mget")) {
757                                         mflag++;
758                                 }
759                                 interactive = ointer;
760                         }
761                 }
762         }
763         signal(SIGINT,oldintr);
764         mflag = 0;
765 }
766
767 char *
768 remglob(char **argv, int doswitch)
769 {
770     char temp[16];
771     static char buf[MaxPathLen];
772     static FILE *ftemp = NULL;
773     static char **args;
774     int oldverbose, oldhash;
775     char *cp, *mode;
776
777     if (!mflag) {
778         if (!doglob) {
779             args = NULL;
780         }
781         else {
782             if (ftemp) {
783                 fclose(ftemp);
784                 ftemp = NULL;
785             }
786         }
787         return (NULL);
788     }
789     if (!doglob) {
790         if (args == NULL)
791             args = argv;
792         if ((cp = *++args) == NULL)
793             args = NULL;
794         return (cp);
795     }
796     if (ftemp == NULL) {
797         int fd;
798         strlcpy(temp, _PATH_TMP_XXX, sizeof(temp));
799         fd = mkstemp(temp);
800         if(fd < 0){
801             warn("unable to create temporary file %s", temp);
802             return NULL;
803         }
804         close(fd);
805         oldverbose = verbose, verbose = 0;
806         oldhash = hash, hash = 0;
807         if (doswitch) {
808             pswitch(!proxy);
809         }
810         for (mode = "w"; *++argv != NULL; mode = "a")
811             recvrequest ("NLST", temp, *argv, mode, 0, 0);
812         if (doswitch) {
813             pswitch(!proxy);
814         }
815         verbose = oldverbose; hash = oldhash;
816         ftemp = fopen(temp, "r");
817         unlink(temp);
818         if (ftemp == NULL) {
819             printf("can't find list of remote files, oops\n");
820             return (NULL);
821         }
822     }
823     while(fgets(buf, sizeof (buf), ftemp)) {
824         if ((cp = strchr(buf, '\n')) != NULL)
825             *cp = '\0';
826         if(!interactive && suspicious_filename(buf)){
827             printf("Ignoring remote globbed file `%s'\n", buf);
828             continue;
829         }
830         return buf;
831     }
832     fclose(ftemp);
833     ftemp = NULL;
834     return (NULL);
835 }
836
837 char *
838 onoff(int bool)
839 {
840
841         return (bool ? "on" : "off");
842 }
843
844 /*
845  * Show status.
846  */
847 /*ARGSUSED*/
848 void
849 status(int argc, char **argv)
850 {
851         int i;
852
853         if (connected)
854                 printf("Connected to %s.\n", hostname);
855         else
856                 printf("Not connected.\n");
857         if (!proxy) {
858                 pswitch(1);
859                 if (connected) {
860                         printf("Connected for proxy commands to %s.\n", hostname);
861                 }
862                 else {
863                         printf("No proxy connection.\n");
864                 }
865                 pswitch(0);
866         }
867         sec_status();
868         printf("Mode: %s; Type: %s; Form: %s; Structure: %s\n",
869                 modename, typename, formname, structname);
870         printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s\n", 
871                 onoff(verbose), onoff(bell), onoff(interactive),
872                 onoff(doglob));
873         printf("Store unique: %s; Receive unique: %s\n", onoff(sunique),
874                 onoff(runique));
875         printf("Case: %s; CR stripping: %s\n",onoff(mcase),onoff(crflag));
876         if (ntflag) {
877                 printf("Ntrans: (in) %s (out) %s\n", ntin,ntout);
878         }
879         else {
880                 printf("Ntrans: off\n");
881         }
882         if (mapflag) {
883                 printf("Nmap: (in) %s (out) %s\n", mapin, mapout);
884         }
885         else {
886                 printf("Nmap: off\n");
887         }
888         printf("Hash mark printing: %s; Use of PORT cmds: %s\n",
889                 onoff(hash), onoff(sendport));
890         if (macnum > 0) {
891                 printf("Macros:\n");
892                 for (i=0; i<macnum; i++) {
893                         printf("\t%s\n",macros[i].mac_name);
894                 }
895         }
896         code = 0;
897 }
898
899 /*
900  * Set beep on cmd completed mode.
901  */
902 /*VARARGS*/
903 void
904 setbell(int argc, char **argv)
905 {
906
907         bell = !bell;
908         printf("Bell mode %s.\n", onoff(bell));
909         code = bell;
910 }
911
912 /*
913  * Turn on packet tracing.
914  */
915 /*VARARGS*/
916 void
917 settrace(int argc, char **argv)
918 {
919
920         trace = !trace;
921         printf("Packet tracing %s.\n", onoff(trace));
922         code = trace;
923 }
924
925 /*
926  * Toggle hash mark printing during transfers.
927  */
928 /*VARARGS*/
929 void
930 sethash(int argc, char **argv)
931 {
932
933         hash = !hash;
934         printf("Hash mark printing %s", onoff(hash));
935         code = hash;
936         if (hash)
937                 printf(" (%d bytes/hash mark)", 1024);
938         printf(".\n");
939 }
940
941 /*
942  * Turn on printing of server echo's.
943  */
944 /*VARARGS*/
945 void
946 setverbose(int argc, char **argv)
947 {
948
949         verbose = !verbose;
950         printf("Verbose mode %s.\n", onoff(verbose));
951         code = verbose;
952 }
953
954 /*
955  * Toggle PORT cmd use before each data connection.
956  */
957 /*VARARGS*/
958 void
959 setport(int argc, char **argv)
960 {
961
962         sendport = !sendport;
963         printf("Use of PORT cmds %s.\n", onoff(sendport));
964         code = sendport;
965 }
966
967 /*
968  * Turn on interactive prompting
969  * during mget, mput, and mdelete.
970  */
971 /*VARARGS*/
972 void
973 setprompt(int argc, char **argv)
974 {
975
976         interactive = !interactive;
977         printf("Interactive mode %s.\n", onoff(interactive));
978         code = interactive;
979 }
980
981 /*
982  * Toggle metacharacter interpretation
983  * on local file names.
984  */
985 /*VARARGS*/
986 void
987 setglob(int argc, char **argv)
988 {
989         
990         doglob = !doglob;
991         printf("Globbing %s.\n", onoff(doglob));
992         code = doglob;
993 }
994
995 /*
996  * Set debugging mode on/off and/or
997  * set level of debugging.
998  */
999 /*VARARGS*/
1000 void
1001 setdebug(int argc, char **argv)
1002 {
1003         int val;
1004
1005         if (argc > 1) {
1006                 val = atoi(argv[1]);
1007                 if (val < 0) {
1008                         printf("%s: bad debugging value.\n", argv[1]);
1009                         code = -1;
1010                         return;
1011                 }
1012         } else
1013                 val = !debug;
1014         debug = val;
1015         if (debug)
1016                 options |= SO_DEBUG;
1017         else
1018                 options &= ~SO_DEBUG;
1019         printf("Debugging %s (debug=%d).\n", onoff(debug), debug);
1020         code = debug > 0;
1021 }
1022
1023 /*
1024  * Set current working directory
1025  * on remote machine.
1026  */
1027 void
1028 cd(int argc, char **argv)
1029 {
1030
1031         if (argc < 2 && !another(&argc, &argv, "remote-directory")) {
1032                 printf("usage: %s remote-directory\n", argv[0]);
1033                 code = -1;
1034                 return;
1035         }
1036         if (command("CWD %s", argv[1]) == ERROR && code == 500) {
1037                 if (verbose)
1038                         printf("CWD command not recognized, trying XCWD\n");
1039                 command("XCWD %s", argv[1]);
1040         }
1041 }
1042
1043 /*
1044  * Set current working directory
1045  * on local machine.
1046  */
1047 void
1048 lcd(int argc, char **argv)
1049 {
1050         char buf[MaxPathLen];
1051
1052         if (argc < 2)
1053                 argc++, argv[1] = home;
1054         if (argc != 2) {
1055                 printf("usage: %s local-directory\n", argv[0]);
1056                 code = -1;
1057                 return;
1058         }
1059         if (!globulize(&argv[1])) {
1060                 code = -1;
1061                 return;
1062         }
1063         if (chdir(argv[1]) < 0) {
1064                 warn("local: %s", argv[1]);
1065                 code = -1;
1066                 return;
1067         }
1068         if (getcwd(buf, sizeof(buf)) != NULL)
1069                 printf("Local directory now %s\n", buf);
1070         else
1071                 warnx("getwd: %s", buf);
1072         code = 0;
1073 }
1074
1075 /*
1076  * Delete a single file.
1077  */
1078 void
1079 delete(int argc, char **argv)
1080 {
1081
1082         if (argc < 2 && !another(&argc, &argv, "remote-file")) {
1083                 printf("usage: %s remote-file\n", argv[0]);
1084                 code = -1;
1085                 return;
1086         }
1087         command("DELE %s", argv[1]);
1088 }
1089
1090 /*
1091  * Delete multiple files.
1092  */
1093 void
1094 mdelete(int argc, char **argv)
1095 {
1096     sighand oldintr;
1097     int ointer;
1098     char *cp;
1099
1100     if (argc < 2 && !another(&argc, &argv, "remote-files")) {
1101         printf("usage: %s remote-files\n", argv[0]);
1102         code = -1;
1103         return;
1104     }
1105     mname = argv[0];
1106     mflag = 1;
1107     oldintr = signal(SIGINT, mabort);
1108     setjmp(jabort);
1109     while ((cp = remglob(argv,0)) != NULL) {
1110         if (*cp == '\0') {
1111             mflag = 0;
1112             continue;
1113         }
1114         if (mflag && confirm(argv[0], cp)) {
1115             command("DELE %s", cp);
1116             if (!mflag && fromatty) {
1117                 ointer = interactive;
1118                 interactive = 1;
1119                 if (confirm("Continue with", "mdelete")) {
1120                     mflag++;
1121                 }
1122                 interactive = ointer;
1123             }
1124         }
1125     }
1126     signal(SIGINT, oldintr);
1127     mflag = 0;
1128 }
1129
1130 /*
1131  * Rename a remote file.
1132  */
1133 void
1134 renamefile(int argc, char **argv)
1135 {
1136
1137         if (argc < 2 && !another(&argc, &argv, "from-name"))
1138                 goto usage;
1139         if (argc < 3 && !another(&argc, &argv, "to-name")) {
1140 usage:
1141                 printf("%s from-name to-name\n", argv[0]);
1142                 code = -1;
1143                 return;
1144         }
1145         if (command("RNFR %s", argv[1]) == CONTINUE)
1146                 command("RNTO %s", argv[2]);
1147 }
1148
1149 /*
1150  * Get a directory listing
1151  * of remote files.
1152  */
1153 void
1154 ls(int argc, char **argv)
1155 {
1156         char *cmd;
1157
1158         if (argc < 2)
1159                 argc++, argv[1] = NULL;
1160         if (argc < 3)
1161                 argc++, argv[2] = "-";
1162         if (argc > 3) {
1163                 printf("usage: %s remote-directory local-file\n", argv[0]);
1164                 code = -1;
1165                 return;
1166         }
1167         cmd = argv[0][0] == 'n' ? "NLST" : "LIST";
1168         if (strcmp(argv[2], "-") && !globulize(&argv[2])) {
1169                 code = -1;
1170                 return;
1171         }
1172         if (strcmp(argv[2], "-") && *argv[2] != '|')
1173             if (!globulize(&argv[2]) || !confirm("output to local-file:", 
1174                                                  argv[2])) {
1175                 code = -1;
1176                 return;
1177             }
1178         recvrequest(cmd, argv[2], argv[1], "w", 0, 1);
1179 }
1180
1181 /*
1182  * Get a directory listing
1183  * of multiple remote files.
1184  */
1185 void
1186 mls(int argc, char **argv)
1187 {
1188         sighand oldintr;
1189         int ointer, i;
1190         char *cmd, mode[1], *dest;
1191
1192         if (argc < 2 && !another(&argc, &argv, "remote-files"))
1193                 goto usage;
1194         if (argc < 3 && !another(&argc, &argv, "local-file")) {
1195 usage:
1196                 printf("usage: %s remote-files local-file\n", argv[0]);
1197                 code = -1;
1198                 return;
1199         }
1200         dest = argv[argc - 1];
1201         argv[argc - 1] = NULL;
1202         if (strcmp(dest, "-") && *dest != '|')
1203                 if (!globulize(&dest) ||
1204                     !confirm("output to local-file:", dest)) {
1205                         code = -1;
1206                         return;
1207         }
1208         cmd = argv[0][1] == 'l' ? "NLST" : "LIST";
1209         mname = argv[0];
1210         mflag = 1;
1211         oldintr = signal(SIGINT, mabort);
1212         setjmp(jabort);
1213         for (i = 1; mflag && i < argc-1; ++i) {
1214                 *mode = (i == 1) ? 'w' : 'a';
1215                 recvrequest(cmd, dest, argv[i], mode, 0, 1);
1216                 if (!mflag && fromatty) {
1217                         ointer = interactive;
1218                         interactive = 1;
1219                         if (confirm("Continue with", argv[0])) {
1220                                 mflag ++;
1221                         }
1222                         interactive = ointer;
1223                 }
1224         }
1225         signal(SIGINT, oldintr);
1226         mflag = 0;
1227 }
1228
1229 /*
1230  * Do a shell escape
1231  */
1232 /*ARGSUSED*/
1233 void
1234 shell(int argc, char **argv)
1235 {
1236         pid_t pid;
1237         RETSIGTYPE (*old1)(int), (*old2)(int);
1238         char shellnam[40], *shell, *namep; 
1239         int status;
1240
1241         old1 = signal (SIGINT, SIG_IGN);
1242         old2 = signal (SIGQUIT, SIG_IGN);
1243         if ((pid = fork()) == 0) {
1244                 for (pid = 3; pid < 20; pid++)
1245                         close(pid);
1246                 signal(SIGINT, SIG_DFL);
1247                 signal(SIGQUIT, SIG_DFL);
1248                 shell = getenv("SHELL");
1249                 if (shell == NULL)
1250                         shell = _PATH_BSHELL;
1251                 namep = strrchr(shell,'/');
1252                 if (namep == NULL)
1253                         namep = shell;
1254                 snprintf (shellnam, sizeof(shellnam),
1255                           "-%s", ++namep);
1256                 if (strcmp(namep, "sh") != 0)
1257                         shellnam[0] = '+';
1258                 if (debug) {
1259                         printf ("%s\n", shell);
1260                         fflush (stdout);
1261                 }
1262                 if (argc > 1) {
1263                         execl(shell,shellnam,"-c",altarg,(char *)0);
1264                 }
1265                 else {
1266                         execl(shell,shellnam,(char *)0);
1267                 }
1268                 warn("%s", shell);
1269                 code = -1;
1270                 exit(1);
1271         }
1272         if (pid > 0)
1273                 while (waitpid(-1, &status, 0) != pid)
1274                         ;
1275         signal(SIGINT, old1);
1276         signal(SIGQUIT, old2);
1277         if (pid == -1) {
1278                 warn("%s", "Try again later");
1279                 code = -1;
1280         }
1281         else {
1282                 code = 0;
1283         }
1284 }
1285
1286 /*
1287  * Send new user information (re-login)
1288  */
1289 void
1290 user(int argc, char **argv)
1291 {
1292         char acct[80];
1293         int n, aflag = 0;
1294         char tmp[256];
1295
1296         if (argc < 2)
1297                 another(&argc, &argv, "username");
1298         if (argc < 2 || argc > 4) {
1299                 printf("usage: %s username [password] [account]\n", argv[0]);
1300                 code = -1;
1301                 return;
1302         }
1303         n = command("USER %s", argv[1]);
1304         if (n == CONTINUE) {
1305             if (argc < 3 ) {
1306                 des_read_pw_string (tmp,
1307                                     sizeof(tmp),
1308                                     "Password: ", 0);
1309                 argv[2] = tmp;
1310                 argc++;
1311             }
1312             n = command("PASS %s", argv[2]);
1313         }
1314         if (n == CONTINUE) {
1315                 if (argc < 4) {
1316                         printf("Account: "); fflush(stdout);
1317                         fgets(acct, sizeof(acct) - 1, stdin);
1318                         acct[strlen(acct) - 1] = '\0';
1319                         argv[3] = acct; argc++;
1320                 }
1321                 n = command("ACCT %s", argv[3]);
1322                 aflag++;
1323         }
1324         if (n != COMPLETE) {
1325                 fprintf(stdout, "Login failed.\n");
1326                 return;
1327         }
1328         if (!aflag && argc == 4) {
1329                 command("ACCT %s", argv[3]);
1330         }
1331 }
1332
1333 /*
1334  * Print working directory.
1335  */
1336 /*VARARGS*/
1337 void
1338 pwd(int argc, char **argv)
1339 {
1340         int oldverbose = verbose;
1341
1342         /*
1343          * If we aren't verbose, this doesn't do anything!
1344          */
1345         verbose = 1;
1346         if (command("PWD") == ERROR && code == 500) {
1347                 printf("PWD command not recognized, trying XPWD\n");
1348                 command("XPWD");
1349         }
1350         verbose = oldverbose;
1351 }
1352
1353 /*
1354  * Make a directory.
1355  */
1356 void
1357 makedir(int argc, char **argv)
1358 {
1359
1360         if (argc < 2 && !another(&argc, &argv, "directory-name")) {
1361                 printf("usage: %s directory-name\n", argv[0]);
1362                 code = -1;
1363                 return;
1364         }
1365         if (command("MKD %s", argv[1]) == ERROR && code == 500) {
1366                 if (verbose)
1367                         printf("MKD command not recognized, trying XMKD\n");
1368                 command("XMKD %s", argv[1]);
1369         }
1370 }
1371
1372 /*
1373  * Remove a directory.
1374  */
1375 void
1376 removedir(int argc, char **argv)
1377 {
1378
1379         if (argc < 2 && !another(&argc, &argv, "directory-name")) {
1380                 printf("usage: %s directory-name\n", argv[0]);
1381                 code = -1;
1382                 return;
1383         }
1384         if (command("RMD %s", argv[1]) == ERROR && code == 500) {
1385                 if (verbose)
1386                         printf("RMD command not recognized, trying XRMD\n");
1387                 command("XRMD %s", argv[1]);
1388         }
1389 }
1390
1391 /*
1392  * Send a line, verbatim, to the remote machine.
1393  */
1394 void
1395 quote(int argc, char **argv)
1396 {
1397
1398         if (argc < 2 && !another(&argc, &argv, "command line to send")) {
1399                 printf("usage: %s line-to-send\n", argv[0]);
1400                 code = -1;
1401                 return;
1402         }
1403         quote1("", argc, argv);
1404 }
1405
1406 /*
1407  * Send a SITE command to the remote machine.  The line
1408  * is sent verbatim to the remote machine, except that the
1409  * word "SITE" is added at the front.
1410  */
1411 void
1412 site(int argc, char **argv)
1413 {
1414
1415         if (argc < 2 && !another(&argc, &argv, "arguments to SITE command")) {
1416                 printf("usage: %s line-to-send\n", argv[0]);
1417                 code = -1;
1418                 return;
1419         }
1420         quote1("SITE ", argc, argv);
1421 }
1422
1423 /*
1424  * Turn argv[1..argc) into a space-separated string, then prepend initial text.
1425  * Send the result as a one-line command and get response.
1426  */
1427 void
1428 quote1(char *initial, int argc, char **argv)
1429 {
1430     int i;
1431     char buf[BUFSIZ];           /* must be >= sizeof(line) */
1432
1433     strlcpy(buf, initial, sizeof(buf));
1434     for(i = 1; i < argc; i++) {
1435         if(i > 1)
1436             strlcat(buf, " ", sizeof(buf));
1437         strlcat(buf, argv[i], sizeof(buf));
1438     }
1439     if (command("%s", buf) == PRELIM) {
1440         while (getreply(0) == PRELIM)
1441             continue;
1442     }
1443 }
1444
1445 void
1446 do_chmod(int argc, char **argv)
1447 {
1448
1449         if (argc < 2 && !another(&argc, &argv, "mode"))
1450                 goto usage;
1451         if (argc < 3 && !another(&argc, &argv, "file-name")) {
1452 usage:
1453                 printf("usage: %s mode file-name\n", argv[0]);
1454                 code = -1;
1455                 return;
1456         }
1457         command("SITE CHMOD %s %s", argv[1], argv[2]);
1458 }
1459
1460 void
1461 do_umask(int argc, char **argv)
1462 {
1463         int oldverbose = verbose;
1464
1465         verbose = 1;
1466         command(argc == 1 ? "SITE UMASK" : "SITE UMASK %s", argv[1]);
1467         verbose = oldverbose;
1468 }
1469
1470 void
1471 ftp_idle(int argc, char **argv)
1472 {
1473         int oldverbose = verbose;
1474
1475         verbose = 1;
1476         command(argc == 1 ? "SITE IDLE" : "SITE IDLE %s", argv[1]);
1477         verbose = oldverbose;
1478 }
1479
1480 /*
1481  * Ask the other side for help.
1482  */
1483 void
1484 rmthelp(int argc, char **argv)
1485 {
1486         int oldverbose = verbose;
1487
1488         verbose = 1;
1489         command(argc == 1 ? "HELP" : "HELP %s", argv[1]);
1490         verbose = oldverbose;
1491 }
1492
1493 /*
1494  * Terminate session and exit.
1495  */
1496 /*VARARGS*/
1497 void
1498 quit(int argc, char **argv)
1499 {
1500
1501         if (connected)
1502                 disconnect(0, 0);
1503         pswitch(1);
1504         if (connected) {
1505                 disconnect(0, 0);
1506         }
1507         exit(0);
1508 }
1509
1510 /*
1511  * Terminate session, but don't exit.
1512  */
1513 void
1514 disconnect(int argc, char **argv)
1515 {
1516
1517         if (!connected)
1518                 return;
1519         command("QUIT");
1520         if (cout) {
1521                 fclose(cout);
1522         }
1523         cout = NULL;
1524         connected = 0;
1525         sec_end();
1526         data = -1;
1527         if (!proxy) {
1528                 macnum = 0;
1529         }
1530 }
1531
1532 int
1533 confirm(char *cmd, char *file)
1534 {
1535         char line[BUFSIZ];
1536
1537         if (!interactive)
1538                 return (1);
1539         printf("%s %s? ", cmd, file);
1540         fflush(stdout);
1541         if (fgets(line, sizeof line, stdin) == NULL)
1542                 return (0);
1543         return (*line == 'y' || *line == 'Y');
1544 }
1545
1546 void
1547 fatal(char *msg)
1548 {
1549
1550         errx(1, "%s", msg);
1551 }
1552
1553 /*
1554  * Glob a local file name specification with
1555  * the expectation of a single return value.
1556  * Can't control multiple values being expanded
1557  * from the expression, we return only the first.
1558  */
1559 int
1560 globulize(char **cpp)
1561 {
1562         glob_t gl;
1563         int flags;
1564
1565         if (!doglob)
1566                 return (1);
1567
1568         flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE;
1569         memset(&gl, 0, sizeof(gl));
1570         if (glob(*cpp, flags, NULL, &gl) ||
1571             gl.gl_pathc == 0) {
1572                 warnx("%s: not found", *cpp);
1573                 globfree(&gl);
1574                 return (0);
1575         }
1576         *cpp = strdup(gl.gl_pathv[0]);  /* XXX - wasted memory */
1577         globfree(&gl);
1578         return (1);
1579 }
1580
1581 void
1582 account(int argc, char **argv)
1583 {
1584         char acct[50];
1585
1586         if (argc > 1) {
1587                 ++argv;
1588                 --argc;
1589                 strlcpy (acct, *argv, sizeof(acct));
1590                 while (argc > 1) {
1591                         --argc;
1592                         ++argv;
1593                         strlcat(acct, *argv, sizeof(acct));
1594                 }
1595         }
1596         else {
1597             des_read_pw_string(acct, sizeof(acct), "Account:", 0);
1598         }
1599         command("ACCT %s", acct);
1600 }
1601
1602 jmp_buf abortprox;
1603
1604 static RETSIGTYPE
1605 proxabort(int sig)
1606 {
1607
1608         if (!proxy) {
1609                 pswitch(1);
1610         }
1611         if (connected) {
1612                 proxflag = 1;
1613         }
1614         else {
1615                 proxflag = 0;
1616         }
1617         pswitch(0);
1618         longjmp(abortprox,1);
1619 }
1620
1621 void
1622 doproxy(int argc, char **argv)
1623 {
1624         struct cmd *c;
1625         RETSIGTYPE (*oldintr)(int);
1626
1627         if (argc < 2 && !another(&argc, &argv, "command")) {
1628                 printf("usage: %s command\n", argv[0]);
1629                 code = -1;
1630                 return;
1631         }
1632         c = getcmd(argv[1]);
1633         if (c == (struct cmd *) -1) {
1634                 printf("?Ambiguous command\n");
1635                 fflush(stdout);
1636                 code = -1;
1637                 return;
1638         }
1639         if (c == 0) {
1640                 printf("?Invalid command\n");
1641                 fflush(stdout);
1642                 code = -1;
1643                 return;
1644         }
1645         if (!c->c_proxy) {
1646                 printf("?Invalid proxy command\n");
1647                 fflush(stdout);
1648                 code = -1;
1649                 return;
1650         }
1651         if (setjmp(abortprox)) {
1652                 code = -1;
1653                 return;
1654         }
1655         oldintr = signal(SIGINT, proxabort);
1656         pswitch(1);
1657         if (c->c_conn && !connected) {
1658                 printf("Not connected\n");
1659                 fflush(stdout);
1660                 pswitch(0);
1661                 signal(SIGINT, oldintr);
1662                 code = -1;
1663                 return;
1664         }
1665         (*c->c_handler)(argc-1, argv+1);
1666         if (connected) {
1667                 proxflag = 1;
1668         }
1669         else {
1670                 proxflag = 0;
1671         }
1672         pswitch(0);
1673         signal(SIGINT, oldintr);
1674 }
1675
1676 void
1677 setcase(int argc, char **argv)
1678 {
1679
1680         mcase = !mcase;
1681         printf("Case mapping %s.\n", onoff(mcase));
1682         code = mcase;
1683 }
1684
1685 void
1686 setcr(int argc, char **argv)
1687 {
1688
1689         crflag = !crflag;
1690         printf("Carriage Return stripping %s.\n", onoff(crflag));
1691         code = crflag;
1692 }
1693
1694 void
1695 setntrans(int argc, char **argv)
1696 {
1697         if (argc == 1) {
1698                 ntflag = 0;
1699                 printf("Ntrans off.\n");
1700                 code = ntflag;
1701                 return;
1702         }
1703         ntflag++;
1704         code = ntflag;
1705         strlcpy (ntin, argv[1], 17);
1706         if (argc == 2) {
1707                 ntout[0] = '\0';
1708                 return;
1709         }
1710         strlcpy (ntout, argv[2], 17);
1711 }
1712
1713 char *
1714 dotrans(char *name)
1715 {
1716         static char new[MaxPathLen];
1717         char *cp1, *cp2 = new;
1718         int i, ostop, found;
1719
1720         for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++)
1721                 continue;
1722         for (cp1 = name; *cp1; cp1++) {
1723                 found = 0;
1724                 for (i = 0; *(ntin + i) && i < 16; i++) {
1725                         if (*cp1 == *(ntin + i)) {
1726                                 found++;
1727                                 if (i < ostop) {
1728                                         *cp2++ = *(ntout + i);
1729                                 }
1730                                 break;
1731                         }
1732                 }
1733                 if (!found) {
1734                         *cp2++ = *cp1;
1735                 }
1736         }
1737         *cp2 = '\0';
1738         return (new);
1739 }
1740
1741 void
1742 setnmap(int argc, char **argv)
1743 {
1744         char *cp;
1745
1746         if (argc == 1) {
1747                 mapflag = 0;
1748                 printf("Nmap off.\n");
1749                 code = mapflag;
1750                 return;
1751         }
1752         if (argc < 3 && !another(&argc, &argv, "mapout")) {
1753                 printf("Usage: %s [mapin mapout]\n",argv[0]);
1754                 code = -1;
1755                 return;
1756         }
1757         mapflag = 1;
1758         code = 1;
1759         cp = strchr(altarg, ' ');
1760         if (proxy) {
1761                 while(*++cp == ' ')
1762                         continue;
1763                 altarg = cp;
1764                 cp = strchr(altarg, ' ');
1765         }
1766         *cp = '\0';
1767         strlcpy(mapin, altarg, MaxPathLen);
1768         while (*++cp == ' ')
1769                 continue;
1770         strlcpy(mapout, cp, MaxPathLen);
1771 }
1772
1773 char *
1774 domap(char *name)
1775 {
1776         static char new[MaxPathLen];
1777         char *cp1 = name, *cp2 = mapin;
1778         char *tp[9], *te[9];
1779         int i, toks[9], toknum = 0, match = 1;
1780
1781         for (i=0; i < 9; ++i) {
1782                 toks[i] = 0;
1783         }
1784         while (match && *cp1 && *cp2) {
1785                 switch (*cp2) {
1786                         case '\\':
1787                                 if (*++cp2 != *cp1) {
1788                                         match = 0;
1789                                 }
1790                                 break;
1791                         case '$':
1792                                 if (*(cp2+1) >= '1' && (*cp2+1) <= '9') {
1793                                         if (*cp1 != *(++cp2+1)) {
1794                                                 toks[toknum = *cp2 - '1']++;
1795                                                 tp[toknum] = cp1;
1796                                                 while (*++cp1 && *(cp2+1)
1797                                                         != *cp1);
1798                                                 te[toknum] = cp1;
1799                                         }
1800                                         cp2++;
1801                                         break;
1802                                 }
1803                                 /* FALLTHROUGH */
1804                         default:
1805                                 if (*cp2 != *cp1) {
1806                                         match = 0;
1807                                 }
1808                                 break;
1809                 }
1810                 if (match && *cp1) {
1811                         cp1++;
1812                 }
1813                 if (match && *cp2) {
1814                         cp2++;
1815                 }
1816         }
1817         if (!match && *cp1) /* last token mismatch */
1818         {
1819                 toks[toknum] = 0;
1820         }
1821         cp1 = new;
1822         *cp1 = '\0';
1823         cp2 = mapout;
1824         while (*cp2) {
1825                 match = 0;
1826                 switch (*cp2) {
1827                         case '\\':
1828                                 if (*(cp2 + 1)) {
1829                                         *cp1++ = *++cp2;
1830                                 }
1831                                 break;
1832                         case '[':
1833 LOOP:
1834                                 if (*++cp2 == '$' && isdigit((unsigned char)*(cp2+1))) { 
1835                                         if (*++cp2 == '0') {
1836                                                 char *cp3 = name;
1837
1838                                                 while (*cp3) {
1839                                                         *cp1++ = *cp3++;
1840                                                 }
1841                                                 match = 1;
1842                                         }
1843                                         else if (toks[toknum = *cp2 - '1']) {
1844                                                 char *cp3 = tp[toknum];
1845
1846                                                 while (cp3 != te[toknum]) {
1847                                                         *cp1++ = *cp3++;
1848                                                 }
1849                                                 match = 1;
1850                                         }
1851                                 }
1852                                 else {
1853                                         while (*cp2 && *cp2 != ',' && 
1854                                             *cp2 != ']') {
1855                                                 if (*cp2 == '\\') {
1856                                                         cp2++;
1857                                                 }
1858                                                 else if (*cp2 == '$' &&
1859                                                         isdigit((unsigned char)*(cp2+1))) {
1860                                                         if (*++cp2 == '0') {
1861                                                            char *cp3 = name;
1862
1863                                                            while (*cp3) {
1864                                                                 *cp1++ = *cp3++;
1865                                                            }
1866                                                         }
1867                                                         else if (toks[toknum =
1868                                                             *cp2 - '1']) {
1869                                                            char *cp3=tp[toknum];
1870
1871                                                            while (cp3 !=
1872                                                                   te[toknum]) {
1873                                                                 *cp1++ = *cp3++;
1874                                                            }
1875                                                         }
1876                                                 }
1877                                                 else if (*cp2) {
1878                                                         *cp1++ = *cp2++;
1879                                                 }
1880                                         }
1881                                         if (!*cp2) {
1882                                                 printf("nmap: unbalanced brackets\n");
1883                                                 return (name);
1884                                         }
1885                                         match = 1;
1886                                         cp2--;
1887                                 }
1888                                 if (match) {
1889                                         while (*++cp2 && *cp2 != ']') {
1890                                               if (*cp2 == '\\' && *(cp2 + 1)) {
1891                                                         cp2++;
1892                                               }
1893                                         }
1894                                         if (!*cp2) {
1895                                                 printf("nmap: unbalanced brackets\n");
1896                                                 return (name);
1897                                         }
1898                                         break;
1899                                 }
1900                                 switch (*++cp2) {
1901                                         case ',':
1902                                                 goto LOOP;
1903                                         case ']':
1904                                                 break;
1905                                         default:
1906                                                 cp2--;
1907                                                 goto LOOP;
1908                                 }
1909                                 break;
1910                         case '$':
1911                                 if (isdigit((unsigned char)*(cp2 + 1))) {
1912                                         if (*++cp2 == '0') {
1913                                                 char *cp3 = name;
1914
1915                                                 while (*cp3) {
1916                                                         *cp1++ = *cp3++;
1917                                                 }
1918                                         }
1919                                         else if (toks[toknum = *cp2 - '1']) {
1920                                                 char *cp3 = tp[toknum];
1921
1922                                                 while (cp3 != te[toknum]) {
1923                                                         *cp1++ = *cp3++;
1924                                                 }
1925                                         }
1926                                         break;
1927                                 }
1928                                 /* intentional drop through */
1929                         default:
1930                                 *cp1++ = *cp2;
1931                                 break;
1932                 }
1933                 cp2++;
1934         }
1935         *cp1 = '\0';
1936         if (!*new) {
1937                 return (name);
1938         }
1939         return (new);
1940 }
1941
1942 void
1943 setpassive(int argc, char **argv)
1944 {
1945
1946         passivemode = !passivemode;
1947         printf("Passive mode %s.\n", onoff(passivemode));
1948         code = passivemode;
1949 }
1950
1951 void
1952 setsunique(int argc, char **argv)
1953 {
1954
1955         sunique = !sunique;
1956         printf("Store unique %s.\n", onoff(sunique));
1957         code = sunique;
1958 }
1959
1960 void
1961 setrunique(int argc, char **argv)
1962 {
1963
1964         runique = !runique;
1965         printf("Receive unique %s.\n", onoff(runique));
1966         code = runique;
1967 }
1968
1969 /* change directory to perent directory */
1970 void
1971 cdup(int argc, char **argv)
1972 {
1973
1974         if (command("CDUP") == ERROR && code == 500) {
1975                 if (verbose)
1976                         printf("CDUP command not recognized, trying XCUP\n");
1977                 command("XCUP");
1978         }
1979 }
1980
1981 /* restart transfer at specific point */
1982 void
1983 restart(int argc, char **argv)
1984 {
1985
1986     if (argc != 2)
1987         printf("restart: offset not specified\n");
1988     else {
1989         restart_point = atol(argv[1]);
1990         printf("restarting at %ld. %s\n", (long)restart_point,
1991                "execute get, put or append to initiate transfer");
1992     }
1993 }
1994
1995 /* show remote system type */
1996 void
1997 syst(int argc, char **argv)
1998 {
1999
2000         command("SYST");
2001 }
2002
2003 void
2004 macdef(int argc, char **argv)
2005 {
2006         char *tmp;
2007         int c;
2008
2009         if (macnum == 16) {
2010                 printf("Limit of 16 macros have already been defined\n");
2011                 code = -1;
2012                 return;
2013         }
2014         if (argc < 2 && !another(&argc, &argv, "macro name")) {
2015                 printf("Usage: %s macro_name\n",argv[0]);
2016                 code = -1;
2017                 return;
2018         }
2019         if (interactive) {
2020                 printf("Enter macro line by line, terminating it with a null line\n");
2021         }
2022         strlcpy(macros[macnum].mac_name,
2023                         argv[1],
2024                         sizeof(macros[macnum].mac_name));
2025         if (macnum == 0) {
2026                 macros[macnum].mac_start = macbuf;
2027         }
2028         else {
2029                 macros[macnum].mac_start = macros[macnum - 1].mac_end + 1;
2030         }
2031         tmp = macros[macnum].mac_start;
2032         while (tmp != macbuf+4096) {
2033                 if ((c = getchar()) == EOF) {
2034                         printf("macdef:end of file encountered\n");
2035                         code = -1;
2036                         return;
2037                 }
2038                 if ((*tmp = c) == '\n') {
2039                         if (tmp == macros[macnum].mac_start) {
2040                                 macros[macnum++].mac_end = tmp;
2041                                 code = 0;
2042                                 return;
2043                         }
2044                         if (*(tmp-1) == '\0') {
2045                                 macros[macnum++].mac_end = tmp - 1;
2046                                 code = 0;
2047                                 return;
2048                         }
2049                         *tmp = '\0';
2050                 }
2051                 tmp++;
2052         }
2053         while (1) {
2054                 while ((c = getchar()) != '\n' && c != EOF)
2055                         /* LOOP */;
2056                 if (c == EOF || getchar() == '\n') {
2057                         printf("Macro not defined - 4k buffer exceeded\n");
2058                         code = -1;
2059                         return;
2060                 }
2061         }
2062 }
2063
2064 /*
2065  * get size of file on remote machine
2066  */
2067 void
2068 sizecmd(int argc, char **argv)
2069 {
2070
2071         if (argc < 2 && !another(&argc, &argv, "filename")) {
2072                 printf("usage: %s filename\n", argv[0]);
2073                 code = -1;
2074                 return;
2075         }
2076         command("SIZE %s", argv[1]);
2077 }
2078
2079 /*
2080  * get last modification time of file on remote machine
2081  */
2082 void
2083 modtime(int argc, char **argv)
2084 {
2085         int overbose;
2086
2087         if (argc < 2 && !another(&argc, &argv, "filename")) {
2088                 printf("usage: %s filename\n", argv[0]);
2089                 code = -1;
2090                 return;
2091         }
2092         overbose = verbose;
2093         if (debug == 0)
2094                 verbose = -1;
2095         if (command("MDTM %s", argv[1]) == COMPLETE) {
2096                 int yy, mo, day, hour, min, sec;
2097                 sscanf(reply_string, "%*s %04d%02d%02d%02d%02d%02d", &yy, &mo,
2098                         &day, &hour, &min, &sec);
2099                 /* might want to print this in local time */
2100                 printf("%s\t%02d/%02d/%04d %02d:%02d:%02d GMT\n", argv[1],
2101                         mo, day, yy, hour, min, sec);
2102         } else
2103                 printf("%s\n", reply_string);
2104         verbose = overbose;
2105 }
2106
2107 /*
2108  * show status on reomte machine
2109  */
2110 void
2111 rmtstatus(int argc, char **argv)
2112 {
2113
2114         command(argc > 1 ? "STAT %s" : "STAT" , argv[1]);
2115 }
2116
2117 /*
2118  * get file if modtime is more recent than current file
2119  */
2120 void
2121 newer(int argc, char **argv)
2122 {
2123
2124         if (getit(argc, argv, -1, curtype == TYPE_I ? "wb" : "w"))
2125                 printf("Local file \"%s\" is newer than remote file \"%s\"\n",
2126                         argv[2], argv[1]);
2127 }