Fix some typos.
[heimdal.git] / appl / ftp / ftp / cmds.c
blobceb127ed39737f928a07d8995cd959edb6e313ad
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 transferring 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, NULL, 0, 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 if (fgets(acctstr, sizeof(acctstr) - 1, stdin) == NULL)
1320 acctstr[0] = '\0';
1321 acctstr[strcspn(acctstr, "\r\n")] = '\0';
1322 argv[3] = acctstr; argc++;
1324 n = command("ACCT %s", argv[3]);
1325 aflag++;
1327 if (n != COMPLETE) {
1328 fprintf(stdout, "Login failed.\n");
1329 return;
1331 if (!aflag && argc == 4) {
1332 command("ACCT %s", argv[3]);
1337 * Print working directory.
1339 /*VARARGS*/
1340 void
1341 pwd(int argc, char **argv)
1343 int oldverbose = verbose;
1346 * If we aren't verbose, this doesn't do anything!
1348 verbose = 1;
1349 if (command("PWD") == ERROR && code == 500) {
1350 printf("PWD command not recognized, trying XPWD\n");
1351 command("XPWD");
1353 verbose = oldverbose;
1357 * Make a directory.
1359 void
1360 makedir(int argc, char **argv)
1363 if (argc < 2 && !another(&argc, &argv, "directory-name")) {
1364 printf("usage: %s directory-name\n", argv[0]);
1365 code = -1;
1366 return;
1368 if (command("MKD %s", argv[1]) == ERROR && code == 500) {
1369 if (verbose)
1370 printf("MKD command not recognized, trying XMKD\n");
1371 command("XMKD %s", argv[1]);
1376 * Remove a directory.
1378 void
1379 removedir(int argc, char **argv)
1382 if (argc < 2 && !another(&argc, &argv, "directory-name")) {
1383 printf("usage: %s directory-name\n", argv[0]);
1384 code = -1;
1385 return;
1387 if (command("RMD %s", argv[1]) == ERROR && code == 500) {
1388 if (verbose)
1389 printf("RMD command not recognized, trying XRMD\n");
1390 command("XRMD %s", argv[1]);
1395 * Send a line, verbatim, to the remote machine.
1397 void
1398 quote(int argc, char **argv)
1401 if (argc < 2 && !another(&argc, &argv, "command line to send")) {
1402 printf("usage: %s line-to-send\n", argv[0]);
1403 code = -1;
1404 return;
1406 quote1("", argc, argv);
1410 * Send a SITE command to the remote machine. The line
1411 * is sent verbatim to the remote machine, except that the
1412 * word "SITE" is added at the front.
1414 void
1415 site(int argc, char **argv)
1418 if (argc < 2 && !another(&argc, &argv, "arguments to SITE command")) {
1419 printf("usage: %s line-to-send\n", argv[0]);
1420 code = -1;
1421 return;
1423 quote1("SITE ", argc, argv);
1427 * Turn argv[1..argc) into a space-separated string, then prepend initial text.
1428 * Send the result as a one-line command and get response.
1430 void
1431 quote1(char *initial, int argc, char **argv)
1433 int i;
1434 char buf[BUFSIZ]; /* must be >= sizeof(line) */
1436 strlcpy(buf, initial, sizeof(buf));
1437 for(i = 1; i < argc; i++) {
1438 if(i > 1)
1439 strlcat(buf, " ", sizeof(buf));
1440 strlcat(buf, argv[i], sizeof(buf));
1442 if (command("%s", buf) == PRELIM) {
1443 while (getreply(0) == PRELIM)
1444 continue;
1448 void
1449 do_chmod(int argc, char **argv)
1452 if (argc < 2 && !another(&argc, &argv, "mode"))
1453 goto usage;
1454 if (argc < 3 && !another(&argc, &argv, "file-name")) {
1455 usage:
1456 printf("usage: %s mode file-name\n", argv[0]);
1457 code = -1;
1458 return;
1460 command("SITE CHMOD %s %s", argv[1], argv[2]);
1463 void
1464 do_umask(int argc, char **argv)
1466 int oldverbose = verbose;
1468 verbose = 1;
1469 command(argc == 1 ? "SITE UMASK" : "SITE UMASK %s", argv[1]);
1470 verbose = oldverbose;
1473 void
1474 ftp_idle(int argc, char **argv)
1476 int oldverbose = verbose;
1478 verbose = 1;
1479 command(argc == 1 ? "SITE IDLE" : "SITE IDLE %s", argv[1]);
1480 verbose = oldverbose;
1484 * Ask the other side for help.
1486 void
1487 rmthelp(int argc, char **argv)
1489 int oldverbose = verbose;
1491 verbose = 1;
1492 command(argc == 1 ? "HELP" : "HELP %s", argv[1]);
1493 verbose = oldverbose;
1497 * Terminate session and exit.
1499 /*VARARGS*/
1500 void
1501 quit(int argc, char **argv)
1504 if (connected)
1505 disconnect(0, 0);
1506 pswitch(1);
1507 if (connected) {
1508 disconnect(0, 0);
1510 exit(0);
1514 * Terminate session, but don't exit.
1516 void
1517 disconnect(int argc, char **argv)
1520 if (!connected)
1521 return;
1522 command("QUIT");
1523 if (cout) {
1524 fclose(cout);
1526 cout = NULL;
1527 connected = 0;
1528 sec_end();
1529 data = -1;
1530 if (!proxy) {
1531 macnum = 0;
1536 confirm(char *cmd, char *file)
1538 char buf[BUFSIZ];
1540 if (!interactive)
1541 return (1);
1542 printf("%s %s? ", cmd, file);
1543 fflush(stdout);
1544 if (fgets(buf, sizeof buf, stdin) == NULL)
1545 return (0);
1546 return (*buf == 'y' || *buf == 'Y');
1549 void
1550 fatal(char *msg)
1553 errx(1, "%s", msg);
1557 * Glob a local file name specification with
1558 * the expectation of a single return value.
1559 * Can't control multiple values being expanded
1560 * from the expression, we return only the first.
1563 globulize(char **cpp)
1565 glob_t gl;
1566 int flags;
1568 if (!doglob)
1569 return (1);
1571 flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE;
1572 memset(&gl, 0, sizeof(gl));
1573 if (glob(*cpp, flags, NULL, &gl) ||
1574 gl.gl_pathc == 0) {
1575 warnx("%s: not found", *cpp);
1576 globfree(&gl);
1577 return (0);
1579 *cpp = strdup(gl.gl_pathv[0]); /* XXX - wasted memory */
1580 globfree(&gl);
1581 return (1);
1584 void
1585 account(int argc, char **argv)
1587 char acctstr[50];
1589 if (argc > 1) {
1590 ++argv;
1591 --argc;
1592 strlcpy (acctstr, *argv, sizeof(acctstr));
1593 while (argc > 1) {
1594 --argc;
1595 ++argv;
1596 strlcat(acctstr, *argv, sizeof(acctstr));
1599 else {
1600 UI_UTIL_read_pw_string(acctstr, sizeof(acctstr), "Account:", 0);
1602 command("ACCT %s", acctstr);
1605 jmp_buf abortprox;
1607 static RETSIGTYPE
1608 proxabort(int sig)
1611 if (!proxy) {
1612 pswitch(1);
1614 if (connected) {
1615 proxflag = 1;
1617 else {
1618 proxflag = 0;
1620 pswitch(0);
1621 longjmp(abortprox,1);
1624 void
1625 doproxy(int argc, char **argv)
1627 struct cmd *c;
1628 RETSIGTYPE (*oldintr)(int);
1630 if (argc < 2 && !another(&argc, &argv, "command")) {
1631 printf("usage: %s command\n", argv[0]);
1632 code = -1;
1633 return;
1635 c = getcmd(argv[1]);
1636 if (c == (struct cmd *) -1) {
1637 printf("?Ambiguous command\n");
1638 fflush(stdout);
1639 code = -1;
1640 return;
1642 if (c == 0) {
1643 printf("?Invalid command\n");
1644 fflush(stdout);
1645 code = -1;
1646 return;
1648 if (!c->c_proxy) {
1649 printf("?Invalid proxy command\n");
1650 fflush(stdout);
1651 code = -1;
1652 return;
1654 if (setjmp(abortprox)) {
1655 code = -1;
1656 return;
1658 oldintr = signal(SIGINT, proxabort);
1659 pswitch(1);
1660 if (c->c_conn && !connected) {
1661 printf("Not connected\n");
1662 fflush(stdout);
1663 pswitch(0);
1664 signal(SIGINT, oldintr);
1665 code = -1;
1666 return;
1668 (*c->c_handler)(argc-1, argv+1);
1669 if (connected) {
1670 proxflag = 1;
1672 else {
1673 proxflag = 0;
1675 pswitch(0);
1676 signal(SIGINT, oldintr);
1679 void
1680 setcase(int argc, char **argv)
1683 mcase = !mcase;
1684 printf("Case mapping %s.\n", onoff(mcase));
1685 code = mcase;
1688 void
1689 setcr(int argc, char **argv)
1692 crflag = !crflag;
1693 printf("Carriage Return stripping %s.\n", onoff(crflag));
1694 code = crflag;
1697 void
1698 setntrans(int argc, char **argv)
1700 if (argc == 1) {
1701 ntflag = 0;
1702 printf("Ntrans off.\n");
1703 code = ntflag;
1704 return;
1706 ntflag++;
1707 code = ntflag;
1708 strlcpy (ntin, argv[1], 17);
1709 if (argc == 2) {
1710 ntout[0] = '\0';
1711 return;
1713 strlcpy (ntout, argv[2], 17);
1716 char *
1717 dotrans(char *name)
1719 static char new[MaxPathLen];
1720 char *cp1, *cp2 = new;
1721 int i, ostop, found;
1723 for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++)
1724 continue;
1725 for (cp1 = name; *cp1; cp1++) {
1726 found = 0;
1727 for (i = 0; *(ntin + i) && i < 16; i++) {
1728 if (*cp1 == *(ntin + i)) {
1729 found++;
1730 if (i < ostop) {
1731 *cp2++ = *(ntout + i);
1733 break;
1736 if (!found) {
1737 *cp2++ = *cp1;
1740 *cp2 = '\0';
1741 return (new);
1744 void
1745 setnmap(int argc, char **argv)
1747 char *cp;
1749 if (argc == 1) {
1750 mapflag = 0;
1751 printf("Nmap off.\n");
1752 code = mapflag;
1753 return;
1755 if (argc < 3 && !another(&argc, &argv, "mapout")) {
1756 printf("Usage: %s [mapin mapout]\n",argv[0]);
1757 code = -1;
1758 return;
1760 mapflag = 1;
1761 code = 1;
1762 cp = strchr(altarg, ' ');
1763 if (cp == NULL) {
1764 printf("Usage: %s missing space\n",argv[0]);
1765 code = -1;
1766 return;
1768 if (proxy) {
1769 while(*++cp == ' ')
1770 continue;
1771 altarg = cp;
1772 cp = strchr(altarg, ' ');
1774 *cp = '\0';
1775 strlcpy(mapin, altarg, MaxPathLen);
1776 while (*++cp == ' ')
1777 continue;
1778 strlcpy(mapout, cp, MaxPathLen);
1781 char *
1782 domap(char *name)
1784 static char new[MaxPathLen];
1785 char *cp1 = name, *cp2 = mapin;
1786 char *tp[9], *te[9];
1787 int i, toks[9], toknum = 0, match = 1;
1789 for (i=0; i < 9; ++i) {
1790 toks[i] = 0;
1792 while (match && *cp1 && *cp2) {
1793 switch (*cp2) {
1794 case '\\':
1795 if (*++cp2 != *cp1) {
1796 match = 0;
1798 break;
1799 case '$':
1800 if (*(cp2+1) >= '1' && (*cp2+1) <= '9') {
1801 if (*cp1 != *(++cp2+1)) {
1802 toks[toknum = *cp2 - '1']++;
1803 tp[toknum] = cp1;
1804 while (*++cp1 && *(cp2+1)
1805 != *cp1);
1806 te[toknum] = cp1;
1808 cp2++;
1809 break;
1811 /* FALLTHROUGH */
1812 default:
1813 if (*cp2 != *cp1) {
1814 match = 0;
1816 break;
1818 if (match && *cp1) {
1819 cp1++;
1821 if (match && *cp2) {
1822 cp2++;
1825 if (!match && *cp1) /* last token mismatch */
1827 toks[toknum] = 0;
1829 cp1 = new;
1830 *cp1 = '\0';
1831 cp2 = mapout;
1832 while (*cp2) {
1833 match = 0;
1834 switch (*cp2) {
1835 case '\\':
1836 if (*(cp2 + 1)) {
1837 *cp1++ = *++cp2;
1839 break;
1840 case '[':
1841 LOOP:
1842 if (*++cp2 == '$' && isdigit((unsigned char)*(cp2+1))) {
1843 if (*++cp2 == '0') {
1844 char *cp3 = name;
1846 while (*cp3) {
1847 *cp1++ = *cp3++;
1849 match = 1;
1851 else if (toks[toknum = *cp2 - '1']) {
1852 char *cp3 = tp[toknum];
1854 while (cp3 != te[toknum]) {
1855 *cp1++ = *cp3++;
1857 match = 1;
1860 else {
1861 while (*cp2 && *cp2 != ',' &&
1862 *cp2 != ']') {
1863 if (*cp2 == '\\') {
1864 cp2++;
1866 else if (*cp2 == '$' &&
1867 isdigit((unsigned char)*(cp2+1))) {
1868 if (*++cp2 == '0') {
1869 char *cp3 = name;
1871 while (*cp3) {
1872 *cp1++ = *cp3++;
1875 else if (toks[toknum =
1876 *cp2 - '1']) {
1877 char *cp3=tp[toknum];
1879 while (cp3 !=
1880 te[toknum]) {
1881 *cp1++ = *cp3++;
1885 else if (*cp2) {
1886 *cp1++ = *cp2++;
1889 if (!*cp2) {
1890 printf("nmap: unbalanced brackets\n");
1891 return (name);
1893 match = 1;
1894 cp2--;
1896 if (match) {
1897 while (*++cp2 && *cp2 != ']') {
1898 if (*cp2 == '\\' && *(cp2 + 1)) {
1899 cp2++;
1902 if (!*cp2) {
1903 printf("nmap: unbalanced brackets\n");
1904 return (name);
1906 break;
1908 switch (*++cp2) {
1909 case ',':
1910 goto LOOP;
1911 case ']':
1912 break;
1913 default:
1914 cp2--;
1915 goto LOOP;
1917 break;
1918 case '$':
1919 if (isdigit((unsigned char)*(cp2 + 1))) {
1920 if (*++cp2 == '0') {
1921 char *cp3 = name;
1923 while (*cp3) {
1924 *cp1++ = *cp3++;
1927 else if (toks[toknum = *cp2 - '1']) {
1928 char *cp3 = tp[toknum];
1930 while (cp3 != te[toknum]) {
1931 *cp1++ = *cp3++;
1934 break;
1936 /* intentional drop through */
1937 default:
1938 *cp1++ = *cp2;
1939 break;
1941 cp2++;
1943 *cp1 = '\0';
1944 if (!*new) {
1945 return (name);
1947 return (new);
1950 void
1951 setpassive(int argc, char **argv)
1954 passivemode = !passivemode;
1955 printf("Passive mode %s.\n", onoff(passivemode));
1956 code = passivemode;
1959 void
1960 setsunique(int argc, char **argv)
1963 sunique = !sunique;
1964 printf("Store unique %s.\n", onoff(sunique));
1965 code = sunique;
1968 void
1969 setrunique(int argc, char **argv)
1972 runique = !runique;
1973 printf("Receive unique %s.\n", onoff(runique));
1974 code = runique;
1977 /* change directory to perent directory */
1978 void
1979 cdup(int argc, char **argv)
1982 if (command("CDUP") == ERROR && code == 500) {
1983 if (verbose)
1984 printf("CDUP command not recognized, trying XCUP\n");
1985 command("XCUP");
1989 /* restart transfer at specific point */
1990 void
1991 restart(int argc, char **argv)
1994 if (argc != 2)
1995 printf("restart: offset not specified\n");
1996 else {
1997 restart_point = atol(argv[1]);
1998 printf("restarting at %ld. %s\n", (long)restart_point,
1999 "execute get, put or append to initiate transfer");
2003 /* show remote system type */
2004 void
2005 syst(int argc, char **argv)
2008 command("SYST");
2011 void
2012 macdef(int argc, char **argv)
2014 char *tmp;
2015 int c;
2017 if (macnum == 16) {
2018 printf("Limit of 16 macros have already been defined\n");
2019 code = -1;
2020 return;
2022 if (argc < 2 && !another(&argc, &argv, "macro name")) {
2023 printf("Usage: %s macro_name\n",argv[0]);
2024 code = -1;
2025 return;
2027 if (interactive) {
2028 printf("Enter macro line by line, terminating it with a null line\n");
2030 strlcpy(macros[macnum].mac_name,
2031 argv[1],
2032 sizeof(macros[macnum].mac_name));
2033 if (macnum == 0) {
2034 macros[macnum].mac_start = macbuf;
2036 else {
2037 macros[macnum].mac_start = macros[macnum - 1].mac_end + 1;
2039 tmp = macros[macnum].mac_start;
2040 while (tmp != macbuf+4096) {
2041 if ((c = getchar()) == EOF) {
2042 printf("macdef:end of file encountered\n");
2043 code = -1;
2044 return;
2046 if ((*tmp = c) == '\n') {
2047 if (tmp == macros[macnum].mac_start) {
2048 macros[macnum++].mac_end = tmp;
2049 code = 0;
2050 return;
2052 if (*(tmp-1) == '\0') {
2053 macros[macnum++].mac_end = tmp - 1;
2054 code = 0;
2055 return;
2057 *tmp = '\0';
2059 tmp++;
2061 while (1) {
2062 while ((c = getchar()) != '\n' && c != EOF)
2063 /* LOOP */;
2064 if (c == EOF || getchar() == '\n') {
2065 printf("Macro not defined - 4k buffer exceeded\n");
2066 code = -1;
2067 return;
2073 * get size of file on remote machine
2075 void
2076 sizecmd(int argc, char **argv)
2079 if (argc < 2 && !another(&argc, &argv, "filename")) {
2080 printf("usage: %s filename\n", argv[0]);
2081 code = -1;
2082 return;
2084 command("SIZE %s", argv[1]);
2088 * get last modification time of file on remote machine
2090 void
2091 modtime(int argc, char **argv)
2093 int overbose;
2095 if (argc < 2 && !another(&argc, &argv, "filename")) {
2096 printf("usage: %s filename\n", argv[0]);
2097 code = -1;
2098 return;
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;
2116 * show status on reomte machine
2118 void
2119 rmtstatus(int argc, char **argv)
2122 command(argc > 1 ? "STAT %s" : "STAT" , argv[1]);
2126 * get file if modtime is more recent than current file
2128 void
2129 newer(int argc, char **argv)
2132 if (getit(argc, argv, -1, curtype == TYPE_I ? "wb" : "w"))
2133 printf("Local file \"%s\" is newer than remote file \"%s\"\n",
2134 argv[2], argv[1]);
2137 void
2138 klist(int argc, char **argv)
2140 int ret;
2141 if(argc != 1){
2142 printf("usage: %s\n", argv[0]);
2143 code = -1;
2144 return;
2147 ret = command("SITE KLIST");
2148 code = (ret == COMPLETE);