remove gcc34
[dragonfly.git] / crypto / heimdal-0.6.3 / appl / ftp / ftp / cmds.c
bloba7928eb830606f36cff5d29af3721a41b75c753b
1 /*
2 * Copyright (c) 1985, 1989, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
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.
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.
35 * FTP User Program -- Command Routines.
38 #include "ftp_locl.h"
39 RCSID("$Id: cmds.c,v 1.44 2001/08/05 06:39:14 assar Exp $");
41 typedef void (*sighand)(int);
43 jmp_buf jabort;
44 char *mname;
45 char *home = "/";
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.
51 * Returns false if no new arguments have been added.
53 int
54 another(int *pargc, char ***pargv, char *prompt)
56 int len = strlen(line), ret;
58 if (len >= sizeof(line) - 3) {
59 printf("sorry, arguments too long\n");
60 intr(0);
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);
77 * Connect to peer server and
78 * auto-login, if possible.
80 void
81 setpeer(int argc, char **argv)
83 char *host;
84 u_short port;
85 struct servent *sp;
87 if (connected) {
88 printf("Already connected to %s, use close first.\n",
89 hostname);
90 code = -1;
91 return;
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;
100 sp = getservbyname("ftp", "tcp");
101 if (sp == NULL)
102 errx(1, "You bastard. You removed ftp/tcp from services");
103 port = sp->s_port;
104 if (argc > 2) {
105 sp = getservbyname(argv[2], "tcp");
106 if (sp != NULL) {
107 port = sp->s_port;
108 } else {
109 char *ep;
111 port = strtol(argv[2], &ep, 0);
112 if (argv[2] == ep) {
113 printf("%s: bad port number-- %s\n",
114 argv[1], argv[2]);
115 printf ("usage: %s host-name [port]\n",
116 argv[0]);
117 code = -1;
118 return;
120 port = htons(port);
123 host = hookup(argv[1], port);
124 if (host) {
125 int overbose;
127 connected = 1;
129 * Set up defaults for FTP.
131 strlcpy(typename, "ascii", sizeof(typename));
132 type = TYPE_A;
133 curtype = TYPE_A;
134 strlcpy(formname, "non-print", sizeof(formname));
135 form = FORM_N;
136 strlcpy(modename, "stream", sizeof(modename));
137 mode = MODE_S;
138 strlcpy(structname, "file", sizeof(structname));
139 stru = STRU_F;
140 strlcpy(bytename, "8", sizeof(bytename));
141 bytesize = 8;
142 if (autologin)
143 login(argv[1]);
145 #if (defined(unix) || defined(__unix__) || defined(__unix) || defined(_AIX) || defined(_CRAY) || defined(__NetBSD__)) && NBBY == 8
147 * this ifdef is to keep someone form "porting" this to an incompatible
148 * system and not checking this out. This way they have to think about it.
150 overbose = verbose;
151 if (debug == 0)
152 verbose = -1;
153 if (command("SYST") == COMPLETE && overbose) {
154 char *cp, c;
155 cp = strchr(reply_string+4, ' ');
156 if (cp == NULL)
157 cp = strchr(reply_string+4, '\r');
158 if (cp) {
159 if (cp[-1] == '.')
160 cp--;
161 c = *cp;
162 *cp = '\0';
165 printf("Remote system type is %s.\n",
166 reply_string+4);
167 if (cp)
168 *cp = c;
170 if (!strncmp(reply_string, "215 UNIX Type: L8", 17)) {
171 if (proxy)
172 unix_proxy = 1;
173 else
174 unix_server = 1;
176 * Set type to 0 (not specified by user),
177 * meaning binary by default, but don't bother
178 * telling server. We can use binary
179 * for text files unless changed by the user.
181 type = 0;
182 strlcpy(typename, "binary", sizeof(typename));
183 if (overbose)
184 printf("Using %s mode to transfer files.\n",
185 typename);
186 } else {
187 if (proxy)
188 unix_proxy = 0;
189 else
190 unix_server = 0;
191 if (overbose &&
192 !strncmp(reply_string, "215 TOPS20", 10))
193 printf(
194 "Remember to set tenex mode when transfering binary files from this machine.\n");
196 verbose = overbose;
197 #endif /* unix */
201 struct types {
202 char *t_name;
203 char *t_mode;
204 int t_type;
205 char *t_arg;
206 } types[] = {
207 { "ascii", "A", TYPE_A, 0 },
208 { "binary", "I", TYPE_I, 0 },
209 { "image", "I", TYPE_I, 0 },
210 { "ebcdic", "E", TYPE_E, 0 },
211 { "tenex", "L", TYPE_L, bytename },
212 { NULL }
216 * Set transfer type.
218 void
219 settype(int argc, char **argv)
221 struct types *p;
222 int comret;
224 if (argc > 2) {
225 char *sep;
227 printf("usage: %s [", argv[0]);
228 sep = " ";
229 for (p = types; p->t_name; p++) {
230 printf("%s%s", sep, p->t_name);
231 sep = " | ";
233 printf(" ]\n");
234 code = -1;
235 return;
237 if (argc < 2) {
238 printf("Using %s mode to transfer files.\n", typename);
239 code = 0;
240 return;
242 for (p = types; p->t_name; p++)
243 if (strcmp(argv[1], p->t_name) == 0)
244 break;
245 if (p->t_name == 0) {
246 printf("%s: unknown mode\n", argv[1]);
247 code = -1;
248 return;
250 if ((p->t_arg != NULL) && (*(p->t_arg) != '\0'))
251 comret = command ("TYPE %s %s", p->t_mode, p->t_arg);
252 else
253 comret = command("TYPE %s", p->t_mode);
254 if (comret == COMPLETE) {
255 strlcpy(typename, p->t_name, sizeof(typename));
256 curtype = type = p->t_type;
261 * Internal form of settype; changes current type in use with server
262 * without changing our notion of the type for data transfers.
263 * Used to change to and from ascii for listings.
265 void
266 changetype(int newtype, int show)
268 struct types *p;
269 int comret, oldverbose = verbose;
271 if (newtype == 0)
272 newtype = TYPE_I;
273 if (newtype == curtype)
274 return;
275 if (debug == 0 && show == 0)
276 verbose = 0;
277 for (p = types; p->t_name; p++)
278 if (newtype == p->t_type)
279 break;
280 if (p->t_name == 0) {
281 printf("ftp: internal error: unknown type %d\n", newtype);
282 return;
284 if (newtype == TYPE_L && bytename[0] != '\0')
285 comret = command("TYPE %s %s", p->t_mode, bytename);
286 else
287 comret = command("TYPE %s", p->t_mode);
288 if (comret == COMPLETE)
289 curtype = newtype;
290 verbose = oldverbose;
293 char *stype[] = {
294 "type",
300 * Set binary transfer type.
302 /*VARARGS*/
303 void
304 setbinary(int argc, char **argv)
307 stype[1] = "binary";
308 settype(2, stype);
312 * Set ascii transfer type.
314 /*VARARGS*/
315 void
316 setascii(int argc, char **argv)
319 stype[1] = "ascii";
320 settype(2, stype);
324 * Set tenex transfer type.
326 /*VARARGS*/
327 void
328 settenex(int argc, char **argv)
331 stype[1] = "tenex";
332 settype(2, stype);
336 * Set file transfer mode.
338 /*ARGSUSED*/
339 void
340 setftmode(int argc, char **argv)
343 printf("We only support %s mode, sorry.\n", modename);
344 code = -1;
348 * Set file transfer format.
350 /*ARGSUSED*/
351 void
352 setform(int argc, char **argv)
355 printf("We only support %s format, sorry.\n", formname);
356 code = -1;
360 * Set file transfer structure.
362 /*ARGSUSED*/
363 void
364 setstruct(int argc, char **argv)
367 printf("We only support %s structure, sorry.\n", structname);
368 code = -1;
372 * Send a single file.
374 void
375 put(int argc, char **argv)
377 char *cmd;
378 int loc = 0;
379 char *oldargv1, *oldargv2;
381 if (argc == 2) {
382 argc++;
383 argv[2] = argv[1];
384 loc++;
386 if (argc < 2 && !another(&argc, &argv, "local-file"))
387 goto usage;
388 if (argc < 3 && !another(&argc, &argv, "remote-file")) {
389 usage:
390 printf("usage: %s local-file remote-file\n", argv[0]);
391 code = -1;
392 return;
394 oldargv1 = argv[1];
395 oldargv2 = argv[2];
396 if (!globulize(&argv[1])) {
397 code = -1;
398 return;
401 * If "globulize" modifies argv[1], and argv[2] is a copy of
402 * the old argv[1], make it a copy of the new argv[1].
404 if (argv[1] != oldargv1 && argv[2] == oldargv1) {
405 argv[2] = argv[1];
407 cmd = (argv[0][0] == 'a') ? "APPE" : ((sunique) ? "STOU" : "STOR");
408 if (loc && ntflag) {
409 argv[2] = dotrans(argv[2]);
411 if (loc && mapflag) {
412 argv[2] = domap(argv[2]);
414 sendrequest(cmd, argv[1], argv[2],
415 curtype == TYPE_I ? "rb" : "r",
416 argv[1] != oldargv1 || argv[2] != oldargv2);
419 /* ARGSUSED */
420 static RETSIGTYPE
421 mabort(int signo)
423 int ointer;
425 printf("\n");
426 fflush(stdout);
427 if (mflag && fromatty) {
428 ointer = interactive;
429 interactive = 1;
430 if (confirm("Continue with", mname)) {
431 interactive = ointer;
432 longjmp(jabort,0);
434 interactive = ointer;
436 mflag = 0;
437 longjmp(jabort,0);
441 * Send multiple files.
443 void
444 mput(int argc, char **argv)
446 int i;
447 RETSIGTYPE (*oldintr)(int);
448 int ointer;
449 char *tp;
451 if (argc < 2 && !another(&argc, &argv, "local-files")) {
452 printf("usage: %s local-files\n", argv[0]);
453 code = -1;
454 return;
456 mname = argv[0];
457 mflag = 1;
458 oldintr = signal(SIGINT, mabort);
459 setjmp(jabort);
460 if (proxy) {
461 char *cp, *tp2, tmpbuf[MaxPathLen];
463 while ((cp = remglob(argv,0)) != NULL) {
464 if (*cp == 0) {
465 mflag = 0;
466 continue;
468 if (mflag && confirm(argv[0], cp)) {
469 tp = cp;
470 if (mcase) {
471 while (*tp && !islower((unsigned char)*tp)) {
472 tp++;
474 if (!*tp) {
475 tp = cp;
476 tp2 = tmpbuf;
477 while ((*tp2 = *tp) != '\0') {
478 if (isupper((unsigned char)*tp2)) {
479 *tp2 = 'a' + *tp2 - 'A';
481 tp++;
482 tp2++;
485 tp = tmpbuf;
487 if (ntflag) {
488 tp = dotrans(tp);
490 if (mapflag) {
491 tp = domap(tp);
493 sendrequest((sunique) ? "STOU" : "STOR",
494 cp, tp,
495 curtype == TYPE_I ? "rb" : "r",
496 cp != tp || !interactive);
497 if (!mflag && fromatty) {
498 ointer = interactive;
499 interactive = 1;
500 if (confirm("Continue with","mput")) {
501 mflag++;
503 interactive = ointer;
507 signal(SIGINT, oldintr);
508 mflag = 0;
509 return;
511 for (i = 1; i < argc; i++) {
512 char **cpp;
513 glob_t gl;
514 int flags;
516 if (!doglob) {
517 if (mflag && confirm(argv[0], argv[i])) {
518 tp = (ntflag) ? dotrans(argv[i]) : argv[i];
519 tp = (mapflag) ? domap(tp) : tp;
520 sendrequest((sunique) ? "STOU" : "STOR",
521 argv[i],
522 curtype == TYPE_I ? "rb" : "r",
523 tp, tp != argv[i] || !interactive);
524 if (!mflag && fromatty) {
525 ointer = interactive;
526 interactive = 1;
527 if (confirm("Continue with","mput")) {
528 mflag++;
530 interactive = ointer;
533 continue;
536 memset(&gl, 0, sizeof(gl));
537 flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE;
538 if (glob(argv[i], flags, NULL, &gl) || gl.gl_pathc == 0) {
539 warnx("%s: not found", argv[i]);
540 globfree(&gl);
541 continue;
543 for (cpp = gl.gl_pathv; cpp && *cpp != NULL; cpp++) {
544 if (mflag && confirm(argv[0], *cpp)) {
545 tp = (ntflag) ? dotrans(*cpp) : *cpp;
546 tp = (mapflag) ? domap(tp) : tp;
547 sendrequest((sunique) ? "STOU" : "STOR",
548 *cpp, tp,
549 curtype == TYPE_I ? "rb" : "r",
550 *cpp != tp || !interactive);
551 if (!mflag && fromatty) {
552 ointer = interactive;
553 interactive = 1;
554 if (confirm("Continue with","mput")) {
555 mflag++;
557 interactive = ointer;
561 globfree(&gl);
563 signal(SIGINT, oldintr);
564 mflag = 0;
567 void
568 reget(int argc, char **argv)
570 getit(argc, argv, 1, curtype == TYPE_I ? "r+wb" : "r+w");
573 void
574 get(int argc, char **argv)
576 char *mode;
578 if (restart_point) {
579 if (curtype == TYPE_I)
580 mode = "r+wb";
581 else
582 mode = "r+w";
583 } else {
584 if (curtype == TYPE_I)
585 mode = "wb";
586 else
587 mode = "w";
590 getit(argc, argv, 0, mode);
594 * Receive one file.
597 getit(int argc, char **argv, int restartit, char *mode)
599 int loc = 0;
600 int local_given = 1;
601 char *oldargv1, *oldargv2;
603 if (argc == 2) {
604 argc++;
605 local_given = 0;
606 argv[2] = argv[1];
607 loc++;
609 if ((argc < 2 && !another(&argc, &argv, "remote-file")) ||
610 (argc < 3 && !another(&argc, &argv, "local-file"))) {
611 printf("usage: %s remote-file [ local-file ]\n", argv[0]);
612 code = -1;
613 return (0);
615 oldargv1 = argv[1];
616 oldargv2 = argv[2];
617 if (!globulize(&argv[2])) {
618 code = -1;
619 return (0);
621 if (loc && mcase) {
622 char *tp = argv[1], *tp2, tmpbuf[MaxPathLen];
624 while (*tp && !islower((unsigned char)*tp)) {
625 tp++;
627 if (!*tp) {
628 tp = argv[2];
629 tp2 = tmpbuf;
630 while ((*tp2 = *tp) != '\0') {
631 if (isupper((unsigned char)*tp2)) {
632 *tp2 = 'a' + *tp2 - 'A';
634 tp++;
635 tp2++;
637 argv[2] = tmpbuf;
640 if (loc && ntflag)
641 argv[2] = dotrans(argv[2]);
642 if (loc && mapflag)
643 argv[2] = domap(argv[2]);
644 if (restartit) {
645 struct stat stbuf;
646 int ret;
648 ret = stat(argv[2], &stbuf);
649 if (restartit == 1) {
650 if (ret < 0) {
651 warn("local: %s", argv[2]);
652 return (0);
654 restart_point = stbuf.st_size;
655 } else if (ret == 0) {
656 int overbose;
657 int cmdret;
658 int yy, mo, day, hour, min, sec;
659 struct tm *tm;
660 time_t mtime = stbuf.st_mtime;
662 overbose = verbose;
663 if (debug == 0)
664 verbose = -1;
665 cmdret = command("MDTM %s", argv[1]);
666 verbose = overbose;
667 if (cmdret != COMPLETE) {
668 printf("%s\n", reply_string);
669 return (0);
671 if (sscanf(reply_string,
672 "%*s %04d%02d%02d%02d%02d%02d",
673 &yy, &mo, &day, &hour, &min, &sec)
674 != 6) {
675 printf ("bad MDTM result\n");
676 return (0);
679 tm = gmtime(&mtime);
680 tm->tm_mon++;
681 tm->tm_year += 1900;
683 if ((tm->tm_year > yy) ||
684 (tm->tm_year == yy &&
685 tm->tm_mon > mo) ||
686 (tm->tm_mon == mo &&
687 tm->tm_mday > day) ||
688 (tm->tm_mday == day &&
689 tm->tm_hour > hour) ||
690 (tm->tm_hour == hour &&
691 tm->tm_min > min) ||
692 (tm->tm_min == min &&
693 tm->tm_sec > sec))
694 return (1);
698 recvrequest("RETR", argv[2], argv[1], mode,
699 argv[1] != oldargv1 || argv[2] != oldargv2, local_given);
700 restart_point = 0;
701 return (0);
704 static int
705 suspicious_filename(const char *fn)
707 return strstr(fn, "../") != NULL || *fn == '/';
711 * Get multiple files.
713 void
714 mget(int argc, char **argv)
716 sighand oldintr;
717 int ch, ointer;
718 char *cp, *tp, *tp2, tmpbuf[MaxPathLen];
720 if (argc < 2 && !another(&argc, &argv, "remote-files")) {
721 printf("usage: %s remote-files\n", argv[0]);
722 code = -1;
723 return;
725 mname = argv[0];
726 mflag = 1;
727 oldintr = signal(SIGINT, mabort);
728 setjmp(jabort);
729 while ((cp = remglob(argv,proxy)) != NULL) {
730 if (*cp == '\0') {
731 mflag = 0;
732 continue;
734 if (mflag && suspicious_filename(cp))
735 printf("*** Suspicious filename: %s\n", cp);
736 if (mflag && confirm(argv[0], cp)) {
737 tp = cp;
738 if (mcase) {
739 for (tp2 = tmpbuf; (ch = *tp++);)
740 *tp2++ = tolower(ch);
741 *tp2 = '\0';
742 tp = tmpbuf;
744 if (ntflag) {
745 tp = dotrans(tp);
747 if (mapflag) {
748 tp = domap(tp);
750 recvrequest("RETR", tp, cp,
751 curtype == TYPE_I ? "wb" : "w",
752 tp != cp || !interactive, 0);
753 if (!mflag && fromatty) {
754 ointer = interactive;
755 interactive = 1;
756 if (confirm("Continue with","mget")) {
757 mflag++;
759 interactive = ointer;
763 signal(SIGINT,oldintr);
764 mflag = 0;
767 char *
768 remglob(char **argv, int doswitch)
770 char temp[16];
771 static char buf[MaxPathLen];
772 static FILE *ftemp = NULL;
773 static char **args;
774 int oldverbose, oldhash;
775 char *cp, *mode;
777 if (!mflag) {
778 if (!doglob) {
779 args = NULL;
781 else {
782 if (ftemp) {
783 fclose(ftemp);
784 ftemp = NULL;
787 return (NULL);
789 if (!doglob) {
790 if (args == NULL)
791 args = argv;
792 if ((cp = *++args) == NULL)
793 args = NULL;
794 return (cp);
796 if (ftemp == NULL) {
797 int fd;
798 strlcpy(temp, _PATH_TMP_XXX, sizeof(temp));
799 fd = mkstemp(temp);
800 if(fd < 0){
801 warn("unable to create temporary file %s", temp);
802 return NULL;
804 close(fd);
805 oldverbose = verbose, verbose = 0;
806 oldhash = hash, hash = 0;
807 if (doswitch) {
808 pswitch(!proxy);
810 for (mode = "w"; *++argv != NULL; mode = "a")
811 recvrequest ("NLST", temp, *argv, mode, 0, 0);
812 if (doswitch) {
813 pswitch(!proxy);
815 verbose = oldverbose; hash = oldhash;
816 ftemp = fopen(temp, "r");
817 unlink(temp);
818 if (ftemp == NULL) {
819 printf("can't find list of remote files, oops\n");
820 return (NULL);
823 while(fgets(buf, sizeof (buf), ftemp)) {
824 if ((cp = strchr(buf, '\n')) != NULL)
825 *cp = '\0';
826 if(!interactive && suspicious_filename(buf)){
827 printf("Ignoring remote globbed file `%s'\n", buf);
828 continue;
830 return buf;
832 fclose(ftemp);
833 ftemp = NULL;
834 return (NULL);
837 char *
838 onoff(int bool)
841 return (bool ? "on" : "off");
845 * Show status.
847 /*ARGSUSED*/
848 void
849 status(int argc, char **argv)
851 int i;
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);
862 else {
863 printf("No proxy connection.\n");
865 pswitch(0);
867 sec_status();
868 printf("Mode: %s; Type: %s; Form: %s; Structure: %s\n",
869 modename, typename, formname, structname);
870 printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s\n",
871 onoff(verbose), onoff(bell), onoff(interactive),
872 onoff(doglob));
873 printf("Store unique: %s; Receive unique: %s\n", onoff(sunique),
874 onoff(runique));
875 printf("Case: %s; CR stripping: %s\n",onoff(mcase),onoff(crflag));
876 if (ntflag) {
877 printf("Ntrans: (in) %s (out) %s\n", ntin,ntout);
879 else {
880 printf("Ntrans: off\n");
882 if (mapflag) {
883 printf("Nmap: (in) %s (out) %s\n", mapin, mapout);
885 else {
886 printf("Nmap: off\n");
888 printf("Hash mark printing: %s; Use of PORT cmds: %s\n",
889 onoff(hash), onoff(sendport));
890 if (macnum > 0) {
891 printf("Macros:\n");
892 for (i=0; i<macnum; i++) {
893 printf("\t%s\n",macros[i].mac_name);
896 code = 0;
900 * Set beep on cmd completed mode.
902 /*VARARGS*/
903 void
904 setbell(int argc, char **argv)
907 bell = !bell;
908 printf("Bell mode %s.\n", onoff(bell));
909 code = bell;
913 * Turn on packet tracing.
915 /*VARARGS*/
916 void
917 settrace(int argc, char **argv)
920 trace = !trace;
921 printf("Packet tracing %s.\n", onoff(trace));
922 code = trace;
926 * Toggle hash mark printing during transfers.
928 /*VARARGS*/
929 void
930 sethash(int argc, char **argv)
933 hash = !hash;
934 printf("Hash mark printing %s", onoff(hash));
935 code = hash;
936 if (hash)
937 printf(" (%d bytes/hash mark)", 1024);
938 printf(".\n");
942 * Turn on printing of server echo's.
944 /*VARARGS*/
945 void
946 setverbose(int argc, char **argv)
949 verbose = !verbose;
950 printf("Verbose mode %s.\n", onoff(verbose));
951 code = verbose;
955 * Toggle PORT cmd use before each data connection.
957 /*VARARGS*/
958 void
959 setport(int argc, char **argv)
962 sendport = !sendport;
963 printf("Use of PORT cmds %s.\n", onoff(sendport));
964 code = sendport;
968 * Turn on interactive prompting
969 * during mget, mput, and mdelete.
971 /*VARARGS*/
972 void
973 setprompt(int argc, char **argv)
976 interactive = !interactive;
977 printf("Interactive mode %s.\n", onoff(interactive));
978 code = interactive;
982 * Toggle metacharacter interpretation
983 * on local file names.
985 /*VARARGS*/
986 void
987 setglob(int argc, char **argv)
990 doglob = !doglob;
991 printf("Globbing %s.\n", onoff(doglob));
992 code = doglob;
996 * Set debugging mode on/off and/or
997 * set level of debugging.
999 /*VARARGS*/
1000 void
1001 setdebug(int argc, char **argv)
1003 int val;
1005 if (argc > 1) {
1006 val = atoi(argv[1]);
1007 if (val < 0) {
1008 printf("%s: bad debugging value.\n", argv[1]);
1009 code = -1;
1010 return;
1012 } else
1013 val = !debug;
1014 debug = val;
1015 if (debug)
1016 options |= SO_DEBUG;
1017 else
1018 options &= ~SO_DEBUG;
1019 printf("Debugging %s (debug=%d).\n", onoff(debug), debug);
1020 code = debug > 0;
1024 * Set current working directory
1025 * on remote machine.
1027 void
1028 cd(int argc, char **argv)
1031 if (argc < 2 && !another(&argc, &argv, "remote-directory")) {
1032 printf("usage: %s remote-directory\n", argv[0]);
1033 code = -1;
1034 return;
1036 if (command("CWD %s", argv[1]) == ERROR && code == 500) {
1037 if (verbose)
1038 printf("CWD command not recognized, trying XCWD\n");
1039 command("XCWD %s", argv[1]);
1044 * Set current working directory
1045 * on local machine.
1047 void
1048 lcd(int argc, char **argv)
1050 char buf[MaxPathLen];
1052 if (argc < 2)
1053 argc++, argv[1] = home;
1054 if (argc != 2) {
1055 printf("usage: %s local-directory\n", argv[0]);
1056 code = -1;
1057 return;
1059 if (!globulize(&argv[1])) {
1060 code = -1;
1061 return;
1063 if (chdir(argv[1]) < 0) {
1064 warn("local: %s", argv[1]);
1065 code = -1;
1066 return;
1068 if (getcwd(buf, sizeof(buf)) != NULL)
1069 printf("Local directory now %s\n", buf);
1070 else
1071 warnx("getwd: %s", buf);
1072 code = 0;
1076 * Delete a single file.
1078 void
1079 delete(int argc, char **argv)
1082 if (argc < 2 && !another(&argc, &argv, "remote-file")) {
1083 printf("usage: %s remote-file\n", argv[0]);
1084 code = -1;
1085 return;
1087 command("DELE %s", argv[1]);
1091 * Delete multiple files.
1093 void
1094 mdelete(int argc, char **argv)
1096 sighand oldintr;
1097 int ointer;
1098 char *cp;
1100 if (argc < 2 && !another(&argc, &argv, "remote-files")) {
1101 printf("usage: %s remote-files\n", argv[0]);
1102 code = -1;
1103 return;
1105 mname = argv[0];
1106 mflag = 1;
1107 oldintr = signal(SIGINT, mabort);
1108 setjmp(jabort);
1109 while ((cp = remglob(argv,0)) != NULL) {
1110 if (*cp == '\0') {
1111 mflag = 0;
1112 continue;
1114 if (mflag && confirm(argv[0], cp)) {
1115 command("DELE %s", cp);
1116 if (!mflag && fromatty) {
1117 ointer = interactive;
1118 interactive = 1;
1119 if (confirm("Continue with", "mdelete")) {
1120 mflag++;
1122 interactive = ointer;
1126 signal(SIGINT, oldintr);
1127 mflag = 0;
1131 * Rename a remote file.
1133 void
1134 renamefile(int argc, char **argv)
1137 if (argc < 2 && !another(&argc, &argv, "from-name"))
1138 goto usage;
1139 if (argc < 3 && !another(&argc, &argv, "to-name")) {
1140 usage:
1141 printf("%s from-name to-name\n", argv[0]);
1142 code = -1;
1143 return;
1145 if (command("RNFR %s", argv[1]) == CONTINUE)
1146 command("RNTO %s", argv[2]);
1150 * Get a directory listing
1151 * of remote files.
1153 void
1154 ls(int argc, char **argv)
1156 char *cmd;
1158 if (argc < 2)
1159 argc++, argv[1] = NULL;
1160 if (argc < 3)
1161 argc++, argv[2] = "-";
1162 if (argc > 3) {
1163 printf("usage: %s remote-directory local-file\n", argv[0]);
1164 code = -1;
1165 return;
1167 cmd = argv[0][0] == 'n' ? "NLST" : "LIST";
1168 if (strcmp(argv[2], "-") && !globulize(&argv[2])) {
1169 code = -1;
1170 return;
1172 if (strcmp(argv[2], "-") && *argv[2] != '|')
1173 if (!globulize(&argv[2]) || !confirm("output to local-file:",
1174 argv[2])) {
1175 code = -1;
1176 return;
1178 recvrequest(cmd, argv[2], argv[1], "w", 0, 1);
1182 * Get a directory listing
1183 * of multiple remote files.
1185 void
1186 mls(int argc, char **argv)
1188 sighand oldintr;
1189 int ointer, i;
1190 char *cmd, mode[1], *dest;
1192 if (argc < 2 && !another(&argc, &argv, "remote-files"))
1193 goto usage;
1194 if (argc < 3 && !another(&argc, &argv, "local-file")) {
1195 usage:
1196 printf("usage: %s remote-files local-file\n", argv[0]);
1197 code = -1;
1198 return;
1200 dest = argv[argc - 1];
1201 argv[argc - 1] = NULL;
1202 if (strcmp(dest, "-") && *dest != '|')
1203 if (!globulize(&dest) ||
1204 !confirm("output to local-file:", dest)) {
1205 code = -1;
1206 return;
1208 cmd = argv[0][1] == 'l' ? "NLST" : "LIST";
1209 mname = argv[0];
1210 mflag = 1;
1211 oldintr = signal(SIGINT, mabort);
1212 setjmp(jabort);
1213 for (i = 1; mflag && i < argc-1; ++i) {
1214 *mode = (i == 1) ? 'w' : 'a';
1215 recvrequest(cmd, dest, argv[i], mode, 0, 1);
1216 if (!mflag && fromatty) {
1217 ointer = interactive;
1218 interactive = 1;
1219 if (confirm("Continue with", argv[0])) {
1220 mflag ++;
1222 interactive = ointer;
1225 signal(SIGINT, oldintr);
1226 mflag = 0;
1230 * Do a shell escape
1232 /*ARGSUSED*/
1233 void
1234 shell(int argc, char **argv)
1236 pid_t pid;
1237 RETSIGTYPE (*old1)(int), (*old2)(int);
1238 char shellnam[40], *shell, *namep;
1239 int status;
1241 old1 = signal (SIGINT, SIG_IGN);
1242 old2 = signal (SIGQUIT, SIG_IGN);
1243 if ((pid = fork()) == 0) {
1244 for (pid = 3; pid < 20; pid++)
1245 close(pid);
1246 signal(SIGINT, SIG_DFL);
1247 signal(SIGQUIT, SIG_DFL);
1248 shell = getenv("SHELL");
1249 if (shell == NULL)
1250 shell = _PATH_BSHELL;
1251 namep = strrchr(shell,'/');
1252 if (namep == NULL)
1253 namep = shell;
1254 snprintf (shellnam, sizeof(shellnam),
1255 "-%s", ++namep);
1256 if (strcmp(namep, "sh") != 0)
1257 shellnam[0] = '+';
1258 if (debug) {
1259 printf ("%s\n", shell);
1260 fflush (stdout);
1262 if (argc > 1) {
1263 execl(shell,shellnam,"-c",altarg,(char *)0);
1265 else {
1266 execl(shell,shellnam,(char *)0);
1268 warn("%s", shell);
1269 code = -1;
1270 exit(1);
1272 if (pid > 0)
1273 while (waitpid(-1, &status, 0) != pid)
1275 signal(SIGINT, old1);
1276 signal(SIGQUIT, old2);
1277 if (pid == -1) {
1278 warn("%s", "Try again later");
1279 code = -1;
1281 else {
1282 code = 0;
1287 * Send new user information (re-login)
1289 void
1290 user(int argc, char **argv)
1292 char acct[80];
1293 int n, aflag = 0;
1294 char tmp[256];
1296 if (argc < 2)
1297 another(&argc, &argv, "username");
1298 if (argc < 2 || argc > 4) {
1299 printf("usage: %s username [password] [account]\n", argv[0]);
1300 code = -1;
1301 return;
1303 n = command("USER %s", argv[1]);
1304 if (n == CONTINUE) {
1305 if (argc < 3 ) {
1306 des_read_pw_string (tmp,
1307 sizeof(tmp),
1308 "Password: ", 0);
1309 argv[2] = tmp;
1310 argc++;
1312 n = command("PASS %s", argv[2]);
1314 if (n == CONTINUE) {
1315 if (argc < 4) {
1316 printf("Account: "); fflush(stdout);
1317 fgets(acct, sizeof(acct) - 1, stdin);
1318 acct[strlen(acct) - 1] = '\0';
1319 argv[3] = acct; argc++;
1321 n = command("ACCT %s", argv[3]);
1322 aflag++;
1324 if (n != COMPLETE) {
1325 fprintf(stdout, "Login failed.\n");
1326 return;
1328 if (!aflag && argc == 4) {
1329 command("ACCT %s", argv[3]);
1334 * Print working directory.
1336 /*VARARGS*/
1337 void
1338 pwd(int argc, char **argv)
1340 int oldverbose = verbose;
1343 * If we aren't verbose, this doesn't do anything!
1345 verbose = 1;
1346 if (command("PWD") == ERROR && code == 500) {
1347 printf("PWD command not recognized, trying XPWD\n");
1348 command("XPWD");
1350 verbose = oldverbose;
1354 * Make a directory.
1356 void
1357 makedir(int argc, char **argv)
1360 if (argc < 2 && !another(&argc, &argv, "directory-name")) {
1361 printf("usage: %s directory-name\n", argv[0]);
1362 code = -1;
1363 return;
1365 if (command("MKD %s", argv[1]) == ERROR && code == 500) {
1366 if (verbose)
1367 printf("MKD command not recognized, trying XMKD\n");
1368 command("XMKD %s", argv[1]);
1373 * Remove a directory.
1375 void
1376 removedir(int argc, char **argv)
1379 if (argc < 2 && !another(&argc, &argv, "directory-name")) {
1380 printf("usage: %s directory-name\n", argv[0]);
1381 code = -1;
1382 return;
1384 if (command("RMD %s", argv[1]) == ERROR && code == 500) {
1385 if (verbose)
1386 printf("RMD command not recognized, trying XRMD\n");
1387 command("XRMD %s", argv[1]);
1392 * Send a line, verbatim, to the remote machine.
1394 void
1395 quote(int argc, char **argv)
1398 if (argc < 2 && !another(&argc, &argv, "command line to send")) {
1399 printf("usage: %s line-to-send\n", argv[0]);
1400 code = -1;
1401 return;
1403 quote1("", argc, argv);
1407 * Send a SITE command to the remote machine. The line
1408 * is sent verbatim to the remote machine, except that the
1409 * word "SITE" is added at the front.
1411 void
1412 site(int argc, char **argv)
1415 if (argc < 2 && !another(&argc, &argv, "arguments to SITE command")) {
1416 printf("usage: %s line-to-send\n", argv[0]);
1417 code = -1;
1418 return;
1420 quote1("SITE ", argc, argv);
1424 * Turn argv[1..argc) into a space-separated string, then prepend initial text.
1425 * Send the result as a one-line command and get response.
1427 void
1428 quote1(char *initial, int argc, char **argv)
1430 int i;
1431 char buf[BUFSIZ]; /* must be >= sizeof(line) */
1433 strlcpy(buf, initial, sizeof(buf));
1434 for(i = 1; i < argc; i++) {
1435 if(i > 1)
1436 strlcat(buf, " ", sizeof(buf));
1437 strlcat(buf, argv[i], sizeof(buf));
1439 if (command("%s", buf) == PRELIM) {
1440 while (getreply(0) == PRELIM)
1441 continue;
1445 void
1446 do_chmod(int argc, char **argv)
1449 if (argc < 2 && !another(&argc, &argv, "mode"))
1450 goto usage;
1451 if (argc < 3 && !another(&argc, &argv, "file-name")) {
1452 usage:
1453 printf("usage: %s mode file-name\n", argv[0]);
1454 code = -1;
1455 return;
1457 command("SITE CHMOD %s %s", argv[1], argv[2]);
1460 void
1461 do_umask(int argc, char **argv)
1463 int oldverbose = verbose;
1465 verbose = 1;
1466 command(argc == 1 ? "SITE UMASK" : "SITE UMASK %s", argv[1]);
1467 verbose = oldverbose;
1470 void
1471 ftp_idle(int argc, char **argv)
1473 int oldverbose = verbose;
1475 verbose = 1;
1476 command(argc == 1 ? "SITE IDLE" : "SITE IDLE %s", argv[1]);
1477 verbose = oldverbose;
1481 * Ask the other side for help.
1483 void
1484 rmthelp(int argc, char **argv)
1486 int oldverbose = verbose;
1488 verbose = 1;
1489 command(argc == 1 ? "HELP" : "HELP %s", argv[1]);
1490 verbose = oldverbose;
1494 * Terminate session and exit.
1496 /*VARARGS*/
1497 void
1498 quit(int argc, char **argv)
1501 if (connected)
1502 disconnect(0, 0);
1503 pswitch(1);
1504 if (connected) {
1505 disconnect(0, 0);
1507 exit(0);
1511 * Terminate session, but don't exit.
1513 void
1514 disconnect(int argc, char **argv)
1517 if (!connected)
1518 return;
1519 command("QUIT");
1520 if (cout) {
1521 fclose(cout);
1523 cout = NULL;
1524 connected = 0;
1525 sec_end();
1526 data = -1;
1527 if (!proxy) {
1528 macnum = 0;
1533 confirm(char *cmd, char *file)
1535 char line[BUFSIZ];
1537 if (!interactive)
1538 return (1);
1539 printf("%s %s? ", cmd, file);
1540 fflush(stdout);
1541 if (fgets(line, sizeof line, stdin) == NULL)
1542 return (0);
1543 return (*line == 'y' || *line == 'Y');
1546 void
1547 fatal(char *msg)
1550 errx(1, "%s", msg);
1554 * Glob a local file name specification with
1555 * the expectation of a single return value.
1556 * Can't control multiple values being expanded
1557 * from the expression, we return only the first.
1560 globulize(char **cpp)
1562 glob_t gl;
1563 int flags;
1565 if (!doglob)
1566 return (1);
1568 flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE;
1569 memset(&gl, 0, sizeof(gl));
1570 if (glob(*cpp, flags, NULL, &gl) ||
1571 gl.gl_pathc == 0) {
1572 warnx("%s: not found", *cpp);
1573 globfree(&gl);
1574 return (0);
1576 *cpp = strdup(gl.gl_pathv[0]); /* XXX - wasted memory */
1577 globfree(&gl);
1578 return (1);
1581 void
1582 account(int argc, char **argv)
1584 char acct[50];
1586 if (argc > 1) {
1587 ++argv;
1588 --argc;
1589 strlcpy (acct, *argv, sizeof(acct));
1590 while (argc > 1) {
1591 --argc;
1592 ++argv;
1593 strlcat(acct, *argv, sizeof(acct));
1596 else {
1597 des_read_pw_string(acct, sizeof(acct), "Account:", 0);
1599 command("ACCT %s", acct);
1602 jmp_buf abortprox;
1604 static RETSIGTYPE
1605 proxabort(int sig)
1608 if (!proxy) {
1609 pswitch(1);
1611 if (connected) {
1612 proxflag = 1;
1614 else {
1615 proxflag = 0;
1617 pswitch(0);
1618 longjmp(abortprox,1);
1621 void
1622 doproxy(int argc, char **argv)
1624 struct cmd *c;
1625 RETSIGTYPE (*oldintr)(int);
1627 if (argc < 2 && !another(&argc, &argv, "command")) {
1628 printf("usage: %s command\n", argv[0]);
1629 code = -1;
1630 return;
1632 c = getcmd(argv[1]);
1633 if (c == (struct cmd *) -1) {
1634 printf("?Ambiguous command\n");
1635 fflush(stdout);
1636 code = -1;
1637 return;
1639 if (c == 0) {
1640 printf("?Invalid command\n");
1641 fflush(stdout);
1642 code = -1;
1643 return;
1645 if (!c->c_proxy) {
1646 printf("?Invalid proxy command\n");
1647 fflush(stdout);
1648 code = -1;
1649 return;
1651 if (setjmp(abortprox)) {
1652 code = -1;
1653 return;
1655 oldintr = signal(SIGINT, proxabort);
1656 pswitch(1);
1657 if (c->c_conn && !connected) {
1658 printf("Not connected\n");
1659 fflush(stdout);
1660 pswitch(0);
1661 signal(SIGINT, oldintr);
1662 code = -1;
1663 return;
1665 (*c->c_handler)(argc-1, argv+1);
1666 if (connected) {
1667 proxflag = 1;
1669 else {
1670 proxflag = 0;
1672 pswitch(0);
1673 signal(SIGINT, oldintr);
1676 void
1677 setcase(int argc, char **argv)
1680 mcase = !mcase;
1681 printf("Case mapping %s.\n", onoff(mcase));
1682 code = mcase;
1685 void
1686 setcr(int argc, char **argv)
1689 crflag = !crflag;
1690 printf("Carriage Return stripping %s.\n", onoff(crflag));
1691 code = crflag;
1694 void
1695 setntrans(int argc, char **argv)
1697 if (argc == 1) {
1698 ntflag = 0;
1699 printf("Ntrans off.\n");
1700 code = ntflag;
1701 return;
1703 ntflag++;
1704 code = ntflag;
1705 strlcpy (ntin, argv[1], 17);
1706 if (argc == 2) {
1707 ntout[0] = '\0';
1708 return;
1710 strlcpy (ntout, argv[2], 17);
1713 char *
1714 dotrans(char *name)
1716 static char new[MaxPathLen];
1717 char *cp1, *cp2 = new;
1718 int i, ostop, found;
1720 for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++)
1721 continue;
1722 for (cp1 = name; *cp1; cp1++) {
1723 found = 0;
1724 for (i = 0; *(ntin + i) && i < 16; i++) {
1725 if (*cp1 == *(ntin + i)) {
1726 found++;
1727 if (i < ostop) {
1728 *cp2++ = *(ntout + i);
1730 break;
1733 if (!found) {
1734 *cp2++ = *cp1;
1737 *cp2 = '\0';
1738 return (new);
1741 void
1742 setnmap(int argc, char **argv)
1744 char *cp;
1746 if (argc == 1) {
1747 mapflag = 0;
1748 printf("Nmap off.\n");
1749 code = mapflag;
1750 return;
1752 if (argc < 3 && !another(&argc, &argv, "mapout")) {
1753 printf("Usage: %s [mapin mapout]\n",argv[0]);
1754 code = -1;
1755 return;
1757 mapflag = 1;
1758 code = 1;
1759 cp = strchr(altarg, ' ');
1760 if (proxy) {
1761 while(*++cp == ' ')
1762 continue;
1763 altarg = cp;
1764 cp = strchr(altarg, ' ');
1766 *cp = '\0';
1767 strlcpy(mapin, altarg, MaxPathLen);
1768 while (*++cp == ' ')
1769 continue;
1770 strlcpy(mapout, cp, MaxPathLen);
1773 char *
1774 domap(char *name)
1776 static char new[MaxPathLen];
1777 char *cp1 = name, *cp2 = mapin;
1778 char *tp[9], *te[9];
1779 int i, toks[9], toknum = 0, match = 1;
1781 for (i=0; i < 9; ++i) {
1782 toks[i] = 0;
1784 while (match && *cp1 && *cp2) {
1785 switch (*cp2) {
1786 case '\\':
1787 if (*++cp2 != *cp1) {
1788 match = 0;
1790 break;
1791 case '$':
1792 if (*(cp2+1) >= '1' && (*cp2+1) <= '9') {
1793 if (*cp1 != *(++cp2+1)) {
1794 toks[toknum = *cp2 - '1']++;
1795 tp[toknum] = cp1;
1796 while (*++cp1 && *(cp2+1)
1797 != *cp1);
1798 te[toknum] = cp1;
1800 cp2++;
1801 break;
1803 /* FALLTHROUGH */
1804 default:
1805 if (*cp2 != *cp1) {
1806 match = 0;
1808 break;
1810 if (match && *cp1) {
1811 cp1++;
1813 if (match && *cp2) {
1814 cp2++;
1817 if (!match && *cp1) /* last token mismatch */
1819 toks[toknum] = 0;
1821 cp1 = new;
1822 *cp1 = '\0';
1823 cp2 = mapout;
1824 while (*cp2) {
1825 match = 0;
1826 switch (*cp2) {
1827 case '\\':
1828 if (*(cp2 + 1)) {
1829 *cp1++ = *++cp2;
1831 break;
1832 case '[':
1833 LOOP:
1834 if (*++cp2 == '$' && isdigit((unsigned char)*(cp2+1))) {
1835 if (*++cp2 == '0') {
1836 char *cp3 = name;
1838 while (*cp3) {
1839 *cp1++ = *cp3++;
1841 match = 1;
1843 else if (toks[toknum = *cp2 - '1']) {
1844 char *cp3 = tp[toknum];
1846 while (cp3 != te[toknum]) {
1847 *cp1++ = *cp3++;
1849 match = 1;
1852 else {
1853 while (*cp2 && *cp2 != ',' &&
1854 *cp2 != ']') {
1855 if (*cp2 == '\\') {
1856 cp2++;
1858 else if (*cp2 == '$' &&
1859 isdigit((unsigned char)*(cp2+1))) {
1860 if (*++cp2 == '0') {
1861 char *cp3 = name;
1863 while (*cp3) {
1864 *cp1++ = *cp3++;
1867 else if (toks[toknum =
1868 *cp2 - '1']) {
1869 char *cp3=tp[toknum];
1871 while (cp3 !=
1872 te[toknum]) {
1873 *cp1++ = *cp3++;
1877 else if (*cp2) {
1878 *cp1++ = *cp2++;
1881 if (!*cp2) {
1882 printf("nmap: unbalanced brackets\n");
1883 return (name);
1885 match = 1;
1886 cp2--;
1888 if (match) {
1889 while (*++cp2 && *cp2 != ']') {
1890 if (*cp2 == '\\' && *(cp2 + 1)) {
1891 cp2++;
1894 if (!*cp2) {
1895 printf("nmap: unbalanced brackets\n");
1896 return (name);
1898 break;
1900 switch (*++cp2) {
1901 case ',':
1902 goto LOOP;
1903 case ']':
1904 break;
1905 default:
1906 cp2--;
1907 goto LOOP;
1909 break;
1910 case '$':
1911 if (isdigit((unsigned char)*(cp2 + 1))) {
1912 if (*++cp2 == '0') {
1913 char *cp3 = name;
1915 while (*cp3) {
1916 *cp1++ = *cp3++;
1919 else if (toks[toknum = *cp2 - '1']) {
1920 char *cp3 = tp[toknum];
1922 while (cp3 != te[toknum]) {
1923 *cp1++ = *cp3++;
1926 break;
1928 /* intentional drop through */
1929 default:
1930 *cp1++ = *cp2;
1931 break;
1933 cp2++;
1935 *cp1 = '\0';
1936 if (!*new) {
1937 return (name);
1939 return (new);
1942 void
1943 setpassive(int argc, char **argv)
1946 passivemode = !passivemode;
1947 printf("Passive mode %s.\n", onoff(passivemode));
1948 code = passivemode;
1951 void
1952 setsunique(int argc, char **argv)
1955 sunique = !sunique;
1956 printf("Store unique %s.\n", onoff(sunique));
1957 code = sunique;
1960 void
1961 setrunique(int argc, char **argv)
1964 runique = !runique;
1965 printf("Receive unique %s.\n", onoff(runique));
1966 code = runique;
1969 /* change directory to perent directory */
1970 void
1971 cdup(int argc, char **argv)
1974 if (command("CDUP") == ERROR && code == 500) {
1975 if (verbose)
1976 printf("CDUP command not recognized, trying XCUP\n");
1977 command("XCUP");
1981 /* restart transfer at specific point */
1982 void
1983 restart(int argc, char **argv)
1986 if (argc != 2)
1987 printf("restart: offset not specified\n");
1988 else {
1989 restart_point = atol(argv[1]);
1990 printf("restarting at %ld. %s\n", (long)restart_point,
1991 "execute get, put or append to initiate transfer");
1995 /* show remote system type */
1996 void
1997 syst(int argc, char **argv)
2000 command("SYST");
2003 void
2004 macdef(int argc, char **argv)
2006 char *tmp;
2007 int c;
2009 if (macnum == 16) {
2010 printf("Limit of 16 macros have already been defined\n");
2011 code = -1;
2012 return;
2014 if (argc < 2 && !another(&argc, &argv, "macro name")) {
2015 printf("Usage: %s macro_name\n",argv[0]);
2016 code = -1;
2017 return;
2019 if (interactive) {
2020 printf("Enter macro line by line, terminating it with a null line\n");
2022 strlcpy(macros[macnum].mac_name,
2023 argv[1],
2024 sizeof(macros[macnum].mac_name));
2025 if (macnum == 0) {
2026 macros[macnum].mac_start = macbuf;
2028 else {
2029 macros[macnum].mac_start = macros[macnum - 1].mac_end + 1;
2031 tmp = macros[macnum].mac_start;
2032 while (tmp != macbuf+4096) {
2033 if ((c = getchar()) == EOF) {
2034 printf("macdef:end of file encountered\n");
2035 code = -1;
2036 return;
2038 if ((*tmp = c) == '\n') {
2039 if (tmp == macros[macnum].mac_start) {
2040 macros[macnum++].mac_end = tmp;
2041 code = 0;
2042 return;
2044 if (*(tmp-1) == '\0') {
2045 macros[macnum++].mac_end = tmp - 1;
2046 code = 0;
2047 return;
2049 *tmp = '\0';
2051 tmp++;
2053 while (1) {
2054 while ((c = getchar()) != '\n' && c != EOF)
2055 /* LOOP */;
2056 if (c == EOF || getchar() == '\n') {
2057 printf("Macro not defined - 4k buffer exceeded\n");
2058 code = -1;
2059 return;
2065 * get size of file on remote machine
2067 void
2068 sizecmd(int argc, char **argv)
2071 if (argc < 2 && !another(&argc, &argv, "filename")) {
2072 printf("usage: %s filename\n", argv[0]);
2073 code = -1;
2074 return;
2076 command("SIZE %s", argv[1]);
2080 * get last modification time of file on remote machine
2082 void
2083 modtime(int argc, char **argv)
2085 int overbose;
2087 if (argc < 2 && !another(&argc, &argv, "filename")) {
2088 printf("usage: %s filename\n", argv[0]);
2089 code = -1;
2090 return;
2092 overbose = verbose;
2093 if (debug == 0)
2094 verbose = -1;
2095 if (command("MDTM %s", argv[1]) == COMPLETE) {
2096 int yy, mo, day, hour, min, sec;
2097 sscanf(reply_string, "%*s %04d%02d%02d%02d%02d%02d", &yy, &mo,
2098 &day, &hour, &min, &sec);
2099 /* might want to print this in local time */
2100 printf("%s\t%02d/%02d/%04d %02d:%02d:%02d GMT\n", argv[1],
2101 mo, day, yy, hour, min, sec);
2102 } else
2103 printf("%s\n", reply_string);
2104 verbose = overbose;
2108 * show status on reomte machine
2110 void
2111 rmtstatus(int argc, char **argv)
2114 command(argc > 1 ? "STAT %s" : "STAT" , argv[1]);
2118 * get file if modtime is more recent than current file
2120 void
2121 newer(int argc, char **argv)
2124 if (getit(argc, argv, -1, curtype == TYPE_I ? "wb" : "w"))
2125 printf("Local file \"%s\" is newer than remote file \"%s\"\n",
2126 argv[2], argv[1]);