Home | History | Annotate | Download | only in ftp
      1 /*
      2  * CDDL HEADER START
      3  *
      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.
      7  *
      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.
     12  *
     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]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  *	Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
     23  *	Use is subject to license terms.
     24  */
     25 
     26 /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
     27 /*	All Rights Reserved  	*/
     28 
     29 /*
     30  *	University Copyright- Copyright (c) 1982, 1986, 1988
     31  *	The Regents of the University of California
     32  *	All Rights Reserved
     33  *
     34  *	University Acknowledgment- Portions of this document are derived from
     35  *	software developed by the University of California, Berkeley, and its
     36  *	contributors.
     37  */
     38 
     39 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     40 
     41 
     42 /*
     43  * FTP User Program -- Command Routines.
     44  */
     45 #define	FTP_NAMES
     46 #include "ftp_var.h"
     47 
     48 FILE	*tmp_nlst = NULL;	/* tmp file; holds NLST results for mget, etc */
     49 
     50 static char *mname;
     51 static jmp_buf jabort;
     52 static jmp_buf abortprox;
     53 
     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);
     63 
     64 static char *getlevel(int);
     65 
     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)
     69 {
     70 	if (strlen(buffer) > buffer_size - 2) {
     71 		(void) printf("Line too long\n");
     72 		return (-1);
     73 	}
     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);
     81 	}
     82 
     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))
     86 			;
     87 		(void) printf("Line too long\n");
     88 		reset_timer();
     89 		return (-1);
     90 	} else
     91 		buffer[strlen(buffer)-1] = 0;
     92 
     93 	reset_timer();
     94 	return (0);
     95 }
     96 
     97 
     98 /*
     99  * Connect to peer server and
    100  * auto-login, if possible.
    101  */
    102 void
    103 setpeer(int argc, char *argv[])
    104 {
    105 	char *host;
    106 
    107 	if (connected) {
    108 		(void) printf("Already connected to %s, use close first.\n",
    109 			hostname);
    110 		code = -1;
    111 		return;
    112 	}
    113 	if (argc < 2) {
    114 		if (prompt_for_arg(line, sizeof (line), "to") == -1) {
    115 			code = -1;
    116 			return;
    117 		}
    118 		makeargv();
    119 		argc = margc;
    120 		argv = margv;
    121 	}
    122 	if (argc > 3 || argc < 2) {
    123 		(void) printf("usage: %s host-name [port]\n", argv[0]);
    124 		code = -1;
    125 		return;
    126 	}
    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[];
    132 
    133 		connected = 1;
    134 		/*
    135 		 * Set up defaults for FTP.
    136 		 */
    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;
    150 			    }
    151 			}
    152 			if ((auth_type != AUTHTYPE_NONE) && (clevel == PROT_C))
    153 				clevel = PROT_S;
    154 		}
    155 
    156 		if (autologin)
    157 			(void) login(argv[1]);
    158 		/* if skipsyst is enabled, then don't send SYST command */
    159 		if (skipsyst)
    160 			return;
    161 
    162 		overbose = verbose;
    163 		if (debug == 0)
    164 			verbose = -1;
    165 		if (command("SYST") == COMPLETE && overbose) {
    166 			char *cp, c;
    167 
    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';
    176 			}
    177 
    178 			(void) printf("Remote system type is %s.\n",
    179 				reply_string+4);
    180 			if (cp)
    181 				*cp = c;
    182 		}
    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");
    194 		}
    195 		verbose = overbose;
    196 	}
    197 }
    198 
    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 },
    210 	0
    211 };
    212 
    213 /*
    214  * Set transfer type.
    215  */
    216 void
    217 settype(int argc, char *argv[])
    218 {
    219 	struct types *p;
    220 	int comret;
    221 
    222 	if (argc > 2) {
    223 		char *sep;
    224 
    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 = " | ";
    231 		}
    232 		(void) printf(" ]\n");
    233 		code = -1;
    234 		return;
    235 	}
    236 	if (argc < 2) {
    237 		(void) printf("Using %s mode to transfer files.\n", typename);
    238 		code = 0;
    239 		return;
    240 	}
    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;
    248 	}
    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;
    256 	}
    257 }
    258 
    259 /*
    260  * Set binary transfer type.
    261  */
    262 /*ARGSUSED*/
    263 void
    264 setbinary(int argc, char *argv[])
    265 {
    266 	call(settype, "type", "binary", 0);
    267 }
    268 
    269 /*
    270  * Set ascii transfer type.
    271  */
    272 /*ARGSUSED*/
    273 void
    274 setascii(int argc, char *argv[])
    275 {
    276 	call(settype, "type", "ascii", 0);
    277 }
    278 
    279 /*
    280  * Set tenex transfer type.
    281  */
    282 /*ARGSUSED*/
    283 void
    284 settenex(int argc, char *argv[])
    285 {
    286 	call(settype, "type", "tenex", 0);
    287 }
    288 
    289 /*
    290  * Set ebcdic transfer type.
    291  */
    292 /*ARGSUSED*/
    293 void
    294 setebcdic(int argc, char *argv[])
    295 {
    296 	call(settype, "type", "ebcdic", 0);
    297 }
    298 
    299 /*
    300  * Set file transfer mode.
    301  */
    302 /*ARGSUSED*/
    303 void
    304 setmode(int argc, char *argv[])
    305 {
    306 	(void) printf("We only support %s mode, sorry.\n", modename);
    307 	code = -1;
    308 }
    309 
    310 /*
    311  * Set file transfer format.
    312  */
    313 /*ARGSUSED*/
    314 void
    315 setform(int argc, char *argv[])
    316 {
    317 	(void) printf("We only support %s format, sorry.\n", formname);
    318 	code = -1;
    319 }
    320 
    321 /*
    322  * Set file transfer structure.
    323  */
    324 /*ARGSUSED*/
    325 void
    326 setstruct(int argc, char *argv[])
    327 {
    328 
    329 	(void) printf("We only support %s structure, sorry.\n", structname);
    330 	code = -1;
    331 }
    332 
    333 /*
    334  * Send a single file.
    335  */
    336 void
    337 put(int argc, char *argv[])
    338 {
    339 	char *cmd;
    340 	int loc = 0;
    341 	char *oldargv1;
    342 
    343 	if (argc == 2) {
    344 		argc++;
    345 		argv[2] = argv[1];
    346 		loc++;
    347 	}
    348 	if (argc < 2) {
    349 		if (prompt_for_arg(line, sizeof (line), "local-file") == -1) {
    350 			code = -1;
    351 			return;
    352 		}
    353 		makeargv();
    354 		argc = margc;
    355 		argv = margv;
    356 	}
    357 	if (argc < 2) {
    358 usage:
    359 		(void) printf("usage: %s local-file remote-file\n", argv[0]);
    360 		code = -1;
    361 		return;
    362 	}
    363 	if (argc < 3) {
    364 		if (prompt_for_arg(line, sizeof (line), "remote-file") == -1) {
    365 			code = -1;
    366 			return;
    367 		}
    368 		makeargv();
    369 		argc = margc;
    370 		argv = margv;
    371 	}
    372 	if (argc < 3)
    373 		goto usage;
    374 	oldargv1 = argv[1];
    375 	if (!globulize(&argv[1])) {
    376 		code = -1;
    377 		return;
    378 	}
    379 	/*
    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].
    382 	 */
    383 	if (argv[1] != oldargv1 && argv[2] == oldargv1) {
    384 		argv[2] = argv[1];
    385 	}
    386 	cmd = (argv[0][0] == 'a') ? "APPE" : ((sunique) ? "STOU" : "STOR");
    387 	if (loc && ntflag) {
    388 		argv[2] = dotrans(argv[2]);
    389 	}
    390 	if (loc && mapflag) {
    391 		argv[2] = domap(argv[2]);
    392 	}
    393 	sendrequest(cmd, argv[1], argv[2], 1);
    394 }
    395 
    396 /*ARGSUSED*/
    397 static void
    398 mabort(int sig)
    399 {
    400 	int ointer;
    401 
    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);
    410 		}
    411 		interactive = ointer;
    412 	}
    413 	mflag = 0;
    414 	longjmp(jabort, 0);
    415 }
    416 
    417 /*
    418  * Send multiple files.
    419  */
    420 void
    421 mput(int argc, char *argv[])
    422 {
    423 	int i;
    424 	int ointer;
    425 	void (*oldintr)();
    426 	char *tp;
    427 	int	len;
    428 
    429 	if (argc < 2) {
    430 		if (prompt_for_arg(line, sizeof (line), "local-files") == -1) {
    431 			code = -1;
    432 			return;
    433 		}
    434 		makeargv();
    435 		argc = margc;
    436 		argv = margv;
    437 	}
    438 	if (argc < 2) {
    439 		(void) printf("usage: %s local-files\n", argv[0]);
    440 		code = -1;
    441 		return;
    442 	}
    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];
    449 
    450 		while ((cp = remglob(argv, 0)) != NULL) {
    451 			if (*cp == 0) {
    452 				mflag = 0;
    453 				continue;
    454 			}
    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;
    465 					}
    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';
    477 							}
    478 							tp += len;
    479 							tp2 += len;
    480 						}
    481 						*tp2 = 0;
    482 						tp = tmpbuf;
    483 					}
    484 				}
    485 				if (ntflag) {
    486 					tp = dotrans(tp);
    487 				}
    488 				if (mapflag) {
    489 					tp = domap(tp);
    490 				}
    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++;
    498 					}
    499 					interactive = ointer;
    500 				}
    501 			}
    502 		}
    503 		(void) signal(SIGINT, oldintr);
    504 		mflag = 0;
    505 		return;
    506 	}
    507 	for (i = 1; i < argc; i++) {
    508 		char **cpp, **gargs;
    509 
    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++;
    521 					}
    522 					interactive = ointer;
    523 				}
    524 			}
    525 			continue;
    526 		}
    527 		gargs = glob(argv[i]);
    528 		if (globerr != NULL) {
    529 			(void) printf("%s\n", globerr);
    530 			if (gargs)
    531 				blkfree(gargs);
    532 			continue;
    533 		}
    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++;
    545 					}
    546 					interactive = ointer;
    547 				}
    548 			}
    549 		}
    550 		if (gargs != NULL)
    551 			blkfree(gargs);
    552 	}
    553 	(void) signal(SIGINT, oldintr);
    554 	mflag = 0;
    555 }
    556 
    557 /*
    558  * Restart transfer at a specific offset.
    559  */
    560 void
    561 restart(int argc, char *argv[])
    562 {
    563 	off_t orestart_point = restart_point;
    564 
    565 	if (argc > 2) {
    566 		(void) printf("usage: %s [marker]\n", argv[0]);
    567 		code = -1;
    568 		return;
    569 	}
    570 	if (argc == 2) {
    571 		longlong_t rp;
    572 		char *endp;
    573 
    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;
    581 	}
    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);
    591 }
    592 
    593 void
    594 reget(int argc, char *argv[])
    595 {
    596 	getit(argc, argv, 1, "r+w");
    597 }
    598 
    599 void
    600 get(int argc, char *argv[])
    601 {
    602 	getit(argc, argv, 0, restart_point ? "r+w" : "w");
    603 }
    604 
    605 /*
    606  * Receive one file.
    607  */
    608 static void
    609 getit(int argc, char *argv[], int restartit, char *mode)
    610 {
    611 	int loc = 0;
    612 	int len;
    613 	int allowpipe = 1;
    614 
    615 	if (argc == 2) {
    616 		argc++;
    617 		argv[2] = argv[1];
    618 		/* Only permit !file if two arguments. */
    619 		allowpipe = 0;
    620 		loc++;
    621 	}
    622 	if (argc < 2) {
    623 		if (prompt_for_arg(line, sizeof (line), "remote-file") == -1) {
    624 			code = -1;
    625 			return;
    626 		}
    627 		makeargv();
    628 		argc = margc;
    629 		argv = margv;
    630 	}
    631 	if (argc < 2) {
    632 usage:
    633 		(void) printf("usage: %s remote-file [ local-file ]\n",
    634 			argv[0]);
    635 		code = -1;
    636 		return;
    637 	}
    638 	if (argc < 3) {
    639 		if (prompt_for_arg(line, sizeof (line), "local-file") == -1) {
    640 			code = -1;
    641 			return;
    642 		}
    643 		makeargv();
    644 		argc = margc;
    645 		argv = margv;
    646 	}
    647 	if (argc < 3)
    648 		goto usage;
    649 	if (!globulize(&argv[2])) {
    650 		code = -1;
    651 		return;
    652 	}
    653 	if (loc && mcase) {
    654 		char *tp = argv[1], *tp2, tmpbuf[MAXPATHLEN];
    655 
    656 		while (*tp) {
    657 			if ((len = mblen(tp, MB_CUR_MAX)) <= 0)
    658 				len = 1;
    659 			if (islower(*tp))
    660 				break;
    661 			tp += len;
    662 		}
    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;
    674 			}
    675 			*tp2 = 0;
    676 			argv[2] = tmpbuf;
    677 		}
    678 	}
    679 	if (loc && ntflag) {
    680 		argv[2] = dotrans(argv[2]);
    681 	}
    682 	if (loc && mapflag) {
    683 		argv[2] = domap(argv[2]);
    684 	}
    685 	if (restartit) {
    686 		struct stat stbuf;
    687 
    688 		if (stat(argv[2], &stbuf) < 0) {
    689 			perror(argv[2]);
    690 			code = -1;
    691 			return;
    692 		}
    693 		restart_point = stbuf.st_size;
    694 	}
    695 	recvrequest("RETR", argv[2], argv[1], mode, allowpipe);
    696 	restart_point = 0;
    697 }
    698 
    699 /*
    700  * Get multiple files.
    701  */
    702 void
    703 mget(int argc, char *argv[])
    704 {
    705 	char *cp, *tp, *tp2, tmpbuf[MAXPATHLEN];
    706 	int ointer;
    707 	void (*oldintr)();
    708 	int need_convert;
    709 	int	len;
    710 
    711 	if (argc < 2) {
    712 		if (prompt_for_arg(line, sizeof (line), "remote-files") < 0) {
    713 			code = -1;
    714 			return;
    715 		}
    716 		makeargv();
    717 		argc = margc;
    718 		argv = margv;
    719 	}
    720 	if (argc < 2) {
    721 		(void) printf("usage: %s remote-files\n", argv[0]);
    722 		code = -1;
    723 		return;
    724 	}
    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;
    733 		}
    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;
    747 				}
    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;
    756 				}
    757 			}
    758 
    759 			if (ntflag) {
    760 				tp = dotrans(tp);
    761 			}
    762 			if (mapflag) {
    763 				tp = domap(tp);
    764 			}
    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++;
    772 				}
    773 				interactive = ointer;
    774 			}
    775 		}
    776 	}
    777 	(void) signal(SIGINT, oldintr);
    778 	mflag = 0;
    779 }
    780 
    781 static char *
    782 remglob(char *argv[], int doswitch)
    783 {
    784 	static char buf[MAXPATHLEN];
    785 	static char **args;
    786 	int oldverbose, oldhash;
    787 	char *cp;
    788 
    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;
    796 			}
    797 		}
    798 		return (NULL);
    799 	}
    800 	if (!doglob) {
    801 		if (args == NULL)
    802 			args = argv;
    803 		if ((cp = *++args) == NULL)
    804 			args = NULL;
    805 		return (cp);
    806 	}
    807 	if (tmp_nlst == NULL) {
    808 		if ((tmp_nlst = tmpfile()) == NULL) {
    809 			(void) printf("%s\n", strerror(errno));
    810 			return (NULL);
    811 		}
    812 		oldverbose = verbose, verbose = 0;
    813 		oldhash = hash, hash = 0;
    814 		if (doswitch) {
    815 			pswitch(!proxy);
    816 		}
    817 		for (; *++argv != NULL; )
    818 			recvrequest("NLST", NULL, *argv, "", 0);
    819 		rewind(tmp_nlst);
    820 		if (doswitch) {
    821 			pswitch(!proxy);
    822 		}
    823 		verbose = oldverbose; hash = oldhash;
    824 	}
    825 	reset_timer();
    826 	if (fgets(buf, sizeof (buf), tmp_nlst) == NULL) {
    827 		(void) fclose(tmp_nlst), tmp_nlst = NULL;
    828 		return (NULL);
    829 	}
    830 	if ((cp = index(buf, '\n')) != NULL)
    831 		*cp = '\0';
    832 	return (buf);
    833 }
    834 
    835 static char *
    836 onoff(int bool)
    837 {
    838 	return (bool ? "on" : "off");
    839 }
    840 
    841 /*
    842  * Show status.
    843  */
    844 /*ARGSUSED*/
    845 void
    846 status(int argc, char *argv[])
    847 {
    848 	int i;
    849 	char *levelp;
    850 
    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");
    862 		}
    863 		pswitch(0);
    864 	}
    865 
    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>");
    880 
    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");
    895 	}
    896 	if (mapflag) {
    897 		(void) printf("Nmap: (in) %s (out) %s\n", mapin, mapout);
    898 	} else {
    899 		(void) printf("Nmap: off\n");
    900 	}
    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);
    907 		}
    908 	}
    909 	code = 0;
    910 }
    911 
    912 /*
    913  * Set beep on cmd completed mode.
    914  */
    915 /*ARGSUSED*/
    916 void
    917 setbell(int argc, char *argv[])
    918 {
    919 	bell = !bell;
    920 	(void) printf("Bell mode %s.\n", onoff(bell));
    921 	code = bell;
    922 }
    923 
    924 /*
    925  * Turn on packet tracing.
    926  */
    927 /*ARGSUSED*/
    928 void
    929 settrace(int argc, char *argv[])
    930 {
    931 	trace = !trace;
    932 	(void) printf("Packet tracing %s.\n", onoff(trace));
    933 	code = trace;
    934 }
    935 
    936 /*
    937  * Toggle hash mark printing during transfers.
    938  */
    939 /*ARGSUSED*/
    940 void
    941 sethash(int argc, char *argv[])
    942 {
    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");
    949 }
    950 
    951 /*
    952  * Turn on printing of server echo's.
    953  */
    954 /*ARGSUSED*/
    955 void
    956 setverbose(int argc, char *argv[])
    957 {
    958 	verbose = !verbose;
    959 	(void) printf("Verbose mode %s.\n", onoff(verbose));
    960 	code = verbose;
    961 }
    962 
    963 /*
    964  * Toggle PORT cmd use before each data connection.
    965  */
    966 /*ARGSUSED*/
    967 void
    968 setport(int argc, char *argv[])
    969 {
    970 	sendport = !sendport;
    971 	(void) printf("Use of PORT cmds %s.\n", onoff(sendport));
    972 	code = sendport;
    973 }
    974 
    975 /*
    976  * Turn on interactive prompting
    977  * during mget, mput, and mdelete.
    978  */
    979 /*ARGSUSED*/
    980 void
    981 setprompt(int argc, char *argv[])
    982 {
    983 	interactive = !interactive;
    984 	(void) printf("Interactive mode %s.\n", onoff(interactive));
    985 	code = interactive;
    986 }
    987 
    988 /*
    989  * Toggle metacharacter interpretation
    990  * on local file names.
    991  */
    992 /*ARGSUSED*/
    993 void
    994 setglob(int argc, char *argv[])
    995 {
    996 	doglob = !doglob;
    997 	(void) printf("Globbing %s.\n", onoff(doglob));
    998 	code = doglob;
    999 }
   1000 
   1001 /*
   1002  * Set debugging mode on/off and/or
   1003  * set level of debugging.
   1004  */
   1005 void
   1006 setdebug(int argc, char *argv[])
   1007 {
   1008 	int val;
   1009 
   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;
   1016 		}
   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;
   1026 }
   1027 
   1028 /*
   1029  * Set current working directory
   1030  * on remote machine.
   1031  */
   1032 void
   1033 cd(int argc, char *argv[])
   1034 {
   1035 	if (argc < 2) {
   1036 		if (prompt_for_arg(line, sizeof (line), "remote-directory") <
   1037 		    0) {
   1038 			code = -1;
   1039 			return;
   1040 		}
   1041 		makeargv();
   1042 		argc = margc;
   1043 		argv = margv;
   1044 	}
   1045 	if (argc < 2) {
   1046 		(void) printf("usage: %s remote-directory\n", argv[0]);
   1047 		code = -1;
   1048 		return;
   1049 	}
   1050 	(void) command("CWD %s", argv[1]);
   1051 }
   1052 
   1053 /*
   1054  * Set current working directory
   1055  * on local machine.
   1056  */
   1057 void
   1058 lcd(int argc, char *argv[])
   1059 {
   1060 	char buf[MAXPATHLEN], *bufptr;
   1061 
   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;
   1068 	}
   1069 	if (!globulize(&argv[1])) {
   1070 		code = -1;
   1071 		return;
   1072 	}
   1073 	if (chdir(argv[1]) < 0) {
   1074 		perror(argv[1]);
   1075 		code = -1;
   1076 		return;
   1077 	}
   1078 	bufptr = getcwd(buf, MAXPATHLEN);
   1079 	/*
   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.
   1083 	 */
   1084 	(void) printf("Local directory now %s\n", (bufptr ? bufptr : argv[1]));
   1085 	code = 0;
   1086 }
   1087 
   1088 /*
   1089  * Delete a single file.
   1090  */
   1091 void
   1092 delete(int argc, char *argv[])
   1093 {
   1094 
   1095 	if (argc < 2) {
   1096 		if (prompt_for_arg(line, sizeof (line), "remote-file") < 0) {
   1097 			code = -1;
   1098 			return;
   1099 		}
   1100 		makeargv();
   1101 		argc = margc;
   1102 		argv = margv;
   1103 	}
   1104 	if (argc < 2) {
   1105 		(void) printf("usage: %s remote-file\n", argv[0]);
   1106 		code = -1;
   1107 		return;
   1108 	}
   1109 	(void) command("DELE %s", argv[1]);
   1110 }
   1111 
   1112 /*
   1113  * Delete multiple files.
   1114  */
   1115 void
   1116 mdelete(int argc, char *argv[])
   1117 {
   1118 	char *cp;
   1119 	int ointer;
   1120 	void (*oldintr)();
   1121 
   1122 	if (argc < 2) {
   1123 		if (prompt_for_arg(line, sizeof (line), "remote-files") < 0) {
   1124 			code = -1;
   1125 			return;
   1126 		}
   1127 		makeargv();
   1128 		argc = margc;
   1129 		argv = margv;
   1130 	}
   1131 	if (argc < 2) {
   1132 		(void) printf("usage: %s remote-files\n", argv[0]);
   1133 		code = -1;
   1134 		return;
   1135 	}
   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;
   1144 		}
   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++;
   1152 				}
   1153 				interactive = ointer;
   1154 			}
   1155 		}
   1156 	}
   1157 	(void) signal(SIGINT, oldintr);
   1158 	mflag = 0;
   1159 }
   1160 
   1161 /*
   1162  * Rename a remote file.
   1163  */
   1164 void
   1165 renamefile(int argc, char *argv[])
   1166 {
   1167 
   1168 	if (argc < 2) {
   1169 		if (prompt_for_arg(line, sizeof (line), "from-name") < 0) {
   1170 			code = -1;
   1171 			return;
   1172 		}
   1173 		makeargv();
   1174 		argc = margc;
   1175 		argv = margv;
   1176 	}
   1177 	if (argc < 2) {
   1178 usage:
   1179 		(void) printf("%s from-name to-name\n", argv[0]);
   1180 		code = -1;
   1181 		return;
   1182 	}
   1183 	if (argc < 3) {
   1184 		if (prompt_for_arg(line, sizeof (line), "to-name") < 0) {
   1185 			code = -1;
   1186 			return;
   1187 		}
   1188 		makeargv();
   1189 		argc = margc;
   1190 		argv = margv;
   1191 	}
   1192 	if (argc < 3)
   1193 		goto usage;
   1194 	if (command("RNFR %s", argv[1]) == CONTINUE)
   1195 		(void) command("RNTO %s", argv[2]);
   1196 }
   1197 
   1198 /*
   1199  * Get a directory listing
   1200  * of remote files.
   1201  */
   1202 void
   1203 ls(int argc, char *argv[])
   1204 {
   1205 	char *cmd;
   1206 
   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;
   1216 	}
   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");
   1222 	}
   1223 	if (strcmp(argv[2], "-") && !globulize(&argv[2])) {
   1224 		code = -1;
   1225 		return;
   1226 	}
   1227 	recvrequest(cmd, argv[2], argv[1], "w", 1);
   1228 }
   1229 
   1230 /*
   1231  * Get a directory listing
   1232  * of multiple remote files.
   1233  */
   1234 void
   1235 mls(int argc, char *argv[])
   1236 {
   1237 	char *cmd, mode[1], *dest;
   1238 	int ointer, i;
   1239 	void (*oldintr)();
   1240 
   1241 	if (argc < 2) {
   1242 		if (prompt_for_arg(line, sizeof (line), "remote-files") < 0) {
   1243 			code = -1;
   1244 			return;
   1245 		}
   1246 		makeargv();
   1247 		argc = margc;
   1248 		argv = margv;
   1249 	}
   1250 	if (argc < 3) {
   1251 		if (prompt_for_arg(line, sizeof (line), "local-file") < 0) {
   1252 			code = -1;
   1253 			return;
   1254 		}
   1255 		makeargv();
   1256 		argc = margc;
   1257 		argv = margv;
   1258 	}
   1259 	if (argc < 3) {
   1260 		(void) printf("usage: %s remote-files local-file\n", argv[0]);
   1261 		code = -1;
   1262 		return;
   1263 	}
   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;
   1271 		}
   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 ++;
   1285 			}
   1286 			interactive = ointer;
   1287 		}
   1288 	}
   1289 	(void) signal(SIGINT, oldintr);
   1290 	mflag = 0;
   1291 }
   1292 
   1293 /*
   1294  * Do a shell escape
   1295  */
   1296 /*ARGSUSED*/
   1297 void
   1298 shell(int argc, char *argv[])
   1299 {
   1300 	pid_t pid;
   1301 	void (*old1)(), (*old2)();
   1302 	char *shellstring, *namep;
   1303 	int status;
   1304 
   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);
   1323 			}
   1324 			execl(shellstring, namep, "-c", altarg, (char *)0);
   1325 		} else {
   1326 			if (debug) {
   1327 				(void) printf("%s\n", shellstring);
   1328 				(void) fflush(stdout);
   1329 			}
   1330 			execl(shellstring, namep, (char *)0);
   1331 		}
   1332 		perror(shellstring);
   1333 		code = -1;
   1334 		exit(1);
   1335 		}
   1336 	if (pid > 0)
   1337 		while (wait(&status) != pid)
   1338 			;
   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;
   1347 	}
   1348 }
   1349 
   1350 /*
   1351  * Send new user information (re-login)
   1352  */
   1353 void
   1354 user(int argc, char *argv[])
   1355 {
   1356 	char acct[80];
   1357 	int n, aflag = 0;
   1358 
   1359 	if (argc < 2) {
   1360 		if (prompt_for_arg(line, sizeof (line), "username") < 0) {
   1361 			code = -1;
   1362 			return;
   1363 		}
   1364 		makeargv();
   1365 		argc = margc;
   1366 		argv = margv;
   1367 	}
   1368 	if (argc > 4) {
   1369 		(void) printf("usage: %s username [password] [account]\n",
   1370 			argv[0]);
   1371 		code = -1;
   1372 		return;
   1373 	}
   1374 	if (argv[1] == 0) {
   1375 		(void) printf("access for user (nil) denied\n");
   1376 		code = -1;
   1377 		return;
   1378 	}
   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;
   1390 	}
   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++;
   1399 		}
   1400 		n = command("ACCT %s", argv[3]);
   1401 		aflag++;
   1402 	}
   1403 	if (n != COMPLETE) {
   1404 		(void) fprintf(stdout, "Login failed.\n");
   1405 		return;
   1406 	}
   1407 	if (!aflag && argc == 4) {
   1408 		(void) command("ACCT %s", argv[3]);
   1409 	}
   1410 }
   1411 
   1412 /*
   1413  * Print working directory.
   1414  */
   1415 /*ARGSUSED*/
   1416 void
   1417 pwd(int argc, char *argv[])
   1418 {
   1419 	(void) command("PWD");
   1420 }
   1421 
   1422 /*
   1423  * Make a directory.
   1424  */
   1425 void
   1426 makedir(int argc, char *argv[])
   1427 {
   1428 	if (argc < 2) {
   1429 		if (prompt_for_arg(line, sizeof (line), "directory-name") <
   1430 		    0) {
   1431 			code = -1;
   1432 			return;
   1433 		}
   1434 		makeargv();
   1435 		argc = margc;
   1436 		argv = margv;
   1437 	}
   1438 	if (argc < 2) {
   1439 		(void) printf("usage: %s directory-name\n", argv[0]);
   1440 		code = -1;
   1441 		return;
   1442 	}
   1443 	(void) command("MKD %s", argv[1]);
   1444 }
   1445 
   1446 /*
   1447  * Remove a directory.
   1448  */
   1449 void
   1450 removedir(int argc, char *argv[])
   1451 {
   1452 	if (argc < 2) {
   1453 		if (prompt_for_arg(line, sizeof (line), "directory-name") <
   1454 		    0) {
   1455 			code = -1;
   1456 			return;
   1457 		}
   1458 		makeargv();
   1459 		argc = margc;
   1460 		argv = margv;
   1461 	}
   1462 	if (argc < 2) {
   1463 		(void) printf("usage: %s directory-name\n", argv[0]);
   1464 		code = -1;
   1465 		return;
   1466 	}
   1467 	(void) command("RMD %s", argv[1]);
   1468 }
   1469 
   1470 /*
   1471  * Send a line, verbatim, to the remote machine.
   1472  */
   1473 void
   1474 quote(int argc, char *argv[])
   1475 {
   1476 	int i, n, len;
   1477 	char buf[FTPBUFSIZ];
   1478 
   1479 	if (argc < 2) {
   1480 		if (prompt_for_arg(line, sizeof (line),
   1481 		    "command line to send") == -1) {
   1482 			code = -1;
   1483 			return;
   1484 		}
   1485 		makeargv();
   1486 		argc = margc;
   1487 		argv = margv;
   1488 	}
   1489 	if (argc < 2) {
   1490 		(void) printf("usage: %s line-to-send\n", argv[0]);
   1491 		code = -1;
   1492 		return;
   1493 	}
   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;
   1502 		}
   1503 	}
   1504 	if (command("%s", buf) == PRELIM) {
   1505 		while (getreply(0) == PRELIM)
   1506 			;
   1507 	}
   1508 }
   1509 
   1510 /*
   1511  * Send a line, verbatim, to the remote machine as a SITE command.
   1512  */
   1513 void
   1514 site(int argc, char *argv[])
   1515 {
   1516 	int i, n, len;
   1517 	char buf[FTPBUFSIZ];
   1518 
   1519 	if (argc < 2) {
   1520 		if (prompt_for_arg(line, sizeof (line),
   1521 		    "arguments to SITE command") == -1) {
   1522 			code = -1;
   1523 			return;
   1524 		}
   1525 		makeargv();
   1526 		argc = margc;
   1527 		argv = margv;
   1528 	}
   1529 	if (argc < 2) {
   1530 		(void) printf("usage: %s arg1 [arg2] ...\n", argv[0]);
   1531 		code = -1;
   1532 		return;
   1533 	}
   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;
   1542 		}
   1543 	}
   1544 	if (command("SITE %s", buf) == PRELIM) {
   1545 		while (getreply(0) == PRELIM)
   1546 			;
   1547 	}
   1548 }
   1549 
   1550 /*
   1551  * Ask the other side for help.
   1552  */
   1553 void
   1554 rmthelp(int argc, char *argv[])
   1555 {
   1556 	int oldverbose = verbose;
   1557 
   1558 	verbose = 1;
   1559 	(void) command(argc == 1 ? "HELP" : "HELP %s", argv[1]);
   1560 	verbose = oldverbose;
   1561 }
   1562 
   1563 /*
   1564  * Terminate session and exit.
   1565  */
   1566 /*ARGSUSED*/
   1567 void
   1568 quit(int argc, char *argv[])
   1569 {
   1570 	if (connected)
   1571 		disconnect(0, NULL);
   1572 	pswitch(1);
   1573 	if (connected) {
   1574 		disconnect(0, NULL);
   1575 	}
   1576 	exit(0);
   1577 }
   1578 
   1579 /*
   1580  * Terminate session, but don't exit.
   1581  */
   1582 /*ARGSUSED*/
   1583 void
   1584 disconnect(int argc, char *argv[])
   1585 {
   1586 	extern FILE *ctrl_in, *ctrl_out;
   1587 	extern int data;
   1588 
   1589 	if (!connected)
   1590 		return;
   1591 	(void) command("QUIT");
   1592 	if (ctrl_in) {
   1593 		reset_timer();
   1594 		(void) fclose(ctrl_in);
   1595 	}
   1596 	if (ctrl_out) {
   1597 		reset_timer();
   1598 		(void) fclose(ctrl_out);
   1599 	}
   1600 	ctrl_out = ctrl_in = NULL;
   1601 	connected = 0;
   1602 	data = -1;
   1603 	if (!proxy) {
   1604 		macnum = 0;
   1605 	}
   1606 
   1607 	auth_type = AUTHTYPE_NONE;
   1608 	clevel = dlevel = PROT_C;
   1609 	goteof = 0;
   1610 }
   1611 
   1612 static int
   1613 confirm(char *cmd, char *file)
   1614 {
   1615 	char line[FTPBUFSIZ];
   1616 
   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');
   1626 }
   1627 
   1628 void
   1629 fatal(char *msg)
   1630 {
   1631 	(void) fprintf(stderr, "ftp: %s\n", msg);
   1632 	exit(1);
   1633 }
   1634 
   1635 /*
   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.
   1640  */
   1641 static int
   1642 globulize(char **cpp)
   1643 {
   1644 	char **globbed;
   1645 
   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);
   1656 	}
   1657 	if (globbed) {
   1658 		*cpp = strdup(*globbed);
   1659 		blkfree(globbed);
   1660 		if (!*cpp)
   1661 			return (0);
   1662 	}
   1663 	return (1);
   1664 }
   1665 
   1666 void
   1667 account(int argc, char *argv[])
   1668 {
   1669 	char acct[50], *ap;
   1670 
   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));
   1680 		}
   1681 		ap = acct;
   1682 	} else {
   1683 		ap = mygetpass("Account:");
   1684 	}
   1685 	(void) command("ACCT %s", ap);
   1686 }
   1687 
   1688 /*ARGSUSED*/
   1689 static void
   1690 proxabort(int sig)
   1691 {
   1692 	extern int proxy;
   1693 
   1694 	if (!proxy) {
   1695 		pswitch(1);
   1696 	}
   1697 	if (connected) {
   1698 		proxflag = 1;
   1699 	} else {
   1700 		proxflag = 0;
   1701 	}
   1702 	pswitch(0);
   1703 	longjmp(abortprox, 1);
   1704 }
   1705 
   1706 void
   1707 doproxy(int argc, char *argv[])
   1708 {
   1709 	void (*oldintr)();
   1710 	struct cmd *c;
   1711 
   1712 	if (argc < 2) {
   1713 		if (prompt_for_arg(line, sizeof (line), "command") == -1) {
   1714 			code = -1;
   1715 			return;
   1716 		}
   1717 		makeargv();
   1718 		argc = margc;
   1719 		argv = margv;
   1720 	}
   1721 	if (argc < 2) {
   1722 		(void) printf("usage: %s command\n", argv[0]);
   1723 		code = -1;
   1724 		return;
   1725 	}
   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;
   1732 	}
   1733 	if (c == 0) {
   1734 		(void) printf("?Invalid command\n");
   1735 		(void) fflush(stdout);
   1736 		code = -1;
   1737 		return;
   1738 	}
   1739 	if (!c->c_proxy) {
   1740 		(void) printf("?Invalid proxy command\n");
   1741 		(void) fflush(stdout);
   1742 		code = -1;
   1743 		return;
   1744 	}
   1745 	if (setjmp(abortprox)) {
   1746 		code = -1;
   1747 		return;
   1748 	}
   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;
   1758 	}
   1759 	(*c->c_handler)(argc-1, argv+1);
   1760 	if (connected) {
   1761 		proxflag = 1;
   1762 	} else {
   1763 		proxflag = 0;
   1764 	}
   1765 	pswitch(0);
   1766 	(void) signal(SIGINT, oldintr);
   1767 }
   1768 
   1769 /*ARGSUSED*/
   1770 void
   1771 setcase(int argc, char *argv[])
   1772 {
   1773 	mcase = !mcase;
   1774 	(void) printf("Case mapping %s.\n", onoff(mcase));
   1775 	code = mcase;
   1776 }
   1777 
   1778 /*ARGSUSED*/
   1779 void
   1780 setcr(int argc, char *argv[])
   1781 {
   1782 	crflag = !crflag;
   1783 	(void) printf("Carriage Return stripping %s.\n", onoff(crflag));
   1784 	code = crflag;
   1785 }
   1786 
   1787 void
   1788 setntrans(int argc, char *argv[])
   1789 {
   1790 	if (argc == 1) {
   1791 		ntflag = 0;
   1792 		(void) printf("Ntrans off.\n");
   1793 		code = ntflag;
   1794 		return;
   1795 	}
   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;
   1803 	}
   1804 	(void) strncpy(ntout, argv[2], 16);
   1805 	ntout[16] = '\0';
   1806 }
   1807 
   1808 static char *
   1809 dotrans(char *name)
   1810 {
   1811 	static char new[MAXPATHLEN];
   1812 	char *cp1, *cp2 = new;
   1813 	int i, ostop, found;
   1814 
   1815 	for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++)
   1816 		;
   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);
   1824 				}
   1825 				break;
   1826 			}
   1827 		}
   1828 		if (!found) {
   1829 			*cp2++ = *cp1;
   1830 		}
   1831 	}
   1832 	*cp2 = '\0';
   1833 	return (new);
   1834 }
   1835 
   1836 void
   1837 setnmap(int argc, char *argv[])
   1838 {
   1839 	char *cp;
   1840 
   1841 	if (argc == 1) {
   1842 		mapflag = 0;
   1843 		(void) printf("Nmap off.\n");
   1844 		code = mapflag;
   1845 		return;
   1846 	}
   1847 	if (argc < 3) {
   1848 		if (prompt_for_arg(line, sizeof (line), "mapout") == -1) {
   1849 			code = -1;
   1850 			return;
   1851 		}
   1852 		makeargv();
   1853 		argc = margc;
   1854 		argv = margv;
   1855 	}
   1856 	if (argc < 3) {
   1857 		(void) printf("Usage: %s [mapin mapout]\n", argv[0]);
   1858 		code = -1;
   1859 		return;
   1860 	}
   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, ' ');
   1869 	}
   1870 	*cp = '\0';
   1871 	(void) strncpy(mapin, altarg, MAXPATHLEN - 1);
   1872 	while (*++cp == ' ')
   1873 		/* NULL */;
   1874 	(void) strncpy(mapout, cp, MAXPATHLEN - 1);
   1875 }
   1876 
   1877 static char *
   1878 domap(char *name)
   1879 {
   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;
   1886 
   1887 	for (i = 0; i < 9; ++i) {
   1888 		toks[i] = 0;
   1889 	}
   1890 	while (match && *cp1 && *cp2) {
   1891 		if ((len1 = mbtowc(&wc1, cp1, MB_CUR_MAX)) <= 0) {
   1892 			wc1 = (unsigned char)*cp1;
   1893 			len1 = 1;
   1894 		}
   1895 		cp1 += len1;
   1896 		if ((len2 = mbtowc(&wc2, cp2, MB_CUR_MAX)) <= 0) {
   1897 			wc2 = (unsigned char)*cp2;
   1898 			len2 = 1;
   1899 		}
   1900 		cp2 += len2;
   1901 
   1902 		switch (wc2) {
   1903 		case '\\':
   1904 			if ((len2 = mbtowc(&wc2, cp2, MB_CUR_MAX)) <= 0) {
   1905 				wc2 = (unsigned char)*cp2;
   1906 				len2 = 1;
   1907 			}
   1908 			cp2 += len2;
   1909 			if (wc2 != wc1)
   1910 				match = 0;
   1911 			break;
   1912 
   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;
   1919 				}
   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;
   1929 						}
   1930 						cp1 += len1;
   1931 						if (wc2 == wc1)
   1932 							break;
   1933 					}
   1934 					if (*cp1 == 0 && wc2 != wc1)
   1935 						te[toknum] = cp1;
   1936 					else
   1937 						te[toknum] = cp1 - len1;
   1938 				}
   1939 				cp2++;			/* Consume the digit */
   1940 				if (wc2)
   1941 					cp2 += len2;	/* Consume wide char */
   1942 				break;
   1943 			}
   1944 			/* intentional drop through */
   1945 		default:
   1946 			if (wc2 != wc1)
   1947 				match = 0;
   1948 			break;
   1949 		}
   1950 	}
   1951 
   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;
   1966 			}
   1967 			break;
   1968 
   1969 		case '[':
   1970 LOOP:
   1971 			cp2++;
   1972 			if (*cp2 == '$' && isdigit(*(cp2+1))) {
   1973 				if (*++cp2 == '0') {
   1974 					char *cp3 = name;
   1975 
   1976 					while (*cp3) {
   1977 						*cp1++ = *cp3++;
   1978 					}
   1979 					match = 1;
   1980 				} else if (toks[toknum = *cp2 - '1']) {
   1981 					char *cp3 = tp[toknum];
   1982 
   1983 					while (cp3 != te[toknum]) {
   1984 						*cp1++ = *cp3++;
   1985 					}
   1986 					match = 1;
   1987 				}
   1988 			} else {
   1989 				while (*cp2 && *cp2 != ',' && *cp2 != ']') {
   1990 					if (*cp2 == '\\') {
   1991 						cp2++;
   1992 						continue;
   1993 					}
   1994 
   1995 					if (*cp2 == '$' && isdigit(*(cp2+1))) {
   1996 						if (*++cp2 == '0') {
   1997 							char *cp3 = name;
   1998 
   1999 							while (*cp3)
   2000 								*cp1++ = *cp3++;
   2001 							continue;
   2002 						}
   2003 						if (toks[toknum = *cp2 - '1']) {
   2004 							char *cp3 = tp[toknum];
   2005 
   2006 							while (cp3 !=
   2007 							    te[toknum])
   2008 								*cp1++ = *cp3++;
   2009 						}
   2010 						continue;
   2011 					}
   2012 					if (*cp2) {
   2013 						if ((len2 =
   2014 						    mblen(cp2, MB_CUR_MAX)) <=
   2015 						    0) {
   2016 							len2 = 1;
   2017 						}
   2018 						memcpy(cp1, cp2, len2);
   2019 						cp1 += len2;
   2020 						cp2 += len2;
   2021 					}
   2022 				}
   2023 				if (!*cp2) {
   2024 					(void) printf(
   2025 						"nmap: unbalanced brackets\n");
   2026 					return (name);
   2027 				}
   2028 				match = 1;
   2029 			}
   2030 			if (match) {
   2031 				while (*cp2 && *cp2 != ']') {
   2032 					if (*cp2 == '\\' && *(cp2 + 1)) {
   2033 						cp2++;
   2034 					}
   2035 					if ((len2 = mblen(cp2, MB_CUR_MAX)) <=
   2036 					    0)
   2037 						len2 = 1;
   2038 					cp2 += len2;
   2039 				}
   2040 				if (!*cp2) {
   2041 					(void) printf(
   2042 						"nmap: unbalanced brackets\n");
   2043 					return (name);
   2044 				}
   2045 				cp2++;
   2046 				break;
   2047 			}
   2048 			switch (*++cp2) {
   2049 				case ',':
   2050 					goto LOOP;
   2051 				case ']':
   2052 					break;
   2053 				default:
   2054 					cp2--;
   2055 					goto LOOP;
   2056 			}
   2057 			cp2++;
   2058 			break;
   2059 		case '$':
   2060 			if (isdigit(*(cp2 + 1))) {
   2061 				if (*++cp2 == '0') {
   2062 					char *cp3 = name;
   2063 
   2064 					while (*cp3) {
   2065 						*cp1++ = *cp3++;
   2066 					}
   2067 				} else if (toks[toknum = *cp2 - '1']) {
   2068 					char *cp3 = tp[toknum];
   2069 
   2070 					while (cp3 != te[toknum]) {
   2071 						*cp1++ = *cp3++;
   2072 					}
   2073 				}
   2074 				cp2++;
   2075 				break;
   2076 			}
   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;
   2085 		}
   2086 	}
   2087 	*cp1 = '\0';
   2088 	if (!*new) {
   2089 		return (name);
   2090 	}
   2091 	return (new);
   2092 }
   2093 
   2094 /*ARGSUSED*/
   2095 void
   2096 setsunique(int argc, char *argv[])
   2097 {
   2098 	sunique = !sunique;
   2099 	(void) printf("Store unique %s.\n", onoff(sunique));
   2100 	code = sunique;
   2101 }
   2102 
   2103 /*ARGSUSED*/
   2104 void
   2105 setrunique(int argc, char *argv[])
   2106 {
   2107 	runique = !runique;
   2108 	(void) printf("Receive unique %s.\n", onoff(runique));
   2109 	code = runique;
   2110 }
   2111 
   2112 /*ARGSUSED*/
   2113 void
   2114 setpassive(int argc, char *argv[])
   2115 {
   2116 	passivemode = !passivemode;
   2117 	(void) printf("Passive mode %s.\n", onoff(passivemode));
   2118 	code = passivemode;
   2119 }
   2120 
   2121 void
   2122 settcpwindow(int argc, char *argv[])
   2123 {
   2124 	int owindowsize = tcpwindowsize;
   2125 
   2126 	if (argc > 2) {
   2127 		(void) printf("usage: %s [size]\n", argv[0]);
   2128 		code = -1;
   2129 		return;
   2130 	}
   2131 	if (argc == 2) {
   2132 		int window;
   2133 		char *endp;
   2134 
   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;
   2142 	}
   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);
   2150 }
   2151 
   2152 /* change directory to parent directory */
   2153 /*ARGSUSED*/
   2154 void
   2155 cdup(int argc, char *argv[])
   2156 {
   2157 	(void) command("CDUP");
   2158 }
   2159 
   2160 void
   2161 macdef(int argc, char *argv[])
   2162 {
   2163 	char *tmp;
   2164 	int c;
   2165 
   2166 	if (macnum == 16) {
   2167 		(void) printf("Limit of 16 macros have already been defined\n");
   2168 		code = -1;
   2169 		return;
   2170 	}
   2171 	if (argc < 2) {
   2172 		if (prompt_for_arg(line, sizeof (line), "macro name") == -1) {
   2173 			code = -1;
   2174 			return;
   2175 		}
   2176 		makeargv();
   2177 		argc = margc;
   2178 		argv = margv;
   2179 	}
   2180 	if (argc != 2) {
   2181 		(void) printf("Usage: %s macro_name\n", argv[0]);
   2182 		code = -1;
   2183 		return;
   2184 	}
   2185 	if (interactive) {
   2186 		(void) printf("Enter macro line by line, terminating "
   2187 		    "it with a null line\n");
   2188 	}
   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;
   2194 	}
   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;
   2201 		}
   2202 		if ((*tmp = c) == '\n') {
   2203 			if (tmp == macros[macnum].mac_start) {
   2204 				macros[macnum++].mac_end = tmp;
   2205 				code = 0;
   2206 				return;
   2207 			}
   2208 			if (*(tmp-1) == '\0') {
   2209 				macros[macnum++].mac_end = tmp - 1;
   2210 				code = 0;
   2211 				return;
   2212 			}
   2213 			*tmp = '\0';
   2214 		}
   2215 		tmp++;
   2216 	}
   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;
   2225 		}
   2226 	}
   2227 }
   2228 
   2229 /*
   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.
   2233  */
   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
   2243 };
   2244 
   2245 /*
   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.
   2248  */
   2249 static char *
   2250 getlevel(int level)
   2251 {
   2252 	struct levels *p;
   2253 
   2254 	for (p = levels; (p != NULL) && (p->p_level != level); p++)
   2255 		;
   2256 	return (p ? p->p_name : NULL);
   2257 }
   2258 
   2259 static char *plevel[] = {
   2260 	"protect",
   2261 	"",
   2262 	NULL
   2263 };
   2264 
   2265 /*
   2266  * Set control channel protection level.
   2267  */
   2268 void
   2269 setclevel(int argc, char *argv[])
   2270 {
   2271 	struct levels *p;
   2272 	char *levelp;
   2273 	int comret;
   2274 
   2275 	if (argc > 2) {
   2276 		char *sep;
   2277 
   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 = " | ";
   2284 		}
   2285 		(void) printf(" ]\n");
   2286 		code = -1;
   2287 		return;
   2288 	}
   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;
   2295 	}
   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;
   2303 	}
   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;
   2309 	}
   2310 	if (strcmp(p->p_name, "clear") == 0) {
   2311 		comret = command("CCC");
   2312 		if (comret == COMPLETE)
   2313 			clevel = PROT_C;
   2314 		return;
   2315 	}
   2316 	clevel = p->p_level;
   2317 	(void) printf("Control channel protection level set to %s.\n",
   2318 		p->p_name);
   2319 }
   2320 
   2321 /*
   2322  * Set data channel protection level.
   2323  */
   2324 void
   2325 setdlevel(int argc, char *argv[])
   2326 {
   2327 	struct levels *p;
   2328 	int comret;
   2329 
   2330 	if (argc != 2) {
   2331 		char *sep;
   2332 
   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 = " | ";
   2339 		}
   2340 		(void) printf(" ]\n");
   2341 		code = -1;
   2342 		return;
   2343 	}
   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;
   2351 	}
   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;
   2357 	}
   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;
   2364 }
   2365 
   2366 /*
   2367  * Set clear command protection level.
   2368  */
   2369 /* VARARGS */
   2370 void
   2371 ccc(int argc, char *argv[])
   2372 {
   2373 	plevel[1] = "clear";
   2374 	setclevel(2, plevel);
   2375 }
   2376 
   2377 /*
   2378  * Set clear data protection level.
   2379  */
   2380 /* VARARGS */
   2381 void
   2382 setclear(int argc, char *argv[])
   2383 {
   2384 	plevel[1] = "clear";
   2385 	setdlevel(2, plevel);
   2386 }
   2387 
   2388 /*
   2389  * Set safe data protection level.
   2390  */
   2391 /* VARARGS */
   2392 void
   2393 setsafe(int argc, char *argv[])
   2394 {
   2395 	plevel[1] = "safe";
   2396 	setdlevel(2, plevel);
   2397 }
   2398 
   2399 /*
   2400  * Set private data protection level.
   2401  */
   2402 /* VARARGS */
   2403 void
   2404 setprivate(int argc, char *argv[])
   2405 {
   2406 	plevel[1] = "private";
   2407 	setdlevel(2, plevel);
   2408 }
   2409 
   2410 /*
   2411  * Set mechanism type
   2412  */
   2413 void
   2414 setmech(int  argc, char *argv[])
   2415 {
   2416 	char	tempmech[MECH_SZ];
   2417 
   2418 	if (argc < 2) {
   2419 		if (prompt_for_arg(line, sizeof (line), "mech-type") == -1) {
   2420 			code = -1;
   2421 			return;
   2422 		}
   2423 		makeargv();
   2424 		argc = margc;
   2425 		argv = margv;
   2426 	}
   2427 
   2428 	if (argc != 2) {
   2429 		(void) printf("usage: %s [ mechanism type ]\n", argv[0]);
   2430 		code = -1;
   2431 		return;
   2432 	}
   2433 
   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;
   2446 	}
   2447 }
   2448