(setnmap): make sure strchr returned a string [CID-65]
[heimdal.git] / appl / ftp / ftp / cmds.c
blob0c1355a8eee6c56f7f4952e389d04742e121d14c
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$");
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__) || defined(__APPLE__)) && 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 && strlen(reply_string) > 4) {
154 char *cp, *p;
156 cp = strdup(reply_string + 4);
157 if (cp == NULL)
158 errx(1, "strdup: out of memory");
159 p = strchr(cp, ' ');
160 if (p == NULL)
161 p = strchr(cp, '\r');
162 if (p) {
163 if (p[-1] == '.')
164 p--;
165 *p = '\0';
168 printf("Remote system type is %s.\n", cp);
169 free(cp);
171 if (!strncmp(reply_string, "215 UNIX Type: L8", 17)) {
172 if (proxy)
173 unix_proxy = 1;
174 else
175 unix_server = 1;
177 * Set type to 0 (not specified by user),
178 * meaning binary by default, but don't bother
179 * telling server. We can use binary
180 * for text files unless changed by the user.
182 type = 0;
183 strlcpy(typename, "binary", sizeof(typename));
184 if (overbose)
185 printf("Using %s mode to transfer files.\n",
186 typename);
187 } else {
188 if (proxy)
189 unix_proxy = 0;
190 else
191 unix_server = 0;
192 if (overbose &&
193 !strncmp(reply_string, "215 TOPS20", 10))
194 printf(
195 "Remember to set tenex mode when transfering binary files from this machine.\n");
197 verbose = overbose;
198 #endif /* unix */
202 struct types {
203 char *t_name;
204 char *t_mode;
205 int t_type;
206 char *t_arg;
207 } types[] = {
208 { "ascii", "A", TYPE_A, 0 },
209 { "binary", "I", TYPE_I, 0 },
210 { "image", "I", TYPE_I, 0 },
211 { "ebcdic", "E", TYPE_E, 0 },
212 { "tenex", "L", TYPE_L, bytename },
213 { NULL }
217 * Set transfer type.
219 void
220 settype(int argc, char **argv)
222 struct types *p;
223 int comret;
225 if (argc > 2) {
226 char *sep;
228 printf("usage: %s [", argv[0]);
229 sep = " ";
230 for (p = types; p->t_name; p++) {
231 printf("%s%s", sep, p->t_name);
232 sep = " | ";
234 printf(" ]\n");
235 code = -1;
236 return;
238 if (argc < 2) {
239 printf("Using %s mode to transfer files.\n", typename);
240 code = 0;
241 return;
243 for (p = types; p->t_name; p++)
244 if (strcmp(argv[1], p->t_name) == 0)
245 break;
246 if (p->t_name == 0) {
247 printf("%s: unknown mode\n", argv[1]);
248 code = -1;
249 return;
251 if ((p->t_arg != NULL) && (*(p->t_arg) != '\0'))
252 comret = command ("TYPE %s %s", p->t_mode, p->t_arg);
253 else
254 comret = command("TYPE %s", p->t_mode);
255 if (comret == COMPLETE) {
256 strlcpy(typename, p->t_name, sizeof(typename));
257 curtype = type = p->t_type;
262 * Internal form of settype; changes current type in use with server
263 * without changing our notion of the type for data transfers.
264 * Used to change to and from ascii for listings.
266 void
267 changetype(int newtype, int show)
269 struct types *p;
270 int comret, oldverbose = verbose;
272 if (newtype == 0)
273 newtype = TYPE_I;
274 if (newtype == curtype)
275 return;
276 if (debug == 0 && show == 0)
277 verbose = 0;
278 for (p = types; p->t_name; p++)
279 if (newtype == p->t_type)
280 break;
281 if (p->t_name == 0) {
282 printf("ftp: internal error: unknown type %d\n", newtype);
283 return;
285 if (newtype == TYPE_L && bytename[0] != '\0')
286 comret = command("TYPE %s %s", p->t_mode, bytename);
287 else
288 comret = command("TYPE %s", p->t_mode);
289 if (comret == COMPLETE)
290 curtype = newtype;
291 verbose = oldverbose;
294 char *stype[] = {
295 "type",
301 * Set binary transfer type.
303 /*VARARGS*/
304 void
305 setbinary(int argc, char **argv)
308 stype[1] = "binary";
309 settype(2, stype);
313 * Set ascii transfer type.
315 /*VARARGS*/
316 void
317 setascii(int argc, char **argv)
320 stype[1] = "ascii";
321 settype(2, stype);
325 * Set tenex transfer type.
327 /*VARARGS*/
328 void
329 settenex(int argc, char **argv)
332 stype[1] = "tenex";
333 settype(2, stype);
337 * Set file transfer mode.
339 /*ARGSUSED*/
340 void
341 setftmode(int argc, char **argv)
344 printf("We only support %s mode, sorry.\n", modename);
345 code = -1;
349 * Set file transfer format.
351 /*ARGSUSED*/
352 void
353 setform(int argc, char **argv)
356 printf("We only support %s format, sorry.\n", formname);
357 code = -1;
361 * Set file transfer structure.
363 /*ARGSUSED*/
364 void
365 setstruct(int argc, char **argv)
368 printf("We only support %s structure, sorry.\n", structname);
369 code = -1;
373 * Send a single file.
375 void
376 put(int argc, char **argv)
378 char *cmd;
379 int loc = 0;
380 char *oldargv1, *oldargv2;
382 if (argc == 2) {
383 argc++;
384 argv[2] = argv[1];
385 loc++;
387 if (argc < 2 && !another(&argc, &argv, "local-file"))
388 goto usage;
389 if (argc < 3 && !another(&argc, &argv, "remote-file")) {
390 usage:
391 printf("usage: %s local-file remote-file\n", argv[0]);
392 code = -1;
393 return;
395 oldargv1 = argv[1];
396 oldargv2 = argv[2];
397 if (!globulize(&argv[1])) {
398 code = -1;
399 return;
402 * If "globulize" modifies argv[1], and argv[2] is a copy of
403 * the old argv[1], make it a copy of the new argv[1].
405 if (argv[1] != oldargv1 && argv[2] == oldargv1) {
406 argv[2] = argv[1];
408 cmd = (argv[0][0] == 'a') ? "APPE" : ((sunique) ? "STOU" : "STOR");
409 if (loc && ntflag) {
410 argv[2] = dotrans(argv[2]);
412 if (loc && mapflag) {
413 argv[2] = domap(argv[2]);
415 sendrequest(cmd, argv[1], argv[2],
416 curtype == TYPE_I ? "rb" : "r",
417 argv[1] != oldargv1 || argv[2] != oldargv2);
420 /* ARGSUSED */
421 static RETSIGTYPE
422 mabort(int signo)
424 int ointer;
426 printf("\n");
427 fflush(stdout);
428 if (mflag && fromatty) {
429 ointer = interactive;
430 interactive = 1;
431 if (confirm("Continue with", mname)) {
432 interactive = ointer;
433 longjmp(jabort,0);
435 interactive = ointer;
437 mflag = 0;
438 longjmp(jabort,0);
442 * Send multiple files.
444 void
445 mput(int argc, char **argv)
447 int i;
448 RETSIGTYPE (*oldintr)(int);
449 int ointer;
450 char *tp;
452 if (argc < 2 && !another(&argc, &argv, "local-files")) {
453 printf("usage: %s local-files\n", argv[0]);
454 code = -1;
455 return;
457 mname = argv[0];
458 mflag = 1;
459 oldintr = signal(SIGINT, mabort);
460 setjmp(jabort);
461 if (proxy) {
462 char *cp, *tp2, tmpbuf[MaxPathLen];
464 while ((cp = remglob(argv,0)) != NULL) {
465 if (*cp == 0) {
466 mflag = 0;
467 continue;
469 if (mflag && confirm(argv[0], cp)) {
470 tp = cp;
471 if (mcase) {
472 while (*tp && !islower((unsigned char)*tp)) {
473 tp++;
475 if (!*tp) {
476 tp = cp;
477 tp2 = tmpbuf;
478 while ((*tp2 = *tp) != '\0') {
479 if (isupper((unsigned char)*tp2)) {
480 *tp2 = 'a' + *tp2 - 'A';
482 tp++;
483 tp2++;
486 tp = tmpbuf;
488 if (ntflag) {
489 tp = dotrans(tp);
491 if (mapflag) {
492 tp = domap(tp);
494 sendrequest((sunique) ? "STOU" : "STOR",
495 cp, tp,
496 curtype == TYPE_I ? "rb" : "r",
497 cp != tp || !interactive);
498 if (!mflag && fromatty) {
499 ointer = interactive;
500 interactive = 1;
501 if (confirm("Continue with","mput")) {
502 mflag++;
504 interactive = ointer;
508 signal(SIGINT, oldintr);
509 mflag = 0;
510 return;
512 for (i = 1; i < argc; i++) {
513 char **cpp;
514 glob_t gl;
515 int flags;
517 if (!doglob) {
518 if (mflag && confirm(argv[0], argv[i])) {
519 tp = (ntflag) ? dotrans(argv[i]) : argv[i];
520 tp = (mapflag) ? domap(tp) : tp;
521 sendrequest((sunique) ? "STOU" : "STOR",
522 argv[i],
523 curtype == TYPE_I ? "rb" : "r",
524 tp, tp != argv[i] || !interactive);
525 if (!mflag && fromatty) {
526 ointer = interactive;
527 interactive = 1;
528 if (confirm("Continue with","mput")) {
529 mflag++;
531 interactive = ointer;
534 continue;
537 memset(&gl, 0, sizeof(gl));
538 flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE;
539 if (glob(argv[i], flags, NULL, &gl) || gl.gl_pathc == 0) {
540 warnx("%s: not found", argv[i]);
541 globfree(&gl);
542 continue;
544 for (cpp = gl.gl_pathv; cpp && *cpp != NULL; cpp++) {
545 if (mflag && confirm(argv[0], *cpp)) {
546 tp = (ntflag) ? dotrans(*cpp) : *cpp;
547 tp = (mapflag) ? domap(tp) : tp;
548 sendrequest((sunique) ? "STOU" : "STOR",
549 *cpp, tp,
550 curtype == TYPE_I ? "rb" : "r",
551 *cpp != tp || !interactive);
552 if (!mflag && fromatty) {
553 ointer = interactive;
554 interactive = 1;
555 if (confirm("Continue with","mput")) {
556 mflag++;
558 interactive = ointer;
562 globfree(&gl);
564 signal(SIGINT, oldintr);
565 mflag = 0;
568 void
569 reget(int argc, char **argv)
571 getit(argc, argv, 1, curtype == TYPE_I ? "r+wb" : "r+w");
574 void
575 get(int argc, char **argv)
577 char *filemode;
579 if (restart_point) {
580 if (curtype == TYPE_I)
581 filemode = "r+wb";
582 else
583 filemode = "r+w";
584 } else {
585 if (curtype == TYPE_I)
586 filemode = "wb";
587 else
588 filemode = "w";
591 getit(argc, argv, 0, filemode);
595 * Receive one file.
598 getit(int argc, char **argv, int restartit, char *filemode)
600 int loc = 0;
601 int local_given = 1;
602 char *oldargv1, *oldargv2;
604 if (argc == 2) {
605 argc++;
606 local_given = 0;
607 argv[2] = argv[1];
608 loc++;
610 if ((argc < 2 && !another(&argc, &argv, "remote-file")) ||
611 (argc < 3 && !another(&argc, &argv, "local-file"))) {
612 printf("usage: %s remote-file [ local-file ]\n", argv[0]);
613 code = -1;
614 return (0);
616 oldargv1 = argv[1];
617 oldargv2 = argv[2];
618 if (!globulize(&argv[2])) {
619 code = -1;
620 return (0);
622 if (loc && mcase) {
623 char *tp = argv[1], *tp2, tmpbuf[MaxPathLen];
625 while (*tp && !islower((unsigned char)*tp)) {
626 tp++;
628 if (!*tp) {
629 tp = argv[2];
630 tp2 = tmpbuf;
631 while ((*tp2 = *tp) != '\0') {
632 if (isupper((unsigned char)*tp2)) {
633 *tp2 = 'a' + *tp2 - 'A';
635 tp++;
636 tp2++;
638 argv[2] = tmpbuf;
641 if (loc && ntflag)
642 argv[2] = dotrans(argv[2]);
643 if (loc && mapflag)
644 argv[2] = domap(argv[2]);
645 if (restartit) {
646 struct stat stbuf;
647 int ret;
649 ret = stat(argv[2], &stbuf);
650 if (restartit == 1) {
651 if (ret < 0) {
652 warn("local: %s", argv[2]);
653 return (0);
655 restart_point = stbuf.st_size;
656 } else if (ret == 0) {
657 int overbose;
658 int cmdret;
659 int yy, mo, day, hour, min, sec;
660 struct tm *tm;
661 time_t mtime = stbuf.st_mtime;
663 overbose = verbose;
664 if (debug == 0)
665 verbose = -1;
666 cmdret = command("MDTM %s", argv[1]);
667 verbose = overbose;
668 if (cmdret != COMPLETE) {
669 printf("%s\n", reply_string);
670 return (0);
672 if (sscanf(reply_string,
673 "%*s %04d%02d%02d%02d%02d%02d",
674 &yy, &mo, &day, &hour, &min, &sec)
675 != 6) {
676 printf ("bad MDTM result\n");
677 return (0);
680 tm = gmtime(&mtime);
681 tm->tm_mon++;
682 tm->tm_year += 1900;
684 if ((tm->tm_year > yy) ||
685 (tm->tm_year == yy &&
686 tm->tm_mon > mo) ||
687 (tm->tm_mon == mo &&
688 tm->tm_mday > day) ||
689 (tm->tm_mday == day &&
690 tm->tm_hour > hour) ||
691 (tm->tm_hour == hour &&
692 tm->tm_min > min) ||
693 (tm->tm_min == min &&
694 tm->tm_sec > sec))
695 return (1);
699 recvrequest("RETR", argv[2], argv[1], filemode,
700 argv[1] != oldargv1 || argv[2] != oldargv2, local_given);
701 restart_point = 0;
702 return (0);
705 static int
706 suspicious_filename(const char *fn)
708 return strstr(fn, "../") != NULL || *fn == '/';
712 * Get multiple files.
714 void
715 mget(int argc, char **argv)
717 sighand oldintr;
718 int ch, ointer;
719 char *cp, *tp, *tp2, tmpbuf[MaxPathLen];
721 if (argc < 2 && !another(&argc, &argv, "remote-files")) {
722 printf("usage: %s remote-files\n", argv[0]);
723 code = -1;
724 return;
726 mname = argv[0];
727 mflag = 1;
728 oldintr = signal(SIGINT, mabort);
729 setjmp(jabort);
730 while ((cp = remglob(argv,proxy)) != NULL) {
731 if (*cp == '\0') {
732 mflag = 0;
733 continue;
735 if (mflag && suspicious_filename(cp))
736 printf("*** Suspicious filename: %s\n", cp);
737 if (mflag && confirm(argv[0], cp)) {
738 tp = cp;
739 if (mcase) {
740 for (tp2 = tmpbuf;(ch = (unsigned char)*tp++);)
741 *tp2++ = tolower(ch);
742 *tp2 = '\0';
743 tp = tmpbuf;
745 if (ntflag) {
746 tp = dotrans(tp);
748 if (mapflag) {
749 tp = domap(tp);
751 recvrequest("RETR", tp, cp,
752 curtype == TYPE_I ? "wb" : "w",
753 tp != cp || !interactive, 0);
754 if (!mflag && fromatty) {
755 ointer = interactive;
756 interactive = 1;
757 if (confirm("Continue with","mget")) {
758 mflag++;
760 interactive = ointer;
764 signal(SIGINT,oldintr);
765 mflag = 0;
768 char *
769 remglob(char **argv, int doswitch)
771 char temp[16];
772 static char buf[MaxPathLen];
773 static FILE *ftemp = NULL;
774 static char **args;
775 int oldverbose, oldhash;
776 char *cp, *filemode;
778 if (!mflag) {
779 if (!doglob) {
780 args = NULL;
782 else {
783 if (ftemp) {
784 fclose(ftemp);
785 ftemp = NULL;
788 return (NULL);
790 if (!doglob) {
791 if (args == NULL)
792 args = argv;
793 if ((cp = *++args) == NULL)
794 args = NULL;
795 return (cp);
797 if (ftemp == NULL) {
798 int fd;
799 strlcpy(temp, _PATH_TMP_XXX, sizeof(temp));
800 fd = mkstemp(temp);
801 if(fd < 0){
802 warn("unable to create temporary file %s", temp);
803 return NULL;
805 close(fd);
806 oldverbose = verbose, verbose = 0;
807 oldhash = hash, hash = 0;
808 if (doswitch) {
809 pswitch(!proxy);
811 for (filemode = "w"; *++argv != NULL; filemode = "a")
812 recvrequest ("NLST", temp, *argv, filemode, 0, 0);
813 if (doswitch) {
814 pswitch(!proxy);
816 verbose = oldverbose; hash = oldhash;
817 ftemp = fopen(temp, "r");
818 unlink(temp);
819 if (ftemp == NULL) {
820 printf("can't find list of remote files, oops\n");
821 return (NULL);
824 while(fgets(buf, sizeof (buf), ftemp)) {
825 if ((cp = strchr(buf, '\n')) != NULL)
826 *cp = '\0';
827 if(!interactive && suspicious_filename(buf)){
828 printf("Ignoring remote globbed file `%s'\n", buf);
829 continue;
831 return buf;
833 fclose(ftemp);
834 ftemp = NULL;
835 return (NULL);
838 char *
839 onoff(int bool)
842 return (bool ? "on" : "off");
846 * Show status.
848 /*ARGSUSED*/
849 void
850 status(int argc, char **argv)
852 int i;
854 if (connected)
855 printf("Connected to %s.\n", hostname);
856 else
857 printf("Not connected.\n");
858 if (!proxy) {
859 pswitch(1);
860 if (connected) {
861 printf("Connected for proxy commands to %s.\n", hostname);
863 else {
864 printf("No proxy connection.\n");
866 pswitch(0);
868 sec_status();
869 printf("Mode: %s; Type: %s; Form: %s; Structure: %s\n",
870 modename, typename, formname, structname);
871 printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s\n",
872 onoff(verbose), onoff(bell), onoff(interactive),
873 onoff(doglob));
874 printf("Store unique: %s; Receive unique: %s\n", onoff(sunique),
875 onoff(runique));
876 printf("Case: %s; CR stripping: %s\n",onoff(mcase),onoff(crflag));
877 if (ntflag) {
878 printf("Ntrans: (in) %s (out) %s\n", ntin,ntout);
880 else {
881 printf("Ntrans: off\n");
883 if (mapflag) {
884 printf("Nmap: (in) %s (out) %s\n", mapin, mapout);
886 else {
887 printf("Nmap: off\n");
889 printf("Hash mark printing: %s; Use of PORT cmds: %s\n",
890 onoff(hash), onoff(sendport));
891 if (macnum > 0) {
892 printf("Macros:\n");
893 for (i=0; i<macnum; i++) {
894 printf("\t%s\n",macros[i].mac_name);
897 code = 0;
901 * Set beep on cmd completed mode.
903 /*VARARGS*/
904 void
905 setbell(int argc, char **argv)
908 bell = !bell;
909 printf("Bell mode %s.\n", onoff(bell));
910 code = bell;
914 * Turn on packet tracing.
916 /*VARARGS*/
917 void
918 settrace(int argc, char **argv)
921 trace = !trace;
922 printf("Packet tracing %s.\n", onoff(trace));
923 code = trace;
927 * Toggle hash mark printing during transfers.
929 /*VARARGS*/
930 void
931 sethash(int argc, char **argv)
934 hash = !hash;
935 printf("Hash mark printing %s", onoff(hash));
936 code = hash;
937 if (hash)
938 printf(" (%d bytes/hash mark)", 1024);
939 printf(".\n");
943 * Turn on printing of server echo's.
945 /*VARARGS*/
946 void
947 setverbose(int argc, char **argv)
950 verbose = !verbose;
951 printf("Verbose mode %s.\n", onoff(verbose));
952 code = verbose;
956 * Toggle PORT cmd use before each data connection.
958 /*VARARGS*/
959 void
960 setport(int argc, char **argv)
963 sendport = !sendport;
964 printf("Use of PORT cmds %s.\n", onoff(sendport));
965 code = sendport;
969 * Turn on interactive prompting
970 * during mget, mput, and mdelete.
972 /*VARARGS*/
973 void
974 setprompt(int argc, char **argv)
977 interactive = !interactive;
978 printf("Interactive mode %s.\n", onoff(interactive));
979 code = interactive;
983 * Toggle metacharacter interpretation
984 * on local file names.
986 /*VARARGS*/
987 void
988 setglob(int argc, char **argv)
991 doglob = !doglob;
992 printf("Globbing %s.\n", onoff(doglob));
993 code = doglob;
997 * Set debugging mode on/off and/or
998 * set level of debugging.
1000 /*VARARGS*/
1001 void
1002 setdebug(int argc, char **argv)
1004 int val;
1006 if (argc > 1) {
1007 val = atoi(argv[1]);
1008 if (val < 0) {
1009 printf("%s: bad debugging value.\n", argv[1]);
1010 code = -1;
1011 return;
1013 } else
1014 val = !debug;
1015 debug = val;
1016 if (debug)
1017 options |= SO_DEBUG;
1018 else
1019 options &= ~SO_DEBUG;
1020 printf("Debugging %s (debug=%d).\n", onoff(debug), debug);
1021 code = debug > 0;
1025 * Set current working directory
1026 * on remote machine.
1028 void
1029 cd(int argc, char **argv)
1032 if (argc < 2 && !another(&argc, &argv, "remote-directory")) {
1033 printf("usage: %s remote-directory\n", argv[0]);
1034 code = -1;
1035 return;
1037 if (command("CWD %s", argv[1]) == ERROR && code == 500) {
1038 if (verbose)
1039 printf("CWD command not recognized, trying XCWD\n");
1040 command("XCWD %s", argv[1]);
1045 * Set current working directory
1046 * on local machine.
1048 void
1049 lcd(int argc, char **argv)
1051 char buf[MaxPathLen];
1053 if (argc < 2)
1054 argc++, argv[1] = home;
1055 if (argc != 2) {
1056 printf("usage: %s local-directory\n", argv[0]);
1057 code = -1;
1058 return;
1060 if (!globulize(&argv[1])) {
1061 code = -1;
1062 return;
1064 if (chdir(argv[1]) < 0) {
1065 warn("local: %s", argv[1]);
1066 code = -1;
1067 return;
1069 if (getcwd(buf, sizeof(buf)) != NULL)
1070 printf("Local directory now %s\n", buf);
1071 else
1072 warnx("getwd: %s", buf);
1073 code = 0;
1077 * Delete a single file.
1079 void
1080 delete(int argc, char **argv)
1083 if (argc < 2 && !another(&argc, &argv, "remote-file")) {
1084 printf("usage: %s remote-file\n", argv[0]);
1085 code = -1;
1086 return;
1088 command("DELE %s", argv[1]);
1092 * Delete multiple files.
1094 void
1095 mdelete(int argc, char **argv)
1097 sighand oldintr;
1098 int ointer;
1099 char *cp;
1101 if (argc < 2 && !another(&argc, &argv, "remote-files")) {
1102 printf("usage: %s remote-files\n", argv[0]);
1103 code = -1;
1104 return;
1106 mname = argv[0];
1107 mflag = 1;
1108 oldintr = signal(SIGINT, mabort);
1109 setjmp(jabort);
1110 while ((cp = remglob(argv,0)) != NULL) {
1111 if (*cp == '\0') {
1112 mflag = 0;
1113 continue;
1115 if (mflag && confirm(argv[0], cp)) {
1116 command("DELE %s", cp);
1117 if (!mflag && fromatty) {
1118 ointer = interactive;
1119 interactive = 1;
1120 if (confirm("Continue with", "mdelete")) {
1121 mflag++;
1123 interactive = ointer;
1127 signal(SIGINT, oldintr);
1128 mflag = 0;
1132 * Rename a remote file.
1134 void
1135 renamefile(int argc, char **argv)
1138 if (argc < 2 && !another(&argc, &argv, "from-name"))
1139 goto usage;
1140 if (argc < 3 && !another(&argc, &argv, "to-name")) {
1141 usage:
1142 printf("%s from-name to-name\n", argv[0]);
1143 code = -1;
1144 return;
1146 if (command("RNFR %s", argv[1]) == CONTINUE)
1147 command("RNTO %s", argv[2]);
1151 * Get a directory listing
1152 * of remote files.
1154 void
1155 ls(int argc, char **argv)
1157 char *cmd;
1159 if (argc < 2)
1160 argc++, argv[1] = NULL;
1161 if (argc < 3)
1162 argc++, argv[2] = "-";
1163 if (argc > 3) {
1164 printf("usage: %s remote-directory local-file\n", argv[0]);
1165 code = -1;
1166 return;
1168 cmd = argv[0][0] == 'n' ? "NLST" : "LIST";
1169 if (strcmp(argv[2], "-") && !globulize(&argv[2])) {
1170 code = -1;
1171 return;
1173 if (strcmp(argv[2], "-") && *argv[2] != '|')
1174 if (!globulize(&argv[2]) || !confirm("output to local-file:",
1175 argv[2])) {
1176 code = -1;
1177 return;
1179 recvrequest(cmd, argv[2], argv[1], "w", 0, 1);
1183 * Get a directory listing
1184 * of multiple remote files.
1186 void
1187 mls(int argc, char **argv)
1189 sighand oldintr;
1190 int ointer, i;
1191 char *cmd, filemode[2], *dest;
1193 if (argc < 2 && !another(&argc, &argv, "remote-files"))
1194 goto usage;
1195 if (argc < 3 && !another(&argc, &argv, "local-file")) {
1196 usage:
1197 printf("usage: %s remote-files local-file\n", argv[0]);
1198 code = -1;
1199 return;
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;
1209 cmd = argv[0][1] == 'l' ? "NLST" : "LIST";
1210 mname = argv[0];
1211 mflag = 1;
1212 oldintr = signal(SIGINT, mabort);
1213 setjmp(jabort);
1214 filemode[1] = '\0';
1215 for (i = 1; mflag && i < argc-1; ++i) {
1216 *filemode = (i == 1) ? 'w' : 'a';
1217 recvrequest(cmd, dest, argv[i], filemode, 0, 1);
1218 if (!mflag && fromatty) {
1219 ointer = interactive;
1220 interactive = 1;
1221 if (confirm("Continue with", argv[0])) {
1222 mflag ++;
1224 interactive = ointer;
1227 signal(SIGINT, oldintr);
1228 mflag = 0;
1232 * Do a shell escape
1234 /*ARGSUSED*/
1235 void
1236 shell(int argc, char **argv)
1238 pid_t pid;
1239 RETSIGTYPE (*old1)(int), (*old2)(int);
1240 char shellnam[40], *shellpath, *namep;
1241 int waitstatus;
1243 old1 = signal (SIGINT, SIG_IGN);
1244 old2 = signal (SIGQUIT, SIG_IGN);
1245 if ((pid = fork()) == 0) {
1246 for (pid = 3; pid < 20; pid++)
1247 close(pid);
1248 signal(SIGINT, SIG_DFL);
1249 signal(SIGQUIT, SIG_DFL);
1250 shellpath = getenv("SHELL");
1251 if (shellpath == NULL)
1252 shellpath = _PATH_BSHELL;
1253 namep = strrchr(shellpath, '/');
1254 if (namep == NULL)
1255 namep = shellpath;
1256 snprintf (shellnam, sizeof(shellnam),
1257 "-%s", ++namep);
1258 if (strcmp(namep, "sh") != 0)
1259 shellnam[0] = '+';
1260 if (debug) {
1261 printf ("%s\n", shellpath);
1262 fflush (stdout);
1264 if (argc > 1) {
1265 execl(shellpath,shellnam,"-c",altarg,(char *)0);
1267 else {
1268 execl(shellpath,shellnam,(char *)0);
1270 warn("%s", shellpath);
1271 code = -1;
1272 exit(1);
1274 if (pid > 0)
1275 while (waitpid(-1, &waitstatus, 0) != pid)
1277 signal(SIGINT, old1);
1278 signal(SIGQUIT, old2);
1279 if (pid == -1) {
1280 warn("%s", "Try again later");
1281 code = -1;
1283 else {
1284 code = 0;
1289 * Send new user information (re-login)
1291 void
1292 user(int argc, char **argv)
1294 char acctstr[80];
1295 int n, aflag = 0;
1296 char tmp[256];
1298 if (argc < 2)
1299 another(&argc, &argv, "username");
1300 if (argc < 2 || argc > 4) {
1301 printf("usage: %s username [password] [account]\n", argv[0]);
1302 code = -1;
1303 return;
1305 n = command("USER %s", argv[1]);
1306 if (n == CONTINUE) {
1307 if (argc < 3 ) {
1308 UI_UTIL_read_pw_string (tmp,
1309 sizeof(tmp),
1310 "Password: ", 0);
1311 argv[2] = tmp;
1312 argc++;
1314 n = command("PASS %s", argv[2]);
1316 if (n == CONTINUE) {
1317 if (argc < 4) {
1318 printf("Account: "); fflush(stdout);
1319 fgets(acctstr, sizeof(acctstr) - 1, stdin);
1320 acctstr[strcspn(acctstr, "\r\n")] = '\0';
1321 argv[3] = acctstr; argc++;
1323 n = command("ACCT %s", argv[3]);
1324 aflag++;
1326 if (n != COMPLETE) {
1327 fprintf(stdout, "Login failed.\n");
1328 return;
1330 if (!aflag && argc == 4) {
1331 command("ACCT %s", argv[3]);
1336 * Print working directory.
1338 /*VARARGS*/
1339 void
1340 pwd(int argc, char **argv)
1342 int oldverbose = verbose;
1345 * If we aren't verbose, this doesn't do anything!
1347 verbose = 1;
1348 if (command("PWD") == ERROR && code == 500) {
1349 printf("PWD command not recognized, trying XPWD\n");
1350 command("XPWD");
1352 verbose = oldverbose;
1356 * Make a directory.
1358 void
1359 makedir(int argc, char **argv)
1362 if (argc < 2 && !another(&argc, &argv, "directory-name")) {
1363 printf("usage: %s directory-name\n", argv[0]);
1364 code = -1;
1365 return;
1367 if (command("MKD %s", argv[1]) == ERROR && code == 500) {
1368 if (verbose)
1369 printf("MKD command not recognized, trying XMKD\n");
1370 command("XMKD %s", argv[1]);
1375 * Remove a directory.
1377 void
1378 removedir(int argc, char **argv)
1381 if (argc < 2 && !another(&argc, &argv, "directory-name")) {
1382 printf("usage: %s directory-name\n", argv[0]);
1383 code = -1;
1384 return;
1386 if (command("RMD %s", argv[1]) == ERROR && code == 500) {
1387 if (verbose)
1388 printf("RMD command not recognized, trying XRMD\n");
1389 command("XRMD %s", argv[1]);
1394 * Send a line, verbatim, to the remote machine.
1396 void
1397 quote(int argc, char **argv)
1400 if (argc < 2 && !another(&argc, &argv, "command line to send")) {
1401 printf("usage: %s line-to-send\n", argv[0]);
1402 code = -1;
1403 return;
1405 quote1("", argc, argv);
1409 * Send a SITE command to the remote machine. The line
1410 * is sent verbatim to the remote machine, except that the
1411 * word "SITE" is added at the front.
1413 void
1414 site(int argc, char **argv)
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;
1422 quote1("SITE ", argc, argv);
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.
1429 void
1430 quote1(char *initial, int argc, char **argv)
1432 int i;
1433 char buf[BUFSIZ]; /* must be >= sizeof(line) */
1435 strlcpy(buf, initial, sizeof(buf));
1436 for(i = 1; i < argc; i++) {
1437 if(i > 1)
1438 strlcat(buf, " ", sizeof(buf));
1439 strlcat(buf, argv[i], sizeof(buf));
1441 if (command("%s", buf) == PRELIM) {
1442 while (getreply(0) == PRELIM)
1443 continue;
1447 void
1448 do_chmod(int argc, char **argv)
1451 if (argc < 2 && !another(&argc, &argv, "mode"))
1452 goto usage;
1453 if (argc < 3 && !another(&argc, &argv, "file-name")) {
1454 usage:
1455 printf("usage: %s mode file-name\n", argv[0]);
1456 code = -1;
1457 return;
1459 command("SITE CHMOD %s %s", argv[1], argv[2]);
1462 void
1463 do_umask(int argc, char **argv)
1465 int oldverbose = verbose;
1467 verbose = 1;
1468 command(argc == 1 ? "SITE UMASK" : "SITE UMASK %s", argv[1]);
1469 verbose = oldverbose;
1472 void
1473 ftp_idle(int argc, char **argv)
1475 int oldverbose = verbose;
1477 verbose = 1;
1478 command(argc == 1 ? "SITE IDLE" : "SITE IDLE %s", argv[1]);
1479 verbose = oldverbose;
1483 * Ask the other side for help.
1485 void
1486 rmthelp(int argc, char **argv)
1488 int oldverbose = verbose;
1490 verbose = 1;
1491 command(argc == 1 ? "HELP" : "HELP %s", argv[1]);
1492 verbose = oldverbose;
1496 * Terminate session and exit.
1498 /*VARARGS*/
1499 void
1500 quit(int argc, char **argv)
1503 if (connected)
1504 disconnect(0, 0);
1505 pswitch(1);
1506 if (connected) {
1507 disconnect(0, 0);
1509 exit(0);
1513 * Terminate session, but don't exit.
1515 void
1516 disconnect(int argc, char **argv)
1519 if (!connected)
1520 return;
1521 command("QUIT");
1522 if (cout) {
1523 fclose(cout);
1525 cout = NULL;
1526 connected = 0;
1527 sec_end();
1528 data = -1;
1529 if (!proxy) {
1530 macnum = 0;
1535 confirm(char *cmd, char *file)
1537 char buf[BUFSIZ];
1539 if (!interactive)
1540 return (1);
1541 printf("%s %s? ", cmd, file);
1542 fflush(stdout);
1543 if (fgets(buf, sizeof buf, stdin) == NULL)
1544 return (0);
1545 return (*buf == 'y' || *buf == 'Y');
1548 void
1549 fatal(char *msg)
1552 errx(1, "%s", msg);
1556 * Glob a local file name specification with
1557 * the expectation of a single return value.
1558 * Can't control multiple values being expanded
1559 * from the expression, we return only the first.
1562 globulize(char **cpp)
1564 glob_t gl;
1565 int flags;
1567 if (!doglob)
1568 return (1);
1570 flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE;
1571 memset(&gl, 0, sizeof(gl));
1572 if (glob(*cpp, flags, NULL, &gl) ||
1573 gl.gl_pathc == 0) {
1574 warnx("%s: not found", *cpp);
1575 globfree(&gl);
1576 return (0);
1578 *cpp = strdup(gl.gl_pathv[0]); /* XXX - wasted memory */
1579 globfree(&gl);
1580 return (1);
1583 void
1584 account(int argc, char **argv)
1586 char acctstr[50];
1588 if (argc > 1) {
1589 ++argv;
1590 --argc;
1591 strlcpy (acctstr, *argv, sizeof(acctstr));
1592 while (argc > 1) {
1593 --argc;
1594 ++argv;
1595 strlcat(acctstr, *argv, sizeof(acctstr));
1598 else {
1599 UI_UTIL_read_pw_string(acctstr, sizeof(acctstr), "Account:", 0);
1601 command("ACCT %s", acctstr);
1604 jmp_buf abortprox;
1606 static RETSIGTYPE
1607 proxabort(int sig)
1610 if (!proxy) {
1611 pswitch(1);
1613 if (connected) {
1614 proxflag = 1;
1616 else {
1617 proxflag = 0;
1619 pswitch(0);
1620 longjmp(abortprox,1);
1623 void
1624 doproxy(int argc, char **argv)
1626 struct cmd *c;
1627 RETSIGTYPE (*oldintr)(int);
1629 if (argc < 2 && !another(&argc, &argv, "command")) {
1630 printf("usage: %s command\n", argv[0]);
1631 code = -1;
1632 return;
1634 c = getcmd(argv[1]);
1635 if (c == (struct cmd *) -1) {
1636 printf("?Ambiguous command\n");
1637 fflush(stdout);
1638 code = -1;
1639 return;
1641 if (c == 0) {
1642 printf("?Invalid command\n");
1643 fflush(stdout);
1644 code = -1;
1645 return;
1647 if (!c->c_proxy) {
1648 printf("?Invalid proxy command\n");
1649 fflush(stdout);
1650 code = -1;
1651 return;
1653 if (setjmp(abortprox)) {
1654 code = -1;
1655 return;
1657 oldintr = signal(SIGINT, proxabort);
1658 pswitch(1);
1659 if (c->c_conn && !connected) {
1660 printf("Not connected\n");
1661 fflush(stdout);
1662 pswitch(0);
1663 signal(SIGINT, oldintr);
1664 code = -1;
1665 return;
1667 (*c->c_handler)(argc-1, argv+1);
1668 if (connected) {
1669 proxflag = 1;
1671 else {
1672 proxflag = 0;
1674 pswitch(0);
1675 signal(SIGINT, oldintr);
1678 void
1679 setcase(int argc, char **argv)
1682 mcase = !mcase;
1683 printf("Case mapping %s.\n", onoff(mcase));
1684 code = mcase;
1687 void
1688 setcr(int argc, char **argv)
1691 crflag = !crflag;
1692 printf("Carriage Return stripping %s.\n", onoff(crflag));
1693 code = crflag;
1696 void
1697 setntrans(int argc, char **argv)
1699 if (argc == 1) {
1700 ntflag = 0;
1701 printf("Ntrans off.\n");
1702 code = ntflag;
1703 return;
1705 ntflag++;
1706 code = ntflag;
1707 strlcpy (ntin, argv[1], 17);
1708 if (argc == 2) {
1709 ntout[0] = '\0';
1710 return;
1712 strlcpy (ntout, argv[2], 17);
1715 char *
1716 dotrans(char *name)
1718 static char new[MaxPathLen];
1719 char *cp1, *cp2 = new;
1720 int i, ostop, found;
1722 for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++)
1723 continue;
1724 for (cp1 = name; *cp1; cp1++) {
1725 found = 0;
1726 for (i = 0; *(ntin + i) && i < 16; i++) {
1727 if (*cp1 == *(ntin + i)) {
1728 found++;
1729 if (i < ostop) {
1730 *cp2++ = *(ntout + i);
1732 break;
1735 if (!found) {
1736 *cp2++ = *cp1;
1739 *cp2 = '\0';
1740 return (new);
1743 void
1744 setnmap(int argc, char **argv)
1746 char *cp;
1748 if (argc == 1) {
1749 mapflag = 0;
1750 printf("Nmap off.\n");
1751 code = mapflag;
1752 return;
1754 if (argc < 3 && !another(&argc, &argv, "mapout")) {
1755 printf("Usage: %s [mapin mapout]\n",argv[0]);
1756 code = -1;
1757 return;
1759 mapflag = 1;
1760 code = 1;
1761 cp = strchr(altarg, ' ');
1762 if (cp == NULL) {
1763 printf("Usage: %s missing space\n",argv[0]);
1764 code = -1;
1765 return;
1767 if (proxy) {
1768 while(*++cp == ' ')
1769 continue;
1770 altarg = cp;
1771 cp = strchr(altarg, ' ');
1773 *cp = '\0';
1774 strlcpy(mapin, altarg, MaxPathLen);
1775 while (*++cp == ' ')
1776 continue;
1777 strlcpy(mapout, cp, MaxPathLen);
1780 char *
1781 domap(char *name)
1783 static char new[MaxPathLen];
1784 char *cp1 = name, *cp2 = mapin;
1785 char *tp[9], *te[9];
1786 int i, toks[9], toknum = 0, match = 1;
1788 for (i=0; i < 9; ++i) {
1789 toks[i] = 0;
1791 while (match && *cp1 && *cp2) {
1792 switch (*cp2) {
1793 case '\\':
1794 if (*++cp2 != *cp1) {
1795 match = 0;
1797 break;
1798 case '$':
1799 if (*(cp2+1) >= '1' && (*cp2+1) <= '9') {
1800 if (*cp1 != *(++cp2+1)) {
1801 toks[toknum = *cp2 - '1']++;
1802 tp[toknum] = cp1;
1803 while (*++cp1 && *(cp2+1)
1804 != *cp1);
1805 te[toknum] = cp1;
1807 cp2++;
1808 break;
1810 /* FALLTHROUGH */
1811 default:
1812 if (*cp2 != *cp1) {
1813 match = 0;
1815 break;
1817 if (match && *cp1) {
1818 cp1++;
1820 if (match && *cp2) {
1821 cp2++;
1824 if (!match && *cp1) /* last token mismatch */
1826 toks[toknum] = 0;
1828 cp1 = new;
1829 *cp1 = '\0';
1830 cp2 = mapout;
1831 while (*cp2) {
1832 match = 0;
1833 switch (*cp2) {
1834 case '\\':
1835 if (*(cp2 + 1)) {
1836 *cp1++ = *++cp2;
1838 break;
1839 case '[':
1840 LOOP:
1841 if (*++cp2 == '$' && isdigit((unsigned char)*(cp2+1))) {
1842 if (*++cp2 == '0') {
1843 char *cp3 = name;
1845 while (*cp3) {
1846 *cp1++ = *cp3++;
1848 match = 1;
1850 else if (toks[toknum = *cp2 - '1']) {
1851 char *cp3 = tp[toknum];
1853 while (cp3 != te[toknum]) {
1854 *cp1++ = *cp3++;
1856 match = 1;
1859 else {
1860 while (*cp2 && *cp2 != ',' &&
1861 *cp2 != ']') {
1862 if (*cp2 == '\\') {
1863 cp2++;
1865 else if (*cp2 == '$' &&
1866 isdigit((unsigned char)*(cp2+1))) {
1867 if (*++cp2 == '0') {
1868 char *cp3 = name;
1870 while (*cp3) {
1871 *cp1++ = *cp3++;
1874 else if (toks[toknum =
1875 *cp2 - '1']) {
1876 char *cp3=tp[toknum];
1878 while (cp3 !=
1879 te[toknum]) {
1880 *cp1++ = *cp3++;
1884 else if (*cp2) {
1885 *cp1++ = *cp2++;
1888 if (!*cp2) {
1889 printf("nmap: unbalanced brackets\n");
1890 return (name);
1892 match = 1;
1893 cp2--;
1895 if (match) {
1896 while (*++cp2 && *cp2 != ']') {
1897 if (*cp2 == '\\' && *(cp2 + 1)) {
1898 cp2++;
1901 if (!*cp2) {
1902 printf("nmap: unbalanced brackets\n");
1903 return (name);
1905 break;
1907 switch (*++cp2) {
1908 case ',':
1909 goto LOOP;
1910 case ']':
1911 break;
1912 default:
1913 cp2--;
1914 goto LOOP;
1916 break;
1917 case '$':
1918 if (isdigit((unsigned char)*(cp2 + 1))) {
1919 if (*++cp2 == '0') {
1920 char *cp3 = name;
1922 while (*cp3) {
1923 *cp1++ = *cp3++;
1926 else if (toks[toknum = *cp2 - '1']) {
1927 char *cp3 = tp[toknum];
1929 while (cp3 != te[toknum]) {
1930 *cp1++ = *cp3++;
1933 break;
1935 /* intentional drop through */
1936 default:
1937 *cp1++ = *cp2;
1938 break;
1940 cp2++;
1942 *cp1 = '\0';
1943 if (!*new) {
1944 return (name);
1946 return (new);
1949 void
1950 setpassive(int argc, char **argv)
1953 passivemode = !passivemode;
1954 printf("Passive mode %s.\n", onoff(passivemode));
1955 code = passivemode;
1958 void
1959 setsunique(int argc, char **argv)
1962 sunique = !sunique;
1963 printf("Store unique %s.\n", onoff(sunique));
1964 code = sunique;
1967 void
1968 setrunique(int argc, char **argv)
1971 runique = !runique;
1972 printf("Receive unique %s.\n", onoff(runique));
1973 code = runique;
1976 /* change directory to perent directory */
1977 void
1978 cdup(int argc, char **argv)
1981 if (command("CDUP") == ERROR && code == 500) {
1982 if (verbose)
1983 printf("CDUP command not recognized, trying XCUP\n");
1984 command("XCUP");
1988 /* restart transfer at specific point */
1989 void
1990 restart(int argc, char **argv)
1993 if (argc != 2)
1994 printf("restart: offset not specified\n");
1995 else {
1996 restart_point = atol(argv[1]);
1997 printf("restarting at %ld. %s\n", (long)restart_point,
1998 "execute get, put or append to initiate transfer");
2002 /* show remote system type */
2003 void
2004 syst(int argc, char **argv)
2007 command("SYST");
2010 void
2011 macdef(int argc, char **argv)
2013 char *tmp;
2014 int c;
2016 if (macnum == 16) {
2017 printf("Limit of 16 macros have already been defined\n");
2018 code = -1;
2019 return;
2021 if (argc < 2 && !another(&argc, &argv, "macro name")) {
2022 printf("Usage: %s macro_name\n",argv[0]);
2023 code = -1;
2024 return;
2026 if (interactive) {
2027 printf("Enter macro line by line, terminating it with a null line\n");
2029 strlcpy(macros[macnum].mac_name,
2030 argv[1],
2031 sizeof(macros[macnum].mac_name));
2032 if (macnum == 0) {
2033 macros[macnum].mac_start = macbuf;
2035 else {
2036 macros[macnum].mac_start = macros[macnum - 1].mac_end + 1;
2038 tmp = macros[macnum].mac_start;
2039 while (tmp != macbuf+4096) {
2040 if ((c = getchar()) == EOF) {
2041 printf("macdef:end of file encountered\n");
2042 code = -1;
2043 return;
2045 if ((*tmp = c) == '\n') {
2046 if (tmp == macros[macnum].mac_start) {
2047 macros[macnum++].mac_end = tmp;
2048 code = 0;
2049 return;
2051 if (*(tmp-1) == '\0') {
2052 macros[macnum++].mac_end = tmp - 1;
2053 code = 0;
2054 return;
2056 *tmp = '\0';
2058 tmp++;
2060 while (1) {
2061 while ((c = getchar()) != '\n' && c != EOF)
2062 /* LOOP */;
2063 if (c == EOF || getchar() == '\n') {
2064 printf("Macro not defined - 4k buffer exceeded\n");
2065 code = -1;
2066 return;
2072 * get size of file on remote machine
2074 void
2075 sizecmd(int argc, char **argv)
2078 if (argc < 2 && !another(&argc, &argv, "filename")) {
2079 printf("usage: %s filename\n", argv[0]);
2080 code = -1;
2081 return;
2083 command("SIZE %s", argv[1]);
2087 * get last modification time of file on remote machine
2089 void
2090 modtime(int argc, char **argv)
2092 int overbose;
2094 if (argc < 2 && !another(&argc, &argv, "filename")) {
2095 printf("usage: %s filename\n", argv[0]);
2096 code = -1;
2097 return;
2099 overbose = verbose;
2100 if (debug == 0)
2101 verbose = -1;
2102 if (command("MDTM %s", argv[1]) == COMPLETE) {
2103 int yy, mo, day, hour, min, sec;
2104 sscanf(reply_string, "%*s %04d%02d%02d%02d%02d%02d", &yy, &mo,
2105 &day, &hour, &min, &sec);
2106 /* might want to print this in local time */
2107 printf("%s\t%02d/%02d/%04d %02d:%02d:%02d GMT\n", argv[1],
2108 mo, day, yy, hour, min, sec);
2109 } else
2110 printf("%s\n", reply_string);
2111 verbose = overbose;
2115 * show status on reomte machine
2117 void
2118 rmtstatus(int argc, char **argv)
2121 command(argc > 1 ? "STAT %s" : "STAT" , argv[1]);
2125 * get file if modtime is more recent than current file
2127 void
2128 newer(int argc, char **argv)
2131 if (getit(argc, argv, -1, curtype == TYPE_I ? "wb" : "w"))
2132 printf("Local file \"%s\" is newer than remote file \"%s\"\n",
2133 argv[2], argv[1]);
2136 void
2137 klist(int argc, char **argv)
2139 int ret;
2140 if(argc != 1){
2141 printf("usage: %s\n", argv[0]);
2142 code = -1;
2143 return;
2146 ret = command("SITE KLIST");
2147 code = (ret == COMPLETE);