8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / cmd-inet / usr.bin / ftp / cmds.c
blob4be0e5d3714ac72349580a5dc6fc753fa96ceb90
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.
39 #pragma ident "%Z%%M% %I% %E% SMI"
43 * FTP User Program -- Command Routines.
45 #define FTP_NAMES
46 #include "ftp_var.h"
48 FILE *tmp_nlst = NULL; /* tmp file; holds NLST results for mget, etc */
50 static char *mname;
51 static jmp_buf jabort;
52 static jmp_buf abortprox;
54 static char *remglob(char *argv[], int doswitch);
55 static char *onoff(int bool);
56 static int confirm(char *cmd, char *file);
57 static int globulize(char **cpp);
58 static void proxabort(int sig);
59 static void mabort(int sig);
60 static char *dotrans(char *name);
61 static char *domap(char *name);
62 static void getit(int argc, char *argv[], int restartit, char *mode);
64 static char *getlevel(int);
66 /* Prompt for command argument, add to buffer with space separator */
67 static int
68 prompt_for_arg(char *buffer, int buffer_size, char *prompt)
70 if (strlen(buffer) > buffer_size - 2) {
71 (void) printf("Line too long\n");
72 return (-1);
74 strcat(buffer, " ");
75 stop_timer();
76 (void) printf("(%s) ", prompt);
77 if (fgets(buffer + strlen(buffer), buffer_size - strlen(buffer), stdin)
78 == NULL) {
79 reset_timer();
80 return (-1);
83 /* Flush what didn't fit in the buffer */
84 if (buffer[strlen(buffer)-1] != '\n') {
85 while (fgetc(stdin) != '\n' && !ferror(stdin) && !feof(stdin))
87 (void) printf("Line too long\n");
88 reset_timer();
89 return (-1);
90 } else
91 buffer[strlen(buffer)-1] = 0;
93 reset_timer();
94 return (0);
99 * Connect to peer server and
100 * auto-login, if possible.
102 void
103 setpeer(int argc, char *argv[])
105 char *host;
107 if (connected) {
108 (void) printf("Already connected to %s, use close first.\n",
109 hostname);
110 code = -1;
111 return;
113 if (argc < 2) {
114 if (prompt_for_arg(line, sizeof (line), "to") == -1) {
115 code = -1;
116 return;
118 makeargv();
119 argc = margc;
120 argv = margv;
122 if (argc > 3 || argc < 2) {
123 (void) printf("usage: %s host-name [port]\n", argv[0]);
124 code = -1;
125 return;
127 strcpy(typename, "ascii");
128 host = hookup(argv[1], (argc > 2 ? argv[2] : "ftp"));
129 if (host) {
130 int overbose;
131 extern char reply_string[];
133 connected = 1;
135 * Set up defaults for FTP.
137 clevel = dlevel = PROT_C;
138 if (autoauth) {
139 if (do_auth() && autoencrypt) {
140 clevel = PROT_P;
141 setpbsz(1<<20);
142 if (command("PROT P") == COMPLETE)
143 dlevel = PROT_P;
144 else {
145 (void) fprintf(stderr,
146 "%s: couldn't enable encryption\n",
147 argv[0]);
148 /* unable to encrypt command channel, too! */
149 dlevel = clevel = PROT_C;
152 if ((auth_type != AUTHTYPE_NONE) && (clevel == PROT_C))
153 clevel = PROT_S;
156 if (autologin)
157 (void) login(argv[1]);
158 /* if skipsyst is enabled, then don't send SYST command */
159 if (skipsyst)
160 return;
162 overbose = verbose;
163 if (debug == 0)
164 verbose = -1;
165 if (command("SYST") == COMPLETE && overbose) {
166 char *cp, c;
168 cp = index(reply_string+4, ' ');
169 if (cp == NULL)
170 cp = index(reply_string+4, '\r');
171 if (cp) {
172 if (cp[-1] == '.')
173 cp--;
174 c = *cp;
175 *cp = '\0';
178 (void) printf("Remote system type is %s.\n",
179 reply_string+4);
180 if (cp)
181 *cp = c;
183 if (strncmp(reply_string, "215 UNIX Type: L8", 17) == 0) {
184 setbinary(0, NULL);
185 if (overbose)
186 (void) printf(
187 "Using %s mode to transfer files.\n",
188 typename);
189 } else if (overbose &&
190 strncmp(reply_string, "215 TOPS20", 10) == 0) {
191 (void) printf(
192 "Remember to set tenex mode when transfering "
193 "binary files from this machine.\n");
195 verbose = overbose;
199 static struct types {
200 char *t_name;
201 char *t_mode;
202 int t_type;
203 char *t_arg;
204 } types[] = {
205 { "ascii", "A", TYPE_A, 0 },
206 { "binary", "I", TYPE_I, 0 },
207 { "image", "I", TYPE_I, 0 },
208 { "ebcdic", "E", TYPE_E, 0 },
209 { "tenex", "L", TYPE_L, bytename },
214 * Set transfer type.
216 void
217 settype(int argc, char *argv[])
219 struct types *p;
220 int comret;
222 if (argc > 2) {
223 char *sep;
225 (void) printf("usage: %s [", argv[0]);
226 sep = " ";
227 for (p = types; p->t_name; p++) {
228 (void) printf("%s%s", sep, p->t_name);
229 if (*sep == ' ')
230 sep = " | ";
232 (void) printf(" ]\n");
233 code = -1;
234 return;
236 if (argc < 2) {
237 (void) printf("Using %s mode to transfer files.\n", typename);
238 code = 0;
239 return;
241 for (p = types; p->t_name; p++)
242 if (strcmp(argv[1], p->t_name) == 0)
243 break;
244 if (p->t_name == 0) {
245 (void) printf("%s: unknown mode\n", argv[1]);
246 code = -1;
247 return;
249 if ((p->t_arg != NULL) && (*(p->t_arg) != '\0'))
250 comret = command("TYPE %s %s", p->t_mode, p->t_arg);
251 else
252 comret = command("TYPE %s", p->t_mode);
253 if (comret == COMPLETE) {
254 (void) strcpy(typename, p->t_name);
255 type = p->t_type;
260 * Set binary transfer type.
262 /*ARGSUSED*/
263 void
264 setbinary(int argc, char *argv[])
266 call(settype, "type", "binary", 0);
270 * Set ascii transfer type.
272 /*ARGSUSED*/
273 void
274 setascii(int argc, char *argv[])
276 call(settype, "type", "ascii", 0);
280 * Set tenex transfer type.
282 /*ARGSUSED*/
283 void
284 settenex(int argc, char *argv[])
286 call(settype, "type", "tenex", 0);
290 * Set ebcdic transfer type.
292 /*ARGSUSED*/
293 void
294 setebcdic(int argc, char *argv[])
296 call(settype, "type", "ebcdic", 0);
300 * Set file transfer mode.
302 /*ARGSUSED*/
303 void
304 setmode(int argc, char *argv[])
306 (void) printf("We only support %s mode, sorry.\n", modename);
307 code = -1;
311 * Set file transfer format.
313 /*ARGSUSED*/
314 void
315 setform(int argc, char *argv[])
317 (void) printf("We only support %s format, sorry.\n", formname);
318 code = -1;
322 * Set file transfer structure.
324 /*ARGSUSED*/
325 void
326 setstruct(int argc, char *argv[])
329 (void) printf("We only support %s structure, sorry.\n", structname);
330 code = -1;
334 * Send a single file.
336 void
337 put(int argc, char *argv[])
339 char *cmd;
340 int loc = 0;
341 char *oldargv1;
343 if (argc == 2) {
344 argc++;
345 argv[2] = argv[1];
346 loc++;
348 if (argc < 2) {
349 if (prompt_for_arg(line, sizeof (line), "local-file") == -1) {
350 code = -1;
351 return;
353 makeargv();
354 argc = margc;
355 argv = margv;
357 if (argc < 2) {
358 usage:
359 (void) printf("usage: %s local-file remote-file\n", argv[0]);
360 code = -1;
361 return;
363 if (argc < 3) {
364 if (prompt_for_arg(line, sizeof (line), "remote-file") == -1) {
365 code = -1;
366 return;
368 makeargv();
369 argc = margc;
370 argv = margv;
372 if (argc < 3)
373 goto usage;
374 oldargv1 = argv[1];
375 if (!globulize(&argv[1])) {
376 code = -1;
377 return;
380 * If "globulize" modifies argv[1], and argv[2] is a copy of
381 * the old argv[1], make it a copy of the new argv[1].
383 if (argv[1] != oldargv1 && argv[2] == oldargv1) {
384 argv[2] = argv[1];
386 cmd = (argv[0][0] == 'a') ? "APPE" : ((sunique) ? "STOU" : "STOR");
387 if (loc && ntflag) {
388 argv[2] = dotrans(argv[2]);
390 if (loc && mapflag) {
391 argv[2] = domap(argv[2]);
393 sendrequest(cmd, argv[1], argv[2], 1);
396 /*ARGSUSED*/
397 static void
398 mabort(int sig)
400 int ointer;
402 (void) printf("\n");
403 (void) fflush(stdout);
404 if (mflag && fromatty) {
405 ointer = interactive;
406 interactive = 1;
407 if (confirm("Continue with", mname)) {
408 interactive = ointer;
409 longjmp(jabort, 0);
411 interactive = ointer;
413 mflag = 0;
414 longjmp(jabort, 0);
418 * Send multiple files.
420 void
421 mput(int argc, char *argv[])
423 int i;
424 int ointer;
425 void (*oldintr)();
426 char *tp;
427 int len;
429 if (argc < 2) {
430 if (prompt_for_arg(line, sizeof (line), "local-files") == -1) {
431 code = -1;
432 return;
434 makeargv();
435 argc = margc;
436 argv = margv;
438 if (argc < 2) {
439 (void) printf("usage: %s local-files\n", argv[0]);
440 code = -1;
441 return;
443 mname = argv[0];
444 mflag = 1;
445 oldintr = signal(SIGINT, mabort);
446 (void) setjmp(jabort);
447 if (proxy) {
448 char *cp, *tp2, tmpbuf[MAXPATHLEN];
450 while ((cp = remglob(argv, 0)) != NULL) {
451 if (*cp == 0) {
452 mflag = 0;
453 continue;
455 if (mflag && confirm(argv[0], cp)) {
456 tp = cp;
457 if (mcase) {
458 while (*tp) {
459 if ((len =
460 mblen(tp, MB_CUR_MAX)) <= 0)
461 len = 1;
462 if (islower(*tp))
463 break;
464 tp += len;
466 if (!*tp) {
467 tp = cp;
468 tp2 = tmpbuf;
469 while (*tp) {
470 if ((len = mblen(tp,
471 MB_CUR_MAX)) <= 0)
472 len = 1;
473 memcpy(tp2, tp, len);
474 if (isupper(*tp2)) {
475 *tp2 = 'a' +
476 *tp2 - 'A';
478 tp += len;
479 tp2 += len;
481 *tp2 = 0;
482 tp = tmpbuf;
485 if (ntflag) {
486 tp = dotrans(tp);
488 if (mapflag) {
489 tp = domap(tp);
491 sendrequest((sunique) ? "STOU" : "STOR",
492 cp, tp, 0);
493 if (!mflag && fromatty) {
494 ointer = interactive;
495 interactive = 1;
496 if (confirm("Continue with", "mput")) {
497 mflag++;
499 interactive = ointer;
503 (void) signal(SIGINT, oldintr);
504 mflag = 0;
505 return;
507 for (i = 1; i < argc; i++) {
508 char **cpp, **gargs;
510 if (!doglob) {
511 if (mflag && confirm(argv[0], argv[i])) {
512 tp = (ntflag) ? dotrans(argv[i]) : argv[i];
513 tp = (mapflag) ? domap(tp) : tp;
514 sendrequest((sunique) ? "STOU" : "STOR",
515 argv[i], tp, 1);
516 if (!mflag && fromatty) {
517 ointer = interactive;
518 interactive = 1;
519 if (confirm("Continue with", "mput")) {
520 mflag++;
522 interactive = ointer;
525 continue;
527 gargs = glob(argv[i]);
528 if (globerr != NULL) {
529 (void) printf("%s\n", globerr);
530 if (gargs)
531 blkfree(gargs);
532 continue;
534 for (cpp = gargs; cpp && *cpp != NULL; cpp++) {
535 if (mflag && confirm(argv[0], *cpp)) {
536 tp = (ntflag) ? dotrans(*cpp) : *cpp;
537 tp = (mapflag) ? domap(tp) : tp;
538 sendrequest((sunique) ? "STOU" : "STOR",
539 *cpp, tp, 0);
540 if (!mflag && fromatty) {
541 ointer = interactive;
542 interactive = 1;
543 if (confirm("Continue with", "mput")) {
544 mflag++;
546 interactive = ointer;
550 if (gargs != NULL)
551 blkfree(gargs);
553 (void) signal(SIGINT, oldintr);
554 mflag = 0;
558 * Restart transfer at a specific offset.
560 void
561 restart(int argc, char *argv[])
563 off_t orestart_point = restart_point;
565 if (argc > 2) {
566 (void) printf("usage: %s [marker]\n", argv[0]);
567 code = -1;
568 return;
570 if (argc == 2) {
571 longlong_t rp;
572 char *endp;
574 errno = 0;
575 rp = strtoll(argv[1], &endp, 10);
576 if (errno || rp < 0 || *endp != '\0')
577 (void) printf("%s: Invalid offset `%s'\n",
578 argv[0], argv[1]);
579 else
580 restart_point = rp;
582 if (restart_point == 0) {
583 if (orestart_point == 0)
584 (void) printf("No restart marker defined\n");
585 else
586 (void) printf("Restart marker cleared\n");
587 } else
588 (void) printf(
589 "Restarting at %lld for next get, put or append\n",
590 (longlong_t)restart_point);
593 void
594 reget(int argc, char *argv[])
596 getit(argc, argv, 1, "r+w");
599 void
600 get(int argc, char *argv[])
602 getit(argc, argv, 0, restart_point ? "r+w" : "w");
606 * Receive one file.
608 static void
609 getit(int argc, char *argv[], int restartit, char *mode)
611 int loc = 0;
612 int len;
613 int allowpipe = 1;
615 if (argc == 2) {
616 argc++;
617 argv[2] = argv[1];
618 /* Only permit !file if two arguments. */
619 allowpipe = 0;
620 loc++;
622 if (argc < 2) {
623 if (prompt_for_arg(line, sizeof (line), "remote-file") == -1) {
624 code = -1;
625 return;
627 makeargv();
628 argc = margc;
629 argv = margv;
631 if (argc < 2) {
632 usage:
633 (void) printf("usage: %s remote-file [ local-file ]\n",
634 argv[0]);
635 code = -1;
636 return;
638 if (argc < 3) {
639 if (prompt_for_arg(line, sizeof (line), "local-file") == -1) {
640 code = -1;
641 return;
643 makeargv();
644 argc = margc;
645 argv = margv;
647 if (argc < 3)
648 goto usage;
649 if (!globulize(&argv[2])) {
650 code = -1;
651 return;
653 if (loc && mcase) {
654 char *tp = argv[1], *tp2, tmpbuf[MAXPATHLEN];
656 while (*tp) {
657 if ((len = mblen(tp, MB_CUR_MAX)) <= 0)
658 len = 1;
659 if (islower(*tp))
660 break;
661 tp += len;
663 if (!*tp) {
664 tp = argv[2];
665 tp2 = tmpbuf;
666 while (*tp) {
667 if ((len = mblen(tp, MB_CUR_MAX)) <= 0)
668 len = 1;
669 memcpy(tp2, tp, len);
670 if (isupper(*tp2))
671 *tp2 = 'a' + *tp2 - 'A';
672 tp += len;
673 tp2 += len;
675 *tp2 = 0;
676 argv[2] = tmpbuf;
679 if (loc && ntflag) {
680 argv[2] = dotrans(argv[2]);
682 if (loc && mapflag) {
683 argv[2] = domap(argv[2]);
685 if (restartit) {
686 struct stat stbuf;
688 if (stat(argv[2], &stbuf) < 0) {
689 perror(argv[2]);
690 code = -1;
691 return;
693 restart_point = stbuf.st_size;
695 recvrequest("RETR", argv[2], argv[1], mode, allowpipe);
696 restart_point = 0;
700 * Get multiple files.
702 void
703 mget(int argc, char *argv[])
705 char *cp, *tp, *tp2, tmpbuf[MAXPATHLEN];
706 int ointer;
707 void (*oldintr)();
708 int need_convert;
709 int len;
711 if (argc < 2) {
712 if (prompt_for_arg(line, sizeof (line), "remote-files") < 0) {
713 code = -1;
714 return;
716 makeargv();
717 argc = margc;
718 argv = margv;
720 if (argc < 2) {
721 (void) printf("usage: %s remote-files\n", argv[0]);
722 code = -1;
723 return;
725 mname = argv[0];
726 mflag = 1;
727 oldintr = signal(SIGINT, mabort);
728 (void) setjmp(jabort);
729 while ((cp = remglob(argv, proxy)) != NULL) {
730 if (*cp == '\0') {
731 mflag = 0;
732 continue;
734 if (mflag && confirm(argv[0], cp)) {
735 strcpy(tmpbuf, cp);
736 tp = tmpbuf;
737 need_convert = 1;
738 if (mcase) {
739 tp2 = tp;
740 while (*tp2 && need_convert) {
741 /* Need any case convert? */
742 if (islower(*tp2))
743 need_convert = 0;
744 if ((len = mblen(tp2, MB_CUR_MAX)) <= 0)
745 len = 1;
746 tp2 += len;
748 tp2 = tp;
749 while (need_convert && *tp2) {
750 /* Convert to lower case */
751 if (isupper(*tp2))
752 *tp2 = tolower(*tp2);
753 if ((len = mblen(tp2, MB_CUR_MAX)) <= 0)
754 len = 1;
755 tp2 += len;
759 if (ntflag) {
760 tp = dotrans(tp);
762 if (mapflag) {
763 tp = domap(tp);
765 recvrequest("RETR", tp, cp, "w", 0);
766 restart_point = 0;
767 if (!mflag && fromatty) {
768 ointer = interactive;
769 interactive = 1;
770 if (confirm("Continue with", "mget")) {
771 mflag++;
773 interactive = ointer;
777 (void) signal(SIGINT, oldintr);
778 mflag = 0;
781 static char *
782 remglob(char *argv[], int doswitch)
784 static char buf[MAXPATHLEN];
785 static char **args;
786 int oldverbose, oldhash;
787 char *cp;
789 if (!mflag) {
790 if (!doglob) {
791 args = NULL;
792 } else {
793 if (tmp_nlst != NULL) {
794 (void) fclose(tmp_nlst);
795 tmp_nlst = NULL;
798 return (NULL);
800 if (!doglob) {
801 if (args == NULL)
802 args = argv;
803 if ((cp = *++args) == NULL)
804 args = NULL;
805 return (cp);
807 if (tmp_nlst == NULL) {
808 if ((tmp_nlst = tmpfile()) == NULL) {
809 (void) printf("%s\n", strerror(errno));
810 return (NULL);
812 oldverbose = verbose, verbose = 0;
813 oldhash = hash, hash = 0;
814 if (doswitch) {
815 pswitch(!proxy);
817 for (; *++argv != NULL; )
818 recvrequest("NLST", NULL, *argv, "", 0);
819 rewind(tmp_nlst);
820 if (doswitch) {
821 pswitch(!proxy);
823 verbose = oldverbose; hash = oldhash;
825 reset_timer();
826 if (fgets(buf, sizeof (buf), tmp_nlst) == NULL) {
827 (void) fclose(tmp_nlst), tmp_nlst = NULL;
828 return (NULL);
830 if ((cp = index(buf, '\n')) != NULL)
831 *cp = '\0';
832 return (buf);
835 static char *
836 onoff(int bool)
838 return (bool ? "on" : "off");
842 * Show status.
844 /*ARGSUSED*/
845 void
846 status(int argc, char *argv[])
848 int i;
849 char *levelp;
851 if (connected)
852 (void) printf("Connected to %s.\n", hostname);
853 else
854 (void) printf("Not connected.\n");
855 if (!proxy) {
856 pswitch(1);
857 if (connected) {
858 (void) printf("Connected for proxy commands to %s.\n",
859 hostname);
860 } else {
861 (void) printf("No proxy connection.\n");
863 pswitch(0);
866 if (auth_type != AUTHTYPE_NONE)
867 (void) printf("Authentication type: %s\n",
868 GSS_AUTHTYPE_NAME(auth_type));
869 else
870 (void) printf("Not authenticated.\n");
871 (void) printf("Mechanism: %s\n", mechstr);
872 (void) printf("Autoauth: %s; Autologin: %s\n",
873 onoff(autoauth), onoff(autologin));
874 levelp = getlevel(clevel);
875 (void) printf("Control Channel Protection Level: %s\n",
876 levelp ? levelp : "<unknown>");
877 levelp = getlevel(dlevel);
878 (void) printf("Data Channel Protection Level: %s\n",
879 levelp ? levelp : "<unknown>");
881 (void) printf("Passive mode: %s.\n", onoff(passivemode));
882 (void) printf("Mode: %s; Type: %s; Form: %s; Structure: %s\n",
883 modename, typename, formname, structname);
884 (void) printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s\n",
885 onoff(verbose), onoff(bell), onoff(interactive),
886 onoff(doglob));
887 (void) printf("Store unique: %s; Receive unique: %s\n", onoff(sunique),
888 onoff(runique));
889 (void) printf("Case: %s; CR stripping: %s\n",
890 onoff(mcase), onoff(crflag));
891 if (ntflag) {
892 (void) printf("Ntrans: (in) %s (out) %s\n", ntin, ntout);
893 } else {
894 (void) printf("Ntrans: off\n");
896 if (mapflag) {
897 (void) printf("Nmap: (in) %s (out) %s\n", mapin, mapout);
898 } else {
899 (void) printf("Nmap: off\n");
901 (void) printf("Hash mark printing: %s; Use of PORT cmds: %s\n",
902 onoff(hash), onoff(sendport));
903 if (macnum > 0) {
904 (void) printf("Macros:\n");
905 for (i = 0; i < macnum; i++) {
906 (void) printf("\t%s\n", macros[i].mac_name);
909 code = 0;
913 * Set beep on cmd completed mode.
915 /*ARGSUSED*/
916 void
917 setbell(int argc, char *argv[])
919 bell = !bell;
920 (void) printf("Bell mode %s.\n", onoff(bell));
921 code = bell;
925 * Turn on packet tracing.
927 /*ARGSUSED*/
928 void
929 settrace(int argc, char *argv[])
931 trace = !trace;
932 (void) printf("Packet tracing %s.\n", onoff(trace));
933 code = trace;
937 * Toggle hash mark printing during transfers.
939 /*ARGSUSED*/
940 void
941 sethash(int argc, char *argv[])
943 hash = !hash;
944 (void) printf("Hash mark printing %s", onoff(hash));
945 code = hash;
946 if (hash)
947 (void) printf(" (%d bytes/hash mark)", HASHSIZ);
948 (void) printf(".\n");
952 * Turn on printing of server echo's.
954 /*ARGSUSED*/
955 void
956 setverbose(int argc, char *argv[])
958 verbose = !verbose;
959 (void) printf("Verbose mode %s.\n", onoff(verbose));
960 code = verbose;
964 * Toggle PORT cmd use before each data connection.
966 /*ARGSUSED*/
967 void
968 setport(int argc, char *argv[])
970 sendport = !sendport;
971 (void) printf("Use of PORT cmds %s.\n", onoff(sendport));
972 code = sendport;
976 * Turn on interactive prompting
977 * during mget, mput, and mdelete.
979 /*ARGSUSED*/
980 void
981 setprompt(int argc, char *argv[])
983 interactive = !interactive;
984 (void) printf("Interactive mode %s.\n", onoff(interactive));
985 code = interactive;
989 * Toggle metacharacter interpretation
990 * on local file names.
992 /*ARGSUSED*/
993 void
994 setglob(int argc, char *argv[])
996 doglob = !doglob;
997 (void) printf("Globbing %s.\n", onoff(doglob));
998 code = doglob;
1002 * Set debugging mode on/off and/or
1003 * set level of debugging.
1005 void
1006 setdebug(int argc, char *argv[])
1008 int val;
1010 if (argc > 1) {
1011 val = atoi(argv[1]);
1012 if (val < 0) {
1013 (void) printf("%s: bad debugging value.\n", argv[1]);
1014 code = -1;
1015 return;
1017 } else
1018 val = !debug;
1019 debug = val;
1020 if (debug)
1021 options |= SO_DEBUG;
1022 else
1023 options &= ~SO_DEBUG;
1024 (void) printf("Debugging %s (debug=%d).\n", onoff(debug), debug);
1025 code = debug > 0;
1029 * Set current working directory
1030 * on remote machine.
1032 void
1033 cd(int argc, char *argv[])
1035 if (argc < 2) {
1036 if (prompt_for_arg(line, sizeof (line), "remote-directory") <
1037 0) {
1038 code = -1;
1039 return;
1041 makeargv();
1042 argc = margc;
1043 argv = margv;
1045 if (argc < 2) {
1046 (void) printf("usage: %s remote-directory\n", argv[0]);
1047 code = -1;
1048 return;
1050 (void) command("CWD %s", argv[1]);
1054 * Set current working directory
1055 * on local machine.
1057 void
1058 lcd(int argc, char *argv[])
1060 char buf[MAXPATHLEN], *bufptr;
1062 if (argc < 2)
1063 argc++, argv[1] = home;
1064 if (argc != 2) {
1065 (void) printf("usage: %s local-directory\n", argv[0]);
1066 code = -1;
1067 return;
1069 if (!globulize(&argv[1])) {
1070 code = -1;
1071 return;
1073 if (chdir(argv[1]) < 0) {
1074 perror(argv[1]);
1075 code = -1;
1076 return;
1078 bufptr = getcwd(buf, MAXPATHLEN);
1080 * Even though chdir may succeed, getcwd may fail if a component
1081 * of the pwd is unreadable. In this case, print the argument to
1082 * chdir as the resultant directory, since we know it succeeded above.
1084 (void) printf("Local directory now %s\n", (bufptr ? bufptr : argv[1]));
1085 code = 0;
1089 * Delete a single file.
1091 void
1092 delete(int argc, char *argv[])
1095 if (argc < 2) {
1096 if (prompt_for_arg(line, sizeof (line), "remote-file") < 0) {
1097 code = -1;
1098 return;
1100 makeargv();
1101 argc = margc;
1102 argv = margv;
1104 if (argc < 2) {
1105 (void) printf("usage: %s remote-file\n", argv[0]);
1106 code = -1;
1107 return;
1109 (void) command("DELE %s", argv[1]);
1113 * Delete multiple files.
1115 void
1116 mdelete(int argc, char *argv[])
1118 char *cp;
1119 int ointer;
1120 void (*oldintr)();
1122 if (argc < 2) {
1123 if (prompt_for_arg(line, sizeof (line), "remote-files") < 0) {
1124 code = -1;
1125 return;
1127 makeargv();
1128 argc = margc;
1129 argv = margv;
1131 if (argc < 2) {
1132 (void) printf("usage: %s remote-files\n", argv[0]);
1133 code = -1;
1134 return;
1136 mname = argv[0];
1137 mflag = 1;
1138 oldintr = signal(SIGINT, mabort);
1139 (void) setjmp(jabort);
1140 while ((cp = remglob(argv, 0)) != NULL) {
1141 if (*cp == '\0') {
1142 mflag = 0;
1143 continue;
1145 if (mflag && confirm(argv[0], cp)) {
1146 (void) command("DELE %s", cp);
1147 if (!mflag && fromatty) {
1148 ointer = interactive;
1149 interactive = 1;
1150 if (confirm("Continue with", "mdelete")) {
1151 mflag++;
1153 interactive = ointer;
1157 (void) signal(SIGINT, oldintr);
1158 mflag = 0;
1162 * Rename a remote file.
1164 void
1165 renamefile(int argc, char *argv[])
1168 if (argc < 2) {
1169 if (prompt_for_arg(line, sizeof (line), "from-name") < 0) {
1170 code = -1;
1171 return;
1173 makeargv();
1174 argc = margc;
1175 argv = margv;
1177 if (argc < 2) {
1178 usage:
1179 (void) printf("%s from-name to-name\n", argv[0]);
1180 code = -1;
1181 return;
1183 if (argc < 3) {
1184 if (prompt_for_arg(line, sizeof (line), "to-name") < 0) {
1185 code = -1;
1186 return;
1188 makeargv();
1189 argc = margc;
1190 argv = margv;
1192 if (argc < 3)
1193 goto usage;
1194 if (command("RNFR %s", argv[1]) == CONTINUE)
1195 (void) command("RNTO %s", argv[2]);
1199 * Get a directory listing
1200 * of remote files.
1202 void
1203 ls(int argc, char *argv[])
1205 char *cmd;
1207 if (argc < 2)
1208 argc++, argv[1] = NULL;
1209 if (argc < 3)
1210 argc++, argv[2] = "-";
1211 if (argc > 3) {
1212 (void) printf("usage: %s remote-directory local-file\n",
1213 argv[0]);
1214 code = -1;
1215 return;
1217 if (ls_invokes_NLST) {
1218 cmd = ((argv[0][0] == 'l' || argv[0][0] == 'n') ?
1219 "NLST" : "LIST");
1220 } else {
1221 cmd = ((argv[0][0] == 'n') ? "NLST" : "LIST");
1223 if (strcmp(argv[2], "-") && !globulize(&argv[2])) {
1224 code = -1;
1225 return;
1227 recvrequest(cmd, argv[2], argv[1], "w", 1);
1231 * Get a directory listing
1232 * of multiple remote files.
1234 void
1235 mls(int argc, char *argv[])
1237 char *cmd, mode[1], *dest;
1238 int ointer, i;
1239 void (*oldintr)();
1241 if (argc < 2) {
1242 if (prompt_for_arg(line, sizeof (line), "remote-files") < 0) {
1243 code = -1;
1244 return;
1246 makeargv();
1247 argc = margc;
1248 argv = margv;
1250 if (argc < 3) {
1251 if (prompt_for_arg(line, sizeof (line), "local-file") < 0) {
1252 code = -1;
1253 return;
1255 makeargv();
1256 argc = margc;
1257 argv = margv;
1259 if (argc < 3) {
1260 (void) printf("usage: %s remote-files local-file\n", argv[0]);
1261 code = -1;
1262 return;
1264 dest = argv[argc - 1];
1265 argv[argc - 1] = NULL;
1266 if (strcmp(dest, "-") && *dest != '|')
1267 if (!globulize(&dest) ||
1268 !confirm("output to local-file:", dest)) {
1269 code = -1;
1270 return;
1272 cmd = argv[0][1] == 'l' ? "NLST" : "LIST";
1273 mname = argv[0];
1274 mflag = 1;
1275 oldintr = signal(SIGINT, mabort);
1276 (void) setjmp(jabort);
1277 for (i = 1; mflag && i < argc-1; ++i) {
1278 *mode = (i == 1) ? 'w' : 'a';
1279 recvrequest(cmd, dest, argv[i], mode, 1);
1280 if (!mflag && fromatty) {
1281 ointer = interactive;
1282 interactive = 1;
1283 if (confirm("Continue with", argv[0])) {
1284 mflag ++;
1286 interactive = ointer;
1289 (void) signal(SIGINT, oldintr);
1290 mflag = 0;
1294 * Do a shell escape
1296 /*ARGSUSED*/
1297 void
1298 shell(int argc, char *argv[])
1300 pid_t pid;
1301 void (*old1)(), (*old2)();
1302 char *shellstring, *namep;
1303 int status;
1305 stop_timer();
1306 old1 = signal(SIGINT, SIG_IGN);
1307 old2 = signal(SIGQUIT, SIG_IGN);
1308 if ((pid = fork()) == 0) {
1309 closefrom(STDERR_FILENO + 1);
1310 (void) signal(SIGINT, SIG_DFL);
1311 (void) signal(SIGQUIT, SIG_DFL);
1312 shellstring = getenv("SHELL");
1313 if (shellstring == NULL)
1314 shellstring = "/bin/sh";
1315 namep = rindex(shellstring, '/');
1316 if (namep == NULL)
1317 namep = shellstring;
1318 if (argc > 1) {
1319 if (debug) {
1320 (void) printf("%s -c %s\n", shellstring,
1321 altarg);
1322 (void) fflush(stdout);
1324 execl(shellstring, namep, "-c", altarg, (char *)0);
1325 } else {
1326 if (debug) {
1327 (void) printf("%s\n", shellstring);
1328 (void) fflush(stdout);
1330 execl(shellstring, namep, (char *)0);
1332 perror(shellstring);
1333 code = -1;
1334 exit(1);
1336 if (pid > 0)
1337 while (wait(&status) != pid)
1339 (void) signal(SIGINT, old1);
1340 (void) signal(SIGQUIT, old2);
1341 reset_timer();
1342 if (pid == (pid_t)-1) {
1343 perror("Try again later");
1344 code = -1;
1345 } else {
1346 code = 0;
1351 * Send new user information (re-login)
1353 void
1354 user(int argc, char *argv[])
1356 char acct[80];
1357 int n, aflag = 0;
1359 if (argc < 2) {
1360 if (prompt_for_arg(line, sizeof (line), "username") < 0) {
1361 code = -1;
1362 return;
1364 makeargv();
1365 argc = margc;
1366 argv = margv;
1368 if (argc > 4) {
1369 (void) printf("usage: %s username [password] [account]\n",
1370 argv[0]);
1371 code = -1;
1372 return;
1374 if (argv[1] == 0) {
1375 (void) printf("access for user (nil) denied\n");
1376 code = -1;
1377 return;
1379 n = command("USER %s", argv[1]);
1380 if (n == CONTINUE) {
1381 int oldclevel;
1382 if (argc < 3)
1383 argv[2] = mygetpass("Password: "), argc++;
1384 if ((oldclevel = clevel) == PROT_S)
1385 clevel = PROT_P;
1386 n = command("PASS %s", argv[2]);
1387 /* level may have changed */
1388 if (clevel == PROT_P)
1389 clevel = oldclevel;
1391 if (n == CONTINUE) {
1392 if (argc < 4) {
1393 (void) printf("Account: "); (void) fflush(stdout);
1394 stop_timer();
1395 (void) fgets(acct, sizeof (acct) - 1, stdin);
1396 reset_timer();
1397 acct[strlen(acct) - 1] = '\0';
1398 argv[3] = acct; argc++;
1400 n = command("ACCT %s", argv[3]);
1401 aflag++;
1403 if (n != COMPLETE) {
1404 (void) fprintf(stdout, "Login failed.\n");
1405 return;
1407 if (!aflag && argc == 4) {
1408 (void) command("ACCT %s", argv[3]);
1413 * Print working directory.
1415 /*ARGSUSED*/
1416 void
1417 pwd(int argc, char *argv[])
1419 (void) command("PWD");
1423 * Make a directory.
1425 void
1426 makedir(int argc, char *argv[])
1428 if (argc < 2) {
1429 if (prompt_for_arg(line, sizeof (line), "directory-name") <
1430 0) {
1431 code = -1;
1432 return;
1434 makeargv();
1435 argc = margc;
1436 argv = margv;
1438 if (argc < 2) {
1439 (void) printf("usage: %s directory-name\n", argv[0]);
1440 code = -1;
1441 return;
1443 (void) command("MKD %s", argv[1]);
1447 * Remove a directory.
1449 void
1450 removedir(int argc, char *argv[])
1452 if (argc < 2) {
1453 if (prompt_for_arg(line, sizeof (line), "directory-name") <
1454 0) {
1455 code = -1;
1456 return;
1458 makeargv();
1459 argc = margc;
1460 argv = margv;
1462 if (argc < 2) {
1463 (void) printf("usage: %s directory-name\n", argv[0]);
1464 code = -1;
1465 return;
1467 (void) command("RMD %s", argv[1]);
1471 * Send a line, verbatim, to the remote machine.
1473 void
1474 quote(int argc, char *argv[])
1476 int i, n, len;
1477 char buf[FTPBUFSIZ];
1479 if (argc < 2) {
1480 if (prompt_for_arg(line, sizeof (line),
1481 "command line to send") == -1) {
1482 code = -1;
1483 return;
1485 makeargv();
1486 argc = margc;
1487 argv = margv;
1489 if (argc < 2) {
1490 (void) printf("usage: %s line-to-send\n", argv[0]);
1491 code = -1;
1492 return;
1494 len = snprintf(buf, sizeof (buf), "%s", argv[1]);
1495 if (len >= 0 && len < sizeof (buf) - 1) {
1496 for (i = 2; i < argc; i++) {
1497 n = snprintf(&buf[len], sizeof (buf) - len, " %s",
1498 argv[i]);
1499 if (n < 0 || n >= sizeof (buf) - len)
1500 break;
1501 len += n;
1504 if (command("%s", buf) == PRELIM) {
1505 while (getreply(0) == PRELIM)
1511 * Send a line, verbatim, to the remote machine as a SITE command.
1513 void
1514 site(int argc, char *argv[])
1516 int i, n, len;
1517 char buf[FTPBUFSIZ];
1519 if (argc < 2) {
1520 if (prompt_for_arg(line, sizeof (line),
1521 "arguments to SITE command") == -1) {
1522 code = -1;
1523 return;
1525 makeargv();
1526 argc = margc;
1527 argv = margv;
1529 if (argc < 2) {
1530 (void) printf("usage: %s arg1 [arg2] ...\n", argv[0]);
1531 code = -1;
1532 return;
1534 len = snprintf(buf, sizeof (buf), "%s", argv[1]);
1535 if (len >= 0 && len < sizeof (buf) - 1) {
1536 for (i = 2; i < argc; i++) {
1537 n = snprintf(&buf[len], sizeof (buf) - len, " %s",
1538 argv[i]);
1539 if (n < 0 || n >= sizeof (buf) - len)
1540 break;
1541 len += n;
1544 if (command("SITE %s", buf) == PRELIM) {
1545 while (getreply(0) == PRELIM)
1551 * Ask the other side for help.
1553 void
1554 rmthelp(int argc, char *argv[])
1556 int oldverbose = verbose;
1558 verbose = 1;
1559 (void) command(argc == 1 ? "HELP" : "HELP %s", argv[1]);
1560 verbose = oldverbose;
1564 * Terminate session and exit.
1566 /*ARGSUSED*/
1567 void
1568 quit(int argc, char *argv[])
1570 if (connected)
1571 disconnect(0, NULL);
1572 pswitch(1);
1573 if (connected) {
1574 disconnect(0, NULL);
1576 exit(0);
1580 * Terminate session, but don't exit.
1582 /*ARGSUSED*/
1583 void
1584 disconnect(int argc, char *argv[])
1586 extern FILE *ctrl_in, *ctrl_out;
1587 extern int data;
1589 if (!connected)
1590 return;
1591 (void) command("QUIT");
1592 if (ctrl_in) {
1593 reset_timer();
1594 (void) fclose(ctrl_in);
1596 if (ctrl_out) {
1597 reset_timer();
1598 (void) fclose(ctrl_out);
1600 ctrl_out = ctrl_in = NULL;
1601 connected = 0;
1602 data = -1;
1603 if (!proxy) {
1604 macnum = 0;
1607 auth_type = AUTHTYPE_NONE;
1608 clevel = dlevel = PROT_C;
1609 goteof = 0;
1612 static int
1613 confirm(char *cmd, char *file)
1615 char line[FTPBUFSIZ];
1617 if (!interactive)
1618 return (1);
1619 stop_timer();
1620 (void) printf("%s %s? ", cmd, file);
1621 (void) fflush(stdout);
1622 *line = '\0';
1623 (void) fgets(line, sizeof (line), stdin);
1624 reset_timer();
1625 return (*line != 'n' && *line != 'N');
1628 void
1629 fatal(char *msg)
1631 (void) fprintf(stderr, "ftp: %s\n", msg);
1632 exit(1);
1636 * Glob a local file name specification with
1637 * the expectation of a single return value.
1638 * Can't control multiple values being expanded
1639 * from the expression, we return only the first.
1641 static int
1642 globulize(char **cpp)
1644 char **globbed;
1646 if (!doglob)
1647 return (1);
1648 globbed = glob(*cpp);
1649 if (globbed != NULL && *globbed == NULL && globerr == NULL)
1650 globerr = "No match";
1651 if (globerr != NULL) {
1652 (void) printf("%s: %s\n", *cpp, globerr);
1653 if (globbed)
1654 blkfree(globbed);
1655 return (0);
1657 if (globbed) {
1658 *cpp = strdup(*globbed);
1659 blkfree(globbed);
1660 if (!*cpp)
1661 return (0);
1663 return (1);
1666 void
1667 account(int argc, char *argv[])
1669 char acct[50], *ap;
1671 if (argc > 1) {
1672 ++argv;
1673 --argc;
1674 (void) strncpy(acct, *argv, 49);
1675 acct[49] = '\0';
1676 while (argc > 1) {
1677 --argc;
1678 ++argv;
1679 (void) strncat(acct, *argv, 49 - strlen(acct));
1681 ap = acct;
1682 } else {
1683 ap = mygetpass("Account:");
1685 (void) command("ACCT %s", ap);
1688 /*ARGSUSED*/
1689 static void
1690 proxabort(int sig)
1692 extern int proxy;
1694 if (!proxy) {
1695 pswitch(1);
1697 if (connected) {
1698 proxflag = 1;
1699 } else {
1700 proxflag = 0;
1702 pswitch(0);
1703 longjmp(abortprox, 1);
1706 void
1707 doproxy(int argc, char *argv[])
1709 void (*oldintr)();
1710 struct cmd *c;
1712 if (argc < 2) {
1713 if (prompt_for_arg(line, sizeof (line), "command") == -1) {
1714 code = -1;
1715 return;
1717 makeargv();
1718 argc = margc;
1719 argv = margv;
1721 if (argc < 2) {
1722 (void) printf("usage: %s command\n", argv[0]);
1723 code = -1;
1724 return;
1726 c = getcmd(argv[1]);
1727 if (c == (struct cmd *)-1) {
1728 (void) printf("?Ambiguous command\n");
1729 (void) fflush(stdout);
1730 code = -1;
1731 return;
1733 if (c == 0) {
1734 (void) printf("?Invalid command\n");
1735 (void) fflush(stdout);
1736 code = -1;
1737 return;
1739 if (!c->c_proxy) {
1740 (void) printf("?Invalid proxy command\n");
1741 (void) fflush(stdout);
1742 code = -1;
1743 return;
1745 if (setjmp(abortprox)) {
1746 code = -1;
1747 return;
1749 oldintr = signal(SIGINT, (void (*)())proxabort);
1750 pswitch(1);
1751 if (c->c_conn && !connected) {
1752 (void) printf("Not connected\n");
1753 (void) fflush(stdout);
1754 pswitch(0);
1755 (void) signal(SIGINT, oldintr);
1756 code = -1;
1757 return;
1759 (*c->c_handler)(argc-1, argv+1);
1760 if (connected) {
1761 proxflag = 1;
1762 } else {
1763 proxflag = 0;
1765 pswitch(0);
1766 (void) signal(SIGINT, oldintr);
1769 /*ARGSUSED*/
1770 void
1771 setcase(int argc, char *argv[])
1773 mcase = !mcase;
1774 (void) printf("Case mapping %s.\n", onoff(mcase));
1775 code = mcase;
1778 /*ARGSUSED*/
1779 void
1780 setcr(int argc, char *argv[])
1782 crflag = !crflag;
1783 (void) printf("Carriage Return stripping %s.\n", onoff(crflag));
1784 code = crflag;
1787 void
1788 setntrans(int argc, char *argv[])
1790 if (argc == 1) {
1791 ntflag = 0;
1792 (void) printf("Ntrans off.\n");
1793 code = ntflag;
1794 return;
1796 ntflag++;
1797 code = ntflag;
1798 (void) strncpy(ntin, argv[1], 16);
1799 ntin[16] = '\0';
1800 if (argc == 2) {
1801 ntout[0] = '\0';
1802 return;
1804 (void) strncpy(ntout, argv[2], 16);
1805 ntout[16] = '\0';
1808 static char *
1809 dotrans(char *name)
1811 static char new[MAXPATHLEN];
1812 char *cp1, *cp2 = new;
1813 int i, ostop, found;
1815 for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++)
1817 for (cp1 = name; *cp1; cp1++) {
1818 found = 0;
1819 for (i = 0; *(ntin + i) && i < 16; i++) {
1820 if (*cp1 == *(ntin + i)) {
1821 found++;
1822 if (i < ostop) {
1823 *cp2++ = *(ntout + i);
1825 break;
1828 if (!found) {
1829 *cp2++ = *cp1;
1832 *cp2 = '\0';
1833 return (new);
1836 void
1837 setnmap(int argc, char *argv[])
1839 char *cp;
1841 if (argc == 1) {
1842 mapflag = 0;
1843 (void) printf("Nmap off.\n");
1844 code = mapflag;
1845 return;
1847 if (argc < 3) {
1848 if (prompt_for_arg(line, sizeof (line), "mapout") == -1) {
1849 code = -1;
1850 return;
1852 makeargv();
1853 argc = margc;
1854 argv = margv;
1856 if (argc < 3) {
1857 (void) printf("Usage: %s [mapin mapout]\n", argv[0]);
1858 code = -1;
1859 return;
1861 mapflag = 1;
1862 code = 1;
1863 cp = index(altarg, ' ');
1864 if (proxy) {
1865 while (*++cp == ' ')
1866 /* NULL */;
1867 altarg = cp;
1868 cp = index(altarg, ' ');
1870 *cp = '\0';
1871 (void) strncpy(mapin, altarg, MAXPATHLEN - 1);
1872 while (*++cp == ' ')
1873 /* NULL */;
1874 (void) strncpy(mapout, cp, MAXPATHLEN - 1);
1877 static char *
1878 domap(char *name)
1880 static char new[MAXPATHLEN];
1881 char *cp1 = name, *cp2 = mapin;
1882 char *tp[9], *te[9];
1883 int i, toks[9], toknum, match = 1;
1884 wchar_t wc1, wc2;
1885 int len1, len2;
1887 for (i = 0; i < 9; ++i) {
1888 toks[i] = 0;
1890 while (match && *cp1 && *cp2) {
1891 if ((len1 = mbtowc(&wc1, cp1, MB_CUR_MAX)) <= 0) {
1892 wc1 = (unsigned char)*cp1;
1893 len1 = 1;
1895 cp1 += len1;
1896 if ((len2 = mbtowc(&wc2, cp2, MB_CUR_MAX)) <= 0) {
1897 wc2 = (unsigned char)*cp2;
1898 len2 = 1;
1900 cp2 += len2;
1902 switch (wc2) {
1903 case '\\':
1904 if ((len2 = mbtowc(&wc2, cp2, MB_CUR_MAX)) <= 0) {
1905 wc2 = (unsigned char)*cp2;
1906 len2 = 1;
1908 cp2 += len2;
1909 if (wc2 != wc1)
1910 match = 0;
1911 break;
1913 case '$':
1914 if (*cp2 >= '1' && *cp2 <= '9') {
1915 if ((len2 =
1916 mbtowc(&wc2, cp2 + 1, MB_CUR_MAX)) <= 0) {
1917 wc2 = (unsigned char)*(cp2 + 1);
1918 len2 = 1;
1920 if (wc1 != wc2) {
1921 toks[toknum = *cp2 - '1']++;
1922 tp[toknum] = cp1 - len1;
1923 while (*cp1) {
1924 if ((len1 = mbtowc(&wc1,
1925 cp1, MB_CUR_MAX)) <= 0) {
1926 wc1 =
1927 (unsigned char)*cp1;
1928 len1 = 1;
1930 cp1 += len1;
1931 if (wc2 == wc1)
1932 break;
1934 if (*cp1 == 0 && wc2 != wc1)
1935 te[toknum] = cp1;
1936 else
1937 te[toknum] = cp1 - len1;
1939 cp2++; /* Consume the digit */
1940 if (wc2)
1941 cp2 += len2; /* Consume wide char */
1942 break;
1944 /* intentional drop through */
1945 default:
1946 if (wc2 != wc1)
1947 match = 0;
1948 break;
1952 cp1 = new;
1953 *cp1 = '\0';
1954 cp2 = mapout;
1955 while (*cp2) {
1956 match = 0;
1957 switch (*cp2) {
1958 case '\\':
1959 cp2++;
1960 if (*cp2) {
1961 if ((len2 = mblen(cp2, MB_CUR_MAX)) <= 0)
1962 len2 = 1;
1963 memcpy(cp1, cp2, len2);
1964 cp1 += len2;
1965 cp2 += len2;
1967 break;
1969 case '[':
1970 LOOP:
1971 cp2++;
1972 if (*cp2 == '$' && isdigit(*(cp2+1))) {
1973 if (*++cp2 == '0') {
1974 char *cp3 = name;
1976 while (*cp3) {
1977 *cp1++ = *cp3++;
1979 match = 1;
1980 } else if (toks[toknum = *cp2 - '1']) {
1981 char *cp3 = tp[toknum];
1983 while (cp3 != te[toknum]) {
1984 *cp1++ = *cp3++;
1986 match = 1;
1988 } else {
1989 while (*cp2 && *cp2 != ',' && *cp2 != ']') {
1990 if (*cp2 == '\\') {
1991 cp2++;
1992 continue;
1995 if (*cp2 == '$' && isdigit(*(cp2+1))) {
1996 if (*++cp2 == '0') {
1997 char *cp3 = name;
1999 while (*cp3)
2000 *cp1++ = *cp3++;
2001 continue;
2003 if (toks[toknum = *cp2 - '1']) {
2004 char *cp3 = tp[toknum];
2006 while (cp3 !=
2007 te[toknum])
2008 *cp1++ = *cp3++;
2010 continue;
2012 if (*cp2) {
2013 if ((len2 =
2014 mblen(cp2, MB_CUR_MAX)) <=
2015 0) {
2016 len2 = 1;
2018 memcpy(cp1, cp2, len2);
2019 cp1 += len2;
2020 cp2 += len2;
2023 if (!*cp2) {
2024 (void) printf(
2025 "nmap: unbalanced brackets\n");
2026 return (name);
2028 match = 1;
2030 if (match) {
2031 while (*cp2 && *cp2 != ']') {
2032 if (*cp2 == '\\' && *(cp2 + 1)) {
2033 cp2++;
2035 if ((len2 = mblen(cp2, MB_CUR_MAX)) <=
2037 len2 = 1;
2038 cp2 += len2;
2040 if (!*cp2) {
2041 (void) printf(
2042 "nmap: unbalanced brackets\n");
2043 return (name);
2045 cp2++;
2046 break;
2048 switch (*++cp2) {
2049 case ',':
2050 goto LOOP;
2051 case ']':
2052 break;
2053 default:
2054 cp2--;
2055 goto LOOP;
2057 cp2++;
2058 break;
2059 case '$':
2060 if (isdigit(*(cp2 + 1))) {
2061 if (*++cp2 == '0') {
2062 char *cp3 = name;
2064 while (*cp3) {
2065 *cp1++ = *cp3++;
2067 } else if (toks[toknum = *cp2 - '1']) {
2068 char *cp3 = tp[toknum];
2070 while (cp3 != te[toknum]) {
2071 *cp1++ = *cp3++;
2074 cp2++;
2075 break;
2077 /* intentional drop through */
2078 default:
2079 if ((len2 = mblen(cp2, MB_CUR_MAX)) <= 0)
2080 len2 = 1;
2081 memcpy(cp1, cp2, len2);
2082 cp1 += len2;
2083 cp2 += len2;
2084 break;
2087 *cp1 = '\0';
2088 if (!*new) {
2089 return (name);
2091 return (new);
2094 /*ARGSUSED*/
2095 void
2096 setsunique(int argc, char *argv[])
2098 sunique = !sunique;
2099 (void) printf("Store unique %s.\n", onoff(sunique));
2100 code = sunique;
2103 /*ARGSUSED*/
2104 void
2105 setrunique(int argc, char *argv[])
2107 runique = !runique;
2108 (void) printf("Receive unique %s.\n", onoff(runique));
2109 code = runique;
2112 /*ARGSUSED*/
2113 void
2114 setpassive(int argc, char *argv[])
2116 passivemode = !passivemode;
2117 (void) printf("Passive mode %s.\n", onoff(passivemode));
2118 code = passivemode;
2121 void
2122 settcpwindow(int argc, char *argv[])
2124 int owindowsize = tcpwindowsize;
2126 if (argc > 2) {
2127 (void) printf("usage: %s [size]\n", argv[0]);
2128 code = -1;
2129 return;
2131 if (argc == 2) {
2132 int window;
2133 char *endp;
2135 errno = 0;
2136 window = (int)strtol(argv[1], &endp, 10);
2137 if (errno || window < 0 || *endp != '\0')
2138 (void) printf("%s: Invalid size `%s'\n",
2139 argv[0], argv[1]);
2140 else
2141 tcpwindowsize = window;
2143 if (tcpwindowsize == 0) {
2144 if (owindowsize == 0)
2145 (void) printf("No TCP window size defined\n");
2146 else
2147 (void) printf("TCP window size cleared\n");
2148 } else
2149 (void) printf("TCP window size is set to %d\n", tcpwindowsize);
2152 /* change directory to parent directory */
2153 /*ARGSUSED*/
2154 void
2155 cdup(int argc, char *argv[])
2157 (void) command("CDUP");
2160 void
2161 macdef(int argc, char *argv[])
2163 char *tmp;
2164 int c;
2166 if (macnum == 16) {
2167 (void) printf("Limit of 16 macros have already been defined\n");
2168 code = -1;
2169 return;
2171 if (argc < 2) {
2172 if (prompt_for_arg(line, sizeof (line), "macro name") == -1) {
2173 code = -1;
2174 return;
2176 makeargv();
2177 argc = margc;
2178 argv = margv;
2180 if (argc != 2) {
2181 (void) printf("Usage: %s macro_name\n", argv[0]);
2182 code = -1;
2183 return;
2185 if (interactive) {
2186 (void) printf("Enter macro line by line, terminating "
2187 "it with a null line\n");
2189 (void) strncpy(macros[macnum].mac_name, argv[1], 8);
2190 if (macnum == 0) {
2191 macros[macnum].mac_start = macbuf;
2192 } else {
2193 macros[macnum].mac_start = macros[macnum - 1].mac_end + 1;
2195 tmp = macros[macnum].mac_start;
2196 while (tmp != macbuf+4096) {
2197 if ((c = getchar()) == EOF) {
2198 (void) printf("macdef:end of file encountered\n");
2199 code = -1;
2200 return;
2202 if ((*tmp = c) == '\n') {
2203 if (tmp == macros[macnum].mac_start) {
2204 macros[macnum++].mac_end = tmp;
2205 code = 0;
2206 return;
2208 if (*(tmp-1) == '\0') {
2209 macros[macnum++].mac_end = tmp - 1;
2210 code = 0;
2211 return;
2213 *tmp = '\0';
2215 tmp++;
2217 for (;;) {
2218 while ((c = getchar()) != '\n' && c != EOF)
2219 /* NULL */;
2220 if (c == EOF || getchar() == '\n') {
2221 (void) printf(
2222 "Macro not defined - 4k buffer exceeded\n");
2223 code = -1;
2224 return;
2230 * The p_name strings are for the getlevel and setlevel commands.
2231 * The name strings for printing are in the arpa/ftp.h file in the
2232 * protnames[] array of strings.
2234 static struct levels {
2235 char *p_name;
2236 char *p_mode;
2237 int p_level;
2238 } levels[] = {
2239 { "clear", "C", PROT_C },
2240 { "safe", "S", PROT_S },
2241 { "private", "P", PROT_P },
2242 NULL
2246 * Return a pointer to a string which is the readable version of the
2247 * protection level, or NULL if the input level is not found.
2249 static char *
2250 getlevel(int level)
2252 struct levels *p;
2254 for (p = levels; (p != NULL) && (p->p_level != level); p++)
2256 return (p ? p->p_name : NULL);
2259 static char *plevel[] = {
2260 "protect",
2262 NULL
2266 * Set control channel protection level.
2268 void
2269 setclevel(int argc, char *argv[])
2271 struct levels *p;
2272 char *levelp;
2273 int comret;
2275 if (argc > 2) {
2276 char *sep;
2278 (void) printf("usage: %s [", argv[0]);
2279 sep = " ";
2280 for (p = levels; p->p_name; p++) {
2281 (void) printf("%s%s", sep, p->p_name);
2282 if (*sep == ' ')
2283 sep = " | ";
2285 (void) printf(" ]\n");
2286 code = -1;
2287 return;
2289 if (argc < 2) {
2290 levelp = getlevel(clevel);
2291 (void) printf("Using %s protection level for commands.\n",
2292 levelp ? levelp : "<unknown>");
2293 code = 0;
2294 return;
2296 for (p = levels; (p != NULL) && (p->p_name); p++)
2297 if (strcmp(argv[1], p->p_name) == 0)
2298 break;
2299 if (p->p_name == 0) {
2300 (void) printf("%s: unknown protection level\n", argv[1]);
2301 code = -1;
2302 return;
2304 if (auth_type == AUTHTYPE_NONE) {
2305 if (strcmp(p->p_name, "clear"))
2306 (void) printf("Cannot set protection level to %s\n",
2307 argv[1]);
2308 return;
2310 if (strcmp(p->p_name, "clear") == 0) {
2311 comret = command("CCC");
2312 if (comret == COMPLETE)
2313 clevel = PROT_C;
2314 return;
2316 clevel = p->p_level;
2317 (void) printf("Control channel protection level set to %s.\n",
2318 p->p_name);
2322 * Set data channel protection level.
2324 void
2325 setdlevel(int argc, char *argv[])
2327 struct levels *p;
2328 int comret;
2330 if (argc != 2) {
2331 char *sep;
2333 (void) printf("usage: %s [", argv[0]);
2334 sep = " ";
2335 for (p = levels; p->p_name; p++) {
2336 (void) printf("%s%s", sep, p->p_name);
2337 if (*sep == ' ')
2338 sep = " | ";
2340 (void) printf(" ]\n");
2341 code = -1;
2342 return;
2344 for (p = levels; p->p_name; p++)
2345 if (strcmp(argv[1], p->p_name) == 0)
2346 break;
2347 if (p->p_name == 0) {
2348 (void) printf("%s: unknown protection level\n", argv[1]);
2349 code = -1;
2350 return;
2352 if (auth_type == AUTHTYPE_NONE) {
2353 if (strcmp(p->p_name, "clear"))
2354 (void) printf("Cannot set protection level to %s\n",
2355 argv[1]);
2356 return;
2358 /* Start with a PBSZ of 1 meg */
2359 if (p->p_level != PROT_C)
2360 setpbsz(1<<20);
2361 comret = command("PROT %s", p->p_mode);
2362 if (comret == COMPLETE)
2363 dlevel = p->p_level;
2367 * Set clear command protection level.
2369 /* VARARGS */
2370 void
2371 ccc(int argc, char *argv[])
2373 plevel[1] = "clear";
2374 setclevel(2, plevel);
2378 * Set clear data protection level.
2380 /* VARARGS */
2381 void
2382 setclear(int argc, char *argv[])
2384 plevel[1] = "clear";
2385 setdlevel(2, plevel);
2389 * Set safe data protection level.
2391 /* VARARGS */
2392 void
2393 setsafe(int argc, char *argv[])
2395 plevel[1] = "safe";
2396 setdlevel(2, plevel);
2400 * Set private data protection level.
2402 /* VARARGS */
2403 void
2404 setprivate(int argc, char *argv[])
2406 plevel[1] = "private";
2407 setdlevel(2, plevel);
2411 * Set mechanism type
2413 void
2414 setmech(int argc, char *argv[])
2416 char tempmech[MECH_SZ];
2418 if (argc < 2) {
2419 if (prompt_for_arg(line, sizeof (line), "mech-type") == -1) {
2420 code = -1;
2421 return;
2423 makeargv();
2424 argc = margc;
2425 argv = margv;
2428 if (argc != 2) {
2429 (void) printf("usage: %s [ mechanism type ]\n", argv[0]);
2430 code = -1;
2431 return;
2434 if ((strlcpy(tempmech, argv[1], MECH_SZ) >= MECH_SZ) ||
2435 __gss_mech_to_oid(tempmech, (gss_OID*)&mechoid) !=
2436 GSS_S_COMPLETE) {
2437 (void) printf("%s: %s: not a valid security mechanism\n",
2438 argv[0], tempmech);
2439 code = -1;
2440 return;
2441 } else {
2442 (void) strlcpy(mechstr, tempmech, MECH_SZ);
2443 (void) printf("Using %s mechanism type\n", mechstr);
2444 code = 0;
2445 return;