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