feature_tests.h: repurpose __UNLEASHED_VISIBLE
[unleashed.git] / usr / src / cmd / cmd-inet / usr.bin / ftp / cmds.c
blobd53545f31d8754369965f4314ef4d861a3000c65
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
30 * University Copyright- Copyright (c) 1982, 1986, 1988
31 * The Regents of the University of California
32 * All Rights Reserved
34 * University Acknowledgment- Portions of this document are derived from
35 * software developed by the University of California, Berkeley, and its
36 * contributors.
40 * FTP User Program -- Command Routines.
42 #define FTP_NAMES
43 #include "ftp_var.h"
45 FILE *tmp_nlst = NULL; /* tmp file; holds NLST results for mget, etc */
47 static char *mname;
48 static jmp_buf jabort;
49 static jmp_buf abortprox;
51 static char *remglob(char *argv[], int doswitch);
52 static char *onoff(int bool);
53 static int confirm(char *cmd, char *file);
54 static int globulize(char **cpp);
55 static void proxabort(int sig);
56 static void mabort(int sig);
57 static char *dotrans(char *name);
58 static char *domap(char *name);
59 static void getit(int argc, char *argv[], int restartit, char *mode);
61 static char *getlevel(int);
63 /* Prompt for command argument, add to buffer with space separator */
64 static int
65 prompt_for_arg(char *buffer, int buffer_size, char *prompt)
67 if (strlen(buffer) > buffer_size - 2) {
68 (void) printf("Line too long\n");
69 return (-1);
71 strcat(buffer, " ");
72 stop_timer();
73 (void) printf("(%s) ", prompt);
74 if (fgets(buffer + strlen(buffer), buffer_size - strlen(buffer), stdin)
75 == NULL) {
76 reset_timer();
77 return (-1);
80 /* Flush what didn't fit in the buffer */
81 if (buffer[strlen(buffer)-1] != '\n') {
82 while (fgetc(stdin) != '\n' && !ferror(stdin) && !feof(stdin))
84 (void) printf("Line too long\n");
85 reset_timer();
86 return (-1);
87 } else
88 buffer[strlen(buffer)-1] = 0;
90 reset_timer();
91 return (0);
96 * Connect to peer server and
97 * auto-login, if possible.
99 void
100 setpeer(int argc, char *argv[])
102 char *host;
104 if (connected) {
105 (void) printf("Already connected to %s, use close first.\n",
106 hostname);
107 code = -1;
108 return;
110 if (argc < 2) {
111 if (prompt_for_arg(line, sizeof (line), "to") == -1) {
112 code = -1;
113 return;
115 makeargv();
116 argc = margc;
117 argv = margv;
119 if (argc > 3 || argc < 2) {
120 (void) printf("usage: %s host-name [port]\n", argv[0]);
121 code = -1;
122 return;
124 strcpy(typename, "ascii");
125 host = hookup(argv[1], (argc > 2 ? argv[2] : "ftp"));
126 if (host) {
127 int overbose;
128 extern char reply_string[];
130 connected = 1;
132 * Set up defaults for FTP.
134 clevel = dlevel = PROT_C;
135 if (autoauth) {
136 if (do_auth() && autoencrypt) {
137 clevel = PROT_P;
138 setpbsz(1<<20);
139 if (command("PROT P") == COMPLETE)
140 dlevel = PROT_P;
141 else {
142 (void) fprintf(stderr,
143 "%s: couldn't enable encryption\n",
144 argv[0]);
145 /* unable to encrypt command channel, too! */
146 dlevel = clevel = PROT_C;
149 if ((auth_type != AUTHTYPE_NONE) && (clevel == PROT_C))
150 clevel = PROT_S;
153 if (autologin)
154 (void) login(argv[1]);
155 /* if skipsyst is enabled, then don't send SYST command */
156 if (skipsyst)
157 return;
159 overbose = verbose;
160 if (debug == 0)
161 verbose = -1;
162 if (command("SYST") == COMPLETE && overbose) {
163 char *cp, c;
165 cp = index(reply_string+4, ' ');
166 if (cp == NULL)
167 cp = index(reply_string+4, '\r');
168 if (cp) {
169 if (cp[-1] == '.')
170 cp--;
171 c = *cp;
172 *cp = '\0';
175 (void) printf("Remote system type is %s.\n",
176 reply_string+4);
177 if (cp)
178 *cp = c;
180 if (strncmp(reply_string, "215 UNIX Type: L8", 17) == 0) {
181 setbinary(0, NULL);
182 if (overbose)
183 (void) printf(
184 "Using %s mode to transfer files.\n",
185 typename);
186 } else if (overbose &&
187 strncmp(reply_string, "215 TOPS20", 10) == 0) {
188 (void) printf(
189 "Remember to set tenex mode when transfering "
190 "binary files from this machine.\n");
192 verbose = overbose;
196 static struct types {
197 char *t_name;
198 char *t_mode;
199 int t_type;
200 char *t_arg;
201 } types[] = {
202 { "ascii", "A", TYPE_A, 0 },
203 { "binary", "I", TYPE_I, 0 },
204 { "image", "I", TYPE_I, 0 },
205 { "ebcdic", "E", TYPE_E, 0 },
206 { "tenex", "L", TYPE_L, bytename },
211 * Set transfer type.
213 void
214 settype(int argc, char *argv[])
216 struct types *p;
217 int comret;
219 if (argc > 2) {
220 char *sep;
222 (void) printf("usage: %s [", argv[0]);
223 sep = " ";
224 for (p = types; p->t_name; p++) {
225 (void) printf("%s%s", sep, p->t_name);
226 if (*sep == ' ')
227 sep = " | ";
229 (void) printf(" ]\n");
230 code = -1;
231 return;
233 if (argc < 2) {
234 (void) printf("Using %s mode to transfer files.\n", typename);
235 code = 0;
236 return;
238 for (p = types; p->t_name; p++)
239 if (strcmp(argv[1], p->t_name) == 0)
240 break;
241 if (p->t_name == 0) {
242 (void) printf("%s: unknown mode\n", argv[1]);
243 code = -1;
244 return;
246 if ((p->t_arg != NULL) && (*(p->t_arg) != '\0'))
247 comret = command("TYPE %s %s", p->t_mode, p->t_arg);
248 else
249 comret = command("TYPE %s", p->t_mode);
250 if (comret == COMPLETE) {
251 (void) strcpy(typename, p->t_name);
252 type = p->t_type;
257 * Set binary transfer type.
259 /*ARGSUSED*/
260 void
261 setbinary(int argc, char *argv[])
263 call(settype, "type", "binary", 0);
267 * Set ascii transfer type.
269 /*ARGSUSED*/
270 void
271 setascii(int argc, char *argv[])
273 call(settype, "type", "ascii", 0);
277 * Set tenex transfer type.
279 /*ARGSUSED*/
280 void
281 settenex(int argc, char *argv[])
283 call(settype, "type", "tenex", 0);
287 * Set ebcdic transfer type.
289 /*ARGSUSED*/
290 void
291 setebcdic(int argc, char *argv[])
293 call(settype, "type", "ebcdic", 0);
297 * Set file transfer mode.
299 /*ARGSUSED*/
300 void
301 setftpmode(int argc, char *argv[])
303 (void) printf("We only support %s mode, sorry.\n", modename);
304 code = -1;
308 * Set file transfer format.
310 /*ARGSUSED*/
311 void
312 setform(int argc, char *argv[])
314 (void) printf("We only support %s format, sorry.\n", formname);
315 code = -1;
319 * Set file transfer structure.
321 /*ARGSUSED*/
322 void
323 setstruct(int argc, char *argv[])
326 (void) printf("We only support %s structure, sorry.\n", structname);
327 code = -1;
331 * Send a single file.
333 void
334 put(int argc, char *argv[])
336 char *cmd;
337 int loc = 0;
338 char *oldargv1;
340 if (argc == 2) {
341 argc++;
342 argv[2] = argv[1];
343 loc++;
345 if (argc < 2) {
346 if (prompt_for_arg(line, sizeof (line), "local-file") == -1) {
347 code = -1;
348 return;
350 makeargv();
351 argc = margc;
352 argv = margv;
354 if (argc < 2) {
355 usage:
356 (void) printf("usage: %s local-file remote-file\n", argv[0]);
357 code = -1;
358 return;
360 if (argc < 3) {
361 if (prompt_for_arg(line, sizeof (line), "remote-file") == -1) {
362 code = -1;
363 return;
365 makeargv();
366 argc = margc;
367 argv = margv;
369 if (argc < 3)
370 goto usage;
371 oldargv1 = argv[1];
372 if (!globulize(&argv[1])) {
373 code = -1;
374 return;
377 * If "globulize" modifies argv[1], and argv[2] is a copy of
378 * the old argv[1], make it a copy of the new argv[1].
380 if (argv[1] != oldargv1 && argv[2] == oldargv1) {
381 argv[2] = argv[1];
383 cmd = (argv[0][0] == 'a') ? "APPE" : ((sunique) ? "STOU" : "STOR");
384 if (loc && ntflag) {
385 argv[2] = dotrans(argv[2]);
387 if (loc && mapflag) {
388 argv[2] = domap(argv[2]);
390 sendrequest(cmd, argv[1], argv[2], 1);
393 /*ARGSUSED*/
394 static void
395 mabort(int sig)
397 int ointer;
399 (void) printf("\n");
400 (void) fflush(stdout);
401 if (mflag && fromatty) {
402 ointer = interactive;
403 interactive = 1;
404 if (confirm("Continue with", mname)) {
405 interactive = ointer;
406 longjmp(jabort, 0);
408 interactive = ointer;
410 mflag = 0;
411 longjmp(jabort, 0);
415 * Send multiple files.
417 void
418 mput(int argc, char *argv[])
420 int i;
421 int ointer;
422 void (*oldintr)();
423 char *tp;
424 int len;
426 if (argc < 2) {
427 if (prompt_for_arg(line, sizeof (line), "local-files") == -1) {
428 code = -1;
429 return;
431 makeargv();
432 argc = margc;
433 argv = margv;
435 if (argc < 2) {
436 (void) printf("usage: %s local-files\n", argv[0]);
437 code = -1;
438 return;
440 mname = argv[0];
441 mflag = 1;
442 oldintr = signal(SIGINT, mabort);
443 (void) setjmp(jabort);
444 if (proxy) {
445 char *cp, *tp2, tmpbuf[MAXPATHLEN];
447 while ((cp = remglob(argv, 0)) != NULL) {
448 if (*cp == 0) {
449 mflag = 0;
450 continue;
452 if (mflag && confirm(argv[0], cp)) {
453 tp = cp;
454 if (mcase) {
455 while (*tp) {
456 if ((len =
457 mblen(tp, MB_CUR_MAX)) <= 0)
458 len = 1;
459 if (islower(*tp))
460 break;
461 tp += len;
463 if (!*tp) {
464 tp = cp;
465 tp2 = tmpbuf;
466 while (*tp) {
467 if ((len = mblen(tp,
468 MB_CUR_MAX)) <= 0)
469 len = 1;
470 memcpy(tp2, tp, len);
471 if (isupper(*tp2)) {
472 *tp2 = 'a' +
473 *tp2 - 'A';
475 tp += len;
476 tp2 += len;
478 *tp2 = 0;
479 tp = tmpbuf;
482 if (ntflag) {
483 tp = dotrans(tp);
485 if (mapflag) {
486 tp = domap(tp);
488 sendrequest((sunique) ? "STOU" : "STOR",
489 cp, tp, 0);
490 if (!mflag && fromatty) {
491 ointer = interactive;
492 interactive = 1;
493 if (confirm("Continue with", "mput")) {
494 mflag++;
496 interactive = ointer;
500 (void) signal(SIGINT, oldintr);
501 mflag = 0;
502 return;
504 for (i = 1; i < argc; i++) {
505 char **cpp, **gargs;
507 if (!doglob) {
508 if (mflag && confirm(argv[0], argv[i])) {
509 tp = (ntflag) ? dotrans(argv[i]) : argv[i];
510 tp = (mapflag) ? domap(tp) : tp;
511 sendrequest((sunique) ? "STOU" : "STOR",
512 argv[i], tp, 1);
513 if (!mflag && fromatty) {
514 ointer = interactive;
515 interactive = 1;
516 if (confirm("Continue with", "mput")) {
517 mflag++;
519 interactive = ointer;
522 continue;
524 gargs = glob(argv[i]);
525 if (globerr != NULL) {
526 (void) printf("%s\n", globerr);
527 if (gargs)
528 blkfree(gargs);
529 continue;
531 for (cpp = gargs; cpp && *cpp != NULL; cpp++) {
532 if (mflag && confirm(argv[0], *cpp)) {
533 tp = (ntflag) ? dotrans(*cpp) : *cpp;
534 tp = (mapflag) ? domap(tp) : tp;
535 sendrequest((sunique) ? "STOU" : "STOR",
536 *cpp, tp, 0);
537 if (!mflag && fromatty) {
538 ointer = interactive;
539 interactive = 1;
540 if (confirm("Continue with", "mput")) {
541 mflag++;
543 interactive = ointer;
547 if (gargs != NULL)
548 blkfree(gargs);
550 (void) signal(SIGINT, oldintr);
551 mflag = 0;
555 * Restart transfer at a specific offset.
557 void
558 restart(int argc, char *argv[])
560 off_t orestart_point = restart_point;
562 if (argc > 2) {
563 (void) printf("usage: %s [marker]\n", argv[0]);
564 code = -1;
565 return;
567 if (argc == 2) {
568 longlong_t rp;
569 char *endp;
571 errno = 0;
572 rp = strtoll(argv[1], &endp, 10);
573 if (errno || rp < 0 || *endp != '\0')
574 (void) printf("%s: Invalid offset `%s'\n",
575 argv[0], argv[1]);
576 else
577 restart_point = rp;
579 if (restart_point == 0) {
580 if (orestart_point == 0)
581 (void) printf("No restart marker defined\n");
582 else
583 (void) printf("Restart marker cleared\n");
584 } else
585 (void) printf(
586 "Restarting at %lld for next get, put or append\n",
587 (longlong_t)restart_point);
590 void
591 reget(int argc, char *argv[])
593 getit(argc, argv, 1, "r+w");
596 void
597 get(int argc, char *argv[])
599 getit(argc, argv, 0, restart_point ? "r+w" : "w");
603 * Receive one file.
605 static void
606 getit(int argc, char *argv[], int restartit, char *mode)
608 int loc = 0;
609 int len;
610 int allowpipe = 1;
612 if (argc == 2) {
613 argc++;
614 argv[2] = argv[1];
615 /* Only permit !file if two arguments. */
616 allowpipe = 0;
617 loc++;
619 if (argc < 2) {
620 if (prompt_for_arg(line, sizeof (line), "remote-file") == -1) {
621 code = -1;
622 return;
624 makeargv();
625 argc = margc;
626 argv = margv;
628 if (argc < 2) {
629 usage:
630 (void) printf("usage: %s remote-file [ local-file ]\n",
631 argv[0]);
632 code = -1;
633 return;
635 if (argc < 3) {
636 if (prompt_for_arg(line, sizeof (line), "local-file") == -1) {
637 code = -1;
638 return;
640 makeargv();
641 argc = margc;
642 argv = margv;
644 if (argc < 3)
645 goto usage;
646 if (!globulize(&argv[2])) {
647 code = -1;
648 return;
650 if (loc && mcase) {
651 char *tp = argv[1], *tp2, tmpbuf[MAXPATHLEN];
653 while (*tp) {
654 if ((len = mblen(tp, MB_CUR_MAX)) <= 0)
655 len = 1;
656 if (islower(*tp))
657 break;
658 tp += len;
660 if (!*tp) {
661 tp = argv[2];
662 tp2 = tmpbuf;
663 while (*tp) {
664 if ((len = mblen(tp, MB_CUR_MAX)) <= 0)
665 len = 1;
666 memcpy(tp2, tp, len);
667 if (isupper(*tp2))
668 *tp2 = 'a' + *tp2 - 'A';
669 tp += len;
670 tp2 += len;
672 *tp2 = 0;
673 argv[2] = tmpbuf;
676 if (loc && ntflag) {
677 argv[2] = dotrans(argv[2]);
679 if (loc && mapflag) {
680 argv[2] = domap(argv[2]);
682 if (restartit) {
683 struct stat stbuf;
685 if (stat(argv[2], &stbuf) < 0) {
686 perror(argv[2]);
687 code = -1;
688 return;
690 restart_point = stbuf.st_size;
692 recvrequest("RETR", argv[2], argv[1], mode, allowpipe);
693 restart_point = 0;
697 * Get multiple files.
699 void
700 mget(int argc, char *argv[])
702 char *cp, *tp, *tp2, tmpbuf[MAXPATHLEN];
703 int ointer;
704 void (*oldintr)();
705 int need_convert;
706 int len;
708 if (argc < 2) {
709 if (prompt_for_arg(line, sizeof (line), "remote-files") < 0) {
710 code = -1;
711 return;
713 makeargv();
714 argc = margc;
715 argv = margv;
717 if (argc < 2) {
718 (void) printf("usage: %s remote-files\n", argv[0]);
719 code = -1;
720 return;
722 mname = argv[0];
723 mflag = 1;
724 oldintr = signal(SIGINT, mabort);
725 (void) setjmp(jabort);
726 while ((cp = remglob(argv, proxy)) != NULL) {
727 if (*cp == '\0') {
728 mflag = 0;
729 continue;
731 if (mflag && confirm(argv[0], cp)) {
732 strcpy(tmpbuf, cp);
733 tp = tmpbuf;
734 need_convert = 1;
735 if (mcase) {
736 tp2 = tp;
737 while (*tp2 && need_convert) {
738 /* Need any case convert? */
739 if (islower(*tp2))
740 need_convert = 0;
741 if ((len = mblen(tp2, MB_CUR_MAX)) <= 0)
742 len = 1;
743 tp2 += len;
745 tp2 = tp;
746 while (need_convert && *tp2) {
747 /* Convert to lower case */
748 if (isupper(*tp2))
749 *tp2 = tolower(*tp2);
750 if ((len = mblen(tp2, MB_CUR_MAX)) <= 0)
751 len = 1;
752 tp2 += len;
756 if (ntflag) {
757 tp = dotrans(tp);
759 if (mapflag) {
760 tp = domap(tp);
762 recvrequest("RETR", tp, cp, "w", 0);
763 restart_point = 0;
764 if (!mflag && fromatty) {
765 ointer = interactive;
766 interactive = 1;
767 if (confirm("Continue with", "mget")) {
768 mflag++;
770 interactive = ointer;
774 (void) signal(SIGINT, oldintr);
775 mflag = 0;
778 static char *
779 remglob(char *argv[], int doswitch)
781 static char buf[MAXPATHLEN];
782 static char **args;
783 int oldverbose, oldhash;
784 char *cp;
786 if (!mflag) {
787 if (!doglob) {
788 args = NULL;
789 } else {
790 if (tmp_nlst != NULL) {
791 (void) fclose(tmp_nlst);
792 tmp_nlst = NULL;
795 return (NULL);
797 if (!doglob) {
798 if (args == NULL)
799 args = argv;
800 if ((cp = *++args) == NULL)
801 args = NULL;
802 return (cp);
804 if (tmp_nlst == NULL) {
805 if ((tmp_nlst = tmpfile()) == NULL) {
806 (void) printf("%s\n", strerror(errno));
807 return (NULL);
809 oldverbose = verbose, verbose = 0;
810 oldhash = hash, hash = 0;
811 if (doswitch) {
812 pswitch(!proxy);
814 for (; *++argv != NULL; )
815 recvrequest("NLST", NULL, *argv, "", 0);
816 rewind(tmp_nlst);
817 if (doswitch) {
818 pswitch(!proxy);
820 verbose = oldverbose; hash = oldhash;
822 reset_timer();
823 if (fgets(buf, sizeof (buf), tmp_nlst) == NULL) {
824 (void) fclose(tmp_nlst), tmp_nlst = NULL;
825 return (NULL);
827 if ((cp = index(buf, '\n')) != NULL)
828 *cp = '\0';
829 return (buf);
832 static char *
833 onoff(int bool)
835 return (bool ? "on" : "off");
839 * Show status.
841 /*ARGSUSED*/
842 void
843 status(int argc, char *argv[])
845 int i;
846 char *levelp;
848 if (connected)
849 (void) printf("Connected to %s.\n", hostname);
850 else
851 (void) printf("Not connected.\n");
852 if (!proxy) {
853 pswitch(1);
854 if (connected) {
855 (void) printf("Connected for proxy commands to %s.\n",
856 hostname);
857 } else {
858 (void) printf("No proxy connection.\n");
860 pswitch(0);
863 if (auth_type != AUTHTYPE_NONE)
864 (void) printf("Authentication type: %s\n",
865 GSS_AUTHTYPE_NAME(auth_type));
866 else
867 (void) printf("Not authenticated.\n");
868 (void) printf("Mechanism: %s\n", mechstr);
869 (void) printf("Autoauth: %s; Autologin: %s\n",
870 onoff(autoauth), onoff(autologin));
871 levelp = getlevel(clevel);
872 (void) printf("Control Channel Protection Level: %s\n",
873 levelp ? levelp : "<unknown>");
874 levelp = getlevel(dlevel);
875 (void) printf("Data Channel Protection Level: %s\n",
876 levelp ? levelp : "<unknown>");
878 (void) printf("Passive mode: %s.\n", onoff(passivemode));
879 (void) printf("Mode: %s; Type: %s; Form: %s; Structure: %s\n",
880 modename, typename, formname, structname);
881 (void) printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s\n",
882 onoff(verbose), onoff(bell), onoff(interactive),
883 onoff(doglob));
884 (void) printf("Store unique: %s; Receive unique: %s\n", onoff(sunique),
885 onoff(runique));
886 (void) printf("Case: %s; CR stripping: %s\n",
887 onoff(mcase), onoff(crflag));
888 if (ntflag) {
889 (void) printf("Ntrans: (in) %s (out) %s\n", ntin, ntout);
890 } else {
891 (void) printf("Ntrans: off\n");
893 if (mapflag) {
894 (void) printf("Nmap: (in) %s (out) %s\n", mapin, mapout);
895 } else {
896 (void) printf("Nmap: off\n");
898 (void) printf("Hash mark printing: %s; Use of PORT cmds: %s\n",
899 onoff(hash), onoff(sendport));
900 if (macnum > 0) {
901 (void) printf("Macros:\n");
902 for (i = 0; i < macnum; i++) {
903 (void) printf("\t%s\n", macros[i].mac_name);
906 code = 0;
910 * Set beep on cmd completed mode.
912 /*ARGSUSED*/
913 void
914 setbell(int argc, char *argv[])
916 bell = !bell;
917 (void) printf("Bell mode %s.\n", onoff(bell));
918 code = bell;
922 * Turn on packet tracing.
924 /*ARGSUSED*/
925 void
926 settrace(int argc, char *argv[])
928 trace = !trace;
929 (void) printf("Packet tracing %s.\n", onoff(trace));
930 code = trace;
934 * Toggle hash mark printing during transfers.
936 /*ARGSUSED*/
937 void
938 sethash(int argc, char *argv[])
940 hash = !hash;
941 (void) printf("Hash mark printing %s", onoff(hash));
942 code = hash;
943 if (hash)
944 (void) printf(" (%d bytes/hash mark)", HASHSIZ);
945 (void) printf(".\n");
949 * Turn on printing of server echo's.
951 /*ARGSUSED*/
952 void
953 setverbose(int argc, char *argv[])
955 verbose = !verbose;
956 (void) printf("Verbose mode %s.\n", onoff(verbose));
957 code = verbose;
961 * Toggle PORT cmd use before each data connection.
963 /*ARGSUSED*/
964 void
965 setport(int argc, char *argv[])
967 sendport = !sendport;
968 (void) printf("Use of PORT cmds %s.\n", onoff(sendport));
969 code = sendport;
973 * Turn on interactive prompting
974 * during mget, mput, and mdelete.
976 /*ARGSUSED*/
977 void
978 setprompt(int argc, char *argv[])
980 interactive = !interactive;
981 (void) printf("Interactive mode %s.\n", onoff(interactive));
982 code = interactive;
986 * Toggle metacharacter interpretation
987 * on local file names.
989 /*ARGSUSED*/
990 void
991 setglob(int argc, char *argv[])
993 doglob = !doglob;
994 (void) printf("Globbing %s.\n", onoff(doglob));
995 code = doglob;
999 * Set debugging mode on/off and/or
1000 * set level of debugging.
1002 void
1003 setdebug(int argc, char *argv[])
1005 int val;
1007 if (argc > 1) {
1008 val = atoi(argv[1]);
1009 if (val < 0) {
1010 (void) printf("%s: bad debugging value.\n", argv[1]);
1011 code = -1;
1012 return;
1014 } else
1015 val = !debug;
1016 debug = val;
1017 if (debug)
1018 options |= SO_DEBUG;
1019 else
1020 options &= ~SO_DEBUG;
1021 (void) printf("Debugging %s (debug=%d).\n", onoff(debug), debug);
1022 code = debug > 0;
1026 * Set current working directory
1027 * on remote machine.
1029 void
1030 cd(int argc, char *argv[])
1032 if (argc < 2) {
1033 if (prompt_for_arg(line, sizeof (line), "remote-directory") <
1034 0) {
1035 code = -1;
1036 return;
1038 makeargv();
1039 argc = margc;
1040 argv = margv;
1042 if (argc < 2) {
1043 (void) printf("usage: %s remote-directory\n", argv[0]);
1044 code = -1;
1045 return;
1047 (void) command("CWD %s", argv[1]);
1051 * Set current working directory
1052 * on local machine.
1054 void
1055 lcd(int argc, char *argv[])
1057 char buf[MAXPATHLEN], *bufptr;
1059 if (argc < 2)
1060 argc++, argv[1] = home;
1061 if (argc != 2) {
1062 (void) printf("usage: %s local-directory\n", argv[0]);
1063 code = -1;
1064 return;
1066 if (!globulize(&argv[1])) {
1067 code = -1;
1068 return;
1070 if (chdir(argv[1]) < 0) {
1071 perror(argv[1]);
1072 code = -1;
1073 return;
1075 bufptr = getcwd(buf, MAXPATHLEN);
1077 * Even though chdir may succeed, getcwd may fail if a component
1078 * of the pwd is unreadable. In this case, print the argument to
1079 * chdir as the resultant directory, since we know it succeeded above.
1081 (void) printf("Local directory now %s\n", (bufptr ? bufptr : argv[1]));
1082 code = 0;
1086 * Delete a single file.
1088 void
1089 delete(int argc, char *argv[])
1092 if (argc < 2) {
1093 if (prompt_for_arg(line, sizeof (line), "remote-file") < 0) {
1094 code = -1;
1095 return;
1097 makeargv();
1098 argc = margc;
1099 argv = margv;
1101 if (argc < 2) {
1102 (void) printf("usage: %s remote-file\n", argv[0]);
1103 code = -1;
1104 return;
1106 (void) command("DELE %s", argv[1]);
1110 * Delete multiple files.
1112 void
1113 mdelete(int argc, char *argv[])
1115 char *cp;
1116 int ointer;
1117 void (*oldintr)();
1119 if (argc < 2) {
1120 if (prompt_for_arg(line, sizeof (line), "remote-files") < 0) {
1121 code = -1;
1122 return;
1124 makeargv();
1125 argc = margc;
1126 argv = margv;
1128 if (argc < 2) {
1129 (void) printf("usage: %s remote-files\n", argv[0]);
1130 code = -1;
1131 return;
1133 mname = argv[0];
1134 mflag = 1;
1135 oldintr = signal(SIGINT, mabort);
1136 (void) setjmp(jabort);
1137 while ((cp = remglob(argv, 0)) != NULL) {
1138 if (*cp == '\0') {
1139 mflag = 0;
1140 continue;
1142 if (mflag && confirm(argv[0], cp)) {
1143 (void) command("DELE %s", cp);
1144 if (!mflag && fromatty) {
1145 ointer = interactive;
1146 interactive = 1;
1147 if (confirm("Continue with", "mdelete")) {
1148 mflag++;
1150 interactive = ointer;
1154 (void) signal(SIGINT, oldintr);
1155 mflag = 0;
1159 * Rename a remote file.
1161 void
1162 renamefile(int argc, char *argv[])
1165 if (argc < 2) {
1166 if (prompt_for_arg(line, sizeof (line), "from-name") < 0) {
1167 code = -1;
1168 return;
1170 makeargv();
1171 argc = margc;
1172 argv = margv;
1174 if (argc < 2) {
1175 usage:
1176 (void) printf("%s from-name to-name\n", argv[0]);
1177 code = -1;
1178 return;
1180 if (argc < 3) {
1181 if (prompt_for_arg(line, sizeof (line), "to-name") < 0) {
1182 code = -1;
1183 return;
1185 makeargv();
1186 argc = margc;
1187 argv = margv;
1189 if (argc < 3)
1190 goto usage;
1191 if (command("RNFR %s", argv[1]) == CONTINUE)
1192 (void) command("RNTO %s", argv[2]);
1196 * Get a directory listing
1197 * of remote files.
1199 void
1200 ls(int argc, char *argv[])
1202 char *cmd;
1204 if (argc < 2)
1205 argc++, argv[1] = NULL;
1206 if (argc < 3)
1207 argc++, argv[2] = "-";
1208 if (argc > 3) {
1209 (void) printf("usage: %s remote-directory local-file\n",
1210 argv[0]);
1211 code = -1;
1212 return;
1214 if (ls_invokes_NLST) {
1215 cmd = ((argv[0][0] == 'l' || argv[0][0] == 'n') ?
1216 "NLST" : "LIST");
1217 } else {
1218 cmd = ((argv[0][0] == 'n') ? "NLST" : "LIST");
1220 if (strcmp(argv[2], "-") && !globulize(&argv[2])) {
1221 code = -1;
1222 return;
1224 recvrequest(cmd, argv[2], argv[1], "w", 1);
1228 * Get a directory listing
1229 * of multiple remote files.
1231 void
1232 mls(int argc, char *argv[])
1234 char *cmd, mode[1], *dest;
1235 int ointer, i;
1236 void (*oldintr)();
1238 if (argc < 2) {
1239 if (prompt_for_arg(line, sizeof (line), "remote-files") < 0) {
1240 code = -1;
1241 return;
1243 makeargv();
1244 argc = margc;
1245 argv = margv;
1247 if (argc < 3) {
1248 if (prompt_for_arg(line, sizeof (line), "local-file") < 0) {
1249 code = -1;
1250 return;
1252 makeargv();
1253 argc = margc;
1254 argv = margv;
1256 if (argc < 3) {
1257 (void) printf("usage: %s remote-files local-file\n", argv[0]);
1258 code = -1;
1259 return;
1261 dest = argv[argc - 1];
1262 argv[argc - 1] = NULL;
1263 if (strcmp(dest, "-") && *dest != '|')
1264 if (!globulize(&dest) ||
1265 !confirm("output to local-file:", dest)) {
1266 code = -1;
1267 return;
1269 cmd = argv[0][1] == 'l' ? "NLST" : "LIST";
1270 mname = argv[0];
1271 mflag = 1;
1272 oldintr = signal(SIGINT, mabort);
1273 (void) setjmp(jabort);
1274 for (i = 1; mflag && i < argc-1; ++i) {
1275 *mode = (i == 1) ? 'w' : 'a';
1276 recvrequest(cmd, dest, argv[i], mode, 1);
1277 if (!mflag && fromatty) {
1278 ointer = interactive;
1279 interactive = 1;
1280 if (confirm("Continue with", argv[0])) {
1281 mflag ++;
1283 interactive = ointer;
1286 (void) signal(SIGINT, oldintr);
1287 mflag = 0;
1291 * Do a shell escape
1293 /*ARGSUSED*/
1294 void
1295 shell(int argc, char *argv[])
1297 pid_t pid;
1298 void (*old1)(), (*old2)();
1299 char *shellstring, *namep;
1300 int status;
1302 stop_timer();
1303 old1 = signal(SIGINT, SIG_IGN);
1304 old2 = signal(SIGQUIT, SIG_IGN);
1305 if ((pid = fork()) == 0) {
1306 closefrom(STDERR_FILENO + 1);
1307 (void) signal(SIGINT, SIG_DFL);
1308 (void) signal(SIGQUIT, SIG_DFL);
1309 shellstring = getenv("SHELL");
1310 if (shellstring == NULL)
1311 shellstring = "/bin/sh";
1312 namep = rindex(shellstring, '/');
1313 if (namep == NULL)
1314 namep = shellstring;
1315 if (argc > 1) {
1316 if (debug) {
1317 (void) printf("%s -c %s\n", shellstring,
1318 altarg);
1319 (void) fflush(stdout);
1321 execl(shellstring, namep, "-c", altarg, (char *)0);
1322 } else {
1323 if (debug) {
1324 (void) printf("%s\n", shellstring);
1325 (void) fflush(stdout);
1327 execl(shellstring, namep, (char *)0);
1329 perror(shellstring);
1330 code = -1;
1331 exit(1);
1333 if (pid > 0)
1334 while (wait(&status) != pid)
1336 (void) signal(SIGINT, old1);
1337 (void) signal(SIGQUIT, old2);
1338 reset_timer();
1339 if (pid == (pid_t)-1) {
1340 perror("Try again later");
1341 code = -1;
1342 } else {
1343 code = 0;
1348 * Send new user information (re-login)
1350 void
1351 user(int argc, char *argv[])
1353 char acct[80];
1354 int n, aflag = 0;
1356 if (argc < 2) {
1357 if (prompt_for_arg(line, sizeof (line), "username") < 0) {
1358 code = -1;
1359 return;
1361 makeargv();
1362 argc = margc;
1363 argv = margv;
1365 if (argc > 4) {
1366 (void) printf("usage: %s username [password] [account]\n",
1367 argv[0]);
1368 code = -1;
1369 return;
1371 if (argv[1] == 0) {
1372 (void) printf("access for user (nil) denied\n");
1373 code = -1;
1374 return;
1376 n = command("USER %s", argv[1]);
1377 if (n == CONTINUE) {
1378 int oldclevel;
1379 if (argc < 3)
1380 argv[2] = mygetpass("Password: "), argc++;
1381 if ((oldclevel = clevel) == PROT_S)
1382 clevel = PROT_P;
1383 n = command("PASS %s", argv[2]);
1384 /* level may have changed */
1385 if (clevel == PROT_P)
1386 clevel = oldclevel;
1388 if (n == CONTINUE) {
1389 if (argc < 4) {
1390 (void) printf("Account: "); (void) fflush(stdout);
1391 stop_timer();
1392 (void) fgets(acct, sizeof (acct) - 1, stdin);
1393 reset_timer();
1394 acct[strlen(acct) - 1] = '\0';
1395 argv[3] = acct; argc++;
1397 n = command("ACCT %s", argv[3]);
1398 aflag++;
1400 if (n != COMPLETE) {
1401 (void) fprintf(stdout, "Login failed.\n");
1402 return;
1404 if (!aflag && argc == 4) {
1405 (void) command("ACCT %s", argv[3]);
1410 * Print working directory.
1412 /*ARGSUSED*/
1413 void
1414 pwd(int argc, char *argv[])
1416 (void) command("PWD");
1420 * Make a directory.
1422 void
1423 makedir(int argc, char *argv[])
1425 if (argc < 2) {
1426 if (prompt_for_arg(line, sizeof (line), "directory-name") <
1427 0) {
1428 code = -1;
1429 return;
1431 makeargv();
1432 argc = margc;
1433 argv = margv;
1435 if (argc < 2) {
1436 (void) printf("usage: %s directory-name\n", argv[0]);
1437 code = -1;
1438 return;
1440 (void) command("MKD %s", argv[1]);
1444 * Remove a directory.
1446 void
1447 removedir(int argc, char *argv[])
1449 if (argc < 2) {
1450 if (prompt_for_arg(line, sizeof (line), "directory-name") <
1451 0) {
1452 code = -1;
1453 return;
1455 makeargv();
1456 argc = margc;
1457 argv = margv;
1459 if (argc < 2) {
1460 (void) printf("usage: %s directory-name\n", argv[0]);
1461 code = -1;
1462 return;
1464 (void) command("RMD %s", argv[1]);
1468 * Send a line, verbatim, to the remote machine.
1470 void
1471 quote(int argc, char *argv[])
1473 int i, n, len;
1474 char buf[FTPBUFSIZ];
1476 if (argc < 2) {
1477 if (prompt_for_arg(line, sizeof (line),
1478 "command line to send") == -1) {
1479 code = -1;
1480 return;
1482 makeargv();
1483 argc = margc;
1484 argv = margv;
1486 if (argc < 2) {
1487 (void) printf("usage: %s line-to-send\n", argv[0]);
1488 code = -1;
1489 return;
1491 len = snprintf(buf, sizeof (buf), "%s", argv[1]);
1492 if (len >= 0 && len < sizeof (buf) - 1) {
1493 for (i = 2; i < argc; i++) {
1494 n = snprintf(&buf[len], sizeof (buf) - len, " %s",
1495 argv[i]);
1496 if (n < 0 || n >= sizeof (buf) - len)
1497 break;
1498 len += n;
1501 if (command("%s", buf) == PRELIM) {
1502 while (getreply(0) == PRELIM)
1508 * Send a line, verbatim, to the remote machine as a SITE command.
1510 void
1511 site(int argc, char *argv[])
1513 int i, n, len;
1514 char buf[FTPBUFSIZ];
1516 if (argc < 2) {
1517 if (prompt_for_arg(line, sizeof (line),
1518 "arguments to SITE command") == -1) {
1519 code = -1;
1520 return;
1522 makeargv();
1523 argc = margc;
1524 argv = margv;
1526 if (argc < 2) {
1527 (void) printf("usage: %s arg1 [arg2] ...\n", argv[0]);
1528 code = -1;
1529 return;
1531 len = snprintf(buf, sizeof (buf), "%s", argv[1]);
1532 if (len >= 0 && len < sizeof (buf) - 1) {
1533 for (i = 2; i < argc; i++) {
1534 n = snprintf(&buf[len], sizeof (buf) - len, " %s",
1535 argv[i]);
1536 if (n < 0 || n >= sizeof (buf) - len)
1537 break;
1538 len += n;
1541 if (command("SITE %s", buf) == PRELIM) {
1542 while (getreply(0) == PRELIM)
1548 * Ask the other side for help.
1550 void
1551 rmthelp(int argc, char *argv[])
1553 int oldverbose = verbose;
1555 verbose = 1;
1556 (void) command(argc == 1 ? "HELP" : "HELP %s", argv[1]);
1557 verbose = oldverbose;
1561 * Terminate session and exit.
1563 /*ARGSUSED*/
1564 void
1565 quit(int argc, char *argv[])
1567 if (connected)
1568 disconnect(0, NULL);
1569 pswitch(1);
1570 if (connected) {
1571 disconnect(0, NULL);
1573 exit(0);
1577 * Terminate session, but don't exit.
1579 /*ARGSUSED*/
1580 void
1581 disconnect(int argc, char *argv[])
1583 extern FILE *ctrl_in, *ctrl_out;
1584 extern int data;
1586 if (!connected)
1587 return;
1588 (void) command("QUIT");
1589 if (ctrl_in) {
1590 reset_timer();
1591 (void) fclose(ctrl_in);
1593 if (ctrl_out) {
1594 reset_timer();
1595 (void) fclose(ctrl_out);
1597 ctrl_out = ctrl_in = NULL;
1598 connected = 0;
1599 data = -1;
1600 if (!proxy) {
1601 macnum = 0;
1604 auth_type = AUTHTYPE_NONE;
1605 clevel = dlevel = PROT_C;
1606 goteof = 0;
1609 static int
1610 confirm(char *cmd, char *file)
1612 char line[FTPBUFSIZ];
1614 if (!interactive)
1615 return (1);
1616 stop_timer();
1617 (void) printf("%s %s? ", cmd, file);
1618 (void) fflush(stdout);
1619 *line = '\0';
1620 (void) fgets(line, sizeof (line), stdin);
1621 reset_timer();
1622 return (*line != 'n' && *line != 'N');
1625 void
1626 fatal(char *msg)
1628 (void) fprintf(stderr, "ftp: %s\n", msg);
1629 exit(1);
1633 * Glob a local file name specification with
1634 * the expectation of a single return value.
1635 * Can't control multiple values being expanded
1636 * from the expression, we return only the first.
1638 static int
1639 globulize(char **cpp)
1641 char **globbed;
1643 if (!doglob)
1644 return (1);
1645 globbed = glob(*cpp);
1646 if (globbed != NULL && *globbed == NULL && globerr == NULL)
1647 globerr = "No match";
1648 if (globerr != NULL) {
1649 (void) printf("%s: %s\n", *cpp, globerr);
1650 if (globbed)
1651 blkfree(globbed);
1652 return (0);
1654 if (globbed) {
1655 *cpp = strdup(*globbed);
1656 blkfree(globbed);
1657 if (!*cpp)
1658 return (0);
1660 return (1);
1663 void
1664 account(int argc, char *argv[])
1666 char acct[50], *ap;
1668 if (argc > 1) {
1669 ++argv;
1670 --argc;
1671 (void) strncpy(acct, *argv, 49);
1672 acct[49] = '\0';
1673 while (argc > 1) {
1674 --argc;
1675 ++argv;
1676 (void) strncat(acct, *argv, 49 - strlen(acct));
1678 ap = acct;
1679 } else {
1680 ap = mygetpass("Account:");
1682 (void) command("ACCT %s", ap);
1685 /*ARGSUSED*/
1686 static void
1687 proxabort(int sig)
1689 extern int proxy;
1691 if (!proxy) {
1692 pswitch(1);
1694 if (connected) {
1695 proxflag = 1;
1696 } else {
1697 proxflag = 0;
1699 pswitch(0);
1700 longjmp(abortprox, 1);
1703 void
1704 doproxy(int argc, char *argv[])
1706 void (*oldintr)();
1707 struct cmd *c;
1709 if (argc < 2) {
1710 if (prompt_for_arg(line, sizeof (line), "command") == -1) {
1711 code = -1;
1712 return;
1714 makeargv();
1715 argc = margc;
1716 argv = margv;
1718 if (argc < 2) {
1719 (void) printf("usage: %s command\n", argv[0]);
1720 code = -1;
1721 return;
1723 c = getcmd(argv[1]);
1724 if (c == (struct cmd *)-1) {
1725 (void) printf("?Ambiguous command\n");
1726 (void) fflush(stdout);
1727 code = -1;
1728 return;
1730 if (c == 0) {
1731 (void) printf("?Invalid command\n");
1732 (void) fflush(stdout);
1733 code = -1;
1734 return;
1736 if (!c->c_proxy) {
1737 (void) printf("?Invalid proxy command\n");
1738 (void) fflush(stdout);
1739 code = -1;
1740 return;
1742 if (setjmp(abortprox)) {
1743 code = -1;
1744 return;
1746 oldintr = signal(SIGINT, (void (*)())proxabort);
1747 pswitch(1);
1748 if (c->c_conn && !connected) {
1749 (void) printf("Not connected\n");
1750 (void) fflush(stdout);
1751 pswitch(0);
1752 (void) signal(SIGINT, oldintr);
1753 code = -1;
1754 return;
1756 (*c->c_handler)(argc-1, argv+1);
1757 if (connected) {
1758 proxflag = 1;
1759 } else {
1760 proxflag = 0;
1762 pswitch(0);
1763 (void) signal(SIGINT, oldintr);
1766 /*ARGSUSED*/
1767 void
1768 setcase(int argc, char *argv[])
1770 mcase = !mcase;
1771 (void) printf("Case mapping %s.\n", onoff(mcase));
1772 code = mcase;
1775 /*ARGSUSED*/
1776 void
1777 setcr(int argc, char *argv[])
1779 crflag = !crflag;
1780 (void) printf("Carriage Return stripping %s.\n", onoff(crflag));
1781 code = crflag;
1784 void
1785 setntrans(int argc, char *argv[])
1787 if (argc == 1) {
1788 ntflag = 0;
1789 (void) printf("Ntrans off.\n");
1790 code = ntflag;
1791 return;
1793 ntflag++;
1794 code = ntflag;
1795 (void) strncpy(ntin, argv[1], 16);
1796 ntin[16] = '\0';
1797 if (argc == 2) {
1798 ntout[0] = '\0';
1799 return;
1801 (void) strncpy(ntout, argv[2], 16);
1802 ntout[16] = '\0';
1805 static char *
1806 dotrans(char *name)
1808 static char new[MAXPATHLEN];
1809 char *cp1, *cp2 = new;
1810 int i, ostop, found;
1812 for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++)
1814 for (cp1 = name; *cp1; cp1++) {
1815 found = 0;
1816 for (i = 0; *(ntin + i) && i < 16; i++) {
1817 if (*cp1 == *(ntin + i)) {
1818 found++;
1819 if (i < ostop) {
1820 *cp2++ = *(ntout + i);
1822 break;
1825 if (!found) {
1826 *cp2++ = *cp1;
1829 *cp2 = '\0';
1830 return (new);
1833 void
1834 setnmap(int argc, char *argv[])
1836 char *cp;
1838 if (argc == 1) {
1839 mapflag = 0;
1840 (void) printf("Nmap off.\n");
1841 code = mapflag;
1842 return;
1844 if (argc < 3) {
1845 if (prompt_for_arg(line, sizeof (line), "mapout") == -1) {
1846 code = -1;
1847 return;
1849 makeargv();
1850 argc = margc;
1851 argv = margv;
1853 if (argc < 3) {
1854 (void) printf("Usage: %s [mapin mapout]\n", argv[0]);
1855 code = -1;
1856 return;
1858 mapflag = 1;
1859 code = 1;
1860 cp = index(altarg, ' ');
1861 if (proxy) {
1862 while (*++cp == ' ')
1863 /* NULL */;
1864 altarg = cp;
1865 cp = index(altarg, ' ');
1867 *cp = '\0';
1868 (void) strncpy(mapin, altarg, MAXPATHLEN - 1);
1869 while (*++cp == ' ')
1870 /* NULL */;
1871 (void) strncpy(mapout, cp, MAXPATHLEN - 1);
1874 static char *
1875 domap(char *name)
1877 static char new[MAXPATHLEN];
1878 char *cp1 = name, *cp2 = mapin;
1879 char *tp[9], *te[9];
1880 int i, toks[9], toknum, match = 1;
1881 wchar_t wc1, wc2;
1882 int len1, len2;
1884 for (i = 0; i < 9; ++i) {
1885 toks[i] = 0;
1887 while (match && *cp1 && *cp2) {
1888 if ((len1 = mbtowc(&wc1, cp1, MB_CUR_MAX)) <= 0) {
1889 wc1 = (unsigned char)*cp1;
1890 len1 = 1;
1892 cp1 += len1;
1893 if ((len2 = mbtowc(&wc2, cp2, MB_CUR_MAX)) <= 0) {
1894 wc2 = (unsigned char)*cp2;
1895 len2 = 1;
1897 cp2 += len2;
1899 switch (wc2) {
1900 case '\\':
1901 if ((len2 = mbtowc(&wc2, cp2, MB_CUR_MAX)) <= 0) {
1902 wc2 = (unsigned char)*cp2;
1903 len2 = 1;
1905 cp2 += len2;
1906 if (wc2 != wc1)
1907 match = 0;
1908 break;
1910 case '$':
1911 if (*cp2 >= '1' && *cp2 <= '9') {
1912 if ((len2 =
1913 mbtowc(&wc2, cp2 + 1, MB_CUR_MAX)) <= 0) {
1914 wc2 = (unsigned char)*(cp2 + 1);
1915 len2 = 1;
1917 if (wc1 != wc2) {
1918 toks[toknum = *cp2 - '1']++;
1919 tp[toknum] = cp1 - len1;
1920 while (*cp1) {
1921 if ((len1 = mbtowc(&wc1,
1922 cp1, MB_CUR_MAX)) <= 0) {
1923 wc1 =
1924 (unsigned char)*cp1;
1925 len1 = 1;
1927 cp1 += len1;
1928 if (wc2 == wc1)
1929 break;
1931 if (*cp1 == 0 && wc2 != wc1)
1932 te[toknum] = cp1;
1933 else
1934 te[toknum] = cp1 - len1;
1936 cp2++; /* Consume the digit */
1937 if (wc2)
1938 cp2 += len2; /* Consume wide char */
1939 break;
1941 /* FALLTHROUGH */
1942 default:
1943 if (wc2 != wc1)
1944 match = 0;
1945 break;
1949 cp1 = new;
1950 *cp1 = '\0';
1951 cp2 = mapout;
1952 while (*cp2) {
1953 match = 0;
1954 switch (*cp2) {
1955 case '\\':
1956 cp2++;
1957 if (*cp2) {
1958 if ((len2 = mblen(cp2, MB_CUR_MAX)) <= 0)
1959 len2 = 1;
1960 memcpy(cp1, cp2, len2);
1961 cp1 += len2;
1962 cp2 += len2;
1964 break;
1966 case '[':
1967 LOOP:
1968 cp2++;
1969 if (*cp2 == '$' && isdigit(*(cp2+1))) {
1970 if (*++cp2 == '0') {
1971 char *cp3 = name;
1973 while (*cp3) {
1974 *cp1++ = *cp3++;
1976 match = 1;
1977 } else if (toks[toknum = *cp2 - '1']) {
1978 char *cp3 = tp[toknum];
1980 while (cp3 != te[toknum]) {
1981 *cp1++ = *cp3++;
1983 match = 1;
1985 } else {
1986 while (*cp2 && *cp2 != ',' && *cp2 != ']') {
1987 if (*cp2 == '\\') {
1988 cp2++;
1989 continue;
1992 if (*cp2 == '$' && isdigit(*(cp2+1))) {
1993 if (*++cp2 == '0') {
1994 char *cp3 = name;
1996 while (*cp3)
1997 *cp1++ = *cp3++;
1998 continue;
2000 if (toks[toknum = *cp2 - '1']) {
2001 char *cp3 = tp[toknum];
2003 while (cp3 !=
2004 te[toknum])
2005 *cp1++ = *cp3++;
2007 continue;
2009 if (*cp2) {
2010 if ((len2 =
2011 mblen(cp2, MB_CUR_MAX)) <=
2012 0) {
2013 len2 = 1;
2015 memcpy(cp1, cp2, len2);
2016 cp1 += len2;
2017 cp2 += len2;
2020 if (!*cp2) {
2021 (void) printf(
2022 "nmap: unbalanced brackets\n");
2023 return (name);
2025 match = 1;
2027 if (match) {
2028 while (*cp2 && *cp2 != ']') {
2029 if (*cp2 == '\\' && *(cp2 + 1)) {
2030 cp2++;
2032 if ((len2 = mblen(cp2, MB_CUR_MAX)) <=
2034 len2 = 1;
2035 cp2 += len2;
2037 if (!*cp2) {
2038 (void) printf(
2039 "nmap: unbalanced brackets\n");
2040 return (name);
2042 cp2++;
2043 break;
2045 switch (*++cp2) {
2046 case ',':
2047 goto LOOP;
2048 case ']':
2049 break;
2050 default:
2051 cp2--;
2052 goto LOOP;
2054 cp2++;
2055 break;
2056 case '$':
2057 if (isdigit(*(cp2 + 1))) {
2058 if (*++cp2 == '0') {
2059 char *cp3 = name;
2061 while (*cp3) {
2062 *cp1++ = *cp3++;
2064 } else if (toks[toknum = *cp2 - '1']) {
2065 char *cp3 = tp[toknum];
2067 while (cp3 != te[toknum]) {
2068 *cp1++ = *cp3++;
2071 cp2++;
2072 break;
2074 /* FALLTHROUGH */
2075 default:
2076 if ((len2 = mblen(cp2, MB_CUR_MAX)) <= 0)
2077 len2 = 1;
2078 memcpy(cp1, cp2, len2);
2079 cp1 += len2;
2080 cp2 += len2;
2081 break;
2084 *cp1 = '\0';
2085 if (!*new) {
2086 return (name);
2088 return (new);
2091 /*ARGSUSED*/
2092 void
2093 setsunique(int argc, char *argv[])
2095 sunique = !sunique;
2096 (void) printf("Store unique %s.\n", onoff(sunique));
2097 code = sunique;
2100 /*ARGSUSED*/
2101 void
2102 setrunique(int argc, char *argv[])
2104 runique = !runique;
2105 (void) printf("Receive unique %s.\n", onoff(runique));
2106 code = runique;
2109 /*ARGSUSED*/
2110 void
2111 setpassive(int argc, char *argv[])
2113 passivemode = !passivemode;
2114 (void) printf("Passive mode %s.\n", onoff(passivemode));
2115 code = passivemode;
2118 void
2119 settcpwindow(int argc, char *argv[])
2121 int owindowsize = tcpwindowsize;
2123 if (argc > 2) {
2124 (void) printf("usage: %s [size]\n", argv[0]);
2125 code = -1;
2126 return;
2128 if (argc == 2) {
2129 int window;
2130 char *endp;
2132 errno = 0;
2133 window = (int)strtol(argv[1], &endp, 10);
2134 if (errno || window < 0 || *endp != '\0')
2135 (void) printf("%s: Invalid size `%s'\n",
2136 argv[0], argv[1]);
2137 else
2138 tcpwindowsize = window;
2140 if (tcpwindowsize == 0) {
2141 if (owindowsize == 0)
2142 (void) printf("No TCP window size defined\n");
2143 else
2144 (void) printf("TCP window size cleared\n");
2145 } else
2146 (void) printf("TCP window size is set to %d\n", tcpwindowsize);
2149 /* change directory to parent directory */
2150 /*ARGSUSED*/
2151 void
2152 cdup(int argc, char *argv[])
2154 (void) command("CDUP");
2157 void
2158 macdef(int argc, char *argv[])
2160 char *tmp;
2161 int c;
2163 if (macnum == 16) {
2164 (void) printf("Limit of 16 macros have already been defined\n");
2165 code = -1;
2166 return;
2168 if (argc < 2) {
2169 if (prompt_for_arg(line, sizeof (line), "macro name") == -1) {
2170 code = -1;
2171 return;
2173 makeargv();
2174 argc = margc;
2175 argv = margv;
2177 if (argc != 2) {
2178 (void) printf("Usage: %s macro_name\n", argv[0]);
2179 code = -1;
2180 return;
2182 if (interactive) {
2183 (void) printf("Enter macro line by line, terminating "
2184 "it with a null line\n");
2186 (void) strncpy(macros[macnum].mac_name, argv[1], 8);
2187 if (macnum == 0) {
2188 macros[macnum].mac_start = macbuf;
2189 } else {
2190 macros[macnum].mac_start = macros[macnum - 1].mac_end + 1;
2192 tmp = macros[macnum].mac_start;
2193 while (tmp != macbuf+4096) {
2194 if ((c = getchar()) == EOF) {
2195 (void) printf("macdef:end of file encountered\n");
2196 code = -1;
2197 return;
2199 if ((*tmp = c) == '\n') {
2200 if (tmp == macros[macnum].mac_start) {
2201 macros[macnum++].mac_end = tmp;
2202 code = 0;
2203 return;
2205 if (*(tmp-1) == '\0') {
2206 macros[macnum++].mac_end = tmp - 1;
2207 code = 0;
2208 return;
2210 *tmp = '\0';
2212 tmp++;
2214 for (;;) {
2215 while ((c = getchar()) != '\n' && c != EOF)
2216 /* NULL */;
2217 if (c == EOF || getchar() == '\n') {
2218 (void) printf(
2219 "Macro not defined - 4k buffer exceeded\n");
2220 code = -1;
2221 return;
2227 * The p_name strings are for the getlevel and setlevel commands.
2228 * The name strings for printing are in the arpa/ftp.h file in the
2229 * protnames[] array of strings.
2231 static struct levels {
2232 char *p_name;
2233 char *p_mode;
2234 int p_level;
2235 } levels[] = {
2236 { "clear", "C", PROT_C },
2237 { "safe", "S", PROT_S },
2238 { "private", "P", PROT_P },
2239 NULL
2243 * Return a pointer to a string which is the readable version of the
2244 * protection level, or NULL if the input level is not found.
2246 static char *
2247 getlevel(int level)
2249 struct levels *p;
2251 for (p = levels; (p != NULL) && (p->p_level != level); p++)
2253 return (p ? p->p_name : NULL);
2256 static char *plevel[] = {
2257 "protect",
2259 NULL
2263 * Set control channel protection level.
2265 void
2266 setclevel(int argc, char *argv[])
2268 struct levels *p;
2269 char *levelp;
2270 int comret;
2272 if (argc > 2) {
2273 char *sep;
2275 (void) printf("usage: %s [", argv[0]);
2276 sep = " ";
2277 for (p = levels; p->p_name; p++) {
2278 (void) printf("%s%s", sep, p->p_name);
2279 if (*sep == ' ')
2280 sep = " | ";
2282 (void) printf(" ]\n");
2283 code = -1;
2284 return;
2286 if (argc < 2) {
2287 levelp = getlevel(clevel);
2288 (void) printf("Using %s protection level for commands.\n",
2289 levelp ? levelp : "<unknown>");
2290 code = 0;
2291 return;
2293 for (p = levels; (p != NULL) && (p->p_name); p++)
2294 if (strcmp(argv[1], p->p_name) == 0)
2295 break;
2296 if (p->p_name == 0) {
2297 (void) printf("%s: unknown protection level\n", argv[1]);
2298 code = -1;
2299 return;
2301 if (auth_type == AUTHTYPE_NONE) {
2302 if (strcmp(p->p_name, "clear"))
2303 (void) printf("Cannot set protection level to %s\n",
2304 argv[1]);
2305 return;
2307 if (strcmp(p->p_name, "clear") == 0) {
2308 comret = command("CCC");
2309 if (comret == COMPLETE)
2310 clevel = PROT_C;
2311 return;
2313 clevel = p->p_level;
2314 (void) printf("Control channel protection level set to %s.\n",
2315 p->p_name);
2319 * Set data channel protection level.
2321 void
2322 setdlevel(int argc, char *argv[])
2324 struct levels *p;
2325 int comret;
2327 if (argc != 2) {
2328 char *sep;
2330 (void) printf("usage: %s [", argv[0]);
2331 sep = " ";
2332 for (p = levels; p->p_name; p++) {
2333 (void) printf("%s%s", sep, p->p_name);
2334 if (*sep == ' ')
2335 sep = " | ";
2337 (void) printf(" ]\n");
2338 code = -1;
2339 return;
2341 for (p = levels; p->p_name; p++)
2342 if (strcmp(argv[1], p->p_name) == 0)
2343 break;
2344 if (p->p_name == 0) {
2345 (void) printf("%s: unknown protection level\n", argv[1]);
2346 code = -1;
2347 return;
2349 if (auth_type == AUTHTYPE_NONE) {
2350 if (strcmp(p->p_name, "clear"))
2351 (void) printf("Cannot set protection level to %s\n",
2352 argv[1]);
2353 return;
2355 /* Start with a PBSZ of 1 meg */
2356 if (p->p_level != PROT_C)
2357 setpbsz(1<<20);
2358 comret = command("PROT %s", p->p_mode);
2359 if (comret == COMPLETE)
2360 dlevel = p->p_level;
2364 * Set clear command protection level.
2366 /* VARARGS */
2367 void
2368 ccc(int argc, char *argv[])
2370 plevel[1] = "clear";
2371 setclevel(2, plevel);
2375 * Set clear data protection level.
2377 /* VARARGS */
2378 void
2379 setclear(int argc, char *argv[])
2381 plevel[1] = "clear";
2382 setdlevel(2, plevel);
2386 * Set safe data protection level.
2388 /* VARARGS */
2389 void
2390 setsafe(int argc, char *argv[])
2392 plevel[1] = "safe";
2393 setdlevel(2, plevel);
2397 * Set private data protection level.
2399 /* VARARGS */
2400 void
2401 setprivate(int argc, char *argv[])
2403 plevel[1] = "private";
2404 setdlevel(2, plevel);
2408 * Set mechanism type
2410 void
2411 setmech(int argc, char *argv[])
2413 char tempmech[MECH_SZ];
2415 if (argc < 2) {
2416 if (prompt_for_arg(line, sizeof (line), "mech-type") == -1) {
2417 code = -1;
2418 return;
2420 makeargv();
2421 argc = margc;
2422 argv = margv;
2425 if (argc != 2) {
2426 (void) printf("usage: %s [ mechanism type ]\n", argv[0]);
2427 code = -1;
2428 return;
2431 if ((strlcpy(tempmech, argv[1], MECH_SZ) >= MECH_SZ) ||
2432 __gss_mech_to_oid(tempmech, (gss_OID*)&mechoid) !=
2433 GSS_S_COMPLETE) {
2434 (void) printf("%s: %s: not a valid security mechanism\n",
2435 argv[0], tempmech);
2436 code = -1;
2437 return;
2438 } else {
2439 (void) strlcpy(mechstr, tempmech, MECH_SZ);
2440 (void) printf("Using %s mechanism type\n", mechstr);
2441 code = 0;
2442 return;