fix globbing - need NOCHECK flag
[unix-history] / usr / src / usr.bin / ftp / cmds.c
CommitLineData
edf71f48 1/*
522da3e4 2 * Copyright (c) 1985, 1989, 1993, 1994
84181c2c 3 * The Regents of the University of California. All rights reserved.
11c5f0a3 4 *
1343342a 5 * %sccs.include.redist.c%
edf71f48
DF
6 */
7
59d0d309 8#ifndef lint
c1a675d4 9static char sccsid[] = "@(#)cmds.c 8.5 (Berkeley) %G%";
11c5f0a3 10#endif /* not lint */
59d0d309
SL
11
12/*
13 * FTP User Program -- Command Routines.
14 */
cdc35b45
MK
15#include <sys/param.h>
16#include <sys/wait.h>
17#include <sys/stat.h>
59d0d309 18#include <sys/socket.h>
26128054 19#include <netinet/in.h>
62c4a390
SL
20#include <arpa/ftp.h>
21
26128054
JSP
22#include <ctype.h>
23#include <err.h>
f224c779 24#include <glob.h>
26128054 25#include <netdb.h>
59d0d309
SL
26#include <signal.h>
27#include <stdio.h>
26128054
JSP
28#include <stdlib.h>
29#include <string.h>
ff00793c 30#include <time.h>
26128054 31#include <unistd.h>
cdc35b45
MK
32
33#include "ftp_var.h"
f58943be 34#include "pathnames.h"
59d0d309 35
26128054
JSP
36jmp_buf jabort;
37char *mname;
f224c779 38char *home = "/";
59d0d309 39
67ff27c7
KB
40/*
41 * `Another' gets another argument, and stores the new argc and argv.
42 * It reverts to the top level (via main.c's intr()) on EOF/error.
43 *
44 * Returns false if no new arguments have been added.
45 */
26128054 46int
67ff27c7
KB
47another(pargc, pargv, prompt)
48 int *pargc;
49 char ***pargv;
50 char *prompt;
51{
52 int len = strlen(line), ret;
67ff27c7
KB
53
54 if (len >= sizeof(line) - 3) {
55 printf("sorry, arguments too long\n");
56 intr();
57 }
58 printf("(%s) ", prompt);
59 line[len++] = ' ';
60 if (fgets(&line[len], sizeof(line) - len, stdin) == NULL)
61 intr();
62 len += strlen(&line[len]);
63 if (len > 0 && line[len - 1] == '\n')
64 line[len - 1] = '\0';
65 makeargv();
66 ret = margc > *pargc;
67 *pargc = margc;
68 *pargv = margv;
69 return (ret);
70}
71
59d0d309
SL
72/*
73 * Connect to peer server and
74 * auto-login, if possible.
75 */
26128054 76void
59d0d309
SL
77setpeer(argc, argv)
78 int argc;
79 char *argv[];
80{
26128054 81 char *host;
11c9b6d7 82 short port;
59d0d309
SL
83
84 if (connected) {
9069f68e 85 printf("Already connected to %s, use close first.\n",
59d0d309 86 hostname);
9069f68e 87 code = -1;
59d0d309
SL
88 return;
89 }
67ff27c7
KB
90 if (argc < 2)
91 (void) another(&argc, &argv, "to");
92 if (argc < 2 || argc > 3) {
59d0d309 93 printf("usage: %s host-name [port]\n", argv[0]);
9069f68e 94 code = -1;
59d0d309
SL
95 return;
96 }
97 port = sp->s_port;
98 if (argc > 2) {
d33c618b 99 port = atoi(argv[2]);
59d0d309 100 if (port <= 0) {
d33c618b
SL
101 printf("%s: bad port number-- %s\n", argv[1], argv[2]);
102 printf ("usage: %s host-name [port]\n", argv[0]);
9069f68e 103 code = -1;
59d0d309
SL
104 return;
105 }
106 port = htons(port);
107 }
108 host = hookup(argv[1], port);
109 if (host) {
c69896ac 110 int overbose;
cdc35b45 111
c69896ac 112 connected = 1;
dcd54a7f
MK
113 /*
114 * Set up defaults for FTP.
115 */
116 (void) strcpy(typename, "ascii"), type = TYPE_A;
117 curtype = TYPE_A;
118 (void) strcpy(formname, "non-print"), form = FORM_N;
119 (void) strcpy(modename, "stream"), mode = MODE_S;
120 (void) strcpy(structname, "file"), stru = STRU_F;
121 (void) strcpy(bytename, "8"), bytesize = 8;
c69896ac 122 if (autologin)
04480325 123 (void) login(argv[1]);
c69896ac 124
ff00793c
MK
125#if defined(unix) && NBBY == 8
126/*
127 * this ifdef is to keep someone form "porting" this to an incompatible
128 * system and not checking this out. This way they have to think about it.
129 */
c69896ac
MK
130 overbose = verbose;
131 if (debug == 0)
132 verbose = -1;
133 if (command("SYST") == COMPLETE && overbose) {
26128054
JSP
134 char *cp, c;
135 cp = strchr(reply_string+4, ' ');
c69896ac 136 if (cp == NULL)
26128054 137 cp = strchr(reply_string+4, '\r');
c69896ac
MK
138 if (cp) {
139 if (cp[-1] == '.')
140 cp--;
141 c = *cp;
142 *cp = '\0';
ff00793c 143 }
c69896ac
MK
144
145 printf("Remote system type is %s.\n",
146 reply_string+4);
147 if (cp)
148 *cp = c;
149 }
150 if (!strncmp(reply_string, "215 UNIX Type: L8", 17)) {
dcd54a7f
MK
151 if (proxy)
152 unix_proxy = 1;
153 else
154 unix_server = 1;
155 /*
156 * Set type to 0 (not specified by user),
157 * meaning binary by default, but don't bother
158 * telling server. We can use binary
159 * for text files unless changed by the user.
160 */
161 type = 0;
162 (void) strcpy(typename, "binary");
c69896ac
MK
163 if (overbose)
164 printf("Using %s mode to transfer files.\n",
165 typename);
dcd54a7f
MK
166 } else {
167 if (proxy)
168 unix_proxy = 0;
169 else
170 unix_server = 0;
171 if (overbose &&
172 !strncmp(reply_string, "215 TOPS20", 10))
173 printf(
cdc35b45 174"Remember to set tenex mode when transfering binary files from this machine.\n");
ff00793c 175 }
c69896ac
MK
176 verbose = overbose;
177#endif /* unix */
59d0d309
SL
178 }
179}
180
181struct types {
182 char *t_name;
183 char *t_mode;
184 int t_type;
d33c618b 185 char *t_arg;
59d0d309 186} types[] = {
d33c618b
SL
187 { "ascii", "A", TYPE_A, 0 },
188 { "binary", "I", TYPE_I, 0 },
189 { "image", "I", TYPE_I, 0 },
190 { "ebcdic", "E", TYPE_E, 0 },
191 { "tenex", "L", TYPE_L, bytename },
26128054 192 { NULL }
59d0d309
SL
193};
194
195/*
196 * Set transfer type.
197 */
26128054 198void
59d0d309 199settype(argc, argv)
67ff27c7 200 int argc;
59d0d309
SL
201 char *argv[];
202{
26128054 203 struct types *p;
d33c618b 204 int comret;
59d0d309
SL
205
206 if (argc > 2) {
207 char *sep;
208
209 printf("usage: %s [", argv[0]);
210 sep = " ";
211 for (p = types; p->t_name; p++) {
212 printf("%s%s", sep, p->t_name);
dcd54a7f 213 sep = " | ";
59d0d309
SL
214 }
215 printf(" ]\n");
9069f68e 216 code = -1;
59d0d309
SL
217 return;
218 }
219 if (argc < 2) {
220 printf("Using %s mode to transfer files.\n", typename);
9069f68e 221 code = 0;
59d0d309
SL
222 return;
223 }
224 for (p = types; p->t_name; p++)
225 if (strcmp(argv[1], p->t_name) == 0)
226 break;
227 if (p->t_name == 0) {
228 printf("%s: unknown mode\n", argv[1]);
9069f68e 229 code = -1;
59d0d309
SL
230 return;
231 }
d33c618b
SL
232 if ((p->t_arg != NULL) && (*(p->t_arg) != '\0'))
233 comret = command ("TYPE %s %s", p->t_mode, p->t_arg);
234 else
235 comret = command("TYPE %s", p->t_mode);
236 if (comret == COMPLETE) {
04480325 237 (void) strcpy(typename, p->t_name);
dcd54a7f 238 curtype = type = p->t_type;
59d0d309
SL
239 }
240}
241
dcd54a7f
MK
242/*
243 * Internal form of settype; changes current type in use with server
244 * without changing our notion of the type for data transfers.
245 * Used to change to and from ascii for listings.
246 */
26128054 247void
dcd54a7f
MK
248changetype(newtype, show)
249 int newtype, show;
250{
26128054 251 struct types *p;
dcd54a7f
MK
252 int comret, oldverbose = verbose;
253
254 if (newtype == 0)
255 newtype = TYPE_I;
256 if (newtype == curtype)
257 return;
258 if (debug == 0 && show == 0)
259 verbose = 0;
260 for (p = types; p->t_name; p++)
261 if (newtype == p->t_type)
262 break;
263 if (p->t_name == 0) {
264 printf("ftp: internal error: unknown type %d\n", newtype);
265 return;
266 }
267 if (newtype == TYPE_L && bytename[0] != '\0')
268 comret = command("TYPE %s %s", p->t_mode, bytename);
269 else
270 comret = command("TYPE %s", p->t_mode);
271 if (comret == COMPLETE)
272 curtype = newtype;
273 verbose = oldverbose;
274}
275
11c9b6d7
RA
276char *stype[] = {
277 "type",
278 "",
279 0
280};
281
59d0d309
SL
282/*
283 * Set binary transfer type.
284 */
285/*VARARGS*/
26128054
JSP
286void
287setbinary(argc, argv)
288 int argc;
289 char **argv;
59d0d309 290{
26128054 291
11c9b6d7
RA
292 stype[1] = "binary";
293 settype(2, stype);
59d0d309
SL
294}
295
296/*
297 * Set ascii transfer type.
298 */
299/*VARARGS*/
26128054
JSP
300void
301setascii(argc, argv)
302 int argc;
303 char *argv[];
59d0d309 304{
26128054 305
11c9b6d7
RA
306 stype[1] = "ascii";
307 settype(2, stype);
59d0d309
SL
308}
309
310/*
311 * Set tenex transfer type.
312 */
313/*VARARGS*/
26128054
JSP
314void
315settenex(argc, argv)
316 int argc;
317 char *argv[];
59d0d309 318{
26128054 319
11c9b6d7
RA
320 stype[1] = "tenex";
321 settype(2, stype);
59d0d309
SL
322}
323
59d0d309
SL
324/*
325 * Set file transfer mode.
326 */
04480325 327/*ARGSUSED*/
26128054
JSP
328void
329setftmode(argc, argv)
67ff27c7 330 int argc;
59d0d309
SL
331 char *argv[];
332{
333
334 printf("We only support %s mode, sorry.\n", modename);
9069f68e 335 code = -1;
59d0d309
SL
336}
337
338/*
339 * Set file transfer format.
340 */
04480325 341/*ARGSUSED*/
26128054 342void
59d0d309 343setform(argc, argv)
67ff27c7 344 int argc;
59d0d309
SL
345 char *argv[];
346{
347
348 printf("We only support %s format, sorry.\n", formname);
9069f68e 349 code = -1;
59d0d309
SL
350}
351
352/*
353 * Set file transfer structure.
354 */
04480325 355/*ARGSUSED*/
26128054 356void
59d0d309 357setstruct(argc, argv)
67ff27c7 358 int argc;
59d0d309
SL
359 char *argv[];
360{
361
362 printf("We only support %s structure, sorry.\n", structname);
9069f68e 363 code = -1;
59d0d309
SL
364}
365
71a655cd
RC
366/*
367 * Send a single file.
368 */
26128054 369void
59d0d309 370put(argc, argv)
5ac6fc46
SL
371 int argc;
372 char *argv[];
373{
9072bd8a 374 char *cmd;
9069f68e 375 int loc = 0;
460419cd 376 char *oldargv1, *oldargv2;
5ac6fc46 377
9069f68e
GM
378 if (argc == 2) {
379 argc++;
380 argv[2] = argv[1];
381 loc++;
382 }
67ff27c7
KB
383 if (argc < 2 && !another(&argc, &argv, "local-file"))
384 goto usage;
385 if (argc < 3 && !another(&argc, &argv, "remote-file")) {
59d0d309 386usage:
67ff27c7 387 printf("usage: %s local-file remote-file\n", argv[0]);
9069f68e 388 code = -1;
59d0d309
SL
389 return;
390 }
14433a73 391 oldargv1 = argv[1];
460419cd 392 oldargv2 = argv[2];
9069f68e
GM
393 if (!globulize(&argv[1])) {
394 code = -1;
cf8133c7 395 return;
9069f68e 396 }
14433a73
KM
397 /*
398 * If "globulize" modifies argv[1], and argv[2] is a copy of
399 * the old argv[1], make it a copy of the new argv[1].
400 */
9069f68e 401 if (argv[1] != oldargv1 && argv[2] == oldargv1) {
14433a73 402 argv[2] = argv[1];
9069f68e
GM
403 }
404 cmd = (argv[0][0] == 'a') ? "APPE" : ((sunique) ? "STOU" : "STOR");
405 if (loc && ntflag) {
406 argv[2] = dotrans(argv[2]);
407 }
408 if (loc && mapflag) {
409 argv[2] = domap(argv[2]);
410 }
460419cd
MK
411 sendrequest(cmd, argv[1], argv[2],
412 argv[1] != oldargv1 || argv[2] != oldargv2);
59d0d309
SL
413}
414
415/*
9072bd8a 416 * Send multiple files.
cf8133c7 417 */
26128054 418void
cf8133c7 419mput(argc, argv)
981fd33c
KB
420 int argc;
421 char **argv;
cf8133c7 422{
26128054 423 int i;
981fd33c 424 sig_t oldintr;
11c9b6d7 425 int ointer;
9069f68e 426 char *tp;
cf8133c7 427
67ff27c7
KB
428 if (argc < 2 && !another(&argc, &argv, "local-files")) {
429 printf("usage: %s local-files\n", argv[0]);
9069f68e
GM
430 code = -1;
431 return;
432 }
433 mname = argv[0];
434 mflag = 1;
435 oldintr = signal(SIGINT, mabort);
436 (void) setjmp(jabort);
437 if (proxy) {
438 char *cp, *tp2, tmpbuf[MAXPATHLEN];
439
04480325 440 while ((cp = remglob(argv,0)) != NULL) {
9069f68e
GM
441 if (*cp == 0) {
442 mflag = 0;
443 continue;
444 }
445 if (mflag && confirm(argv[0], cp)) {
446 tp = cp;
447 if (mcase) {
448 while (*tp && !islower(*tp)) {
449 tp++;
450 }
451 if (!*tp) {
452 tp = cp;
453 tp2 = tmpbuf;
454 while ((*tp2 = *tp) != NULL) {
455 if (isupper(*tp2)) {
456 *tp2 = 'a' + *tp2 - 'A';
457 }
458 tp++;
459 tp2++;
460 }
461 }
462 tp = tmpbuf;
463 }
464 if (ntflag) {
465 tp = dotrans(tp);
466 }
467 if (mapflag) {
468 tp = domap(tp);
469 }
460419cd
MK
470 sendrequest((sunique) ? "STOU" : "STOR",
471 cp, tp, cp != tp || !interactive);
9069f68e
GM
472 if (!mflag && fromatty) {
473 ointer = interactive;
474 interactive = 1;
475 if (confirm("Continue with","mput")) {
476 mflag++;
477 }
478 interactive = ointer;
479 }
480 }
481 }
482 (void) signal(SIGINT, oldintr);
483 mflag = 0;
cf8133c7
SL
484 return;
485 }
614e24b6 486 for (i = 1; i < argc; i++) {
26128054 487 char **cpp, **gargs;
f224c779 488 glob_t gl;
c1a675d4 489 int flags;
614e24b6
SL
490
491 if (!doglob) {
9069f68e
GM
492 if (mflag && confirm(argv[0], argv[i])) {
493 tp = (ntflag) ? dotrans(argv[i]) : argv[i];
494 tp = (mapflag) ? domap(tp) : tp;
495 sendrequest((sunique) ? "STOU" : "STOR",
460419cd 496 argv[i], tp, tp != argv[i] || !interactive);
9069f68e
GM
497 if (!mflag && fromatty) {
498 ointer = interactive;
499 interactive = 1;
500 if (confirm("Continue with","mput")) {
501 mflag++;
502 }
503 interactive = ointer;
504 }
505 }
614e24b6
SL
506 continue;
507 }
f224c779
JSP
508
509 memset(&gl, 0, sizeof(gl));
c1a675d4
JSP
510 flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE;
511 if (glob(argv[i], flags, NULL, &gl) || gl.gl_pathc == 0) {
f224c779
JSP
512 warnx("%s: not found", argv[i]);
513 globfree(&gl);
614e24b6 514 continue;
cf8133c7 515 }
f224c779 516 for (cpp = gl.gl_pathv; cpp && *cpp != NULL; cpp++) {
9069f68e
GM
517 if (mflag && confirm(argv[0], *cpp)) {
518 tp = (ntflag) ? dotrans(*cpp) : *cpp;
519 tp = (mapflag) ? domap(tp) : tp;
520 sendrequest((sunique) ? "STOU" : "STOR",
460419cd 521 *cpp, tp, *cpp != tp || !interactive);
9069f68e
GM
522 if (!mflag && fromatty) {
523 ointer = interactive;
524 interactive = 1;
525 if (confirm("Continue with","mput")) {
526 mflag++;
527 }
528 interactive = ointer;
529 }
530 }
531 }
f224c779 532 globfree(&gl);
cf8133c7 533 }
9069f68e
GM
534 (void) signal(SIGINT, oldintr);
535 mflag = 0;
cf8133c7
SL
536}
537
26128054 538void
ff00793c 539
26128054 540void
cf8133c7
SL
541/*
542 * Receive one file.
59d0d309 543 */
26128054 544int
63c685da 545get(argc, argv)
59d0d309
SL
546 char *argv[];
547{
9069f68e 548 int loc = 0;
460419cd 549 char *oldargv1, *oldargv2;
59d0d309 550
9069f68e
GM
551 if (argc == 2) {
552 argc++;
553 argv[2] = argv[1];
554 loc++;
555 }
67ff27c7
KB
556 if (argc < 2 && !another(&argc, &argv, "remote-file"))
557 goto usage;
558 if (argc < 3 && !another(&argc, &argv, "local-file")) {
59d0d309 559usage:
9069f68e
GM
560 printf("usage: %s remote-file [ local-file ]\n", argv[0]);
561 code = -1;
63c685da 562 return;
59d0d309 563 }
460419cd
MK
564 oldargv1 = argv[1];
565 oldargv2 = argv[2];
9069f68e
GM
566 if (!globulize(&argv[2])) {
567 code = -1;
63c685da 568 return;
9069f68e
GM
569 }
570 if (loc && mcase) {
571 char *tp = argv[1], *tp2, tmpbuf[MAXPATHLEN];
572
573 while (*tp && !islower(*tp)) {
574 tp++;
575 }
576 if (!*tp) {
577 tp = argv[2];
578 tp2 = tmpbuf;
579 while ((*tp2 = *tp) != NULL) {
580 if (isupper(*tp2)) {
581 *tp2 = 'a' + *tp2 - 'A';
582 }
583 tp++;
584 tp2++;
585 }
586 argv[2] = tmpbuf;
587 }
588 }
cdc35b45 589 if (loc && ntflag)
9069f68e 590 argv[2] = dotrans(argv[2]);
cdc35b45 591 if (loc && mapflag)
9069f68e 592 argv[2] = domap(argv[2]);
63c685da 593 recvrequest("RETR", argv[2], argv[1], "w");
59d0d309
SL
594}
595
26128054 596/* ARGSUSED */
981fd33c 597void
26128054
JSP
598mabort(signo)
599 int signo;
9069f68e
GM
600{
601 int ointer;
9069f68e
GM
602
603 printf("\n");
604 (void) fflush(stdout);
605 if (mflag && fromatty) {
606 ointer = interactive;
607 interactive = 1;
608 if (confirm("Continue with", mname)) {
609 interactive = ointer;
610 longjmp(jabort,0);
611 }
612 interactive = ointer;
613 }
614 mflag = 0;
615 longjmp(jabort,0);
616}
617
cf8133c7
SL
618/*
619 * Get multiple files.
620 */
26128054 621void
cf8133c7 622mget(argc, argv)
981fd33c
KB
623 int argc;
624 char **argv;
cf8133c7 625{
981fd33c 626 sig_t oldintr;
37c5a70c 627 int ch, ointer;
981fd33c 628 char *cp, *tp, *tp2, tmpbuf[MAXPATHLEN];
cf8133c7 629
67ff27c7
KB
630 if (argc < 2 && !another(&argc, &argv, "remote-files")) {
631 printf("usage: %s remote-files\n", argv[0]);
9069f68e 632 code = -1;
cf8133c7
SL
633 return;
634 }
9069f68e
GM
635 mname = argv[0];
636 mflag = 1;
26128054 637 oldintr = signal(SIGINT, mabort);
9069f68e 638 (void) setjmp(jabort);
04480325 639 while ((cp = remglob(argv,proxy)) != NULL) {
9069f68e
GM
640 if (*cp == '\0') {
641 mflag = 0;
642 continue;
643 }
644 if (mflag && confirm(argv[0], cp)) {
645 tp = cp;
646 if (mcase) {
37c5a70c
AC
647 for (tp2 = tmpbuf; ch = *tp++;)
648 *tp2++ = isupper(ch) ? tolower(ch) : ch;
9069f68e
GM
649 tp = tmpbuf;
650 }
651 if (ntflag) {
652 tp = dotrans(tp);
653 }
654 if (mapflag) {
655 tp = domap(tp);
656 }
460419cd
MK
657 recvrequest("RETR", tp, cp, "w",
658 tp != cp || !interactive);
9069f68e
GM
659 if (!mflag && fromatty) {
660 ointer = interactive;
661 interactive = 1;
662 if (confirm("Continue with","mget")) {
663 mflag++;
664 }
665 interactive = ointer;
666 }
667 }
668 }
669 (void) signal(SIGINT,oldintr);
670 mflag = 0;
5ac6fc46 671}
cf8133c7 672
5ac6fc46 673char *
04480325 674remglob(argv,doswitch)
5ac6fc46 675 char *argv[];
04480325 676 int doswitch;
5ac6fc46 677{
9072bd8a 678 char temp[16];
5ac6fc46
SL
679 static char buf[MAXPATHLEN];
680 static FILE *ftemp = NULL;
681 static char **args;
614e24b6 682 int oldverbose, oldhash;
9072bd8a 683 char *cp, *mode;
5ac6fc46 684
9069f68e
GM
685 if (!mflag) {
686 if (!doglob) {
687 args = NULL;
688 }
689 else {
690 if (ftemp) {
04480325 691 (void) fclose(ftemp);
9069f68e
GM
692 ftemp = NULL;
693 }
694 }
26128054 695 return (NULL);
9069f68e 696 }
5ac6fc46 697 if (!doglob) {
9072bd8a 698 if (args == NULL)
5ac6fc46
SL
699 args = argv;
700 if ((cp = *++args) == NULL)
701 args = NULL;
702 return (cp);
cf8133c7 703 }
cf8133c7 704 if (ftemp == NULL) {
f58943be 705 (void) strcpy(temp, _PATH_TMP);
04480325 706 (void) mktemp(temp);
5ac6fc46 707 oldverbose = verbose, verbose = 0;
614e24b6 708 oldhash = hash, hash = 0;
9069f68e
GM
709 if (doswitch) {
710 pswitch(!proxy);
711 }
9072bd8a 712 for (mode = "w"; *++argv != NULL; mode = "a")
460419cd 713 recvrequest ("NLST", temp, *argv, mode, 0);
9069f68e
GM
714 if (doswitch) {
715 pswitch(!proxy);
716 }
614e24b6 717 verbose = oldverbose; hash = oldhash;
5ac6fc46 718 ftemp = fopen(temp, "r");
04480325 719 (void) unlink(temp);
5ac6fc46
SL
720 if (ftemp == NULL) {
721 printf("can't find list of remote files, oops\n");
9072bd8a 722 return (NULL);
5ac6fc46 723 }
cf8133c7 724 }
5ac6fc46 725 if (fgets(buf, sizeof (buf), ftemp) == NULL) {
04480325 726 (void) fclose(ftemp), ftemp = NULL;
5ac6fc46 727 return (NULL);
cf8133c7 728 }
26128054 729 if ((cp = strchr(buf, '\n')) != NULL)
5ac6fc46
SL
730 *cp = '\0';
731 return (buf);
cf8133c7
SL
732}
733
59d0d309
SL
734char *
735onoff(bool)
736 int bool;
737{
738
739 return (bool ? "on" : "off");
740}
741
742/*
743 * Show status.
744 */
04480325 745/*ARGSUSED*/
26128054 746void
59d0d309 747status(argc, argv)
67ff27c7 748 int argc;
59d0d309
SL
749 char *argv[];
750{
9069f68e 751 int i;
59d0d309
SL
752
753 if (connected)
754 printf("Connected to %s.\n", hostname);
755 else
756 printf("Not connected.\n");
9069f68e
GM
757 if (!proxy) {
758 pswitch(1);
759 if (connected) {
760 printf("Connected for proxy commands to %s.\n", hostname);
761 }
762 else {
763 printf("No proxy connection.\n");
764 }
765 pswitch(0);
766 }
59d0d309
SL
767 printf("Mode: %s; Type: %s; Form: %s; Structure: %s\n",
768 modename, typename, formname, structname);
cf8133c7
SL
769 printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s\n",
770 onoff(verbose), onoff(bell), onoff(interactive),
771 onoff(doglob));
9069f68e
GM
772 printf("Store unique: %s; Receive unique: %s\n", onoff(sunique),
773 onoff(runique));
774 printf("Case: %s; CR stripping: %s\n",onoff(mcase),onoff(crflag));
775 if (ntflag) {
776 printf("Ntrans: (in) %s (out) %s\n", ntin,ntout);
777 }
778 else {
779 printf("Ntrans: off\n");
780 }
781 if (mapflag) {
782 printf("Nmap: (in) %s (out) %s\n", mapin, mapout);
783 }
784 else {
785 printf("Nmap: off\n");
786 }
7136ef0a
SL
787 printf("Hash mark printing: %s; Use of PORT cmds: %s\n",
788 onoff(hash), onoff(sendport));
9069f68e
GM
789 if (macnum > 0) {
790 printf("Macros:\n");
791 for (i=0; i<macnum; i++) {
792 printf("\t%s\n",macros[i].mac_name);
793 }
794 }
795 code = 0;
59d0d309
SL
796}
797
798/*
799 * Set beep on cmd completed mode.
800 */
801/*VARARGS*/
26128054
JSP
802void
803setbell(argc, argv)
804 int argc;
805 char *argv[];
59d0d309
SL
806{
807
808 bell = !bell;
809 printf("Bell mode %s.\n", onoff(bell));
9069f68e 810 code = bell;
59d0d309
SL
811}
812
813/*
814 * Turn on packet tracing.
815 */
816/*VARARGS*/
26128054
JSP
817void
818settrace(argc, argv)
819 int argc;
820 char *argv[];
59d0d309
SL
821{
822
823 trace = !trace;
824 printf("Packet tracing %s.\n", onoff(trace));
9069f68e 825 code = trace;
59d0d309
SL
826}
827
5ac6fc46
SL
828/*
829 * Toggle hash mark printing during transfers.
830 */
831/*VARARGS*/
26128054
JSP
832void
833sethash(argc, argv)
834 int argc;
835 char *argv[];
5ac6fc46
SL
836{
837
838 hash = !hash;
839 printf("Hash mark printing %s", onoff(hash));
9069f68e 840 code = hash;
5ac6fc46 841 if (hash)
23d74d65 842 printf(" (%d bytes/hash mark)", 1024);
5ac6fc46
SL
843 printf(".\n");
844}
845
59d0d309
SL
846/*
847 * Turn on printing of server echo's.
848 */
849/*VARARGS*/
26128054
JSP
850void
851setverbose(argc, argv)
852 int argc;
853 char *argv[];
59d0d309
SL
854{
855
856 verbose = !verbose;
857 printf("Verbose mode %s.\n", onoff(verbose));
9069f68e 858 code = verbose;
59d0d309
SL
859}
860
5ac6fc46
SL
861/*
862 * Toggle PORT cmd use before each data connection.
863 */
864/*VARARGS*/
26128054
JSP
865void
866setport(argc, argv)
867 int argc;
868 char *argv[];
5ac6fc46
SL
869{
870
871 sendport = !sendport;
872 printf("Use of PORT cmds %s.\n", onoff(sendport));
9069f68e 873 code = sendport;
5ac6fc46
SL
874}
875
59d0d309
SL
876/*
877 * Turn on interactive prompting
878 * during mget, mput, and mdelete.
879 */
880/*VARARGS*/
26128054
JSP
881void
882setprompt(argc, argv)
883 int argc;
884 char *argv[];
59d0d309
SL
885{
886
887 interactive = !interactive;
888 printf("Interactive mode %s.\n", onoff(interactive));
9069f68e 889 code = interactive;
59d0d309
SL
890}
891
cf8133c7
SL
892/*
893 * Toggle metacharacter interpretation
894 * on local file names.
895 */
896/*VARARGS*/
26128054
JSP
897void
898setglob(argc, argv)
899 int argc;
900 char *argv[];
cf8133c7
SL
901{
902
903 doglob = !doglob;
904 printf("Globbing %s.\n", onoff(doglob));
9069f68e 905 code = doglob;
cf8133c7
SL
906}
907
59d0d309
SL
908/*
909 * Set debugging mode on/off and/or
910 * set level of debugging.
911 */
9072bd8a 912/*VARARGS*/
26128054 913void
59d0d309 914setdebug(argc, argv)
67ff27c7 915 int argc;
59d0d309
SL
916 char *argv[];
917{
918 int val;
919
920 if (argc > 1) {
921 val = atoi(argv[1]);
922 if (val < 0) {
923 printf("%s: bad debugging value.\n", argv[1]);
9069f68e 924 code = -1;
59d0d309
SL
925 return;
926 }
927 } else
928 val = !debug;
929 debug = val;
930 if (debug)
931 options |= SO_DEBUG;
932 else
933 options &= ~SO_DEBUG;
934 printf("Debugging %s (debug=%d).\n", onoff(debug), debug);
9069f68e 935 code = debug > 0;
59d0d309
SL
936}
937
938/*
939 * Set current working directory
940 * on remote machine.
941 */
26128054 942void
59d0d309 943cd(argc, argv)
67ff27c7 944 int argc;
59d0d309
SL
945 char *argv[];
946{
947
67ff27c7
KB
948 if (argc < 2 && !another(&argc, &argv, "remote-directory")) {
949 printf("usage: %s remote-directory\n", argv[0]);
9069f68e 950 code = -1;
59d0d309
SL
951 return;
952 }
23d74d65
MK
953 if (command("CWD %s", argv[1]) == ERROR && code == 500) {
954 if (verbose)
955 printf("CWD command not recognized, trying XCWD\n");
956 (void) command("XCWD %s", argv[1]);
957 }
59d0d309
SL
958}
959
59d0d309
SL
960/*
961 * Set current working directory
962 * on local machine.
963 */
26128054 964void
59d0d309 965lcd(argc, argv)
67ff27c7 966 int argc;
59d0d309
SL
967 char *argv[];
968{
cf8133c7 969 char buf[MAXPATHLEN];
59d0d309 970
cf8133c7
SL
971 if (argc < 2)
972 argc++, argv[1] = home;
59d0d309 973 if (argc != 2) {
67ff27c7 974 printf("usage: %s local-directory\n", argv[0]);
9069f68e 975 code = -1;
59d0d309
SL
976 return;
977 }
9069f68e
GM
978 if (!globulize(&argv[1])) {
979 code = -1;
cf8133c7 980 return;
9069f68e 981 }
cf8133c7 982 if (chdir(argv[1]) < 0) {
26128054 983 warn("local: %s", argv[1]);
9069f68e 984 code = -1;
cf8133c7
SL
985 return;
986 }
f224c779
JSP
987 if (getwd(buf) != NULL)
988 printf("Local directory now %s\n", buf);
989 else
990 warnx("getwd: %s", buf);
9069f68e 991 code = 0;
59d0d309
SL
992}
993
994/*
995 * Delete a single file.
996 */
26128054 997void
59d0d309 998delete(argc, argv)
67ff27c7 999 int argc;
59d0d309
SL
1000 char *argv[];
1001{
1002
67ff27c7
KB
1003 if (argc < 2 && !another(&argc, &argv, "remote-file")) {
1004 printf("usage: %s remote-file\n", argv[0]);
9069f68e 1005 code = -1;
59d0d309
SL
1006 return;
1007 }
1008 (void) command("DELE %s", argv[1]);
1009}
1010
5ac6fc46
SL
1011/*
1012 * Delete multiple files.
1013 */
26128054 1014void
5ac6fc46 1015mdelete(argc, argv)
981fd33c
KB
1016 int argc;
1017 char **argv;
5ac6fc46 1018{
981fd33c
KB
1019 sig_t oldintr;
1020 int ointer;
1021 char *cp;
5ac6fc46 1022
67ff27c7
KB
1023 if (argc < 2 && !another(&argc, &argv, "remote-files")) {
1024 printf("usage: %s remote-files\n", argv[0]);
9069f68e 1025 code = -1;
5ac6fc46
SL
1026 return;
1027 }
9069f68e
GM
1028 mname = argv[0];
1029 mflag = 1;
1030 oldintr = signal(SIGINT, mabort);
1031 (void) setjmp(jabort);
04480325 1032 while ((cp = remglob(argv,0)) != NULL) {
9069f68e
GM
1033 if (*cp == '\0') {
1034 mflag = 0;
1035 continue;
1036 }
1037 if (mflag && confirm(argv[0], cp)) {
5ac6fc46 1038 (void) command("DELE %s", cp);
9069f68e
GM
1039 if (!mflag && fromatty) {
1040 ointer = interactive;
1041 interactive = 1;
1042 if (confirm("Continue with", "mdelete")) {
1043 mflag++;
1044 }
1045 interactive = ointer;
1046 }
1047 }
1048 }
1049 (void) signal(SIGINT, oldintr);
1050 mflag = 0;
5ac6fc46 1051}
9072bd8a 1052
59d0d309
SL
1053/*
1054 * Rename a remote file.
1055 */
26128054 1056void
59d0d309 1057renamefile(argc, argv)
67ff27c7 1058 int argc;
59d0d309
SL
1059 char *argv[];
1060{
1061
67ff27c7
KB
1062 if (argc < 2 && !another(&argc, &argv, "from-name"))
1063 goto usage;
1064 if (argc < 3 && !another(&argc, &argv, "to-name")) {
59d0d309
SL
1065usage:
1066 printf("%s from-name to-name\n", argv[0]);
9069f68e 1067 code = -1;
59d0d309
SL
1068 return;
1069 }
59d0d309
SL
1070 if (command("RNFR %s", argv[1]) == CONTINUE)
1071 (void) command("RNTO %s", argv[2]);
1072}
1073
1074/*
1075 * Get a directory listing
1076 * of remote files.
1077 */
26128054 1078void
59d0d309 1079ls(argc, argv)
67ff27c7 1080 int argc;
59d0d309
SL
1081 char *argv[];
1082{
9072bd8a 1083 char *cmd;
59d0d309
SL
1084
1085 if (argc < 2)
1086 argc++, argv[1] = NULL;
1087 if (argc < 3)
1088 argc++, argv[2] = "-";
9072bd8a
SL
1089 if (argc > 3) {
1090 printf("usage: %s remote-directory local-file\n", argv[0]);
9069f68e 1091 code = -1;
9072bd8a
SL
1092 return;
1093 }
ff00793c 1094 cmd = argv[0][0] == 'n' ? "NLST" : "LIST";
9069f68e
GM
1095 if (strcmp(argv[2], "-") && !globulize(&argv[2])) {
1096 code = -1;
cf8133c7 1097 return;
9069f68e 1098 }
e95608cc
SJ
1099 if (strcmp(argv[2], "-") && *argv[2] != '|')
1100 if (!globulize(&argv[2]) || !confirm("output to local-file:", argv[2])) {
1101 code = -1;
1102 return;
1103 }
460419cd 1104 recvrequest(cmd, argv[2], argv[1], "w", 0);
9072bd8a
SL
1105}
1106
1107/*
1108 * Get a directory listing
1109 * of multiple remote files.
1110 */
26128054 1111void
9072bd8a 1112mls(argc, argv)
981fd33c
KB
1113 int argc;
1114 char **argv;
9072bd8a 1115{
981fd33c
KB
1116 sig_t oldintr;
1117 int ointer, i;
1118 char *cmd, mode[1], *dest;
9072bd8a 1119
67ff27c7
KB
1120 if (argc < 2 && !another(&argc, &argv, "remote-files"))
1121 goto usage;
1122 if (argc < 3 && !another(&argc, &argv, "local-file")) {
1123usage:
1124 printf("usage: %s remote-files local-file\n", argv[0]);
9069f68e 1125 code = -1;
614e24b6
SL
1126 return;
1127 }
1128 dest = argv[argc - 1];
1129 argv[argc - 1] = NULL;
9069f68e 1130 if (strcmp(dest, "-") && *dest != '|')
67ff27c7
KB
1131 if (!globulize(&dest) ||
1132 !confirm("output to local-file:", dest)) {
9069f68e 1133 code = -1;
9072bd8a 1134 return;
9069f68e 1135 }
cdc35b45 1136 cmd = argv[0][1] == 'l' ? "NLST" : "LIST";
9069f68e
GM
1137 mname = argv[0];
1138 mflag = 1;
1139 oldintr = signal(SIGINT, mabort);
1140 (void) setjmp(jabort);
1141 for (i = 1; mflag && i < argc-1; ++i) {
1142 *mode = (i == 1) ? 'w' : 'a';
460419cd 1143 recvrequest(cmd, dest, argv[i], mode, 0);
9069f68e
GM
1144 if (!mflag && fromatty) {
1145 ointer = interactive;
1146 interactive = 1;
1147 if (confirm("Continue with", argv[0])) {
1148 mflag ++;
1149 }
1150 interactive = ointer;
1151 }
1152 }
1153 (void) signal(SIGINT, oldintr);
1154 mflag = 0;
59d0d309
SL
1155}
1156
1157/*
1158 * Do a shell escape
1159 */
04480325 1160/*ARGSUSED*/
26128054 1161void
59d0d309 1162shell(argc, argv)
981fd33c
KB
1163 int argc;
1164 char **argv;
59d0d309 1165{
26128054 1166 pid_t pid;
981fd33c 1167 sig_t old1, old2;
9069f68e 1168 char shellnam[40], *shell, *namep;
04480325 1169 union wait status;
9072bd8a
SL
1170
1171 old1 = signal (SIGINT, SIG_IGN);
1172 old2 = signal (SIGQUIT, SIG_IGN);
1173 if ((pid = fork()) == 0) {
1174 for (pid = 3; pid < 20; pid++)
04480325
GM
1175 (void) close(pid);
1176 (void) signal(SIGINT, SIG_DFL);
1177 (void) signal(SIGQUIT, SIG_DFL);
14433a73
KM
1178 shell = getenv("SHELL");
1179 if (shell == NULL)
f58943be 1180 shell = _PATH_BSHELL;
26128054 1181 namep = strrchr(shell,'/');
14433a73
KM
1182 if (namep == NULL)
1183 namep = shell;
04480325
GM
1184 (void) strcpy(shellnam,"-");
1185 (void) strcat(shellnam, ++namep);
9069f68e
GM
1186 if (strcmp(namep, "sh") != 0)
1187 shellnam[0] = '+';
1188 if (debug) {
1189 printf ("%s\n", shell);
04480325 1190 (void) fflush (stdout);
9069f68e
GM
1191 }
1192 if (argc > 1) {
1193 execl(shell,shellnam,"-c",altarg,(char *)0);
1194 }
1195 else {
1196 execl(shell,shellnam,(char *)0);
9072bd8a 1197 }
26128054 1198 warn("%s", shell);
9069f68e 1199 code = -1;
9072bd8a 1200 exit(1);
26128054 1201 }
9072bd8a 1202 if (pid > 0)
b61c5edc 1203 while (wait((int *)&status) != pid)
9072bd8a 1204 ;
04480325
GM
1205 (void) signal(SIGINT, old1);
1206 (void) signal(SIGQUIT, old2);
9069f68e 1207 if (pid == -1) {
26128054 1208 warn("%s", "Try again later");
9069f68e
GM
1209 code = -1;
1210 }
1211 else {
1212 code = 0;
1213 }
59d0d309
SL
1214}
1215
1216/*
1217 * Send new user information (re-login)
1218 */
26128054 1219void
59d0d309
SL
1220user(argc, argv)
1221 int argc;
1222 char **argv;
1223{
26128054 1224 char acct[80];
9069f68e 1225 int n, aflag = 0;
59d0d309 1226
67ff27c7
KB
1227 if (argc < 2)
1228 (void) another(&argc, &argv, "username");
1229 if (argc < 2 || argc > 4) {
59d0d309 1230 printf("usage: %s username [password] [account]\n", argv[0]);
9069f68e 1231 code = -1;
26128054 1232 return;
59d0d309
SL
1233 }
1234 n = command("USER %s", argv[1]);
1235 if (n == CONTINUE) {
1236 if (argc < 3 )
aeac6782 1237 argv[2] = getpass("Password: "), argc++;
59d0d309
SL
1238 n = command("PASS %s", argv[2]);
1239 }
1240 if (n == CONTINUE) {
1241 if (argc < 4) {
1242 printf("Account: "); (void) fflush(stdout);
1243 (void) fgets(acct, sizeof(acct) - 1, stdin);
1244 acct[strlen(acct) - 1] = '\0';
1245 argv[3] = acct; argc++;
1246 }
9069f68e
GM
1247 n = command("ACCT %s", argv[3]);
1248 aflag++;
59d0d309
SL
1249 }
1250 if (n != COMPLETE) {
04480325 1251 fprintf(stdout, "Login failed.\n");
26128054 1252 return;
59d0d309 1253 }
9069f68e
GM
1254 if (!aflag && argc == 4) {
1255 (void) command("ACCT %s", argv[3]);
1256 }
59d0d309
SL
1257}
1258
1259/*
1260 * Print working directory.
1261 */
1262/*VARARGS*/
26128054
JSP
1263void
1264pwd(argc, argv)
1265 int argc;
1266 char *argv[];
59d0d309 1267{
23d74d65 1268 int oldverbose = verbose;
9072bd8a 1269
23d74d65
MK
1270 /*
1271 * If we aren't verbose, this doesn't do anything!
1272 */
1273 verbose = 1;
1274 if (command("PWD") == ERROR && code == 500) {
1275 printf("PWD command not recognized, trying XPWD\n");
1276 (void) command("XPWD");
1277 }
1278 verbose = oldverbose;
59d0d309
SL
1279}
1280
1281/*
1282 * Make a directory.
1283 */
26128054 1284void
59d0d309 1285makedir(argc, argv)
67ff27c7 1286 int argc;
59d0d309
SL
1287 char *argv[];
1288{
1289
67ff27c7 1290 if (argc < 2 && !another(&argc, &argv, "directory-name")) {
9069f68e
GM
1291 printf("usage: %s directory-name\n", argv[0]);
1292 code = -1;
59d0d309
SL
1293 return;
1294 }
23d74d65
MK
1295 if (command("MKD %s", argv[1]) == ERROR && code == 500) {
1296 if (verbose)
1297 printf("MKD command not recognized, trying XMKD\n");
1298 (void) command("XMKD %s", argv[1]);
1299 }
59d0d309
SL
1300}
1301
1302/*
1303 * Remove a directory.
1304 */
26128054 1305void
59d0d309 1306removedir(argc, argv)
67ff27c7 1307 int argc;
59d0d309
SL
1308 char *argv[];
1309{
1310
67ff27c7 1311 if (argc < 2 && !another(&argc, &argv, "directory-name")) {
9069f68e
GM
1312 printf("usage: %s directory-name\n", argv[0]);
1313 code = -1;
59d0d309
SL
1314 return;
1315 }
23d74d65
MK
1316 if (command("RMD %s", argv[1]) == ERROR && code == 500) {
1317 if (verbose)
1318 printf("RMD command not recognized, trying XRMD\n");
1319 (void) command("XRMD %s", argv[1]);
1320 }
59d0d309
SL
1321}
1322
1323/*
1324 * Send a line, verbatim, to the remote machine.
1325 */
26128054 1326void
59d0d309 1327quote(argc, argv)
67ff27c7 1328 int argc;
59d0d309
SL
1329 char *argv[];
1330{
59d0d309 1331
67ff27c7 1332 if (argc < 2 && !another(&argc, &argv, "command line to send")) {
59d0d309 1333 printf("usage: %s line-to-send\n", argv[0]);
9069f68e 1334 code = -1;
59d0d309
SL
1335 return;
1336 }
67ff27c7 1337 quote1("", argc, argv);
59d0d309
SL
1338}
1339
23d74d65
MK
1340/*
1341 * Send a SITE command to the remote machine. The line
67ff27c7
KB
1342 * is sent verbatim to the remote machine, except that the
1343 * word "SITE" is added at the front.
23d74d65 1344 */
26128054 1345void
23d74d65 1346site(argc, argv)
67ff27c7 1347 int argc;
23d74d65
MK
1348 char *argv[];
1349{
23d74d65 1350
67ff27c7 1351 if (argc < 2 && !another(&argc, &argv, "arguments to SITE command")) {
23d74d65
MK
1352 printf("usage: %s line-to-send\n", argv[0]);
1353 code = -1;
1354 return;
1355 }
67ff27c7
KB
1356 quote1("SITE ", argc, argv);
1357}
1358
1359/*
1360 * Turn argv[1..argc) into a space-separated string, then prepend initial text.
1361 * Send the result as a one-line command and get response.
1362 */
26128054 1363void
67ff27c7
KB
1364quote1(initial, argc, argv)
1365 char *initial;
1366 int argc;
1367 char **argv;
1368{
26128054 1369 int i, len;
67ff27c7
KB
1370 char buf[BUFSIZ]; /* must be >= sizeof(line) */
1371
1372 (void) strcpy(buf, initial);
1373 if (argc > 1) {
1374 len = strlen(buf);
1375 len += strlen(strcpy(&buf[len], argv[1]));
1376 for (i = 2; i < argc; i++) {
1377 buf[len++] = ' ';
1378 len += strlen(strcpy(&buf[len], argv[i]));
1379 }
23d74d65
MK
1380 }
1381 if (command(buf) == PRELIM) {
26128054
JSP
1382 while (getreply(0) == PRELIM)
1383 continue;
23d74d65
MK
1384 }
1385}
1386
26128054 1387void
23d74d65 1388do_chmod(argc, argv)
67ff27c7 1389 int argc;
23d74d65
MK
1390 char *argv[];
1391{
67ff27c7
KB
1392
1393 if (argc < 2 && !another(&argc, &argv, "mode"))
1394 goto usage;
1395 if (argc < 3 && !another(&argc, &argv, "file-name")) {
1396usage:
23d74d65
MK
1397 printf("usage: %s mode file-name\n", argv[0]);
1398 code = -1;
1399 return;
1400 }
67ff27c7 1401 (void) command("SITE CHMOD %s %s", argv[1], argv[2]);
23d74d65
MK
1402}
1403
26128054 1404void
23d74d65 1405do_umask(argc, argv)
67ff27c7 1406 int argc;
23d74d65
MK
1407 char *argv[];
1408{
1409 int oldverbose = verbose;
1410
1411 verbose = 1;
1412 (void) command(argc == 1 ? "SITE UMASK" : "SITE UMASK %s", argv[1]);
1413 verbose = oldverbose;
1414}
1415
26128054 1416void
23d74d65 1417idle(argc, argv)
67ff27c7 1418 int argc;
23d74d65
MK
1419 char *argv[];
1420{
1421 int oldverbose = verbose;
1422
1423 verbose = 1;
1424 (void) command(argc == 1 ? "SITE IDLE" : "SITE IDLE %s", argv[1]);
1425 verbose = oldverbose;
1426}
1427
59d0d309
SL
1428/*
1429 * Ask the other side for help.
1430 */
26128054 1431void
59d0d309 1432rmthelp(argc, argv)
67ff27c7 1433 int argc;
59d0d309
SL
1434 char *argv[];
1435{
1436 int oldverbose = verbose;
1437
1438 verbose = 1;
1439 (void) command(argc == 1 ? "HELP" : "HELP %s", argv[1]);
1440 verbose = oldverbose;
1441}
1442
1443/*
1444 * Terminate session and exit.
1445 */
1446/*VARARGS*/
26128054
JSP
1447void
1448quit(argc, argv)
1449 int argc;
1450 char *argv[];
59d0d309
SL
1451{
1452
71a655cd 1453 if (connected)
26128054 1454 disconnect(0, 0);
9069f68e
GM
1455 pswitch(1);
1456 if (connected) {
26128054 1457 disconnect(0, 0);
9069f68e 1458 }
59d0d309
SL
1459 exit(0);
1460}
1461
1462/*
1463 * Terminate session, but don't exit.
1464 */
26128054
JSP
1465void
1466disconnect(argc, argv)
1467 int argc;
1468 char *argv[];
59d0d309 1469{
59d0d309
SL
1470
1471 if (!connected)
1472 return;
1473 (void) command("QUIT");
9069f68e
GM
1474 if (cout) {
1475 (void) fclose(cout);
1476 }
59d0d309
SL
1477 cout = NULL;
1478 connected = 0;
1479 data = -1;
9069f68e
GM
1480 if (!proxy) {
1481 macnum = 0;
1482 }
59d0d309 1483}
cf8133c7 1484
26128054 1485int
5ac6fc46 1486confirm(cmd, file)
cf8133c7
SL
1487 char *cmd, *file;
1488{
1489 char line[BUFSIZ];
1490
1491 if (!interactive)
5ac6fc46 1492 return (1);
cf8133c7 1493 printf("%s %s? ", cmd, file);
04480325 1494 (void) fflush(stdout);
67ff27c7
KB
1495 if (fgets(line, sizeof line, stdin) == NULL)
1496 return (0);
5ac6fc46 1497 return (*line != 'n' && *line != 'N');
cf8133c7
SL
1498}
1499
26128054 1500void
cf8133c7
SL
1501fatal(msg)
1502 char *msg;
1503{
1504
26128054 1505 errx(1, "%s", msg);
cf8133c7
SL
1506}
1507
1508/*
1509 * Glob a local file name specification with
1510 * the expectation of a single return value.
1511 * Can't control multiple values being expanded
1512 * from the expression, we return only the first.
1513 */
26128054 1514int
cf8133c7
SL
1515globulize(cpp)
1516 char **cpp;
1517{
f224c779 1518 glob_t gl;
c1a675d4 1519 int flags;
cf8133c7
SL
1520
1521 if (!doglob)
1522 return (1);
f224c779 1523
c1a675d4 1524 flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE;
f224c779 1525 memset(&gl, 0, sizeof(gl));
c1a675d4 1526 if (glob(*cpp, flags, NULL, &gl) ||
f224c779
JSP
1527 gl.gl_pathc == 0) {
1528 warnx("%s: not found", *cpp);
1529 globfree(&gl);
cf8133c7
SL
1530 return (0);
1531 }
f224c779
JSP
1532 *cpp = strdup(gl.gl_pathv[0]); /* XXX - wasted memory */
1533 globfree(&gl);
cf8133c7
SL
1534 return (1);
1535}
9069f68e 1536
26128054 1537void
9069f68e 1538account(argc,argv)
9069f68e
GM
1539 int argc;
1540 char **argv;
1541{
f224c779 1542 char acct[50], *ap;
9069f68e
GM
1543
1544 if (argc > 1) {
1545 ++argv;
1546 --argc;
1547 (void) strncpy(acct,*argv,49);
0c7d4ecf 1548 acct[49] = '\0';
9069f68e
GM
1549 while (argc > 1) {
1550 --argc;
1551 ++argv;
1552 (void) strncat(acct,*argv, 49-strlen(acct));
1553 }
1554 ap = acct;
1555 }
1556 else {
aeac6782 1557 ap = getpass("Account:");
9069f68e
GM
1558 }
1559 (void) command("ACCT %s", ap);
1560}
1561
1562jmp_buf abortprox;
1563
981fd33c 1564void
9069f68e
GM
1565proxabort()
1566{
9069f68e
GM
1567
1568 if (!proxy) {
1569 pswitch(1);
1570 }
1571 if (connected) {
1572 proxflag = 1;
1573 }
1574 else {
1575 proxflag = 0;
1576 }
1577 pswitch(0);
1578 longjmp(abortprox,1);
1579}
1580
26128054
JSP
1581void
1582doproxy(argc, argv)
9069f68e
GM
1583 int argc;
1584 char *argv[];
1585{
26128054 1586 struct cmd *c;
981fd33c 1587 sig_t oldintr;
9069f68e 1588
67ff27c7
KB
1589 if (argc < 2 && !another(&argc, &argv, "command")) {
1590 printf("usage: %s command\n", argv[0]);
9069f68e
GM
1591 code = -1;
1592 return;
1593 }
1594 c = getcmd(argv[1]);
1595 if (c == (struct cmd *) -1) {
1596 printf("?Ambiguous command\n");
04480325 1597 (void) fflush(stdout);
9069f68e
GM
1598 code = -1;
1599 return;
1600 }
1601 if (c == 0) {
1602 printf("?Invalid command\n");
04480325 1603 (void) fflush(stdout);
9069f68e
GM
1604 code = -1;
1605 return;
1606 }
1607 if (!c->c_proxy) {
1608 printf("?Invalid proxy command\n");
04480325 1609 (void) fflush(stdout);
9069f68e
GM
1610 code = -1;
1611 return;
1612 }
1613 if (setjmp(abortprox)) {
1614 code = -1;
1615 return;
1616 }
1617 oldintr = signal(SIGINT, proxabort);
1618 pswitch(1);
1619 if (c->c_conn && !connected) {
1620 printf("Not connected\n");
04480325 1621 (void) fflush(stdout);
9069f68e
GM
1622 pswitch(0);
1623 (void) signal(SIGINT, oldintr);
1624 code = -1;
1625 return;
1626 }
1627 (*c->c_handler)(argc-1, argv+1);
1628 if (connected) {
1629 proxflag = 1;
1630 }
1631 else {
1632 proxflag = 0;
1633 }
1634 pswitch(0);
1635 (void) signal(SIGINT, oldintr);
1636}
1637
26128054
JSP
1638void
1639setcase(argc, argv)
1640 int argc;
1641 char *argv[];
9069f68e 1642{
26128054 1643
9069f68e
GM
1644 mcase = !mcase;
1645 printf("Case mapping %s.\n", onoff(mcase));
1646 code = mcase;
1647}
1648
26128054
JSP
1649void
1650setcr(argc, argv)
1651 int argc;
1652 char *argv[];
9069f68e 1653{
26128054 1654
9069f68e
GM
1655 crflag = !crflag;
1656 printf("Carriage Return stripping %s.\n", onoff(crflag));
1657 code = crflag;
1658}
1659
26128054 1660void
9069f68e
GM
1661setntrans(argc,argv)
1662 int argc;
1663 char *argv[];
1664{
1665 if (argc == 1) {
1666 ntflag = 0;
1667 printf("Ntrans off.\n");
1668 code = ntflag;
1669 return;
1670 }
1671 ntflag++;
1672 code = ntflag;
1673 (void) strncpy(ntin, argv[1], 16);
1674 ntin[16] = '\0';
1675 if (argc == 2) {
1676 ntout[0] = '\0';
1677 return;
1678 }
1679 (void) strncpy(ntout, argv[2], 16);
1680 ntout[16] = '\0';
1681}
1682
1683char *
1684dotrans(name)
1685 char *name;
1686{
1687 static char new[MAXPATHLEN];
1688 char *cp1, *cp2 = new;
26128054 1689 int i, ostop, found;
9069f68e 1690
26128054
JSP
1691 for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++)
1692 continue;
9069f68e
GM
1693 for (cp1 = name; *cp1; cp1++) {
1694 found = 0;
1695 for (i = 0; *(ntin + i) && i < 16; i++) {
1696 if (*cp1 == *(ntin + i)) {
1697 found++;
1698 if (i < ostop) {
1699 *cp2++ = *(ntout + i);
1700 }
1701 break;
1702 }
1703 }
1704 if (!found) {
1705 *cp2++ = *cp1;
1706 }
1707 }
1708 *cp2 = '\0';
26128054 1709 return (new);
9069f68e
GM
1710}
1711
26128054 1712void
9069f68e
GM
1713setnmap(argc, argv)
1714 int argc;
1715 char *argv[];
1716{
1717 char *cp;
1718
1719 if (argc == 1) {
1720 mapflag = 0;
1721 printf("Nmap off.\n");
1722 code = mapflag;
1723 return;
1724 }
67ff27c7 1725 if (argc < 3 && !another(&argc, &argv, "mapout")) {
9069f68e
GM
1726 printf("Usage: %s [mapin mapout]\n",argv[0]);
1727 code = -1;
1728 return;
1729 }
1730 mapflag = 1;
1731 code = 1;
26128054 1732 cp = strchr(altarg, ' ');
9069f68e 1733 if (proxy) {
26128054
JSP
1734 while(*++cp == ' ')
1735 continue;
9069f68e 1736 altarg = cp;
26128054 1737 cp = strchr(altarg, ' ');
9069f68e
GM
1738 }
1739 *cp = '\0';
1740 (void) strncpy(mapin, altarg, MAXPATHLEN - 1);
26128054
JSP
1741 while (*++cp == ' ')
1742 continue;
9069f68e
GM
1743 (void) strncpy(mapout, cp, MAXPATHLEN - 1);
1744}
1745
1746char *
1747domap(name)
1748 char *name;
1749{
1750 static char new[MAXPATHLEN];
26128054 1751 char *cp1 = name, *cp2 = mapin;
9069f68e 1752 char *tp[9], *te[9];
7c1d95cd 1753 int i, toks[9], toknum = 0, match = 1;
9069f68e
GM
1754
1755 for (i=0; i < 9; ++i) {
1756 toks[i] = 0;
1757 }
1758 while (match && *cp1 && *cp2) {
1759 switch (*cp2) {
1760 case '\\':
1761 if (*++cp2 != *cp1) {
1762 match = 0;
1763 }
1764 break;
1765 case '$':
1766 if (*(cp2+1) >= '1' && (*cp2+1) <= '9') {
1767 if (*cp1 != *(++cp2+1)) {
1768 toks[toknum = *cp2 - '1']++;
1769 tp[toknum] = cp1;
1770 while (*++cp1 && *(cp2+1)
1771 != *cp1);
1772 te[toknum] = cp1;
1773 }
1774 cp2++;
1775 break;
1776 }
ff00793c 1777 /* FALLTHROUGH */
9069f68e
GM
1778 default:
1779 if (*cp2 != *cp1) {
1780 match = 0;
1781 }
1782 break;
1783 }
7c1d95cd 1784 if (match && *cp1) {
9069f68e
GM
1785 cp1++;
1786 }
7c1d95cd 1787 if (match && *cp2) {
9069f68e
GM
1788 cp2++;
1789 }
1790 }
7c1d95cd
SJ
1791 if (!match && *cp1) /* last token mismatch */
1792 {
1793 toks[toknum] = 0;
1794 }
9069f68e
GM
1795 cp1 = new;
1796 *cp1 = '\0';
1797 cp2 = mapout;
1798 while (*cp2) {
1799 match = 0;
1800 switch (*cp2) {
1801 case '\\':
1802 if (*(cp2 + 1)) {
1803 *cp1++ = *++cp2;
1804 }
1805 break;
1806 case '[':
1807LOOP:
1808 if (*++cp2 == '$' && isdigit(*(cp2+1))) {
1809 if (*++cp2 == '0') {
1810 char *cp3 = name;
1811
1812 while (*cp3) {
1813 *cp1++ = *cp3++;
1814 }
1815 match = 1;
1816 }
1817 else if (toks[toknum = *cp2 - '1']) {
1818 char *cp3 = tp[toknum];
1819
1820 while (cp3 != te[toknum]) {
1821 *cp1++ = *cp3++;
1822 }
1823 match = 1;
1824 }
1825 }
1826 else {
1827 while (*cp2 && *cp2 != ',' &&
1828 *cp2 != ']') {
1829 if (*cp2 == '\\') {
1830 cp2++;
1831 }
1832 else if (*cp2 == '$' &&
1833 isdigit(*(cp2+1))) {
1834 if (*++cp2 == '0') {
1835 char *cp3 = name;
1836
1837 while (*cp3) {
1838 *cp1++ = *cp3++;
1839 }
1840 }
1841 else if (toks[toknum =
1842 *cp2 - '1']) {
1843 char *cp3=tp[toknum];
1844
1845 while (cp3 !=
1846 te[toknum]) {
1847 *cp1++ = *cp3++;
1848 }
1849 }
1850 }
1851 else if (*cp2) {
1852 *cp1++ = *cp2++;
1853 }
1854 }
1855 if (!*cp2) {
1856 printf("nmap: unbalanced brackets\n");
26128054 1857 return (name);
9069f68e
GM
1858 }
1859 match = 1;
1860 cp2--;
1861 }
1862 if (match) {
1863 while (*++cp2 && *cp2 != ']') {
1864 if (*cp2 == '\\' && *(cp2 + 1)) {
1865 cp2++;
1866 }
1867 }
1868 if (!*cp2) {
1869 printf("nmap: unbalanced brackets\n");
26128054 1870 return (name);
9069f68e
GM
1871 }
1872 break;
1873 }
1874 switch (*++cp2) {
1875 case ',':
1876 goto LOOP;
1877 case ']':
1878 break;
1879 default:
1880 cp2--;
1881 goto LOOP;
1882 }
1883 break;
1884 case '$':
1885 if (isdigit(*(cp2 + 1))) {
1886 if (*++cp2 == '0') {
1887 char *cp3 = name;
1888
1889 while (*cp3) {
1890 *cp1++ = *cp3++;
1891 }
1892 }
1893 else if (toks[toknum = *cp2 - '1']) {
1894 char *cp3 = tp[toknum];
1895
1896 while (cp3 != te[toknum]) {
1897 *cp1++ = *cp3++;
1898 }
1899 }
1900 break;
1901 }
1902 /* intentional drop through */
1903 default:
1904 *cp1++ = *cp2;
1905 break;
1906 }
1907 cp2++;
1908 }
1909 *cp1 = '\0';
1910 if (!*new) {
26128054 1911 return (name);
9069f68e 1912 }
26128054 1913 return (new);
9069f68e
GM
1914}
1915
26128054
JSP
1916void
1917setsunique(argc, argv)
1918 int argc;
1919 char *argv[];
9069f68e 1920{
26128054 1921
9069f68e
GM
1922 sunique = !sunique;
1923 printf("Store unique %s.\n", onoff(sunique));
1924 code = sunique;
1925}
1926
26128054
JSP
1927void
1928setrunique(argc, argv)
1929 int argc;
1930 char *argv[];
9069f68e 1931{
26128054 1932
9069f68e
GM
1933 runique = !runique;
1934 printf("Receive unique %s.\n", onoff(runique));
1935 code = runique;
1936}
1937
1938/* change directory to perent directory */
26128054
JSP
1939void
1940cdup(argc, argv)
1941 int argc;
1942 char *argv[];
9069f68e 1943{
26128054 1944
23d74d65
MK
1945 if (command("CDUP") == ERROR && code == 500) {
1946 if (verbose)
1947 printf("CDUP command not recognized, trying XCUP\n");
1948 (void) command("XCUP");
1949 }
9069f68e
GM
1950}
1951
ff00793c
MK
1952
1953/* show remote system type */
26128054
JSP
1954void
1955syst(argc, argv)
1956 int argc;
1957 char *argv[];
ff00793c 1958{
26128054 1959
ff00793c
MK
1960 (void) command("SYST");
1961}
1962
26128054 1963void
9069f68e
GM
1964macdef(argc, argv)
1965 int argc;
1966 char *argv[];
1967{
1968 char *tmp;
1969 int c;
1970
1971 if (macnum == 16) {
1972 printf("Limit of 16 macros have already been defined\n");
1973 code = -1;
1974 return;
1975 }
67ff27c7 1976 if (argc < 2 && !another(&argc, &argv, "macro name")) {
9069f68e
GM
1977 printf("Usage: %s macro_name\n",argv[0]);
1978 code = -1;
1979 return;
1980 }
1981 if (interactive) {
1982 printf("Enter macro line by line, terminating it with a null line\n");
1983 }
04480325 1984 (void) strncpy(macros[macnum].mac_name, argv[1], 8);
9069f68e
GM
1985 if (macnum == 0) {
1986 macros[macnum].mac_start = macbuf;
1987 }
1988 else {
1989 macros[macnum].mac_start = macros[macnum - 1].mac_end + 1;
1990 }
1991 tmp = macros[macnum].mac_start;
1992 while (tmp != macbuf+4096) {
1993 if ((c = getchar()) == EOF) {
1994 printf("macdef:end of file encountered\n");
1995 code = -1;
1996 return;
1997 }
1998 if ((*tmp = c) == '\n') {
1999 if (tmp == macros[macnum].mac_start) {
2000 macros[macnum++].mac_end = tmp;
2001 code = 0;
2002 return;
2003 }
2004 if (*(tmp-1) == '\0') {
2005 macros[macnum++].mac_end = tmp - 1;
2006 code = 0;
2007 return;
2008 }
2009 *tmp = '\0';
2010 }
2011 tmp++;
2012 }
2013 while (1) {
ff00793c
MK
2014 while ((c = getchar()) != '\n' && c != EOF)
2015 /* LOOP */;
9069f68e
GM
2016 if (c == EOF || getchar() == '\n') {
2017 printf("Macro not defined - 4k buffer exceeded\n");
2018 code = -1;
2019 return;
2020 }
2021 }
2022}
ff00793c
MK
2023
2024/*
2025 * get size of file on remote machine
2026 */
26128054 2027void
ff00793c 2028sizecmd(argc, argv)
67ff27c7 2029 int argc;
ff00793c
MK
2030 char *argv[];
2031{
2032
67ff27c7
KB
2033 if (argc < 2 && !another(&argc, &argv, "filename")) {
2034 printf("usage: %s filename\n", argv[0]);
ff00793c
MK
2035 code = -1;
2036 return;
2037 }
2038 (void) command("SIZE %s", argv[1]);
2039}
2040
2041/*
2042 * get last modification time of file on remote machine
2043 */
26128054 2044void
ff00793c 2045modtime(argc, argv)
67ff27c7 2046 int argc;
ff00793c
MK
2047 char *argv[];
2048{
2049 int overbose;
2050
67ff27c7
KB
2051 if (argc < 2 && !another(&argc, &argv, "filename")) {
2052 printf("usage: %s filename\n", argv[0]);
ff00793c
MK
2053 code = -1;
2054 return;
2055 }
cdc35b45
MK
2056 overbose = verbose;
2057 if (debug == 0)
2058 verbose = -1;
ff00793c
MK
2059 if (command("MDTM %s", argv[1]) == COMPLETE) {
2060 int yy, mo, day, hour, min, sec;
2061 sscanf(reply_string, "%*s %04d%02d%02d%02d%02d%02d", &yy, &mo,
2062 &day, &hour, &min, &sec);
2063 /* might want to print this in local time */
2064 printf("%s\t%02d/%02d/%04d %02d:%02d:%02d GMT\n", argv[1],
2065 mo, day, yy, hour, min, sec);
2066 } else
11c9b6d7 2067 printf("%s\n", reply_string);
ff00793c
MK
2068 verbose = overbose;
2069}
2070
2071/*
63c685da 2072 * show status on remote machine
ff00793c 2073 */
26128054 2074void
ff00793c 2075rmtstatus(argc, argv)
67ff27c7 2076 int argc;
ff00793c
MK
2077 char *argv[];
2078{
26128054 2079
ff00793c
MK
2080 (void) command(argc > 1 ? "STAT %s" : "STAT" , argv[1]);
2081}