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