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