use glob in libc instead of local version
[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
7c871e89 9static char sccsid[] = "@(#)cmds.c 8.4 (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>
24#include <netdb.h>
59d0d309
SL
25#include <signal.h>
26#include <stdio.h>
26128054
JSP
27#include <stdlib.h>
28#include <string.h>
ff00793c 29#include <time.h>
26128054 30#include <unistd.h>
cdc35b45
MK
31
32#include "ftp_var.h"
f58943be 33#include "pathnames.h"
59d0d309 34
26128054
JSP
35jmp_buf jabort;
36char *mname;
59d0d309 37
67ff27c7
KB
38/*
39 * `Another' gets another argument, and stores the new argc and argv.
40 * It reverts to the top level (via main.c's intr()) on EOF/error.
41 *
42 * Returns false if no new arguments have been added.
43 */
26128054 44int
67ff27c7
KB
45another(pargc, pargv, prompt)
46 int *pargc;
47 char ***pargv;
48 char *prompt;
49{
50 int len = strlen(line), ret;
67ff27c7
KB
51
52 if (len >= sizeof(line) - 3) {
53 printf("sorry, arguments too long\n");
54 intr();
55 }
56 printf("(%s) ", prompt);
57 line[len++] = ' ';
58 if (fgets(&line[len], sizeof(line) - len, stdin) == NULL)
59 intr();
60 len += strlen(&line[len]);
61 if (len > 0 && line[len - 1] == '\n')
62 line[len - 1] = '\0';
63 makeargv();
64 ret = margc > *pargc;
65 *pargc = margc;
66 *pargv = margv;
67 return (ret);
68}
69
59d0d309
SL
70/*
71 * Connect to peer server and
72 * auto-login, if possible.
73 */
26128054 74void
59d0d309
SL
75setpeer(argc, argv)
76 int argc;
77 char *argv[];
78{
26128054 79 char *host;
11c9b6d7 80 short port;
59d0d309
SL
81
82 if (connected) {
9069f68e 83 printf("Already connected to %s, use close first.\n",
59d0d309 84 hostname);
9069f68e 85 code = -1;
59d0d309
SL
86 return;
87 }
67ff27c7
KB
88 if (argc < 2)
89 (void) another(&argc, &argv, "to");
90 if (argc < 2 || argc > 3) {
59d0d309 91 printf("usage: %s host-name [port]\n", argv[0]);
9069f68e 92 code = -1;
59d0d309
SL
93 return;
94 }
95 port = sp->s_port;
96 if (argc > 2) {
d33c618b 97 port = atoi(argv[2]);
59d0d309 98 if (port <= 0) {
d33c618b
SL
99 printf("%s: bad port number-- %s\n", argv[1], argv[2]);
100 printf ("usage: %s host-name [port]\n", argv[0]);
9069f68e 101 code = -1;
59d0d309
SL
102 return;
103 }
104 port = htons(port);
105 }
106 host = hookup(argv[1], port);
107 if (host) {
c69896ac 108 int overbose;
cdc35b45 109
c69896ac 110 connected = 1;
dcd54a7f
MK
111 /*
112 * Set up defaults for FTP.
113 */
114 (void) strcpy(typename, "ascii"), type = TYPE_A;
115 curtype = TYPE_A;
116 (void) strcpy(formname, "non-print"), form = FORM_N;
117 (void) strcpy(modename, "stream"), mode = MODE_S;
118 (void) strcpy(structname, "file"), stru = STRU_F;
119 (void) strcpy(bytename, "8"), bytesize = 8;
c69896ac 120 if (autologin)
04480325 121 (void) login(argv[1]);
c69896ac 122
ff00793c
MK
123#if defined(unix) && NBBY == 8
124/*
125 * this ifdef is to keep someone form "porting" this to an incompatible
126 * system and not checking this out. This way they have to think about it.
127 */
c69896ac
MK
128 overbose = verbose;
129 if (debug == 0)
130 verbose = -1;
131 if (command("SYST") == COMPLETE && overbose) {
26128054
JSP
132 char *cp, c;
133 cp = strchr(reply_string+4, ' ');
c69896ac 134 if (cp == NULL)
26128054 135 cp = strchr(reply_string+4, '\r');
c69896ac
MK
136 if (cp) {
137 if (cp[-1] == '.')
138 cp--;
139 c = *cp;
140 *cp = '\0';
ff00793c 141 }
c69896ac
MK
142
143 printf("Remote system type is %s.\n",
144 reply_string+4);
145 if (cp)
146 *cp = c;
147 }
148 if (!strncmp(reply_string, "215 UNIX Type: L8", 17)) {
dcd54a7f
MK
149 if (proxy)
150 unix_proxy = 1;
151 else
152 unix_server = 1;
153 /*
154 * Set type to 0 (not specified by user),
155 * meaning binary by default, but don't bother
156 * telling server. We can use binary
157 * for text files unless changed by the user.
158 */
159 type = 0;
160 (void) strcpy(typename, "binary");
c69896ac
MK
161 if (overbose)
162 printf("Using %s mode to transfer files.\n",
163 typename);
dcd54a7f
MK
164 } else {
165 if (proxy)
166 unix_proxy = 0;
167 else
168 unix_server = 0;
169 if (overbose &&
170 !strncmp(reply_string, "215 TOPS20", 10))
171 printf(
cdc35b45 172"Remember to set tenex mode when transfering binary files from this machine.\n");
ff00793c 173 }
c69896ac
MK
174 verbose = overbose;
175#endif /* unix */
59d0d309
SL
176 }
177}
178
179struct types {
180 char *t_name;
181 char *t_mode;
182 int t_type;
d33c618b 183 char *t_arg;
59d0d309 184} types[] = {
d33c618b
SL
185 { "ascii", "A", TYPE_A, 0 },
186 { "binary", "I", TYPE_I, 0 },
187 { "image", "I", TYPE_I, 0 },
188 { "ebcdic", "E", TYPE_E, 0 },
189 { "tenex", "L", TYPE_L, bytename },
26128054 190 { NULL }
59d0d309
SL
191};
192
193/*
194 * Set transfer type.
195 */
26128054 196void
59d0d309 197settype(argc, argv)
67ff27c7 198 int argc;
59d0d309
SL
199 char *argv[];
200{
26128054 201 struct types *p;
d33c618b 202 int comret;
59d0d309
SL
203
204 if (argc > 2) {
205 char *sep;
206
207 printf("usage: %s [", argv[0]);
208 sep = " ";
209 for (p = types; p->t_name; p++) {
210 printf("%s%s", sep, p->t_name);
dcd54a7f 211 sep = " | ";
59d0d309
SL
212 }
213 printf(" ]\n");
9069f68e 214 code = -1;
59d0d309
SL
215 return;
216 }
217 if (argc < 2) {
218 printf("Using %s mode to transfer files.\n", typename);
9069f68e 219 code = 0;
59d0d309
SL
220 return;
221 }
222 for (p = types; p->t_name; p++)
223 if (strcmp(argv[1], p->t_name) == 0)
224 break;
225 if (p->t_name == 0) {
226 printf("%s: unknown mode\n", argv[1]);
9069f68e 227 code = -1;
59d0d309
SL
228 return;
229 }
d33c618b
SL
230 if ((p->t_arg != NULL) && (*(p->t_arg) != '\0'))
231 comret = command ("TYPE %s %s", p->t_mode, p->t_arg);
232 else
233 comret = command("TYPE %s", p->t_mode);
234 if (comret == COMPLETE) {
04480325 235 (void) strcpy(typename, p->t_name);
dcd54a7f 236 curtype = type = p->t_type;
59d0d309
SL
237 }
238}
239
dcd54a7f
MK
240/*
241 * Internal form of settype; changes current type in use with server
242 * without changing our notion of the type for data transfers.
243 * Used to change to and from ascii for listings.
244 */
26128054 245void
dcd54a7f
MK
246changetype(newtype, show)
247 int newtype, show;
248{
26128054 249 struct types *p;
dcd54a7f
MK
250 int comret, oldverbose = verbose;
251
252 if (newtype == 0)
253 newtype = TYPE_I;
254 if (newtype == curtype)
255 return;
256 if (debug == 0 && show == 0)
257 verbose = 0;
258 for (p = types; p->t_name; p++)
259 if (newtype == p->t_type)
260 break;
261 if (p->t_name == 0) {
262 printf("ftp: internal error: unknown type %d\n", newtype);
263 return;
264 }
265 if (newtype == TYPE_L && bytename[0] != '\0')
266 comret = command("TYPE %s %s", p->t_mode, bytename);
267 else
268 comret = command("TYPE %s", p->t_mode);
269 if (comret == COMPLETE)
270 curtype = newtype;
271 verbose = oldverbose;
272}
273
11c9b6d7
RA
274char *stype[] = {
275 "type",
276 "",
277 0
278};
279
59d0d309
SL
280/*
281 * Set binary transfer type.
282 */
283/*VARARGS*/
26128054
JSP
284void
285setbinary(argc, argv)
286 int argc;
287 char **argv;
59d0d309 288{
26128054 289
11c9b6d7
RA
290 stype[1] = "binary";
291 settype(2, stype);
59d0d309
SL
292}
293
294/*
295 * Set ascii transfer type.
296 */
297/*VARARGS*/
26128054
JSP
298void
299setascii(argc, argv)
300 int argc;
301 char *argv[];
59d0d309 302{
26128054 303
11c9b6d7
RA
304 stype[1] = "ascii";
305 settype(2, stype);
59d0d309
SL
306}
307
308/*
309 * Set tenex transfer type.
310 */
311/*VARARGS*/
26128054
JSP
312void
313settenex(argc, argv)
314 int argc;
315 char *argv[];
59d0d309 316{
26128054 317
11c9b6d7
RA
318 stype[1] = "tenex";
319 settype(2, stype);
59d0d309
SL
320}
321
59d0d309
SL
322/*
323 * Set file transfer mode.
324 */
04480325 325/*ARGSUSED*/
26128054
JSP
326void
327setftmode(argc, argv)
67ff27c7 328 int argc;
59d0d309
SL
329 char *argv[];
330{
331
332 printf("We only support %s mode, sorry.\n", modename);
9069f68e 333 code = -1;
59d0d309
SL
334}
335
336/*
337 * Set file transfer format.
338 */
04480325 339/*ARGSUSED*/
26128054 340void
59d0d309 341setform(argc, argv)
67ff27c7 342 int argc;
59d0d309
SL
343 char *argv[];
344{
345
346 printf("We only support %s format, sorry.\n", formname);
9069f68e 347 code = -1;
59d0d309
SL
348}
349
350/*
351 * Set file transfer structure.
352 */
04480325 353/*ARGSUSED*/
26128054 354void
59d0d309 355setstruct(argc, argv)
67ff27c7 356 int argc;
59d0d309
SL
357 char *argv[];
358{
359
360 printf("We only support %s structure, sorry.\n", structname);
9069f68e 361 code = -1;
59d0d309
SL
362}
363
71a655cd
RC
364/*
365 * Send a single file.
366 */
26128054 367void
59d0d309 368put(argc, argv)
5ac6fc46
SL
369 int argc;
370 char *argv[];
371{
9072bd8a 372 char *cmd;
9069f68e 373 int loc = 0;
460419cd 374 char *oldargv1, *oldargv2;
5ac6fc46 375
9069f68e
GM
376 if (argc == 2) {
377 argc++;
378 argv[2] = argv[1];
379 loc++;
380 }
67ff27c7
KB
381 if (argc < 2 && !another(&argc, &argv, "local-file"))
382 goto usage;
383 if (argc < 3 && !another(&argc, &argv, "remote-file")) {
59d0d309 384usage:
67ff27c7 385 printf("usage: %s local-file remote-file\n", argv[0]);
9069f68e 386 code = -1;
59d0d309
SL
387 return;
388 }
14433a73 389 oldargv1 = argv[1];
460419cd 390 oldargv2 = argv[2];
9069f68e
GM
391 if (!globulize(&argv[1])) {
392 code = -1;
cf8133c7 393 return;
9069f68e 394 }
14433a73
KM
395 /*
396 * If "globulize" modifies argv[1], and argv[2] is a copy of
397 * the old argv[1], make it a copy of the new argv[1].
398 */
9069f68e 399 if (argv[1] != oldargv1 && argv[2] == oldargv1) {
14433a73 400 argv[2] = argv[1];
9069f68e
GM
401 }
402 cmd = (argv[0][0] == 'a') ? "APPE" : ((sunique) ? "STOU" : "STOR");
403 if (loc && ntflag) {
404 argv[2] = dotrans(argv[2]);
405 }
406 if (loc && mapflag) {
407 argv[2] = domap(argv[2]);
408 }
460419cd
MK
409 sendrequest(cmd, argv[1], argv[2],
410 argv[1] != oldargv1 || argv[2] != oldargv2);
59d0d309
SL
411}
412
413/*
9072bd8a 414 * Send multiple files.
cf8133c7 415 */
26128054 416void
cf8133c7 417mput(argc, argv)
981fd33c
KB
418 int argc;
419 char **argv;
cf8133c7 420{
26128054 421 int i;
981fd33c 422 sig_t oldintr;
11c9b6d7 423 int ointer;
9069f68e 424 char *tp;
cf8133c7 425
67ff27c7
KB
426 if (argc < 2 && !another(&argc, &argv, "local-files")) {
427 printf("usage: %s local-files\n", argv[0]);
9069f68e
GM
428 code = -1;
429 return;
430 }
431 mname = argv[0];
432 mflag = 1;
433 oldintr = signal(SIGINT, mabort);
434 (void) setjmp(jabort);
435 if (proxy) {
436 char *cp, *tp2, tmpbuf[MAXPATHLEN];
437
04480325 438 while ((cp = remglob(argv,0)) != NULL) {
9069f68e
GM
439 if (*cp == 0) {
440 mflag = 0;
441 continue;
442 }
443 if (mflag && confirm(argv[0], cp)) {
444 tp = cp;
445 if (mcase) {
446 while (*tp && !islower(*tp)) {
447 tp++;
448 }
449 if (!*tp) {
450 tp = cp;
451 tp2 = tmpbuf;
452 while ((*tp2 = *tp) != NULL) {
453 if (isupper(*tp2)) {
454 *tp2 = 'a' + *tp2 - 'A';
455 }
456 tp++;
457 tp2++;
458 }
459 }
460 tp = tmpbuf;
461 }
462 if (ntflag) {
463 tp = dotrans(tp);
464 }
465 if (mapflag) {
466 tp = domap(tp);
467 }
460419cd
MK
468 sendrequest((sunique) ? "STOU" : "STOR",
469 cp, tp, cp != tp || !interactive);
9069f68e
GM
470 if (!mflag && fromatty) {
471 ointer = interactive;
472 interactive = 1;
473 if (confirm("Continue with","mput")) {
474 mflag++;
475 }
476 interactive = ointer;
477 }
478 }
479 }
480 (void) signal(SIGINT, oldintr);
481 mflag = 0;
cf8133c7
SL
482 return;
483 }
614e24b6 484 for (i = 1; i < argc; i++) {
26128054 485 char **cpp, **gargs;
614e24b6
SL
486
487 if (!doglob) {
9069f68e
GM
488 if (mflag && confirm(argv[0], argv[i])) {
489 tp = (ntflag) ? dotrans(argv[i]) : argv[i];
490 tp = (mapflag) ? domap(tp) : tp;
491 sendrequest((sunique) ? "STOU" : "STOR",
460419cd 492 argv[i], tp, tp != argv[i] || !interactive);
9069f68e
GM
493 if (!mflag && fromatty) {
494 ointer = interactive;
495 interactive = 1;
496 if (confirm("Continue with","mput")) {
497 mflag++;
498 }
499 interactive = ointer;
500 }
501 }
614e24b6
SL
502 continue;
503 }
77c99353 504 gargs = ftpglob(argv[i]);
cf8133c7 505 if (globerr != NULL) {
5ac6fc46 506 printf("%s\n", globerr);
c075c3ce 507 if (gargs) {
5ac6fc46 508 blkfree(gargs);
11c9b6d7 509 free((char *)gargs);
c075c3ce 510 }
614e24b6 511 continue;
cf8133c7 512 }
9069f68e
GM
513 for (cpp = gargs; cpp && *cpp != NULL; cpp++) {
514 if (mflag && confirm(argv[0], *cpp)) {
515 tp = (ntflag) ? dotrans(*cpp) : *cpp;
516 tp = (mapflag) ? domap(tp) : tp;
517 sendrequest((sunique) ? "STOU" : "STOR",
460419cd 518 *cpp, tp, *cpp != tp || !interactive);
9069f68e
GM
519 if (!mflag && fromatty) {
520 ointer = interactive;
521 interactive = 1;
522 if (confirm("Continue with","mput")) {
523 mflag++;
524 }
525 interactive = ointer;
526 }
527 }
528 }
c075c3ce 529 if (gargs != NULL) {
614e24b6 530 blkfree(gargs);
11c9b6d7 531 free((char *)gargs);
c075c3ce 532 }
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 }
987 printf("Local directory now %s\n", getwd(buf));
9069f68e 988 code = 0;
59d0d309
SL
989}
990
991/*
992 * Delete a single file.
993 */
26128054 994void
59d0d309 995delete(argc, argv)
67ff27c7 996 int argc;
59d0d309
SL
997 char *argv[];
998{
999
67ff27c7
KB
1000 if (argc < 2 && !another(&argc, &argv, "remote-file")) {
1001 printf("usage: %s remote-file\n", argv[0]);
9069f68e 1002 code = -1;
59d0d309
SL
1003 return;
1004 }
1005 (void) command("DELE %s", argv[1]);
1006}
1007
5ac6fc46
SL
1008/*
1009 * Delete multiple files.
1010 */
26128054 1011void
5ac6fc46 1012mdelete(argc, argv)
981fd33c
KB
1013 int argc;
1014 char **argv;
5ac6fc46 1015{
981fd33c
KB
1016 sig_t oldintr;
1017 int ointer;
1018 char *cp;
5ac6fc46 1019
67ff27c7
KB
1020 if (argc < 2 && !another(&argc, &argv, "remote-files")) {
1021 printf("usage: %s remote-files\n", argv[0]);
9069f68e 1022 code = -1;
5ac6fc46
SL
1023 return;
1024 }
9069f68e
GM
1025 mname = argv[0];
1026 mflag = 1;
1027 oldintr = signal(SIGINT, mabort);
1028 (void) setjmp(jabort);
04480325 1029 while ((cp = remglob(argv,0)) != NULL) {
9069f68e
GM
1030 if (*cp == '\0') {
1031 mflag = 0;
1032 continue;
1033 }
1034 if (mflag && confirm(argv[0], cp)) {
5ac6fc46 1035 (void) command("DELE %s", cp);
9069f68e
GM
1036 if (!mflag && fromatty) {
1037 ointer = interactive;
1038 interactive = 1;
1039 if (confirm("Continue with", "mdelete")) {
1040 mflag++;
1041 }
1042 interactive = ointer;
1043 }
1044 }
1045 }
1046 (void) signal(SIGINT, oldintr);
1047 mflag = 0;
5ac6fc46 1048}
9072bd8a 1049
59d0d309
SL
1050/*
1051 * Rename a remote file.
1052 */
26128054 1053void
59d0d309 1054renamefile(argc, argv)
67ff27c7 1055 int argc;
59d0d309
SL
1056 char *argv[];
1057{
1058
67ff27c7
KB
1059 if (argc < 2 && !another(&argc, &argv, "from-name"))
1060 goto usage;
1061 if (argc < 3 && !another(&argc, &argv, "to-name")) {
59d0d309
SL
1062usage:
1063 printf("%s from-name to-name\n", argv[0]);
9069f68e 1064 code = -1;
59d0d309
SL
1065 return;
1066 }
59d0d309
SL
1067 if (command("RNFR %s", argv[1]) == CONTINUE)
1068 (void) command("RNTO %s", argv[2]);
1069}
1070
1071/*
1072 * Get a directory listing
1073 * of remote files.
1074 */
26128054 1075void
59d0d309 1076ls(argc, argv)
67ff27c7 1077 int argc;
59d0d309
SL
1078 char *argv[];
1079{
9072bd8a 1080 char *cmd;
59d0d309
SL
1081
1082 if (argc < 2)
1083 argc++, argv[1] = NULL;
1084 if (argc < 3)
1085 argc++, argv[2] = "-";
9072bd8a
SL
1086 if (argc > 3) {
1087 printf("usage: %s remote-directory local-file\n", argv[0]);
9069f68e 1088 code = -1;
9072bd8a
SL
1089 return;
1090 }
ff00793c 1091 cmd = argv[0][0] == 'n' ? "NLST" : "LIST";
9069f68e
GM
1092 if (strcmp(argv[2], "-") && !globulize(&argv[2])) {
1093 code = -1;
cf8133c7 1094 return;
9069f68e 1095 }
e95608cc
SJ
1096 if (strcmp(argv[2], "-") && *argv[2] != '|')
1097 if (!globulize(&argv[2]) || !confirm("output to local-file:", argv[2])) {
1098 code = -1;
1099 return;
1100 }
460419cd 1101 recvrequest(cmd, argv[2], argv[1], "w", 0);
9072bd8a
SL
1102}
1103
1104/*
1105 * Get a directory listing
1106 * of multiple remote files.
1107 */
26128054 1108void
9072bd8a 1109mls(argc, argv)
981fd33c
KB
1110 int argc;
1111 char **argv;
9072bd8a 1112{
981fd33c
KB
1113 sig_t oldintr;
1114 int ointer, i;
1115 char *cmd, mode[1], *dest;
9072bd8a 1116
67ff27c7
KB
1117 if (argc < 2 && !another(&argc, &argv, "remote-files"))
1118 goto usage;
1119 if (argc < 3 && !another(&argc, &argv, "local-file")) {
1120usage:
1121 printf("usage: %s remote-files local-file\n", argv[0]);
9069f68e 1122 code = -1;
614e24b6
SL
1123 return;
1124 }
1125 dest = argv[argc - 1];
1126 argv[argc - 1] = NULL;
9069f68e 1127 if (strcmp(dest, "-") && *dest != '|')
67ff27c7
KB
1128 if (!globulize(&dest) ||
1129 !confirm("output to local-file:", dest)) {
9069f68e 1130 code = -1;
9072bd8a 1131 return;
9069f68e 1132 }
cdc35b45 1133 cmd = argv[0][1] == 'l' ? "NLST" : "LIST";
9069f68e
GM
1134 mname = argv[0];
1135 mflag = 1;
1136 oldintr = signal(SIGINT, mabort);
1137 (void) setjmp(jabort);
1138 for (i = 1; mflag && i < argc-1; ++i) {
1139 *mode = (i == 1) ? 'w' : 'a';
460419cd 1140 recvrequest(cmd, dest, argv[i], mode, 0);
9069f68e
GM
1141 if (!mflag && fromatty) {
1142 ointer = interactive;
1143 interactive = 1;
1144 if (confirm("Continue with", argv[0])) {
1145 mflag ++;
1146 }
1147 interactive = ointer;
1148 }
1149 }
1150 (void) signal(SIGINT, oldintr);
1151 mflag = 0;
59d0d309
SL
1152}
1153
1154/*
1155 * Do a shell escape
1156 */
04480325 1157/*ARGSUSED*/
26128054 1158void
59d0d309 1159shell(argc, argv)
981fd33c
KB
1160 int argc;
1161 char **argv;
59d0d309 1162{
26128054 1163 pid_t pid;
981fd33c 1164 sig_t old1, old2;
9069f68e 1165 char shellnam[40], *shell, *namep;
04480325 1166 union wait status;
9072bd8a
SL
1167
1168 old1 = signal (SIGINT, SIG_IGN);
1169 old2 = signal (SIGQUIT, SIG_IGN);
1170 if ((pid = fork()) == 0) {
1171 for (pid = 3; pid < 20; pid++)
04480325
GM
1172 (void) close(pid);
1173 (void) signal(SIGINT, SIG_DFL);
1174 (void) signal(SIGQUIT, SIG_DFL);
14433a73
KM
1175 shell = getenv("SHELL");
1176 if (shell == NULL)
f58943be 1177 shell = _PATH_BSHELL;
26128054 1178 namep = strrchr(shell,'/');
14433a73
KM
1179 if (namep == NULL)
1180 namep = shell;
04480325
GM
1181 (void) strcpy(shellnam,"-");
1182 (void) strcat(shellnam, ++namep);
9069f68e
GM
1183 if (strcmp(namep, "sh") != 0)
1184 shellnam[0] = '+';
1185 if (debug) {
1186 printf ("%s\n", shell);
04480325 1187 (void) fflush (stdout);
9069f68e
GM
1188 }
1189 if (argc > 1) {
1190 execl(shell,shellnam,"-c",altarg,(char *)0);
1191 }
1192 else {
1193 execl(shell,shellnam,(char *)0);
9072bd8a 1194 }
26128054 1195 warn("%s", shell);
9069f68e 1196 code = -1;
9072bd8a 1197 exit(1);
26128054 1198 }
9072bd8a 1199 if (pid > 0)
b61c5edc 1200 while (wait((int *)&status) != pid)
9072bd8a 1201 ;
04480325
GM
1202 (void) signal(SIGINT, old1);
1203 (void) signal(SIGQUIT, old2);
9069f68e 1204 if (pid == -1) {
26128054 1205 warn("%s", "Try again later");
9069f68e
GM
1206 code = -1;
1207 }
1208 else {
1209 code = 0;
1210 }
59d0d309
SL
1211}
1212
1213/*
1214 * Send new user information (re-login)
1215 */
26128054 1216void
59d0d309
SL
1217user(argc, argv)
1218 int argc;
1219 char **argv;
1220{
26128054 1221 char acct[80];
9069f68e 1222 int n, aflag = 0;
59d0d309 1223
67ff27c7
KB
1224 if (argc < 2)
1225 (void) another(&argc, &argv, "username");
1226 if (argc < 2 || argc > 4) {
59d0d309 1227 printf("usage: %s username [password] [account]\n", argv[0]);
9069f68e 1228 code = -1;
26128054 1229 return;
59d0d309
SL
1230 }
1231 n = command("USER %s", argv[1]);
1232 if (n == CONTINUE) {
1233 if (argc < 3 )
aeac6782 1234 argv[2] = getpass("Password: "), argc++;
59d0d309
SL
1235 n = command("PASS %s", argv[2]);
1236 }
1237 if (n == CONTINUE) {
1238 if (argc < 4) {
1239 printf("Account: "); (void) fflush(stdout);
1240 (void) fgets(acct, sizeof(acct) - 1, stdin);
1241 acct[strlen(acct) - 1] = '\0';
1242 argv[3] = acct; argc++;
1243 }
9069f68e
GM
1244 n = command("ACCT %s", argv[3]);
1245 aflag++;
59d0d309
SL
1246 }
1247 if (n != COMPLETE) {
04480325 1248 fprintf(stdout, "Login failed.\n");
26128054 1249 return;
59d0d309 1250 }
9069f68e
GM
1251 if (!aflag && argc == 4) {
1252 (void) command("ACCT %s", argv[3]);
1253 }
59d0d309
SL
1254}
1255
1256/*
1257 * Print working directory.
1258 */
1259/*VARARGS*/
26128054
JSP
1260void
1261pwd(argc, argv)
1262 int argc;
1263 char *argv[];
59d0d309 1264{
23d74d65 1265 int oldverbose = verbose;
9072bd8a 1266
23d74d65
MK
1267 /*
1268 * If we aren't verbose, this doesn't do anything!
1269 */
1270 verbose = 1;
1271 if (command("PWD") == ERROR && code == 500) {
1272 printf("PWD command not recognized, trying XPWD\n");
1273 (void) command("XPWD");
1274 }
1275 verbose = oldverbose;
59d0d309
SL
1276}
1277
1278/*
1279 * Make a directory.
1280 */
26128054 1281void
59d0d309 1282makedir(argc, argv)
67ff27c7 1283 int argc;
59d0d309
SL
1284 char *argv[];
1285{
1286
67ff27c7 1287 if (argc < 2 && !another(&argc, &argv, "directory-name")) {
9069f68e
GM
1288 printf("usage: %s directory-name\n", argv[0]);
1289 code = -1;
59d0d309
SL
1290 return;
1291 }
23d74d65
MK
1292 if (command("MKD %s", argv[1]) == ERROR && code == 500) {
1293 if (verbose)
1294 printf("MKD command not recognized, trying XMKD\n");
1295 (void) command("XMKD %s", argv[1]);
1296 }
59d0d309
SL
1297}
1298
1299/*
1300 * Remove a directory.
1301 */
26128054 1302void
59d0d309 1303removedir(argc, argv)
67ff27c7 1304 int argc;
59d0d309
SL
1305 char *argv[];
1306{
1307
67ff27c7 1308 if (argc < 2 && !another(&argc, &argv, "directory-name")) {
9069f68e
GM
1309 printf("usage: %s directory-name\n", argv[0]);
1310 code = -1;
59d0d309
SL
1311 return;
1312 }
23d74d65
MK
1313 if (command("RMD %s", argv[1]) == ERROR && code == 500) {
1314 if (verbose)
1315 printf("RMD command not recognized, trying XRMD\n");
1316 (void) command("XRMD %s", argv[1]);
1317 }
59d0d309
SL
1318}
1319
1320/*
1321 * Send a line, verbatim, to the remote machine.
1322 */
26128054 1323void
59d0d309 1324quote(argc, argv)
67ff27c7 1325 int argc;
59d0d309
SL
1326 char *argv[];
1327{
59d0d309 1328
67ff27c7 1329 if (argc < 2 && !another(&argc, &argv, "command line to send")) {
59d0d309 1330 printf("usage: %s line-to-send\n", argv[0]);
9069f68e 1331 code = -1;
59d0d309
SL
1332 return;
1333 }
67ff27c7 1334 quote1("", argc, argv);
59d0d309
SL
1335}
1336
23d74d65
MK
1337/*
1338 * Send a SITE command to the remote machine. The line
67ff27c7
KB
1339 * is sent verbatim to the remote machine, except that the
1340 * word "SITE" is added at the front.
23d74d65 1341 */
26128054 1342void
23d74d65 1343site(argc, argv)
67ff27c7 1344 int argc;
23d74d65
MK
1345 char *argv[];
1346{
23d74d65 1347
67ff27c7 1348 if (argc < 2 && !another(&argc, &argv, "arguments to SITE command")) {
23d74d65
MK
1349 printf("usage: %s line-to-send\n", argv[0]);
1350 code = -1;
1351 return;
1352 }
67ff27c7
KB
1353 quote1("SITE ", argc, argv);
1354}
1355
1356/*
1357 * Turn argv[1..argc) into a space-separated string, then prepend initial text.
1358 * Send the result as a one-line command and get response.
1359 */
26128054 1360void
67ff27c7
KB
1361quote1(initial, argc, argv)
1362 char *initial;
1363 int argc;
1364 char **argv;
1365{
26128054 1366 int i, len;
67ff27c7
KB
1367 char buf[BUFSIZ]; /* must be >= sizeof(line) */
1368
1369 (void) strcpy(buf, initial);
1370 if (argc > 1) {
1371 len = strlen(buf);
1372 len += strlen(strcpy(&buf[len], argv[1]));
1373 for (i = 2; i < argc; i++) {
1374 buf[len++] = ' ';
1375 len += strlen(strcpy(&buf[len], argv[i]));
1376 }
23d74d65
MK
1377 }
1378 if (command(buf) == PRELIM) {
26128054
JSP
1379 while (getreply(0) == PRELIM)
1380 continue;
23d74d65
MK
1381 }
1382}
1383
26128054 1384void
23d74d65 1385do_chmod(argc, argv)
67ff27c7 1386 int argc;
23d74d65
MK
1387 char *argv[];
1388{
67ff27c7
KB
1389
1390 if (argc < 2 && !another(&argc, &argv, "mode"))
1391 goto usage;
1392 if (argc < 3 && !another(&argc, &argv, "file-name")) {
1393usage:
23d74d65
MK
1394 printf("usage: %s mode file-name\n", argv[0]);
1395 code = -1;
1396 return;
1397 }
67ff27c7 1398 (void) command("SITE CHMOD %s %s", argv[1], argv[2]);
23d74d65
MK
1399}
1400
26128054 1401void
23d74d65 1402do_umask(argc, argv)
67ff27c7 1403 int argc;
23d74d65
MK
1404 char *argv[];
1405{
1406 int oldverbose = verbose;
1407
1408 verbose = 1;
1409 (void) command(argc == 1 ? "SITE UMASK" : "SITE UMASK %s", argv[1]);
1410 verbose = oldverbose;
1411}
1412
26128054 1413void
23d74d65 1414idle(argc, argv)
67ff27c7 1415 int argc;
23d74d65
MK
1416 char *argv[];
1417{
1418 int oldverbose = verbose;
1419
1420 verbose = 1;
1421 (void) command(argc == 1 ? "SITE IDLE" : "SITE IDLE %s", argv[1]);
1422 verbose = oldverbose;
1423}
1424
59d0d309
SL
1425/*
1426 * Ask the other side for help.
1427 */
26128054 1428void
59d0d309 1429rmthelp(argc, argv)
67ff27c7 1430 int argc;
59d0d309
SL
1431 char *argv[];
1432{
1433 int oldverbose = verbose;
1434
1435 verbose = 1;
1436 (void) command(argc == 1 ? "HELP" : "HELP %s", argv[1]);
1437 verbose = oldverbose;
1438}
1439
1440/*
1441 * Terminate session and exit.
1442 */
1443/*VARARGS*/
26128054
JSP
1444void
1445quit(argc, argv)
1446 int argc;
1447 char *argv[];
59d0d309
SL
1448{
1449
71a655cd 1450 if (connected)
26128054 1451 disconnect(0, 0);
9069f68e
GM
1452 pswitch(1);
1453 if (connected) {
26128054 1454 disconnect(0, 0);
9069f68e 1455 }
59d0d309
SL
1456 exit(0);
1457}
1458
1459/*
1460 * Terminate session, but don't exit.
1461 */
26128054
JSP
1462void
1463disconnect(argc, argv)
1464 int argc;
1465 char *argv[];
59d0d309 1466{
59d0d309
SL
1467
1468 if (!connected)
1469 return;
1470 (void) command("QUIT");
9069f68e
GM
1471 if (cout) {
1472 (void) fclose(cout);
1473 }
59d0d309
SL
1474 cout = NULL;
1475 connected = 0;
1476 data = -1;
9069f68e
GM
1477 if (!proxy) {
1478 macnum = 0;
1479 }
59d0d309 1480}
cf8133c7 1481
26128054 1482int
5ac6fc46 1483confirm(cmd, file)
cf8133c7
SL
1484 char *cmd, *file;
1485{
1486 char line[BUFSIZ];
1487
1488 if (!interactive)
5ac6fc46 1489 return (1);
cf8133c7 1490 printf("%s %s? ", cmd, file);
04480325 1491 (void) fflush(stdout);
67ff27c7
KB
1492 if (fgets(line, sizeof line, stdin) == NULL)
1493 return (0);
5ac6fc46 1494 return (*line != 'n' && *line != 'N');
cf8133c7
SL
1495}
1496
26128054 1497void
cf8133c7
SL
1498fatal(msg)
1499 char *msg;
1500{
1501
26128054 1502 errx(1, "%s", msg);
cf8133c7
SL
1503}
1504
1505/*
1506 * Glob a local file name specification with
1507 * the expectation of a single return value.
1508 * Can't control multiple values being expanded
1509 * from the expression, we return only the first.
1510 */
26128054 1511int
cf8133c7
SL
1512globulize(cpp)
1513 char **cpp;
1514{
1515 char **globbed;
1516
1517 if (!doglob)
1518 return (1);
77c99353 1519 globbed = ftpglob(*cpp);
cf8133c7
SL
1520 if (globerr != NULL) {
1521 printf("%s: %s\n", *cpp, globerr);
c075c3ce 1522 if (globbed) {
cf8133c7 1523 blkfree(globbed);
11c9b6d7 1524 free((char *)globbed);
c075c3ce 1525 }
cf8133c7
SL
1526 return (0);
1527 }
1528 if (globbed) {
1529 *cpp = *globbed++;
1530 /* don't waste too much memory */
26128054
JSP
1531 if (globbed) {
1532 blkfree(globbed);
536cf433 1533 free((char *)*globbed);
c075c3ce 1534 }
cf8133c7
SL
1535 }
1536 return (1);
1537}
9069f68e 1538
26128054 1539void
9069f68e 1540account(argc,argv)
9069f68e
GM
1541 int argc;
1542 char **argv;
1543{
aeac6782 1544 char acct[50], *getpass(), *ap;
9069f68e
GM
1545
1546 if (argc > 1) {
1547 ++argv;
1548 --argc;
1549 (void) strncpy(acct,*argv,49);
0c7d4ecf 1550 acct[49] = '\0';
9069f68e
GM
1551 while (argc > 1) {
1552 --argc;
1553 ++argv;
1554 (void) strncat(acct,*argv, 49-strlen(acct));
1555 }
1556 ap = acct;
1557 }
1558 else {
aeac6782 1559 ap = getpass("Account:");
9069f68e
GM
1560 }
1561 (void) command("ACCT %s", ap);
1562}
1563
1564jmp_buf abortprox;
1565
981fd33c 1566void
9069f68e
GM
1567proxabort()
1568{
9069f68e
GM
1569
1570 if (!proxy) {
1571 pswitch(1);
1572 }
1573 if (connected) {
1574 proxflag = 1;
1575 }
1576 else {
1577 proxflag = 0;
1578 }
1579 pswitch(0);
1580 longjmp(abortprox,1);
1581}
1582
26128054
JSP
1583void
1584doproxy(argc, argv)
9069f68e
GM
1585 int argc;
1586 char *argv[];
1587{
26128054 1588 struct cmd *c;
981fd33c 1589 sig_t oldintr;
9069f68e 1590
67ff27c7
KB
1591 if (argc < 2 && !another(&argc, &argv, "command")) {
1592 printf("usage: %s command\n", argv[0]);
9069f68e
GM
1593 code = -1;
1594 return;
1595 }
1596 c = getcmd(argv[1]);
1597 if (c == (struct cmd *) -1) {
1598 printf("?Ambiguous command\n");
04480325 1599 (void) fflush(stdout);
9069f68e
GM
1600 code = -1;
1601 return;
1602 }
1603 if (c == 0) {
1604 printf("?Invalid command\n");
04480325 1605 (void) fflush(stdout);
9069f68e
GM
1606 code = -1;
1607 return;
1608 }
1609 if (!c->c_proxy) {
1610 printf("?Invalid proxy command\n");
04480325 1611 (void) fflush(stdout);
9069f68e
GM
1612 code = -1;
1613 return;
1614 }
1615 if (setjmp(abortprox)) {
1616 code = -1;
1617 return;
1618 }
1619 oldintr = signal(SIGINT, proxabort);
1620 pswitch(1);
1621 if (c->c_conn && !connected) {
1622 printf("Not connected\n");
04480325 1623 (void) fflush(stdout);
9069f68e
GM
1624 pswitch(0);
1625 (void) signal(SIGINT, oldintr);
1626 code = -1;
1627 return;
1628 }
1629 (*c->c_handler)(argc-1, argv+1);
1630 if (connected) {
1631 proxflag = 1;
1632 }
1633 else {
1634 proxflag = 0;
1635 }
1636 pswitch(0);
1637 (void) signal(SIGINT, oldintr);
1638}
1639
26128054
JSP
1640void
1641setcase(argc, argv)
1642 int argc;
1643 char *argv[];
9069f68e 1644{
26128054 1645
9069f68e
GM
1646 mcase = !mcase;
1647 printf("Case mapping %s.\n", onoff(mcase));
1648 code = mcase;
1649}
1650
26128054
JSP
1651void
1652setcr(argc, argv)
1653 int argc;
1654 char *argv[];
9069f68e 1655{
26128054 1656
9069f68e
GM
1657 crflag = !crflag;
1658 printf("Carriage Return stripping %s.\n", onoff(crflag));
1659 code = crflag;
1660}
1661
26128054 1662void
9069f68e
GM
1663setntrans(argc,argv)
1664 int argc;
1665 char *argv[];
1666{
1667 if (argc == 1) {
1668 ntflag = 0;
1669 printf("Ntrans off.\n");
1670 code = ntflag;
1671 return;
1672 }
1673 ntflag++;
1674 code = ntflag;
1675 (void) strncpy(ntin, argv[1], 16);
1676 ntin[16] = '\0';
1677 if (argc == 2) {
1678 ntout[0] = '\0';
1679 return;
1680 }
1681 (void) strncpy(ntout, argv[2], 16);
1682 ntout[16] = '\0';
1683}
1684
1685char *
1686dotrans(name)
1687 char *name;
1688{
1689 static char new[MAXPATHLEN];
1690 char *cp1, *cp2 = new;
26128054 1691 int i, ostop, found;
9069f68e 1692
26128054
JSP
1693 for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++)
1694 continue;
9069f68e
GM
1695 for (cp1 = name; *cp1; cp1++) {
1696 found = 0;
1697 for (i = 0; *(ntin + i) && i < 16; i++) {
1698 if (*cp1 == *(ntin + i)) {
1699 found++;
1700 if (i < ostop) {
1701 *cp2++ = *(ntout + i);
1702 }
1703 break;
1704 }
1705 }
1706 if (!found) {
1707 *cp2++ = *cp1;
1708 }
1709 }
1710 *cp2 = '\0';
26128054 1711 return (new);
9069f68e
GM
1712}
1713
26128054 1714void
9069f68e
GM
1715setnmap(argc, argv)
1716 int argc;
1717 char *argv[];
1718{
1719 char *cp;
1720
1721 if (argc == 1) {
1722 mapflag = 0;
1723 printf("Nmap off.\n");
1724 code = mapflag;
1725 return;
1726 }
67ff27c7 1727 if (argc < 3 && !another(&argc, &argv, "mapout")) {
9069f68e
GM
1728 printf("Usage: %s [mapin mapout]\n",argv[0]);
1729 code = -1;
1730 return;
1731 }
1732 mapflag = 1;
1733 code = 1;
26128054 1734 cp = strchr(altarg, ' ');
9069f68e 1735 if (proxy) {
26128054
JSP
1736 while(*++cp == ' ')
1737 continue;
9069f68e 1738 altarg = cp;
26128054 1739 cp = strchr(altarg, ' ');
9069f68e
GM
1740 }
1741 *cp = '\0';
1742 (void) strncpy(mapin, altarg, MAXPATHLEN - 1);
26128054
JSP
1743 while (*++cp == ' ')
1744 continue;
9069f68e
GM
1745 (void) strncpy(mapout, cp, MAXPATHLEN - 1);
1746}
1747
1748char *
1749domap(name)
1750 char *name;
1751{
1752 static char new[MAXPATHLEN];
26128054 1753 char *cp1 = name, *cp2 = mapin;
9069f68e 1754 char *tp[9], *te[9];
7c1d95cd 1755 int i, toks[9], toknum = 0, match = 1;
9069f68e
GM
1756
1757 for (i=0; i < 9; ++i) {
1758 toks[i] = 0;
1759 }
1760 while (match && *cp1 && *cp2) {
1761 switch (*cp2) {
1762 case '\\':
1763 if (*++cp2 != *cp1) {
1764 match = 0;
1765 }
1766 break;
1767 case '$':
1768 if (*(cp2+1) >= '1' && (*cp2+1) <= '9') {
1769 if (*cp1 != *(++cp2+1)) {
1770 toks[toknum = *cp2 - '1']++;
1771 tp[toknum] = cp1;
1772 while (*++cp1 && *(cp2+1)
1773 != *cp1);
1774 te[toknum] = cp1;
1775 }
1776 cp2++;
1777 break;
1778 }
ff00793c 1779 /* FALLTHROUGH */
9069f68e
GM
1780 default:
1781 if (*cp2 != *cp1) {
1782 match = 0;
1783 }
1784 break;
1785 }
7c1d95cd 1786 if (match && *cp1) {
9069f68e
GM
1787 cp1++;
1788 }
7c1d95cd 1789 if (match && *cp2) {
9069f68e
GM
1790 cp2++;
1791 }
1792 }
7c1d95cd
SJ
1793 if (!match && *cp1) /* last token mismatch */
1794 {
1795 toks[toknum] = 0;
1796 }
9069f68e
GM
1797 cp1 = new;
1798 *cp1 = '\0';
1799 cp2 = mapout;
1800 while (*cp2) {
1801 match = 0;
1802 switch (*cp2) {
1803 case '\\':
1804 if (*(cp2 + 1)) {
1805 *cp1++ = *++cp2;
1806 }
1807 break;
1808 case '[':
1809LOOP:
1810 if (*++cp2 == '$' && isdigit(*(cp2+1))) {
1811 if (*++cp2 == '0') {
1812 char *cp3 = name;
1813
1814 while (*cp3) {
1815 *cp1++ = *cp3++;
1816 }
1817 match = 1;
1818 }
1819 else if (toks[toknum = *cp2 - '1']) {
1820 char *cp3 = tp[toknum];
1821
1822 while (cp3 != te[toknum]) {
1823 *cp1++ = *cp3++;
1824 }
1825 match = 1;
1826 }
1827 }
1828 else {
1829 while (*cp2 && *cp2 != ',' &&
1830 *cp2 != ']') {
1831 if (*cp2 == '\\') {
1832 cp2++;
1833 }
1834 else if (*cp2 == '$' &&
1835 isdigit(*(cp2+1))) {
1836 if (*++cp2 == '0') {
1837 char *cp3 = name;
1838
1839 while (*cp3) {
1840 *cp1++ = *cp3++;
1841 }
1842 }
1843 else if (toks[toknum =
1844 *cp2 - '1']) {
1845 char *cp3=tp[toknum];
1846
1847 while (cp3 !=
1848 te[toknum]) {
1849 *cp1++ = *cp3++;
1850 }
1851 }
1852 }
1853 else if (*cp2) {
1854 *cp1++ = *cp2++;
1855 }
1856 }
1857 if (!*cp2) {
1858 printf("nmap: unbalanced brackets\n");
26128054 1859 return (name);
9069f68e
GM
1860 }
1861 match = 1;
1862 cp2--;
1863 }
1864 if (match) {
1865 while (*++cp2 && *cp2 != ']') {
1866 if (*cp2 == '\\' && *(cp2 + 1)) {
1867 cp2++;
1868 }
1869 }
1870 if (!*cp2) {
1871 printf("nmap: unbalanced brackets\n");
26128054 1872 return (name);
9069f68e
GM
1873 }
1874 break;
1875 }
1876 switch (*++cp2) {
1877 case ',':
1878 goto LOOP;
1879 case ']':
1880 break;
1881 default:
1882 cp2--;
1883 goto LOOP;
1884 }
1885 break;
1886 case '$':
1887 if (isdigit(*(cp2 + 1))) {
1888 if (*++cp2 == '0') {
1889 char *cp3 = name;
1890
1891 while (*cp3) {
1892 *cp1++ = *cp3++;
1893 }
1894 }
1895 else if (toks[toknum = *cp2 - '1']) {
1896 char *cp3 = tp[toknum];
1897
1898 while (cp3 != te[toknum]) {
1899 *cp1++ = *cp3++;
1900 }
1901 }
1902 break;
1903 }
1904 /* intentional drop through */
1905 default:
1906 *cp1++ = *cp2;
1907 break;
1908 }
1909 cp2++;
1910 }
1911 *cp1 = '\0';
1912 if (!*new) {
26128054 1913 return (name);
9069f68e 1914 }
26128054 1915 return (new);
9069f68e
GM
1916}
1917
26128054
JSP
1918void
1919setsunique(argc, argv)
1920 int argc;
1921 char *argv[];
9069f68e 1922{
26128054 1923
9069f68e
GM
1924 sunique = !sunique;
1925 printf("Store unique %s.\n", onoff(sunique));
1926 code = sunique;
1927}
1928
26128054
JSP
1929void
1930setrunique(argc, argv)
1931 int argc;
1932 char *argv[];
9069f68e 1933{
26128054 1934
9069f68e
GM
1935 runique = !runique;
1936 printf("Receive unique %s.\n", onoff(runique));
1937 code = runique;
1938}
1939
1940/* change directory to perent directory */
26128054
JSP
1941void
1942cdup(argc, argv)
1943 int argc;
1944 char *argv[];
9069f68e 1945{
26128054 1946
23d74d65
MK
1947 if (command("CDUP") == ERROR && code == 500) {
1948 if (verbose)
1949 printf("CDUP command not recognized, trying XCUP\n");
1950 (void) command("XCUP");
1951 }
9069f68e
GM
1952}
1953
ff00793c
MK
1954
1955/* show remote system type */
26128054
JSP
1956void
1957syst(argc, argv)
1958 int argc;
1959 char *argv[];
ff00793c 1960{
26128054 1961
ff00793c
MK
1962 (void) command("SYST");
1963}
1964
26128054 1965void
9069f68e
GM
1966macdef(argc, argv)
1967 int argc;
1968 char *argv[];
1969{
1970 char *tmp;
1971 int c;
1972
1973 if (macnum == 16) {
1974 printf("Limit of 16 macros have already been defined\n");
1975 code = -1;
1976 return;
1977 }
67ff27c7 1978 if (argc < 2 && !another(&argc, &argv, "macro name")) {
9069f68e
GM
1979 printf("Usage: %s macro_name\n",argv[0]);
1980 code = -1;
1981 return;
1982 }
1983 if (interactive) {
1984 printf("Enter macro line by line, terminating it with a null line\n");
1985 }
04480325 1986 (void) strncpy(macros[macnum].mac_name, argv[1], 8);
9069f68e
GM
1987 if (macnum == 0) {
1988 macros[macnum].mac_start = macbuf;
1989 }
1990 else {
1991 macros[macnum].mac_start = macros[macnum - 1].mac_end + 1;
1992 }
1993 tmp = macros[macnum].mac_start;
1994 while (tmp != macbuf+4096) {
1995 if ((c = getchar()) == EOF) {
1996 printf("macdef:end of file encountered\n");
1997 code = -1;
1998 return;
1999 }
2000 if ((*tmp = c) == '\n') {
2001 if (tmp == macros[macnum].mac_start) {
2002 macros[macnum++].mac_end = tmp;
2003 code = 0;
2004 return;
2005 }
2006 if (*(tmp-1) == '\0') {
2007 macros[macnum++].mac_end = tmp - 1;
2008 code = 0;
2009 return;
2010 }
2011 *tmp = '\0';
2012 }
2013 tmp++;
2014 }
2015 while (1) {
ff00793c
MK
2016 while ((c = getchar()) != '\n' && c != EOF)
2017 /* LOOP */;
9069f68e
GM
2018 if (c == EOF || getchar() == '\n') {
2019 printf("Macro not defined - 4k buffer exceeded\n");
2020 code = -1;
2021 return;
2022 }
2023 }
2024}
ff00793c
MK
2025
2026/*
2027 * get size of file on remote machine
2028 */
26128054 2029void
ff00793c 2030sizecmd(argc, argv)
67ff27c7 2031 int argc;
ff00793c
MK
2032 char *argv[];
2033{
2034
67ff27c7
KB
2035 if (argc < 2 && !another(&argc, &argv, "filename")) {
2036 printf("usage: %s filename\n", argv[0]);
ff00793c
MK
2037 code = -1;
2038 return;
2039 }
2040 (void) command("SIZE %s", argv[1]);
2041}
2042
2043/*
2044 * get last modification time of file on remote machine
2045 */
26128054 2046void
ff00793c 2047modtime(argc, argv)
67ff27c7 2048 int argc;
ff00793c
MK
2049 char *argv[];
2050{
2051 int overbose;
2052
67ff27c7
KB
2053 if (argc < 2 && !another(&argc, &argv, "filename")) {
2054 printf("usage: %s filename\n", argv[0]);
ff00793c
MK
2055 code = -1;
2056 return;
2057 }
cdc35b45
MK
2058 overbose = verbose;
2059 if (debug == 0)
2060 verbose = -1;
ff00793c
MK
2061 if (command("MDTM %s", argv[1]) == COMPLETE) {
2062 int yy, mo, day, hour, min, sec;
2063 sscanf(reply_string, "%*s %04d%02d%02d%02d%02d%02d", &yy, &mo,
2064 &day, &hour, &min, &sec);
2065 /* might want to print this in local time */
2066 printf("%s\t%02d/%02d/%04d %02d:%02d:%02d GMT\n", argv[1],
2067 mo, day, yy, hour, min, sec);
2068 } else
11c9b6d7 2069 printf("%s\n", reply_string);
ff00793c
MK
2070 verbose = overbose;
2071}
2072
2073/*
63c685da 2074 * show status on remote machine
ff00793c 2075 */
26128054 2076void
ff00793c 2077rmtstatus(argc, argv)
67ff27c7 2078 int argc;
ff00793c
MK
2079 char *argv[];
2080{
26128054 2081
ff00793c
MK
2082 (void) command(argc > 1 ? "STAT %s" : "STAT" , argv[1]);
2083}