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