Changes from Steve Jacobson (from <csvsj@ucbopal>).
authorGregory Minshall <minshall@ucbvax.Berkeley.EDU>
Tue, 4 Feb 1986 06:41:14 +0000 (22:41 -0800)
committerGregory Minshall <minshall@ucbvax.Berkeley.EDU>
Tue, 4 Feb 1986 06:41:14 +0000 (22:41 -0800)
SCCS-vsn: usr.bin/ftp/main.c 5.4
SCCS-vsn: usr.bin/ftp/ftp.c 5.6
SCCS-vsn: usr.bin/ftp/cmdtab.c 5.3
SCCS-vsn: usr.bin/ftp/Makefile 5.2
SCCS-vsn: usr.bin/ftp/ftp_var.h 5.2
SCCS-vsn: usr.bin/ftp/cmds.c 5.4

usr/src/usr.bin/ftp/Makefile
usr/src/usr.bin/ftp/cmds.c
usr/src/usr.bin/ftp/cmdtab.c
usr/src/usr.bin/ftp/ftp.c
usr/src/usr.bin/ftp/ftp_var.h
usr/src/usr.bin/ftp/main.c

index c77b127..91c9012 100644 (file)
@@ -1,9 +1,9 @@
 #
 #
-# Copyright (c) 1980 Regents of the University of California.
+# Copyright (c) 1985 Regents of the University of California.
 # All rights reserved.  The Berkeley software License Agreement
 # specifies the terms and conditions for redistribution.
 #
 # All rights reserved.  The Berkeley software License Agreement
 # specifies the terms and conditions for redistribution.
 #
-#      @(#)Makefile    5.1 (Berkeley) %G%
+#      @(#)Makefile    5.2 (Berkeley) %G%
 #
 ALL=   ftp
 DESTDIR=
 #
 ALL=   ftp
 DESTDIR=
@@ -11,8 +11,8 @@ CFLAGS=       -O
 
 all:   ${ALL}
 
 
 all:   ${ALL}
 
-ftp:   cmds.o cmdtab.o ftp.o getpass.o glob.o main.o
-       ${CC} cmds.o cmdtab.o ftp.o getpass.o glob.o main.o -o ftp 
+ftp:   cmds.o cmdtab.o ftp.o getpass.o glob.o main.o pclose.o ruserpass.o              domacro.o
+       ${CC} cmds.o cmdtab.o ftp.o getpass.o glob.o main.o pclose.o ruserpass.o         domacro.o -o ftp 
 
 ftp.o: /usr/include/arpa/ftp.h ftp_var.h
 cmds.o:        /usr/include/arpa/ftp.h ftp_var.h
 
 ftp.o: /usr/include/arpa/ftp.h ftp_var.h
 cmds.o:        /usr/include/arpa/ftp.h ftp_var.h
index 658fada..ee96d20 100644 (file)
@@ -1,17 +1,17 @@
 /*
 /*
- * Copyright (c) 1983 Regents of the University of California.
+ * Copyright (c) 1985 Regents of the University of California.
  * All rights reserved.  The Berkeley software License Agreement
  * specifies the terms and conditions for redistribution.
  */
 
 #ifndef lint
  * All rights reserved.  The Berkeley software License Agreement
  * specifies the terms and conditions for redistribution.
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)cmds.c     5.3 (Berkeley) %G%";
+static char sccsid[] = "@(#)cmds.c     5.4 (Berkeley) %G%";
 #endif not lint
 
 /*
  * FTP User Program -- Command Routines.
  */
 #endif not lint
 
 /*
  * FTP User Program -- Command Routines.
  */
-#include <sys/param.h>
+#include "ftp_var.h"
 #include <sys/socket.h>
 
 #include <arpa/ftp.h>
 #include <sys/socket.h>
 
 #include <arpa/ftp.h>
@@ -20,8 +20,8 @@ static char sccsid[] = "@(#)cmds.c    5.3 (Berkeley) %G%";
 #include <stdio.h>
 #include <errno.h>
 #include <netdb.h>
 #include <stdio.h>
 #include <errno.h>
 #include <netdb.h>
+#include <ctype.h>
 
 
-#include "ftp_var.h"
 
 extern char *globerr;
 extern char **glob();
 
 extern char *globerr;
 extern char **glob();
@@ -31,6 +31,9 @@ extern        char *remglob();
 extern char *getenv();
 extern char *index();
 extern char *rindex();
 extern char *getenv();
 extern char *index();
 extern char *rindex();
+char *mname;
+jmp_buf jabort;
+char *dotrans(), *domap();
 
 /*
  * Connect to peer server and
 
 /*
  * Connect to peer server and
@@ -44,8 +47,9 @@ setpeer(argc, argv)
        int port;
 
        if (connected) {
        int port;
 
        if (connected) {
-               printf("Already connected to %s, use disconnect first.\n",
+               printf("Already connected to %s, use close first.\n",
                        hostname);
                        hostname);
+               code = -1;
                return;
        }
        if (argc < 2) {
                return;
        }
        if (argc < 2) {
@@ -58,6 +62,7 @@ setpeer(argc, argv)
        }
        if (argc > 3) {
                printf("usage: %s host-name [port]\n", argv[0]);
        }
        if (argc > 3) {
                printf("usage: %s host-name [port]\n", argv[0]);
+               code = -1;
                return;
        }
        port = sp->s_port;
                return;
        }
        port = sp->s_port;
@@ -66,6 +71,7 @@ setpeer(argc, argv)
                if (port <= 0) {
                        printf("%s: bad port number-- %s\n", argv[1], argv[2]);
                        printf ("usage: %s host-name [port]\n", argv[0]);
                if (port <= 0) {
                        printf("%s: bad port number-- %s\n", argv[1], argv[2]);
                        printf ("usage: %s host-name [port]\n", argv[0]);
+                       code = -1;
                        return;
                }
                port = htons(port);
                        return;
                }
                port = htons(port);
@@ -74,7 +80,7 @@ setpeer(argc, argv)
        if (host) {
                connected = 1;
                if (autologin)
        if (host) {
                connected = 1;
                if (autologin)
-                       login(host);
+                       login(argv[1]);
        }
 }
 
        }
 }
 
@@ -112,10 +118,12 @@ settype(argc, argv)
                                sep = " | ";
                }
                printf(" ]\n");
                                sep = " | ";
                }
                printf(" ]\n");
+               code = -1;
                return;
        }
        if (argc < 2) {
                printf("Using %s mode to transfer files.\n", typename);
                return;
        }
        if (argc < 2) {
                printf("Using %s mode to transfer files.\n", typename);
+               code = 0;
                return;
        }
        for (p = types; p->t_name; p++)
                return;
        }
        for (p = types; p->t_name; p++)
@@ -123,6 +131,7 @@ settype(argc, argv)
                        break;
        if (p->t_name == 0) {
                printf("%s: unknown mode\n", argv[1]);
                        break;
        if (p->t_name == 0) {
                printf("%s: unknown mode\n", argv[1]);
+               code = -1;
                return;
        }
        if ((p->t_arg != NULL) && (*(p->t_arg) != '\0'))
                return;
        }
        if ((p->t_arg != NULL) && (*(p->t_arg) != '\0'))
@@ -183,6 +192,7 @@ setmode(argc, argv)
 {
 
        printf("We only support %s mode, sorry.\n", modename);
 {
 
        printf("We only support %s mode, sorry.\n", modename);
+       code = -1;
 }
 
 /*
 }
 
 /*
@@ -193,6 +203,7 @@ setform(argc, argv)
 {
 
        printf("We only support %s format, sorry.\n", formname);
 {
 
        printf("We only support %s format, sorry.\n", formname);
+       code = -1;
 }
 
 /*
 }
 
 /*
@@ -203,6 +214,7 @@ setstruct(argc, argv)
 {
 
        printf("We only support %s structure, sorry.\n", structname);
 {
 
        printf("We only support %s structure, sorry.\n", structname);
+       code = -1;
 }
 
 /*
 }
 
 /*
@@ -213,10 +225,14 @@ put(argc, argv)
        char *argv[];
 {
        char *cmd;
        char *argv[];
 {
        char *cmd;
+       int loc = 0;
        char *oldargv1;
 
        char *oldargv1;
 
-       if (argc == 2)
-               argc++, argv[2] = argv[1];
+       if (argc == 2) {
+               argc++;
+               argv[2] = argv[1];
+               loc++;
+       }
        if (argc < 2) {
                strcat(line, " ");
                printf("(local-file) ");
        if (argc < 2) {
                strcat(line, " ");
                printf("(local-file) ");
@@ -227,7 +243,8 @@ put(argc, argv)
        }
        if (argc < 2) {
 usage:
        }
        if (argc < 2) {
 usage:
-               printf("%s local-file remote-file\n", argv[0]);
+               printf("usage:%s local-file remote-file\n", argv[0]);
+               code = -1;
                return;
        }
        if (argc < 3) {
                return;
        }
        if (argc < 3) {
@@ -241,15 +258,24 @@ usage:
        if (argc < 3) 
                goto usage;
        oldargv1 = argv[1];
        if (argc < 3) 
                goto usage;
        oldargv1 = argv[1];
-       if (!globulize(&argv[1]))
+       if (!globulize(&argv[1])) {
+               code = -1;
                return;
                return;
+       }
        /*
         * If "globulize" modifies argv[1], and argv[2] is a copy of
         * the old argv[1], make it a copy of the new argv[1].
         */
        /*
         * If "globulize" modifies argv[1], and argv[2] is a copy of
         * the old argv[1], make it a copy of the new argv[1].
         */
-       if (argv[1] != oldargv1 && argv[2] == oldargv1)
+       if (argv[1] != oldargv1 && argv[2] == oldargv1) {
                argv[2] = argv[1];
                argv[2] = argv[1];
-       cmd = (argv[0][0] == 'a') ? "APPE" : "STOR";
+       }
+       cmd = (argv[0][0] == 'a') ? "APPE" : ((sunique) ? "STOU" : "STOR");
+       if (loc && ntflag) {
+               argv[2] = dotrans(argv[2]);
+       }
+       if (loc && mapflag) {
+               argv[2] = domap(argv[2]);
+       }
        sendrequest(cmd, argv[1], argv[2]);
 }
 
        sendrequest(cmd, argv[1], argv[2]);
 }
 
@@ -260,6 +286,9 @@ mput(argc, argv)
        char *argv[];
 {
        register int i;
        char *argv[];
 {
        register int i;
+       int ointer, (*oldintr)(), mabort();
+       extern jmp_buf jabort;
+       char *tp;
 
        if (argc < 2) {
                strcat(line, " ");
 
        if (argc < 2) {
                strcat(line, " ");
@@ -270,15 +299,80 @@ mput(argc, argv)
                argv = margv;
        }
        if (argc < 2) {
                argv = margv;
        }
        if (argc < 2) {
-               printf("%s local-files\n", argv[0]);
+               printf("usage:%s local-files\n", argv[0]);
+               code = -1;
+               return;
+       }
+       mname = argv[0];
+       mflag = 1;
+       oldintr = signal(SIGINT, mabort);
+       (void) setjmp(jabort);
+       if (proxy) {
+               char *cp, *tp2, tmpbuf[MAXPATHLEN];
+
+               while ((cp = remglob(argc, argv, 0)) != NULL) {
+                       if (*cp == 0) {
+                               mflag = 0;
+                               continue;
+                       }
+                       if (mflag && confirm(argv[0], cp)) {
+                               tp = cp;
+                               if (mcase) {
+                                       while (*tp && !islower(*tp)) {
+                                               tp++;
+                                       }
+                                       if (!*tp) {
+                                               tp = cp;
+                                               tp2 = tmpbuf;
+                                               while ((*tp2 = *tp) != NULL) {
+                                                    if (isupper(*tp2)) {
+                                                       *tp2 = 'a' + *tp2 - 'A';
+                                                    }
+                                                    tp++;
+                                                    tp2++;
+                                               }
+                                       }
+                                       tp = tmpbuf;
+                               }
+                               if (ntflag) {
+                                       tp = dotrans(tp);
+                               }
+                               if (mapflag) {
+                                       tp = domap(tp);
+                               }
+                               sendrequest((sunique) ? "STOU" : "STOR", cp,tp);
+                               if (!mflag && fromatty) {
+                                       ointer = interactive;
+                                       interactive = 1;
+                                       if (confirm("Continue with","mput")) {
+                                               mflag++;
+                                       }
+                                       interactive = ointer;
+                               }
+                       }
+               }
+               (void) signal(SIGINT, oldintr);
+               mflag = 0;
                return;
        }
        for (i = 1; i < argc; i++) {
                register char **cpp, **gargs;
 
                if (!doglob) {
                return;
        }
        for (i = 1; i < argc; i++) {
                register char **cpp, **gargs;
 
                if (!doglob) {
-                       if (confirm(argv[0], argv[i]))
-                               sendrequest("STOR", argv[i], argv[i]);
+                       if (mflag && confirm(argv[0], argv[i])) {
+                               tp = (ntflag) ? dotrans(argv[i]) : argv[i];
+                               tp = (mapflag) ? domap(tp) : tp;
+                               sendrequest((sunique) ? "STOU" : "STOR",
+                                           argv[i], tp);
+                               if (!mflag && fromatty) {
+                                       ointer = interactive;
+                                       interactive = 1;
+                                       if (confirm("Continue with","mput")) {
+                                               mflag++;
+                                       }
+                                       interactive = ointer;
+                               }
+                       }
                        continue;
                }
                gargs = glob(argv[i]);
                        continue;
                }
                gargs = glob(argv[i]);
@@ -288,12 +382,27 @@ mput(argc, argv)
                                blkfree(gargs);
                        continue;
                }
                                blkfree(gargs);
                        continue;
                }
-               for (cpp = gargs; cpp && *cpp != NULL; cpp++)
-                       if (confirm(argv[0], *cpp))
-                               sendrequest("STOR", *cpp, *cpp);
+               for (cpp = gargs; cpp && *cpp != NULL; cpp++) {
+                       if (mflag && confirm(argv[0], *cpp)) {
+                               tp = (ntflag) ? dotrans(*cpp) : *cpp;
+                               tp = (mapflag) ? domap(tp) : tp;
+                               sendrequest((sunique) ? "STOU" : "STOR",
+                                          *cpp, tp);
+                               if (!mflag && fromatty) {
+                                       ointer = interactive;
+                                       interactive = 1;
+                                       if (confirm("Continue with","mput")) {
+                                               mflag++;
+                                       }
+                                       interactive = ointer;
+                               }
+                       }
+               }
                if (gargs != NULL)
                        blkfree(gargs);
        }
                if (gargs != NULL)
                        blkfree(gargs);
        }
+       (void) signal(SIGINT, oldintr);
+       mflag = 0;
 }
 
 /*
 }
 
 /*
@@ -302,9 +411,13 @@ mput(argc, argv)
 get(argc, argv)
        char *argv[];
 {
 get(argc, argv)
        char *argv[];
 {
+       int loc = 0;
 
 
-       if (argc == 2)
-               argc++, argv[2] = argv[1];
+       if (argc == 2) {
+               argc++;
+               argv[2] = argv[1];
+               loc++;
+       }
        if (argc < 2) {
                strcat(line, " ");
                printf("(remote-file) ");
        if (argc < 2) {
                strcat(line, " ");
                printf("(remote-file) ");
@@ -315,7 +428,8 @@ get(argc, argv)
        }
        if (argc < 2) {
 usage:
        }
        if (argc < 2) {
 usage:
-               printf("%s remote-file [ local-file ]\n", argv[0]);
+               printf("usage: %s remote-file [ local-file ]\n", argv[0]);
+               code = -1;
                return;
        }
        if (argc < 3) {
                return;
        }
        if (argc < 3) {
@@ -328,18 +442,67 @@ usage:
        }
        if (argc < 3) 
                goto usage;
        }
        if (argc < 3) 
                goto usage;
-       if (!globulize(&argv[2]))
+       if (!globulize(&argv[2])) {
+               code = -1;
                return;
                return;
+       }
+       if (loc && mcase) {
+               char *tp = argv[1], *tp2, tmpbuf[MAXPATHLEN];
+
+               while (*tp && !islower(*tp)) {
+                       tp++;
+               }
+               if (!*tp) {
+                       tp = argv[2];
+                       tp2 = tmpbuf;
+                       while ((*tp2 = *tp) != NULL) {
+                               if (isupper(*tp2)) {
+                                       *tp2 = 'a' + *tp2 - 'A';
+                               }
+                               tp++;
+                               tp2++;
+                       }
+                       argv[2] = tmpbuf;
+               }
+       }
+       if (loc && ntflag) {
+               argv[2] = dotrans(argv[2]);
+       }
+       if (loc && mapflag) {
+               argv[2] = domap(argv[2]);
+       }
        recvrequest("RETR", argv[2], argv[1], "w");
 }
 
        recvrequest("RETR", argv[2], argv[1], "w");
 }
 
+mabort()
+{
+       int ointer;
+       extern jmp_buf jabort;
+
+       printf("\n");
+       (void) fflush(stdout);
+       if (mflag && fromatty) {
+               ointer = interactive;
+               interactive = 1;
+               if (confirm("Continue with", mname)) {
+                       interactive = ointer;
+                       longjmp(jabort,0);
+               }
+               interactive = ointer;
+       }
+       mflag = 0;
+       longjmp(jabort,0);
+}
+
 /*
  * Get multiple files.
  */
 mget(argc, argv)
        char *argv[];
 {
 /*
  * Get multiple files.
  */
 mget(argc, argv)
        char *argv[];
 {
-       char *cp;
+       char *cp, *tp, *tp2, tmpbuf[MAXPATHLEN];
+       int ointer, (*oldintr)(), mabort();
+       extern jmp_buf jabort;
 
        if (argc < 2) {
                strcat(line, " ");
 
        if (argc < 2) {
                strcat(line, " ");
@@ -350,16 +513,62 @@ mget(argc, argv)
                argv = margv;
        }
        if (argc < 2) {
                argv = margv;
        }
        if (argc < 2) {
-               printf("%s remote-files\n", argv[0]);
+               printf("usage:%s remote-files\n", argv[0]);
+               code = -1;
                return;
        }
                return;
        }
-       while ((cp = remglob(argc, argv)) != NULL)
-               if (confirm(argv[0], cp))
-                       recvrequest("RETR", cp, cp, "w");
+       mname = argv[0];
+       mflag = 1;
+       oldintr = signal(SIGINT,mabort);
+       (void) setjmp(jabort);
+       while ((cp = remglob(argc, argv, proxy)) != NULL) {
+               if (*cp == '\0') {
+                       mflag = 0;
+                       continue;
+               }
+               if (mflag && confirm(argv[0], cp)) {
+                       tp = cp;
+                       if (mcase) {
+                               while (*tp && !islower(*tp)) {
+                                       tp++;
+                               }
+                               if (!*tp) {
+                                       tp = cp;
+                                       tp2 = tmpbuf;
+                                       while ((*tp2 = *tp) != NULL) {
+                                               if (isupper(*tp2)) {
+                                                       *tp2 = 'a' + *tp2 - 'A';
+                                               }
+                                               tp++;
+                                               tp2++;
+                                       }
+                               }
+                               tp = tmpbuf;
+                       }
+                       if (ntflag) {
+                               tp = dotrans(tp);
+                       }
+                       if (mapflag) {
+                               tp = domap(tp);
+                       }
+                       recvrequest("RETR", tp, cp, "w");
+                       if (!mflag && fromatty) {
+                               ointer = interactive;
+                               interactive = 1;
+                               if (confirm("Continue with","mget")) {
+                                       mflag++;
+                               }
+                               interactive = ointer;
+                       }
+               }
+       }
+       (void) signal(SIGINT,oldintr);
+       mflag = 0;
 }
 
 char *
 }
 
 char *
-remglob(argc, argv)
+remglob(argc, argv, doswitch)
+       int argc, doswitch;
        char *argv[];
 {
        char temp[16];
        char *argv[];
 {
        char temp[16];
@@ -369,6 +578,18 @@ remglob(argc, argv)
        int oldverbose, oldhash;
        char *cp, *mode;
 
        int oldverbose, oldhash;
        char *cp, *mode;
 
+       if (!mflag) {
+               if (!doglob) {
+                       args = NULL;
+               }
+               else {
+                       if (ftemp) {
+                               fclose(ftemp);
+                               ftemp = NULL;
+                       }
+               }
+               return(NULL);
+       }
        if (!doglob) {
                if (args == NULL)
                        args = argv;
        if (!doglob) {
                if (args == NULL)
                        args = argv;
@@ -381,8 +602,14 @@ remglob(argc, argv)
                mktemp(temp);
                oldverbose = verbose, verbose = 0;
                oldhash = hash, hash = 0;
                mktemp(temp);
                oldverbose = verbose, verbose = 0;
                oldhash = hash, hash = 0;
+               if (doswitch) {
+                       pswitch(!proxy);
+               }
                for (mode = "w"; *++argv != NULL; mode = "a")
                        recvrequest ("NLST", temp, *argv, mode);
                for (mode = "w"; *++argv != NULL; mode = "a")
                        recvrequest ("NLST", temp, *argv, mode);
+               if (doswitch) {
+                       pswitch(!proxy);
+               }
                verbose = oldverbose; hash = oldhash;
                ftemp = fopen(temp, "r");
                unlink(temp);
                verbose = oldverbose; hash = oldhash;
                ftemp = fopen(temp, "r");
                unlink(temp);
@@ -414,18 +641,51 @@ onoff(bool)
 status(argc, argv)
        char *argv[];
 {
 status(argc, argv)
        char *argv[];
 {
+       int i;
 
        if (connected)
                printf("Connected to %s.\n", hostname);
        else
                printf("Not connected.\n");
 
        if (connected)
                printf("Connected to %s.\n", hostname);
        else
                printf("Not connected.\n");
+       if (!proxy) {
+               pswitch(1);
+               if (connected) {
+                       printf("Connected for proxy commands to %s.\n", hostname);
+               }
+               else {
+                       printf("No proxy connection.\n");
+               }
+               pswitch(0);
+       }
        printf("Mode: %s; Type: %s; Form: %s; Structure: %s\n",
                modename, typename, formname, structname);
        printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s\n", 
                onoff(verbose), onoff(bell), onoff(interactive),
                onoff(doglob));
        printf("Mode: %s; Type: %s; Form: %s; Structure: %s\n",
                modename, typename, formname, structname);
        printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s\n", 
                onoff(verbose), onoff(bell), onoff(interactive),
                onoff(doglob));
+       printf("Store unique: %s; Receive unique: %s\n", onoff(sunique),
+               onoff(runique));
+       printf("Case: %s; CR stripping: %s\n",onoff(mcase),onoff(crflag));
+       if (ntflag) {
+               printf("Ntrans: (in) %s (out) %s\n", ntin,ntout);
+       }
+       else {
+               printf("Ntrans: off\n");
+       }
+       if (mapflag) {
+               printf("Nmap: (in) %s (out) %s\n", mapin, mapout);
+       }
+       else {
+               printf("Nmap: off\n");
+       }
        printf("Hash mark printing: %s; Use of PORT cmds: %s\n",
                onoff(hash), onoff(sendport));
        printf("Hash mark printing: %s; Use of PORT cmds: %s\n",
                onoff(hash), onoff(sendport));
+       if (macnum > 0) {
+               printf("Macros:\n");
+               for (i=0; i<macnum; i++) {
+                       printf("\t%s\n",macros[i].mac_name);
+               }
+       }
+       code = 0;
 }
 
 /*
 }
 
 /*
@@ -437,6 +697,7 @@ setbell()
 
        bell = !bell;
        printf("Bell mode %s.\n", onoff(bell));
 
        bell = !bell;
        printf("Bell mode %s.\n", onoff(bell));
+       code = bell;
 }
 
 /*
 }
 
 /*
@@ -448,6 +709,7 @@ settrace()
 
        trace = !trace;
        printf("Packet tracing %s.\n", onoff(trace));
 
        trace = !trace;
        printf("Packet tracing %s.\n", onoff(trace));
+       code = trace;
 }
 
 /*
 }
 
 /*
@@ -459,6 +721,7 @@ sethash()
 
        hash = !hash;
        printf("Hash mark printing %s", onoff(hash));
 
        hash = !hash;
        printf("Hash mark printing %s", onoff(hash));
+       code = hash;
        if (hash)
                printf(" (%d bytes/hash mark)", BUFSIZ);
        printf(".\n");
        if (hash)
                printf(" (%d bytes/hash mark)", BUFSIZ);
        printf(".\n");
@@ -473,6 +736,7 @@ setverbose()
 
        verbose = !verbose;
        printf("Verbose mode %s.\n", onoff(verbose));
 
        verbose = !verbose;
        printf("Verbose mode %s.\n", onoff(verbose));
+       code = verbose;
 }
 
 /*
 }
 
 /*
@@ -484,6 +748,7 @@ setport()
 
        sendport = !sendport;
        printf("Use of PORT cmds %s.\n", onoff(sendport));
 
        sendport = !sendport;
        printf("Use of PORT cmds %s.\n", onoff(sendport));
+       code = sendport;
 }
 
 /*
 }
 
 /*
@@ -496,6 +761,7 @@ setprompt()
 
        interactive = !interactive;
        printf("Interactive mode %s.\n", onoff(interactive));
 
        interactive = !interactive;
        printf("Interactive mode %s.\n", onoff(interactive));
+       code = interactive;
 }
 
 /*
 }
 
 /*
@@ -508,6 +774,7 @@ setglob()
        
        doglob = !doglob;
        printf("Globbing %s.\n", onoff(doglob));
        
        doglob = !doglob;
        printf("Globbing %s.\n", onoff(doglob));
+       code = doglob;
 }
 
 /*
 }
 
 /*
@@ -524,6 +791,7 @@ setdebug(argc, argv)
                val = atoi(argv[1]);
                if (val < 0) {
                        printf("%s: bad debugging value.\n", argv[1]);
                val = atoi(argv[1]);
                if (val < 0) {
                        printf("%s: bad debugging value.\n", argv[1]);
+                       code = -1;
                        return;
                }
        } else
                        return;
                }
        } else
@@ -534,6 +802,7 @@ setdebug(argc, argv)
        else
                options &= ~SO_DEBUG;
        printf("Debugging %s (debug=%d).\n", onoff(debug), debug);
        else
                options &= ~SO_DEBUG;
        printf("Debugging %s (debug=%d).\n", onoff(debug), debug);
+       code = debug > 0;
 }
 
 /*
 }
 
 /*
@@ -553,7 +822,8 @@ cd(argc, argv)
                argv = margv;
        }
        if (argc < 2) {
                argv = margv;
        }
        if (argc < 2) {
-               printf("%s remote-directory\n", argv[0]);
+               printf("usage:%s remote-directory\n", argv[0]);
+               code = -1;
                return;
        }
        (void) command("CWD %s", argv[1]);
                return;
        }
        (void) command("CWD %s", argv[1]);
@@ -571,16 +841,21 @@ lcd(argc, argv)
        if (argc < 2)
                argc++, argv[1] = home;
        if (argc != 2) {
        if (argc < 2)
                argc++, argv[1] = home;
        if (argc != 2) {
-               printf("%s local-directory\n", argv[0]);
+               printf("usage:%s local-directory\n", argv[0]);
+               code = -1;
                return;
        }
                return;
        }
-       if (!globulize(&argv[1]))
+       if (!globulize(&argv[1])) {
+               code = -1;
                return;
                return;
+       }
        if (chdir(argv[1]) < 0) {
                perror(argv[1]);
        if (chdir(argv[1]) < 0) {
                perror(argv[1]);
+               code = -1;
                return;
        }
        printf("Local directory now %s\n", getwd(buf));
                return;
        }
        printf("Local directory now %s\n", getwd(buf));
+       code = 0;
 }
 
 /*
 }
 
 /*
@@ -599,7 +874,8 @@ delete(argc, argv)
                argv = margv;
        }
        if (argc < 2) {
                argv = margv;
        }
        if (argc < 2) {
-               printf("%s remote-file\n", argv[0]);
+               printf("usage:%s remote-file\n", argv[0]);
+               code = -1;
                return;
        }
        (void) command("DELE %s", argv[1]);
                return;
        }
        (void) command("DELE %s", argv[1]);
@@ -612,6 +888,8 @@ mdelete(argc, argv)
        char *argv[];
 {
        char *cp;
        char *argv[];
 {
        char *cp;
+       int ointer, (*oldintr)(), mabort();
+       extern jmp_buf jabort;
 
        if (argc < 2) {
                strcat(line, " ");
 
        if (argc < 2) {
                strcat(line, " ");
@@ -622,12 +900,33 @@ mdelete(argc, argv)
                argv = margv;
        }
        if (argc < 2) {
                argv = margv;
        }
        if (argc < 2) {
-               printf("%s remote-files\n", argv[0]);
+               printf("usage:%s remote-files\n", argv[0]);
+               code = -1;
                return;
        }
                return;
        }
-       while ((cp = remglob(argc, argv)) != NULL)
-               if (confirm(argv[0], cp))
+       mname = argv[0];
+       mflag = 1;
+       oldintr = signal(SIGINT, mabort);
+       (void) setjmp(jabort);
+       while ((cp = remglob(argc, argv, 0)) != NULL) {
+               if (*cp == '\0') {
+                       mflag = 0;
+                       continue;
+               }
+               if (mflag && confirm(argv[0], cp)) {
                        (void) command("DELE %s", cp);
                        (void) command("DELE %s", cp);
+                       if (!mflag && fromatty) {
+                               ointer = interactive;
+                               interactive = 1;
+                               if (confirm("Continue with", "mdelete")) {
+                                       mflag++;
+                               }
+                               interactive = ointer;
+                       }
+               }
+       }
+       (void) signal(SIGINT, oldintr);
+       mflag = 0;
 }
 
 /*
 }
 
 /*
@@ -648,6 +947,7 @@ renamefile(argc, argv)
        if (argc < 2) {
 usage:
                printf("%s from-name to-name\n", argv[0]);
        if (argc < 2) {
 usage:
                printf("%s from-name to-name\n", argv[0]);
+               code = -1;
                return;
        }
        if (argc < 3) {
                return;
        }
        if (argc < 3) {
@@ -679,11 +979,14 @@ ls(argc, argv)
                argc++, argv[2] = "-";
        if (argc > 3) {
                printf("usage: %s remote-directory local-file\n", argv[0]);
                argc++, argv[2] = "-";
        if (argc > 3) {
                printf("usage: %s remote-directory local-file\n", argv[0]);
+               code = -1;
                return;
        }
        cmd = argv[0][0] == 'l' ? "NLST" : "LIST";
                return;
        }
        cmd = argv[0][0] == 'l' ? "NLST" : "LIST";
-       if (strcmp(argv[2], "-") && !globulize(&argv[2]))
+       if (strcmp(argv[2], "-") && !globulize(&argv[2])) {
+               code = -1;
                return;
                return;
+       }
        recvrequest(cmd, argv[2], argv[1], "w");
 }
 
        recvrequest(cmd, argv[2], argv[1], "w");
 }
 
@@ -694,7 +997,9 @@ ls(argc, argv)
 mls(argc, argv)
        char *argv[];
 {
 mls(argc, argv)
        char *argv[];
 {
-       char *cmd, *mode, *cp, *dest;
+       char *cmd, mode[1], *dest;
+       int ointer, i, (*oldintr)(), mabort();
+       extern jmp_buf jabort;
 
        if (argc < 2) {
                strcat(line, " ");
 
        if (argc < 2) {
                strcat(line, " ");
@@ -713,18 +1018,36 @@ mls(argc, argv)
                argv = margv;
        }
        if (argc < 3) {
                argv = margv;
        }
        if (argc < 3) {
-               printf("%s remote-files local-file\n", argv[0]);
+               printf("usage:%s remote-files local-file\n", argv[0]);
+               code = -1;
                return;
        }
        dest = argv[argc - 1];
        argv[argc - 1] = NULL;
                return;
        }
        dest = argv[argc - 1];
        argv[argc - 1] = NULL;
-       if (strcmp(dest, "-"))
-               if (!globulize(&dest) || !confirm("local-file", dest))
+       if (strcmp(dest, "-") && *dest != '|')
+               if (!globulize(&dest) || !confirm("output to local-file:", dest)) {
+                       code = -1;
                        return;
                        return;
+       }
        cmd = argv[0][1] == 'l' ? "NLST" : "LIST";
        cmd = argv[0][1] == 'l' ? "NLST" : "LIST";
-       for (mode = "w"; cp = remglob(argc, argv); mode = "a")
-               if (confirm(argv[0], cp))
-                       recvrequest(cmd, dest, cp, mode);
+       mname = argv[0];
+       mflag = 1;
+       oldintr = signal(SIGINT, mabort);
+       (void) setjmp(jabort);
+       for (i = 1; mflag && i < argc-1; ++i) {
+               *mode = (i == 1) ? 'w' : 'a';
+               recvrequest(cmd, dest, argv[i], mode);
+               if (!mflag && fromatty) {
+                       ointer = interactive;
+                       interactive = 1;
+                       if (confirm("Continue with", argv[0])) {
+                               mflag ++;
+                       }
+                       interactive = ointer;
+               }
+       }
+       (void) signal(SIGINT, oldintr);
+       mflag = 0;
 }
 
 /*
 }
 
 /*
@@ -733,9 +1056,8 @@ mls(argc, argv)
 shell(argc, argv)
        char *argv[];
 {
 shell(argc, argv)
        char *argv[];
 {
-       int pid, status, (*old1)(), (*old2)();
-       char shellnam[40], *shell, *namep;
-       char **cpp, **gargs;
+       int i, pid, status, (*old1)(), (*old2)();
+       char shellnam[40], *shell, *namep; 
 
        old1 = signal (SIGINT, SIG_IGN);
        old2 = signal (SIGQUIT, SIG_IGN);
 
        old1 = signal (SIGINT, SIG_IGN);
        old2 = signal (SIGQUIT, SIG_IGN);
@@ -750,35 +1072,36 @@ shell(argc, argv)
                namep = rindex(shell,'/');
                if (namep == NULL)
                        namep = shell;
                namep = rindex(shell,'/');
                if (namep == NULL)
                        namep = shell;
-               if (argc <= 1) {
-                       if (debug) {
-                               printf ("%s\n", shell);
-                               fflush (stdout);
-                       }
-                       execl(shell, shell, (char *)0);
-               } else {
-                       char *args[4];  /* "sh" "-c" <command> NULL */
-
-                       args[0] = shell;
-                       args[1] = "-c";
-                       args[2] = argv[1];
-                       args[3] = NULL;
-                       if (debug) {
-                               printf("%s -c %s\n", shell, argv[1]);
-                               fflush(stdout);
-                       }
-                       execv(shell, args);
+               strcpy(shellnam,"-");
+               strcat(shellnam, ++namep);
+               if (strcmp(namep, "sh") != 0)
+                       shellnam[0] = '+';
+               if (debug) {
+                       printf ("%s\n", shell);
+                       fflush (stdout);
+               }
+               if (argc > 1) {
+                       execl(shell,shellnam,"-c",altarg,(char *)0);
+               }
+               else {
+                       execl(shell,shellnam,(char *)0);
                }
                perror(shell);
                }
                perror(shell);
+               code = -1;
                exit(1);
                exit(1);
-       }
+               }
        if (pid > 0)
                while (wait(&status) != pid)
                        ;
        signal(SIGINT, old1);
        signal(SIGQUIT, old2);
        if (pid > 0)
                while (wait(&status) != pid)
                        ;
        signal(SIGINT, old1);
        signal(SIGQUIT, old2);
-       if (pid == -1)
+       if (pid == -1) {
                perror("Try again later");
                perror("Try again later");
+               code = -1;
+       }
+       else {
+               code = 0;
+       }
        return (0);
 }
 
        return (0);
 }
 
@@ -790,7 +1113,7 @@ user(argc, argv)
        char **argv;
 {
        char acct[80], *getpass();
        char **argv;
 {
        char acct[80], *getpass();
-       int n;
+       int n, aflag = 0;
 
        if (argc < 2) {
                strcat(line, " ");
 
        if (argc < 2) {
                strcat(line, " ");
@@ -802,6 +1125,7 @@ user(argc, argv)
        }
        if (argc > 4) {
                printf("usage: %s username [password] [account]\n", argv[0]);
        }
        if (argc > 4) {
                printf("usage: %s username [password] [account]\n", argv[0]);
+               code = -1;
                return (0);
        }
        n = command("USER %s", argv[1]);
                return (0);
        }
        n = command("USER %s", argv[1]);
@@ -817,12 +1141,16 @@ user(argc, argv)
                        acct[strlen(acct) - 1] = '\0';
                        argv[3] = acct; argc++;
                }
                        acct[strlen(acct) - 1] = '\0';
                        argv[3] = acct; argc++;
                }
-               n = command("ACCT %s", acct);
+               n = command("ACCT %s", argv[3]);
+               aflag++;
        }
        if (n != COMPLETE) {
                fprintf(stderr, "Login failed.\n");
                return (0);
        }
        }
        if (n != COMPLETE) {
                fprintf(stderr, "Login failed.\n");
                return (0);
        }
+       if (!aflag && argc == 4) {
+               (void) command("ACCT %s", argv[3]);
+       }
        return (1);
 }
 
        return (1);
 }
 
@@ -833,7 +1161,7 @@ user(argc, argv)
 pwd()
 {
 
 pwd()
 {
 
-       (void) command("XPWD");
+       (void) command("PWD");
 }
 
 /*
 }
 
 /*
@@ -852,10 +1180,11 @@ makedir(argc, argv)
                argv = margv;
        }
        if (argc < 2) {
                argv = margv;
        }
        if (argc < 2) {
-               printf("%s directory-name\n", argv[0]);
+               printf("usage: %s directory-name\n", argv[0]);
+               code = -1;
                return;
        }
                return;
        }
-       (void) command("XMKD %s", argv[1]);
+       (void) command("MKD %s", argv[1]);
 }
 
 /*
 }
 
 /*
@@ -874,10 +1203,11 @@ removedir(argc, argv)
                argv = margv;
        }
        if (argc < 2) {
                argv = margv;
        }
        if (argc < 2) {
-               printf("%s directory-name\n", argv[0]);
+               printf("usage: %s directory-name\n", argv[0]);
+               code = -1;
                return;
        }
                return;
        }
-       (void) command("XRMD %s", argv[1]);
+       (void) command("RMD %s", argv[1]);
 }
 
 /*
 }
 
 /*
@@ -899,6 +1229,7 @@ quote(argc, argv)
        }
        if (argc < 2) {
                printf("usage: %s line-to-send\n", argv[0]);
        }
        if (argc < 2) {
                printf("usage: %s line-to-send\n", argv[0]);
+               code = -1;
                return;
        }
        strcpy(buf, argv[1]);
                return;
        }
        strcpy(buf, argv[1]);
@@ -906,7 +1237,9 @@ quote(argc, argv)
                strcat(buf, " ");
                strcat(buf, argv[i]);
        }
                strcat(buf, " ");
                strcat(buf, argv[i]);
        }
-       (void) command(buf);
+       if (command(buf) == PRELIM) {
+               while (getreply(0) == PRELIM);
+       }
 }
 
 /*
 }
 
 /*
@@ -931,6 +1264,10 @@ quit()
 
        if (connected)
                disconnect();
 
        if (connected)
                disconnect();
+       pswitch(1);
+       if (connected) {
+               disconnect();
+       }
        exit(0);
 }
 
        exit(0);
 }
 
@@ -945,10 +1282,15 @@ disconnect()
        if (!connected)
                return;
        (void) command("QUIT");
        if (!connected)
                return;
        (void) command("QUIT");
-       (void) fclose(cout);
+       if (cout) {
+               (void) fclose(cout);
+       }
        cout = NULL;
        connected = 0;
        data = -1;
        cout = NULL;
        connected = 0;
        data = -1;
+       if (!proxy) {
+               macnum = 0;
+       }
 }
 
 confirm(cmd, file)
 }
 
 confirm(cmd, file)
@@ -1000,3 +1342,470 @@ globulize(cpp)
        }
        return (1);
 }
        }
        return (1);
 }
+
+account(argc,argv)
+
+       int argc;
+       char **argv;
+{
+       char acct[50], *getpass(), *ap;
+
+       if (argc > 1) {
+               ++argv;
+               --argc;
+               (void) strncpy(acct,*argv,49);
+               acct[50] = '\0';
+               while (argc > 1) {
+                       --argc;
+                       ++argv;
+                       (void) strncat(acct,*argv, 49-strlen(acct));
+               }
+               ap = acct;
+       }
+       else {
+               ap = getpass("Account:");
+       }
+       (void) command("ACCT %s", ap);
+}
+
+jmp_buf abortprox;
+
+proxabort()
+{
+       extern int proxy;
+
+       if (!proxy) {
+               pswitch(1);
+       }
+       if (connected) {
+               proxflag = 1;
+       }
+       else {
+               proxflag = 0;
+       }
+       pswitch(0);
+       longjmp(abortprox,1);
+}
+
+doproxy(argc,argv)
+       int argc;
+       char *argv[];
+{
+       int (*oldintr)(), proxabort();
+       register struct cmd *c;
+       struct cmd *getcmd();
+       extern struct cmd cmdtab[];
+       extern jmp_buf abortprox;
+
+       if (argc < 2) {
+               strcat(line, " ");
+               printf("(command) ");
+               gets(&line[strlen(line)]);
+               makeargv();
+               argc = margc;
+               argv = margv;
+       }
+       if (argc < 2) {
+               printf("usage:%s command\n", argv[0]);
+               code = -1;
+               return;
+       }
+       c = getcmd(argv[1]);
+       if (c == (struct cmd *) -1) {
+               printf("?Ambiguous command\n");
+               fflush(stdout);
+               code = -1;
+               return;
+       }
+       if (c == 0) {
+               printf("?Invalid command\n");
+               fflush(stdout);
+               code = -1;
+               return;
+       }
+       if (!c->c_proxy) {
+               printf("?Invalid proxy command\n");
+               fflush(stdout);
+               code = -1;
+               return;
+       }
+       if (setjmp(abortprox)) {
+               code = -1;
+               return;
+       }
+       oldintr = signal(SIGINT, proxabort);
+       pswitch(1);
+       if (c->c_conn && !connected) {
+               printf("Not connected\n");
+               fflush(stdout);
+               pswitch(0);
+               (void) signal(SIGINT, oldintr);
+               code = -1;
+               return;
+       }
+       (*c->c_handler)(argc-1, argv+1);
+       if (connected) {
+               proxflag = 1;
+       }
+       else {
+               proxflag = 0;
+       }
+       pswitch(0);
+       (void) signal(SIGINT, oldintr);
+}
+
+setcase()
+{
+       mcase = !mcase;
+       printf("Case mapping %s.\n", onoff(mcase));
+       code = mcase;
+}
+
+setcr()
+{
+       crflag = !crflag;
+       printf("Carriage Return stripping %s.\n", onoff(crflag));
+       code = crflag;
+}
+
+setntrans(argc,argv)
+       int argc;
+       char *argv[];
+{
+       if (argc == 1) {
+               ntflag = 0;
+               printf("Ntrans off.\n");
+               code = ntflag;
+               return;
+       }
+       ntflag++;
+       code = ntflag;
+       (void) strncpy(ntin, argv[1], 16);
+       ntin[16] = '\0';
+       if (argc == 2) {
+               ntout[0] = '\0';
+               return;
+       }
+       (void) strncpy(ntout, argv[2], 16);
+       ntout[16] = '\0';
+}
+
+char *
+dotrans(name)
+       char *name;
+{
+       static char new[MAXPATHLEN];
+       char *cp1, *cp2 = new;
+       register int i, ostop, found;
+
+       for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++);
+       for (cp1 = name; *cp1; cp1++) {
+               found = 0;
+               for (i = 0; *(ntin + i) && i < 16; i++) {
+                       if (*cp1 == *(ntin + i)) {
+                               found++;
+                               if (i < ostop) {
+                                       *cp2++ = *(ntout + i);
+                               }
+                               break;
+                       }
+               }
+               if (!found) {
+                       *cp2++ = *cp1;
+               }
+       }
+       *cp2 = '\0';
+       return(new);
+}
+
+setnmap(argc, argv)
+       int argc;
+       char *argv[];
+{
+       char *cp;
+
+       if (argc == 1) {
+               mapflag = 0;
+               printf("Nmap off.\n");
+               code = mapflag;
+               return;
+       }
+       if (argc < 3) {
+               strcat(line, " ");
+               printf("(mapout) ");
+               gets(&line[strlen(line)]);
+               makeargv();
+               argc = margc;
+               argv = margv;
+       }
+       if (argc < 3) {
+               printf("Usage: %s [mapin mapout]\n",argv[0]);
+               code = -1;
+               return;
+       }
+       mapflag = 1;
+       code = 1;
+       cp = index(altarg, ' ');
+       if (proxy) {
+               while(*++cp == ' ');
+               altarg = cp;
+               cp = index(altarg, ' ');
+       }
+       *cp = '\0';
+       (void) strncpy(mapin, altarg, MAXPATHLEN - 1);
+       while (*++cp == ' ');
+       (void) strncpy(mapout, cp, MAXPATHLEN - 1);
+}
+
+char *
+domap(name)
+       char *name;
+{
+       static char new[MAXPATHLEN];
+       register char *cp1 = name, *cp2 = mapin;
+       char *tp[9], *te[9];
+       int i, toks[9], toknum, match = 1;
+
+       for (i=0; i < 9; ++i) {
+               toks[i] = 0;
+       }
+       while (match && *cp1 && *cp2) {
+               switch (*cp2) {
+                       case '\\':
+                               if (*++cp2 != *cp1) {
+                                       match = 0;
+                               }
+                               break;
+                       case '$':
+                               if (*(cp2+1) >= '1' && (*cp2+1) <= '9') {
+                                       if (*cp1 != *(++cp2+1)) {
+                                               toks[toknum = *cp2 - '1']++;
+                                               tp[toknum] = cp1;
+                                               while (*++cp1 && *(cp2+1)
+                                                       != *cp1);
+                                               te[toknum] = cp1;
+                                       }
+                                       cp2++;
+                                       break;
+                               }
+                               /* intentional drop through */
+                       default:
+                               if (*cp2 != *cp1) {
+                                       match = 0;
+                               }
+                               break;
+               }
+               if (*cp1) {
+                       cp1++;
+               }
+               if (*cp2) {
+                       cp2++;
+               }
+       }
+       cp1 = new;
+       *cp1 = '\0';
+       cp2 = mapout;
+       while (*cp2) {
+               match = 0;
+               switch (*cp2) {
+                       case '\\':
+                               if (*(cp2 + 1)) {
+                                       *cp1++ = *++cp2;
+                               }
+                               break;
+                       case '[':
+LOOP:
+                               if (*++cp2 == '$' && isdigit(*(cp2+1))) { 
+                                       if (*++cp2 == '0') {
+                                               char *cp3 = name;
+
+                                               while (*cp3) {
+                                                       *cp1++ = *cp3++;
+                                               }
+                                               match = 1;
+                                       }
+                                       else if (toks[toknum = *cp2 - '1']) {
+                                               char *cp3 = tp[toknum];
+
+                                               while (cp3 != te[toknum]) {
+                                                       *cp1++ = *cp3++;
+                                               }
+                                               match = 1;
+                                       }
+                               }
+                               else {
+                                       while (*cp2 && *cp2 != ',' && 
+                                           *cp2 != ']') {
+                                               if (*cp2 == '\\') {
+                                                       cp2++;
+                                               }
+                                               else if (*cp2 == '$' &&
+                                                       isdigit(*(cp2+1))) {
+                                                       if (*++cp2 == '0') {
+                                                          char *cp3 = name;
+
+                                                          while (*cp3) {
+                                                               *cp1++ = *cp3++;
+                                                          }
+                                                       }
+                                                       else if (toks[toknum =
+                                                           *cp2 - '1']) {
+                                                          char *cp3=tp[toknum];
+
+                                                          while (cp3 !=
+                                                                 te[toknum]) {
+                                                               *cp1++ = *cp3++;
+                                                          }
+                                                       }
+                                               }
+                                               else if (*cp2) {
+                                                       *cp1++ = *cp2++;
+                                               }
+                                       }
+                                       if (!*cp2) {
+                                               printf("nmap: unbalanced brackets\n");
+                                               return(name);
+                                       }
+                                       match = 1;
+                                       cp2--;
+                               }
+                               if (match) {
+                                       while (*++cp2 && *cp2 != ']') {
+                                             if (*cp2 == '\\' && *(cp2 + 1)) {
+                                                       cp2++;
+                                             }
+                                       }
+                                       if (!*cp2) {
+                                               printf("nmap: unbalanced brackets\n");
+                                               return(name);
+                                       }
+                                       break;
+                               }
+                               switch (*++cp2) {
+                                       case ',':
+                                               goto LOOP;
+                                       case ']':
+                                               break;
+                                       default:
+                                               cp2--;
+                                               goto LOOP;
+                               }
+                               break;
+                       case '$':
+                               if (isdigit(*(cp2 + 1))) {
+                                       if (*++cp2 == '0') {
+                                               char *cp3 = name;
+
+                                               while (*cp3) {
+                                                       *cp1++ = *cp3++;
+                                               }
+                                       }
+                                       else if (toks[toknum = *cp2 - '1']) {
+                                               char *cp3 = tp[toknum];
+
+                                               while (cp3 != te[toknum]) {
+                                                       *cp1++ = *cp3++;
+                                               }
+                                       }
+                                       break;
+                               }
+                               /* intentional drop through */
+                       default:
+                               *cp1++ = *cp2;
+                               break;
+               }
+               cp2++;
+       }
+       *cp1 = '\0';
+       if (!*new) {
+               return(name);
+       }
+       return(new);
+}
+
+setsunique()
+{
+       sunique = !sunique;
+       printf("Store unique %s.\n", onoff(sunique));
+       code = sunique;
+}
+
+setrunique()
+{
+       runique = !runique;
+       printf("Receive unique %s.\n", onoff(runique));
+       code = runique;
+}
+
+/* change directory to perent directory */
+cdup()
+{
+       (void) command("CDUP");
+}
+
+macdef(argc, argv)
+       int argc;
+       char *argv[];
+{
+       char *tmp;
+       int c;
+
+       if (macnum == 16) {
+               printf("Limit of 16 macros have already been defined\n");
+               code = -1;
+               return;
+       }
+       if (argc < 2) {
+               strcat(line, " ");
+               printf("(macro name) ");
+               gets(&line[strlen(line)]);
+               makeargv();
+               argc = margc;
+               argv = margv;
+       }
+       if (argc != 2) {
+               printf("Usage: %s macro_name\n",argv[0]);
+               code = -1;
+               return;
+       }
+       if (interactive) {
+               printf("Enter macro line by line, terminating it with a null line\n");
+       }
+       strncpy(macros[macnum].mac_name, argv[1], 8);
+       if (macnum == 0) {
+               macros[macnum].mac_start = macbuf;
+       }
+       else {
+               macros[macnum].mac_start = macros[macnum - 1].mac_end + 1;
+       }
+       tmp = macros[macnum].mac_start;
+       while (tmp != macbuf+4096) {
+               if ((c = getchar()) == EOF) {
+                       printf("macdef:end of file encountered\n");
+                       code = -1;
+                       return;
+               }
+               if ((*tmp = c) == '\n') {
+                       if (tmp == macros[macnum].mac_start) {
+                               macros[macnum++].mac_end = tmp;
+                               code = 0;
+                               return;
+                       }
+                       if (*(tmp-1) == '\0') {
+                               macros[macnum++].mac_end = tmp - 1;
+                               code = 0;
+                               return;
+                       }
+                       *tmp = '\0';
+               }
+               tmp++;
+       }
+       while (1) {
+               while ((c = getchar()) != '\n' && c != EOF);
+               if (c == EOF || getchar() == '\n') {
+                       printf("Macro not defined - 4k buffer exceeded\n");
+                       code = -1;
+                       return;
+               }
+       }
+}
index f5dd29a..23078b7 100644 (file)
@@ -1,11 +1,11 @@
 /*
 /*
- * Copyright (c) 1980 Regents of the University of California.
+ * Copyright (c) 1985 Regents of the University of California.
  * All rights reserved.  The Berkeley software License Agreement
  * specifies the terms and conditions for redistribution.
  */
 
 #ifndef lint
  * All rights reserved.  The Berkeley software License Agreement
  * specifies the terms and conditions for redistribution.
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)cmdtab.c   5.2 (Berkeley) %G%";
+static char sccsid[] = "@(#)cmdtab.c   5.3 (Berkeley) %G%";
 #endif not lint
 
 #include "ftp_var.h"
 #endif not lint
 
 #include "ftp_var.h"
@@ -22,24 +22,32 @@ int cd(), lcd(), delete(), mdelete(), user();
 int    ls(), mls(), get(), mget(), help(), append(), put(), mput();
 int    quit(), renamefile(), status();
 int    quote(), rmthelp(), shell();
 int    ls(), mls(), get(), mget(), help(), append(), put(), mput();
 int    quit(), renamefile(), status();
 int    quote(), rmthelp(), shell();
-int    pwd(), makedir(), removedir();
+int    pwd(), makedir(), removedir(), setcr();
+int    account(), doproxy(), reset(), setcase(), setntrans(), setnmap();
+int    setsunique(), setrunique(), cdup(), macdef(), domacro();
 
 
+char   accounthelp[] = "send account command to remote server";
 char   appendhelp[] =  "append to a file";
 char   asciihelp[] =   "set ascii transfer type";
 char   beephelp[] =    "beep when command completed";
 char   binaryhelp[] =  "set binary transfer type";
 char   appendhelp[] =  "append to a file";
 char   asciihelp[] =   "set ascii transfer type";
 char   beephelp[] =    "beep when command completed";
 char   binaryhelp[] =  "set binary transfer type";
+char   casehelp[] =    "toggle mget upper/lower case id mapping";
 char   cdhelp[] =      "change remote working directory";
 char   cdhelp[] =      "change remote working directory";
+char   cduphelp[] =    "change remote working directory to parent directory";
 char   connecthelp[] = "connect to remote tftp";
 char   connecthelp[] = "connect to remote tftp";
+char   crhelp[] =      "toggle carriage return stripping on ascii gets";
 char   deletehelp[] =  "delete remote file";
 char   debughelp[] =   "toggle/set debugging mode";
 char   dirhelp[] =     "list contents of remote directory";
 char   disconhelp[] =  "terminate ftp session";
 char   deletehelp[] =  "delete remote file";
 char   debughelp[] =   "toggle/set debugging mode";
 char   dirhelp[] =     "list contents of remote directory";
 char   disconhelp[] =  "terminate ftp session";
+char   domachelp[] =   "execute macro";
 char   formhelp[] =    "set file transfer format";
 char   globhelp[] =    "toggle metacharacter expansion of local file names";
 char   hashhelp[] =    "toggle printing `#' for each buffer transferred";
 char   helphelp[] =    "print local help information";
 char   lcdhelp[] =     "change local working directory";
 char   lshelp[] =      "nlist contents of remote directory";
 char   formhelp[] =    "set file transfer format";
 char   globhelp[] =    "toggle metacharacter expansion of local file names";
 char   hashhelp[] =    "toggle printing `#' for each buffer transferred";
 char   helphelp[] =    "print local help information";
 char   lcdhelp[] =     "change local working directory";
 char   lshelp[] =      "nlist contents of remote directory";
+char   macdefhelp[] =  "define a macro";
 char   mdeletehelp[] = "delete multiple files";
 char   mdirhelp[] =    "list contents of multiple remote directories";
 char   mgethelp[] =    "get multiple files";
 char   mdeletehelp[] = "delete multiple files";
 char   mdirhelp[] =    "list contents of multiple remote directories";
 char   mgethelp[] =    "get multiple files";
@@ -47,8 +55,11 @@ char mkdirhelp[] =   "make directory on the remote machine";
 char   mlshelp[] =     "nlist contents of multiple remote directories";
 char   modehelp[] =    "set file transfer mode";
 char   mputhelp[] =    "send multiple files";
 char   mlshelp[] =     "nlist contents of multiple remote directories";
 char   modehelp[] =    "set file transfer mode";
 char   mputhelp[] =    "send multiple files";
+char   nmaphelp[] =    "set templates for default file name mapping";
+char   ntranshelp[] =  "set translation table for default file name mapping";
 char   porthelp[] =    "toggle use of PORT cmd for each data connection";
 char   prompthelp[] =  "force interactive prompting on multiple commands";
 char   porthelp[] =    "toggle use of PORT cmd for each data connection";
 char   prompthelp[] =  "force interactive prompting on multiple commands";
+char   proxyhelp[] =   "issue command on alternate connection";
 char   pwdhelp[] =     "print working directory on remote machine";
 char   quithelp[] =    "terminate ftp session and exit";
 char   quotehelp[] =   "send arbitrary ftp command";
 char   pwdhelp[] =     "print working directory on remote machine";
 char   quithelp[] =    "terminate ftp session and exit";
 char   quotehelp[] =   "send arbitrary ftp command";
@@ -56,10 +67,13 @@ char        receivehelp[] = "receive file";
 char   remotehelp[] =  "get help from remote server";
 char   renamehelp[] =  "rename file";
 char   rmdirhelp[] =   "remove directory on the remote machine";
 char   remotehelp[] =  "get help from remote server";
 char   renamehelp[] =  "rename file";
 char   rmdirhelp[] =   "remove directory on the remote machine";
+char   runiquehelp[] = "toggle store unique for local files";
+char   resethelp[] =   "clear queued command replies";
 char   sendhelp[] =    "send one file";
 char   shellhelp[] =   "escape to the shell";
 char   statushelp[] =  "show current status";
 char   structhelp[] =  "set file transfer structure";
 char   sendhelp[] =    "send one file";
 char   shellhelp[] =   "escape to the shell";
 char   statushelp[] =  "show current status";
 char   structhelp[] =  "set file transfer structure";
+char   suniquehelp[] = "toggle store unique on remote machine";
 char   tenexhelp[] =   "set tenex file transfer type";
 char   tracehelp[] =   "toggle packet tracing";
 char   typehelp[] =    "set file transfer type";
 char   tenexhelp[] =   "set tenex file transfer type";
 char   tracehelp[] =   "toggle packet tracing";
 char   typehelp[] =    "set file transfer type";
@@ -67,52 +81,64 @@ char        userhelp[] =    "send new user information";
 char   verbosehelp[] = "toggle verbose mode";
 
 struct cmd cmdtab[] = {
 char   verbosehelp[] = "toggle verbose mode";
 
 struct cmd cmdtab[] = {
-       { "!",          shellhelp,      0,      0,      shell },
-       { "append",     appendhelp,     1,      1,      put },
-       { "ascii",      asciihelp,      0,      1,      setascii },
-       { "bell",       beephelp,       0,      0,      setbell },
-       { "binary",     binaryhelp,     0,      1,      setbinary },
-       { "bye",        quithelp,       0,      0,      quit },
-       { "cd",         cdhelp,         0,      1,      cd },
-       { "close",      disconhelp,     0,      1,      disconnect },
-       { "delete",     deletehelp,     0,      1,      delete },
-       { "debug",      debughelp,      0,      0,      setdebug },
-       { "dir",        dirhelp,        1,      1,      ls },
-       { "disconnect", disconhelp,     0,      1,      disconnect },
-       { "form",       formhelp,       0,      1,      setform },
-       { "get",        receivehelp,    1,      1,      get },
-       { "glob",       globhelp,       0,      0,      setglob },
-       { "hash",       hashhelp,       0,      0,      sethash },
-       { "help",       helphelp,       0,      0,      help },
-       { "lcd",        lcdhelp,        0,      0,      lcd },
-       { "ls",         lshelp,         1,      1,      ls },
-       { "mdelete",    mdeletehelp,    1,      1,      mdelete },
-       { "mdir",       mdirhelp,       1,      1,      mls },
-       { "mget",       mgethelp,       1,      1,      mget },
-       { "mkdir",      mkdirhelp,      0,      1,      makedir },
-       { "mls",        mlshelp,        1,      1,      mls },
-       { "mode",       modehelp,       0,      1,      setmode },
-       { "mput",       mputhelp,       1,      1,      mput },
-       { "open",       connecthelp,    0,      0,      setpeer },
-       { "prompt",     prompthelp,     0,      0,      setprompt },
-       { "sendport",   porthelp,       0,      0,      setport },
-       { "put",        sendhelp,       1,      1,      put },
-       { "pwd",        pwdhelp,        0,      1,      pwd },
-       { "quit",       quithelp,       0,      0,      quit },
-       { "quote",      quotehelp,      1,      1,      quote },
-       { "recv",       receivehelp,    1,      1,      get },
-       { "remotehelp", remotehelp,     0,      1,      rmthelp },
-       { "rename",     renamehelp,     0,      1,      renamefile },
-       { "rmdir",      rmdirhelp,      0,      1,      removedir },
-       { "send",       sendhelp,       1,      1,      put },
-       { "status",     statushelp,     0,      0,      status },
-       { "struct",     structhelp,     0,      1,      setstruct },
-       { "tenex",      tenexhelp,      0,      1,      settenex },
-       { "trace",      tracehelp,      0,      0,      settrace },
-       { "type",       typehelp,       0,      1,      settype },
-       { "user",       userhelp,       0,      1,      user },
-       { "verbose",    verbosehelp,    0,      0,      setverbose },
-       { "?",          helphelp,       0,      0,      help },
+       { "!",          shellhelp,      0,      0,      0,      shell },
+       { "$",          domachelp,      1,      0,      0,      domacro },
+       { "account",    accounthelp,    0,      1,      1,      account},
+       { "append",     appendhelp,     1,      1,      1,      put },
+       { "ascii",      asciihelp,      0,      1,      1,      setascii },
+       { "bell",       beephelp,       0,      0,      0,      setbell },
+       { "binary",     binaryhelp,     0,      1,      1,      setbinary },
+       { "bye",        quithelp,       0,      0,      0,      quit },
+       { "case",       casehelp,       0,      0,      1,      setcase },
+       { "cd",         cdhelp,         0,      1,      1,      cd },
+       { "cdup",       cduphelp,       0,      1,      1,      cdup },
+       { "close",      disconhelp,     0,      1,      1,      disconnect },
+       { "cr",         crhelp,         0,      0,      0,      setcr },
+       { "delete",     deletehelp,     0,      1,      1,      delete },
+       { "debug",      debughelp,      0,      0,      0,      setdebug },
+       { "dir",        dirhelp,        1,      1,      1,      ls },
+       { "disconnect", disconhelp,     0,      1,      1,      disconnect },
+       { "form",       formhelp,       0,      1,      1,      setform },
+       { "get",        receivehelp,    1,      1,      1,      get },
+       { "glob",       globhelp,       0,      0,      0,      setglob },
+       { "hash",       hashhelp,       0,      0,      0,      sethash },
+       { "help",       helphelp,       0,      0,      1,      help },
+       { "lcd",        lcdhelp,        0,      0,      0,      lcd },
+       { "ls",         lshelp,         1,      1,      1,      ls },
+       { "macdef",     macdefhelp,     0,      0,      0,      macdef },
+       { "mdelete",    mdeletehelp,    1,      1,      1,      mdelete },
+       { "mdir",       mdirhelp,       1,      1,      1,      mls },
+       { "mget",       mgethelp,       1,      1,      1,      mget },
+       { "mkdir",      mkdirhelp,      0,      1,      1,      makedir },
+       { "mls",        mlshelp,        1,      1,      1,      mls },
+       { "mode",       modehelp,       0,      1,      1,      setmode },
+       { "mput",       mputhelp,       1,      1,      1,      mput },
+       { "nmap",       nmaphelp,       0,      0,      1,      setnmap },
+       { "ntrans",     ntranshelp,     0,      0,      1,      setntrans },
+       { "open",       connecthelp,    0,      0,      1,      setpeer },
+       { "prompt",     prompthelp,     0,      0,      0,      setprompt },
+       { "proxy",      proxyhelp,      0,      0,      1,      doproxy },
+       { "sendport",   porthelp,       0,      0,      0,      setport },
+       { "put",        sendhelp,       1,      1,      1,      put },
+       { "pwd",        pwdhelp,        0,      1,      1,      pwd },
+       { "quit",       quithelp,       0,      0,      0,      quit },
+       { "quote",      quotehelp,      1,      1,      1,      quote },
+       { "recv",       receivehelp,    1,      1,      1,      get },
+       { "remotehelp", remotehelp,     0,      1,      1,      rmthelp },
+       { "rename",     renamehelp,     0,      1,      1,      renamefile },
+       { "reset",      resethelp,      0,      1,      1,      reset },
+       { "rmdir",      rmdirhelp,      0,      1,      1,      removedir },
+       { "runique",    runiquehelp,    0,      0,      1,      setrunique },
+       { "send",       sendhelp,       1,      1,      1,      put },
+       { "status",     statushelp,     0,      0,      1,      status },
+       { "struct",     structhelp,     0,      1,      1,      setstruct },
+       { "sunique",    suniquehelp,    0,      0,      1,      setsunique },
+       { "tenex",      tenexhelp,      0,      1,      1,      settenex },
+       { "trace",      tracehelp,      0,      0,      0,      settrace },
+       { "type",       typehelp,       0,      1,      1,      settype },
+       { "user",       userhelp,       0,      1,      1,      user },
+       { "verbose",    verbosehelp,    0,      0,      0,      setverbose },
+       { "?",          helphelp,       0,      0,      1,      help },
        { 0 },
 };
 
        { 0 },
 };
 
index ab1ac06..8e8d6eb 100644 (file)
@@ -1,14 +1,15 @@
 /*
 /*
- * Copyright (c) 1980 Regents of the University of California.
+ * Copyright (c) 1985 Regents of the University of California.
  * All rights reserved.  The Berkeley software License Agreement
  * specifies the terms and conditions for redistribution.
  */
 
 #ifndef lint
  * All rights reserved.  The Berkeley software License Agreement
  * specifies the terms and conditions for redistribution.
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)ftp.c      5.5 (Berkeley) %G%";
+static char sccsid[] = "@(#)ftp.c      5.6 (Berkeley) %G%";
 #endif not lint
 
 #endif not lint
 
-#include <sys/param.h>
+#include "ftp_var.h"
+
 #include <sys/stat.h>
 #include <sys/ioctl.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
 #include <sys/ioctl.h>
 #include <sys/socket.h>
@@ -16,17 +17,21 @@ static char sccsid[] = "@(#)ftp.c   5.5 (Berkeley) %G%";
 
 #include <netinet/in.h>
 #include <arpa/ftp.h>
 
 #include <netinet/in.h>
 #include <arpa/ftp.h>
+#include <arpa/telnet.h>
 
 #include <stdio.h>
 #include <signal.h>
 #include <errno.h>
 #include <netdb.h>
 
 #include <stdio.h>
 #include <signal.h>
 #include <errno.h>
 #include <netdb.h>
-
-#include "ftp_var.h"
+#include <fcntl.h>
+#include <pwd.h>
 
 struct sockaddr_in hisctladdr;
 struct sockaddr_in data_addr;
 int    data = -1;
 
 struct sockaddr_in hisctladdr;
 struct sockaddr_in data_addr;
 int    data = -1;
+int     telflag = 0;
+int    abrtflag = 0;
+int    ptflag = 0;
 int    connected;
 struct sockaddr_in myctladdr;
 
 int    connected;
 struct sockaddr_in myctladdr;
 
@@ -39,19 +44,22 @@ hookup(host, port)
        int port;
 {
        register struct hostent *hp = 0;
        int port;
 {
        register struct hostent *hp = 0;
+       int s,len,oldverbose;
        static char hostnamebuf[80];
        static char hostnamebuf[80];
-       int s, len;
+       char msg[2];
 
        bzero((char *)&hisctladdr, sizeof (hisctladdr));
        hisctladdr.sin_addr.s_addr = inet_addr(host);
        if (hisctladdr.sin_addr.s_addr != -1) {
                hisctladdr.sin_family = AF_INET;
                (void) strcpy(hostnamebuf, host);
 
        bzero((char *)&hisctladdr, sizeof (hisctladdr));
        hisctladdr.sin_addr.s_addr = inet_addr(host);
        if (hisctladdr.sin_addr.s_addr != -1) {
                hisctladdr.sin_family = AF_INET;
                (void) strcpy(hostnamebuf, host);
-       } else {
+       }
+       else {
                hp = gethostbyname(host);
                if (hp == NULL) {
                        printf("%s: unknown host\n", host);
                hp = gethostbyname(host);
                if (hp == NULL) {
                        printf("%s: unknown host\n", host);
-                       return (0);
+                       code = -1;
+                       return((char *) 0);
                }
                hisctladdr.sin_family = hp->h_addrtype;
                bcopy(hp->h_addr_list[0],
                }
                hisctladdr.sin_family = hp->h_addrtype;
                bcopy(hp->h_addr_list[0],
@@ -62,6 +70,7 @@ hookup(host, port)
        s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
        if (s < 0) {
                perror("ftp: socket");
        s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
        if (s < 0) {
                perror("ftp: socket");
+               code = -1;
                return (0);
        }
        hisctladdr.sin_port = port;
                return (0);
        }
        hisctladdr.sin_port = port;
@@ -75,17 +84,19 @@ hookup(host, port)
                        perror(0);
                        hp->h_addr_list++;
                        bcopy(hp->h_addr_list[0],
                        perror(0);
                        hp->h_addr_list++;
                        bcopy(hp->h_addr_list[0],
-                           (caddr_t)&hisctladdr.sin_addr, hp->h_length);
+                            (caddr_t)&hisctladdr.sin_addr, hp->h_length);
                        fprintf(stderr, "Trying %s...\n",
                                inet_ntoa(hisctladdr.sin_addr));
                        continue;
                }
                perror("ftp: connect");
                        fprintf(stderr, "Trying %s...\n",
                                inet_ntoa(hisctladdr.sin_addr));
                        continue;
                }
                perror("ftp: connect");
+               code = -1;
                goto bad;
        }
        len = sizeof (myctladdr);
        if (getsockname(s, (char *)&myctladdr, &len) < 0) {
                perror("ftp: getsockname");
                goto bad;
        }
        len = sizeof (myctladdr);
        if (getsockname(s, (char *)&myctladdr, &len) < 0) {
                perror("ftp: getsockname");
+               code = -1;
                goto bad;
        }
        cin = fdopen(s, "r");
                goto bad;
        }
        cin = fdopen(s, "r");
@@ -96,11 +107,40 @@ hookup(host, port)
                        fclose(cin);
                if (cout)
                        fclose(cout);
                        fclose(cin);
                if (cout)
                        fclose(cout);
+               code = -1;
                goto bad;
        }
        if (verbose)
                goto bad;
        }
        if (verbose)
-               printf("Connected to %s.\n", hostname);
-       (void) getreply(0);             /* read startup message from server */
+               printf("Connected to %s.\n", hp->h_name);
+       if (getreply(0) != 2) {         /* read startup message from server */
+               if (cin)
+                       fclose(cin);
+               if (cout)
+                       fclose(cout);
+               code = -1;
+               goto bad;
+       }
+
+/* test to see if server command parser understands TELNET SYNC command */
+
+       fprintf(cout,"%c%c",IAC,NOP);
+       (void) fflush(cout);
+       *msg = IAC;
+       *(msg+1) = DM;
+       if (send(s,msg,2,MSG_OOB) != 2) {
+               perror("sync");
+       }
+       oldverbose = verbose;
+       if (!debug) {
+               verbose = -1;
+       }
+       if (command("NOOP") == COMPLETE) {
+               telflag = 1;
+       }
+       else {
+               telflag = 0;
+       }
+       verbose = oldverbose;
        return (hostname);
 bad:
        close(s);
        return (hostname);
 bad:
        close(s);
@@ -110,33 +150,88 @@ bad:
 login(host)
        char *host;
 {
 login(host)
        char *host;
 {
-       char acct[80];
-       char *user, *pass;
-       int n;
+       char tmp[80];
+       char *user, *pass, *acct, *getlogin(), *getpass();
+       int n, aflag = 0;
+
+       user = pass = acct = 0;
+       if (ruserpass(host, &user, &pass, &acct) < 0) {
+               disconnect();
+               code = -1;
+               return(0);
+       }
+       if (user == NULL) {
+               char *myname = getlogin();
 
 
-       user = pass = 0;
-       ruserpass(host, &user, &pass);
+               if (myname == NULL) {
+                       struct passwd *pp = getpwuid(getuid());
+
+                       if (pp != NULL) {
+                               myname = pp->pw_name;
+                       }
+               }
+               printf("Name (%s:%s): ", host, myname);
+               (void) fgets(tmp, sizeof(tmp) - 1, stdin);
+               tmp[strlen(tmp) - 1] = '\0';
+               if (*tmp == '\0') {
+                       user = myname;
+               }
+               else {
+                       user = tmp;
+               }
+       }
        n = command("USER %s", user);
        n = command("USER %s", user);
-       if (n == CONTINUE)
+       if (n == CONTINUE) {
+               if (pass == NULL) {
+                       pass = getpass("Password:");
+               }
                n = command("PASS %s", pass);
                n = command("PASS %s", pass);
+       }
        if (n == CONTINUE) {
        if (n == CONTINUE) {
-               printf("Account: "); (void) fflush(stdout);
-               (void) fgets(acct, sizeof(acct) - 1, stdin);
-               acct[strlen(acct) - 1] = '\0';
+               aflag++;
+               acct = getpass("Account:");
                n = command("ACCT %s", acct);
        }
        if (n != COMPLETE) {
                fprintf(stderr, "Login failed.\n");
                return (0);
        }
                n = command("ACCT %s", acct);
        }
        if (n != COMPLETE) {
                fprintf(stderr, "Login failed.\n");
                return (0);
        }
+       if (!aflag && acct != NULL) {
+               (void) command("ACCT %s", acct);
+       }
+       if (proxy) {
+               return(1);
+       }
+       for (n = 0; n < macnum; ++n) {
+               if (!strcmp("init", macros[n].mac_name)) {
+                       strcpy(line, "$init");
+                       makeargv();
+                       domacro(margc, margv);
+                       break;
+               }
+       }
        return (1);
 }
 
        return (1);
 }
 
+cmdabort()
+{
+       extern jmp_buf ptabort;
+
+       printf("\n");
+       (void) fflush(stdout);
+       abrtflag++;
+       if (ptflag) {
+               longjmp(ptabort,1);
+       }
+}
+
 /*VARARGS 1*/
 command(fmt, args)
        char *fmt;
 {
 /*VARARGS 1*/
 command(fmt, args)
        char *fmt;
 {
+       int r, (*oldintr)(), cmdabort();
 
 
+       abrtflag = 0;
        if (debug) {
                printf("---> ");
                _doprnt(fmt, &args, stdout);
        if (debug) {
                printf("---> ");
                _doprnt(fmt, &args, stdout);
@@ -145,12 +240,20 @@ command(fmt, args)
        }
        if (cout == NULL) {
                perror ("No control connection for command");
        }
        if (cout == NULL) {
                perror ("No control connection for command");
+               code = -1;
                return (0);
        }
                return (0);
        }
+       oldintr = signal(SIGINT,cmdabort);
        _doprnt(fmt, &args, cout);
        fprintf(cout, "\r\n");
        (void) fflush(cout);
        _doprnt(fmt, &args, cout);
        fprintf(cout, "\r\n");
        (void) fflush(cout);
-       return (getreply(!strcmp(fmt, "QUIT")));
+       cpend = 1;
+       r = getreply(!strcmp(fmt, "QUIT"));
+       if (abrtflag && oldintr != SIG_IGN) {
+               (*oldintr)();
+       }
+       (void) signal(SIGINT, oldintr);
+       return(r);
 }
 
 #include <ctype.h>
 }
 
 #include <ctype.h>
@@ -159,30 +262,65 @@ getreply(expecteof)
        int expecteof;
 {
        register int c, n;
        int expecteof;
 {
        register int c, n;
-       register int code, dig;
-       int originalcode = 0, continuation = 0;
+       register int dig;
+       int originalcode = 0, continuation = 0, (*oldintr)(), cmdabort();
+       int pflag = 0;
+       char *pt = pasv;
 
 
+       oldintr = signal(SIGINT,cmdabort);
        for (;;) {
                dig = n = code = 0;
                while ((c = getc(cin)) != '\n') {
                        dig++;
                        if (c == EOF) {
        for (;;) {
                dig = n = code = 0;
                while ((c = getc(cin)) != '\n') {
                        dig++;
                        if (c == EOF) {
-                               if (expecteof)
+                               if (expecteof) {
+                                       (void) signal(SIGINT,oldintr);
+                                       code = 221;
                                        return (0);
                                        return (0);
+                               }
                                lostpeer();
                                lostpeer();
-                               exit(1);
+                               if (verbose) {
+                                       printf("421 Service not available, remote server has closed connection\n");
+                                       (void) fflush(stdout);
+                                       code = 421;
+                                       return(4);
+                               }
                        }
                        }
-                       if (verbose && c != '\r' ||
-                           (n == '5' && dig > 4))
+                       if (c != '\r' && (verbose > 0 ||
+                           (verbose > -1 && n == '5' && dig > 4))) {
+                               if ( proxflag && 
+                                  (dig == 1 || dig == 5 && verbose == 0)) {
+                                       printf("%s:",hostname);
+                               }
                                putchar(c);
                                putchar(c);
+                       }
                        if (dig < 4 && isdigit(c))
                                code = code * 10 + (c - '0');
                        if (dig < 4 && isdigit(c))
                                code = code * 10 + (c - '0');
-                       if (dig == 4 && c == '-')
+                       if (!pflag && code == 227) {
+                               pflag = 1;
+                       }
+                       if (dig > 4 && pflag == 1 && isdigit(c)) {
+                               pflag = 2;
+                       }
+                       if (pflag == 2) {
+                               if (c != '\r' && c != ')') {
+                                       *pt++ = c;
+                               }
+                               else {
+                                       *pt = '\0';
+                                       pflag = 3;
+                               }
+                       }
+                       if (dig == 4 && c == '-') {
+                               if (continuation) {
+                                       code = 0;
+                               }
                                continuation++;
                                continuation++;
+                       }
                        if (n == 0)
                                n = c;
                }
                        if (n == 0)
                                n = c;
                }
-               if (verbose || n == '5') {
+               if (verbose > 0 || verbose > -1 && n == '5') {
                        putchar(c);
                        (void) fflush (stdout);
                }
                        putchar(c);
                        (void) fflush (stdout);
                }
@@ -191,74 +329,144 @@ getreply(expecteof)
                                originalcode = code;
                        continue;
                }
                                originalcode = code;
                        continue;
                }
+               if (n != '1') {
+                       cpend = 0;
+               }
+               (void) signal(SIGINT,oldintr);
+               if (code == 421 || originalcode == 421) {
+                       lostpeer();
+               }
+               if (abrtflag && oldintr != cmdabort && oldintr != SIG_IGN) {
+                       (*oldintr)();
+               }
                return (n - '0');
        }
 }
 
                return (n - '0');
        }
 }
 
+empty(mask, sec)
+       long mask;
+       int sec;
+{
+       struct timeval t;
+
+       t.tv_sec = (long) sec;
+       t.tv_usec = 0;
+       if (select(20, &mask, 0, 0, &t) < 0) {
+               return(-1);
+       }
+       return (mask);
+}
+
 jmp_buf        sendabort;
 
 abortsend()
 {
 
 jmp_buf        sendabort;
 
 abortsend()
 {
 
+       mflag = 0;
+       abrtflag = 0;
+       printf("\nsend aborted\n");
+       (void) fflush(stdout);
        longjmp(sendabort, 1);
 }
 
 sendrequest(cmd, local, remote)
        char *cmd, *local, *remote;
 {
        longjmp(sendabort, 1);
 }
 
 sendrequest(cmd, local, remote)
        char *cmd, *local, *remote;
 {
-       FILE *fin, *dout, *popen();
-       int (*closefunc)(), pclose(), fclose(), (*oldintr)();
+       FILE *fin, *dout = 0, *popen();
+       int (*closefunc)(), pclose(), fclose(), (*oldintr)(), (*oldintp)();
+       int abortsend();
        char buf[BUFSIZ];
        char buf[BUFSIZ];
-       int expectingreply = 0;
        long bytes = 0, hashbytes = sizeof (buf);
        register int c, d;
        struct stat st;
        struct timeval start, stop;
 
        long bytes = 0, hashbytes = sizeof (buf);
        register int c, d;
        struct stat st;
        struct timeval start, stop;
 
+       if (proxy) {
+               proxtrans(cmd, local, remote);
+               return;
+       }
        closefunc = NULL;
        closefunc = NULL;
-       if (setjmp(sendabort))
-               goto bad;
+       oldintr = NULL;
+       oldintp = NULL;
+       if (setjmp(sendabort)) {
+               while (cpend) {
+                       (void) getreply(0);
+               }
+               if (data >= 0) {
+                       (void) close(data);
+                       data = -1;
+               }
+               if (oldintr) {
+                       (void) signal(SIGINT,oldintr);
+               }
+               if (oldintp) {
+                       (void) signal(SIGPIPE,oldintp);
+               }
+               code = -1;
+               return;
+       }
        oldintr = signal(SIGINT, abortsend);
        if (strcmp(local, "-") == 0)
                fin = stdin;
        else if (*local == '|') {
        oldintr = signal(SIGINT, abortsend);
        if (strcmp(local, "-") == 0)
                fin = stdin;
        else if (*local == '|') {
-               /*
-                * Advance local so further uses just yield file name
-                * thus later references for error messages need not check
-                * for '|' special case.
-                */
-               local += 1;
-               fin = popen(local, "r");
+               oldintp = signal(SIGPIPE,SIG_IGN);
+               fin = popen(local + 1, "r");
                if (fin == NULL) {
                if (fin == NULL) {
-                       perror(local);
-                       goto bad;
+                       perror(local + 1);
+                       (void) signal(SIGINT, oldintr);
+                       (void) signal(SIGPIPE, oldintp);
+                       code = -1;
+                       return;
                }
                closefunc = pclose;
        } else {
                fin = fopen(local, "r");
                if (fin == NULL) {
                        perror(local);
                }
                closefunc = pclose;
        } else {
                fin = fopen(local, "r");
                if (fin == NULL) {
                        perror(local);
-                       goto bad;
+                       (void) signal(SIGINT, oldintr);
+                       code = -1;
+                       return;
                }
                closefunc = fclose;
                if (fstat(fileno(fin), &st) < 0 ||
                    (st.st_mode&S_IFMT) != S_IFREG) {
                        fprintf(stderr, "%s: not a plain file.\n", local);
                }
                closefunc = fclose;
                if (fstat(fileno(fin), &st) < 0 ||
                    (st.st_mode&S_IFMT) != S_IFREG) {
                        fprintf(stderr, "%s: not a plain file.\n", local);
-                       goto bad;
+                       (void) signal(SIGINT, oldintr);
+                       code = -1;
+                       return;
                }
        }
                }
        }
-       if (initconn())
-               goto bad;
+       if (initconn()) {
+               (void) signal(SIGINT, oldintr);
+               if (oldintp) {
+                       (void) signal(SIGPIPE, oldintp);
+               }
+               code = -1;
+               return;
+       }
+       if (setjmp(sendabort)) {
+               goto abort;
+       }
        if (remote) {
        if (remote) {
-               if (command("%s %s", cmd, remote) != PRELIM)
-                       goto bad;
+               if (command("%s %s", cmd, remote) != PRELIM) {
+                       (void) signal(SIGINT, oldintr);
+                       if (oldintp) {
+                               (void) signal(SIGPIPE, oldintp);
+                       }
+                       return;
+               }
        } else
        } else
-               if (command("%s", cmd) != PRELIM)
-                       goto bad;
-       expectingreply++;       /* got preliminary reply, expecting final reply */
+               if (command("%s", cmd) != PRELIM) {
+                       (void) signal(SIGINT, oldintr);
+                       if (oldintp) {
+                               (void) signal(SIGPIPE, oldintp);
+                       }
+                       return;
+               }
        dout = dataconn("w");
        dout = dataconn("w");
-       if (dout == NULL)
-               goto bad;
+       if (dout == NULL) {
+               goto abort;
+       }
        gettimeofday(&start, (struct timezone *)0);
        switch (type) {
 
        gettimeofday(&start, (struct timezone *)0);
        switch (type) {
 
@@ -299,10 +507,10 @@ sendrequest(cmd, local, remote)
                        }
                        putc(c, dout);
                        bytes++;
                        }
                        putc(c, dout);
                        bytes++;
-                       if (c == '\r') {
-                               putc('\0', dout);
-                               bytes++;
-                       }
+       /*              if (c == '\r') {                                */
+       /*                      putc('\0', dout);  /* this violates rfc */
+       /*                      bytes++;                                */
+       /*              }                                               */      
                }
                if (hash) {
                        if (bytes < hashbytes)
                }
                if (hash) {
                        if (bytes < hashbytes)
@@ -318,24 +526,36 @@ sendrequest(cmd, local, remote)
        }
        gettimeofday(&stop, (struct timezone *)0);
        if (closefunc != NULL)
        }
        gettimeofday(&stop, (struct timezone *)0);
        if (closefunc != NULL)
-               (*closefunc)(fin), closefunc = NULL;
+               (*closefunc)(fin);
        (void) fclose(dout);
        (void) fclose(dout);
-done:
-       if (expectingreply) {
-               (void) getreply(0);
-               expectingreply = 0;
-       }
-       signal(SIGINT, oldintr);
+       (void) getreply(0);
+       (void) signal(SIGINT, oldintr);
        if (bytes > 0 && verbose)
        if (bytes > 0 && verbose)
-               ptransfer("sent", bytes, &start, &stop);
+               ptransfer("sent", bytes, &start, &stop, local, remote);
        return;
        return;
-bad:
-       if (data >= 0)
-               (void) close(data), data = -1;
+abort:
+       gettimeofday(&stop, (struct timezone *)0);
+       (void) signal(SIGINT, oldintr);
+       if (oldintp) {
+               (void) signal(SIGPIPE, oldintp);
+       }
+       if (!cpend) {
+               code = -1;
+               return;
+       }
+       if (data >= 0) {
+               (void) close(data);
+               data = -1;
+       }
+       if (dout) {
+               (void) fclose(dout);
+       }
+       (void) getreply(0);
+       code = -1;
        if (closefunc != NULL && fin != NULL)
        if (closefunc != NULL && fin != NULL)
-               (*closefunc)(fin), closefunc = NULL;
-       bytes = 0;      /* so we don't print a message if the transfer was aborted */
-       goto done;
+               (*closefunc)(fin);
+       if (bytes > 0 && verbose)
+               ptransfer("sent", bytes, &start, &stop, local, remote);
 }
 
 jmp_buf        recvabort;
 }
 
 jmp_buf        recvabort;
@@ -343,73 +563,173 @@ jmp_buf  recvabort;
 abortrecv()
 {
 
 abortrecv()
 {
 
+       mflag = 0;
+       abrtflag = 0;
+       printf("\n");
+       (void) fflush(stdout);
        longjmp(recvabort, 1);
 }
 
 recvrequest(cmd, local, remote, mode)
        char *cmd, *local, *remote, *mode;
 {
        longjmp(recvabort, 1);
 }
 
 recvrequest(cmd, local, remote, mode)
        char *cmd, *local, *remote, *mode;
 {
-       FILE *fout, *din, *popen();
-       int (*closefunc)(), pclose(), fclose(), (*oldintr)();
-       char buf[BUFSIZ];
-       int expectingreply = 0;
-       long bytes = 0, hashbytes = sizeof (buf);
+       FILE *fout, *din = 0, *popen();
+       int (*closefunc)(), pclose(), fclose(), (*oldintr)(), (*oldintp)(); 
+       int abortrecv(), oldverbose, oldtype = 0, tcrflag;
+       char buf[BUFSIZ], *gunique();
+       long bytes = 0, hashbytes = sizeof (buf), mask;
        register int c, d;
        struct timeval start, stop;
 
        register int c, d;
        struct timeval start, stop;
 
+       if (proxy && strcmp(cmd,"RETR") == 0) {
+               proxtrans(cmd, local, remote);
+               return;
+       }
        closefunc = NULL;
        closefunc = NULL;
-       if (setjmp(recvabort))
-               goto bad;
+       oldintr = NULL;
+       oldintp = NULL;
+       tcrflag = !crflag && !strcmp(cmd, "RETR");
+       if (setjmp(recvabort)) {
+               while (cpend) {
+                       (void) getreply(0);
+               }
+               if (data >= 0) {
+                       (void) close(data);
+                       data = -1;
+               }
+               if (oldintr) {
+                       (void) signal(SIGINT, oldintr);
+               }
+               code = -1;
+               return;
+       }
        oldintr = signal(SIGINT, abortrecv);
        oldintr = signal(SIGINT, abortrecv);
-       if (strcmp(local, "-") && *local != '|')
+       if (strcmp(local, "-") && *local != '|') {
                if (access(local, 2) < 0) {
                if (access(local, 2) < 0) {
-                       if (errno == ENOENT) {
-                               char *dir = rindex(local, '/');
-
-                               if (dir != NULL)
-                                       *dir = 0;
-                               d = access(dir ? local : ".", 2);
-                               if (dir != NULL)
-                                       *dir = '/';
-                               if (d < 0) {
-                                       perror(local);
-                                       goto bad;
-                               }
-                       } else {
+                       char *dir = rindex(local, '/');
+
+                       if (errno != ENOENT && errno != EACCES) {
+                               perror(local);
+                               (void) signal(SIGINT, oldintr);
+                               code = -1;
+                               return;
+                       }
+                       if (dir != NULL)
+                               *dir = 0;
+                       d = access(dir ? local : ".", 2);
+                       if (dir != NULL)
+                               *dir = '/';
+                       if (d < 0) {
+                               perror(local);
+                               (void) signal(SIGINT, oldintr);
+                               code = -1;
+                               return;
+                       }
+                       if (!runique && errno == EACCES &&
+                           chmod(local,0600) < 0) {
                                perror(local);
                                perror(local);
-                               goto bad;
+                               (void) signal(SIGINT, oldintr);
+                               code = -1;
+                               return;
+                       }
+                       if (runique && errno == EACCES &&
+                          (local = gunique(local)) == NULL) {
+                               (void) signal(SIGINT, oldintr);
+                               code = -1;
+                               return;
                        }
                }
                        }
                }
-       if (initconn())
-               goto bad;
+               else if (runique && (local = gunique(local)) == NULL) {
+                       (void) signal(SIGINT, oldintr);
+                       code = -1;
+                       return;
+               }
+       }
+       if (initconn()) {
+               (void) signal(SIGINT, oldintr);
+               code = -1;
+               return;
+       }
+       if (setjmp(recvabort)) {
+               goto abort;
+       }
+       if (strcmp(cmd, "RETR") && type != TYPE_A) {
+               oldtype = type;
+               oldverbose = verbose;
+               if (!debug) {
+                       verbose = 0;
+               }
+               setascii();
+               verbose = oldverbose;
+       }
        if (remote) {
        if (remote) {
-               if (command("%s %s", cmd, remote) != PRELIM)
-                       goto bad;
-       } else
-               if (command("%s", cmd) != PRELIM)
-                       goto bad;
-       expectingreply++;       /* got preliminary reply, expecting final reply */
-       if (strcmp(local, "-") == 0)
+               if (command("%s %s", cmd, remote) != PRELIM) {
+                       (void) signal(SIGINT, oldintr);
+                       if (oldtype) {
+                               if (!debug) {
+                                       verbose = 0;
+                               }
+                               switch (oldtype) {
+                                       case TYPE_I:
+                                               setbinary();
+                                               break;
+                                       case TYPE_E:
+                                               setebcdic();
+                                               break;
+                                       case TYPE_L:
+                                               settenex();
+                                               break;
+                               }
+                               verbose = oldverbose;
+                       }
+                       return;
+               }
+       } else {
+               if (command("%s", cmd) != PRELIM) {
+                       (void) signal(SIGINT, oldintr);
+                       if (oldtype) {
+                               if (!debug) {
+                                       verbose = 0;
+                               }
+                               switch (oldtype) {
+                                       case TYPE_I:
+                                               setbinary();
+                                               break;
+                                       case TYPE_E:
+                                               setebcdic();
+                                               break;
+                                       case TYPE_L:
+                                               settenex();
+                                               break;
+                               }
+                               verbose = oldverbose;
+                       }
+                       return;
+               }
+       }
+       din = dataconn("r");
+       if (din == NULL)
+               goto abort;
+       if (strcmp(local, "-") == 0) {
                fout = stdout;
                fout = stdout;
+       }
        else if (*local == '|') {
        else if (*local == '|') {
-               /*
-                * Advance local over '|' so don't need to check for
-                * '|' special case any further.
-                */
-               local += 1;
-               fout = popen(local, "w");
+               oldintp = signal(SIGPIPE, SIG_IGN);
+               fout = popen(local + 1, "w");
+               if (fout == NULL) {
+                       perror(local+1);
+                       goto abort;
+               }
                closefunc = pclose;
                closefunc = pclose;
-       } else {
+       }
+       else {
                fout = fopen(local, mode);
                fout = fopen(local, mode);
+               if (fout == NULL) {
+                       perror(local);
+                       goto abort;
+               }
                closefunc = fclose;
        }
                closefunc = fclose;
        }
-       if (fout == NULL) {
-               perror(local);
-               goto bad;
-       }
-       din = dataconn("r");
-       if (din == NULL)
-               goto bad;
        gettimeofday(&start, (struct timezone *)0);
        switch (type) {
 
        gettimeofday(&start, (struct timezone *)0);
        switch (type) {
 
@@ -444,15 +764,15 @@ recvrequest(cmd, local, remote, mode)
                                        hashbytes += sizeof (buf);
                                }
                                bytes++;
                                        hashbytes += sizeof (buf);
                                }
                                bytes++;
-                               if ((c = getc(din)) != '\n') {
+                               if ((c = getc(din)) != '\n' || tcrflag) {
                                        if (ferror (fout))
                                                break;
                                        putc ('\r', fout);
                                }
                                        if (ferror (fout))
                                                break;
                                        putc ('\r', fout);
                                }
-                               if (c == '\0') {
+                               /*if (c == '\0') {
                                        bytes++;
                                        continue;
                                        bytes++;
                                        continue;
-                               }
+                               }*/
                        }
                        putc (c, fout);
                        bytes++;
                        }
                        putc (c, fout);
                        bytes++;
@@ -469,26 +789,112 @@ recvrequest(cmd, local, remote, mode)
                        perror (local);
                break;
        }
                        perror (local);
                break;
        }
-       gettimeofday(&stop, (struct timezone *)0);
-       (void) fclose(din);
-       if (closefunc != NULL)
-               (*closefunc)(fout), closefunc = NULL;
-done:
-       if (expectingreply) {
-               (void) getreply(0);
-               expectingreply = 0;
+       if (closefunc != NULL) {
+               (*closefunc)(fout);
        }
        signal(SIGINT, oldintr);
        }
        signal(SIGINT, oldintr);
+       if (oldintp) {
+               (void) signal(SIGPIPE, oldintp);
+       }
+       gettimeofday(&stop, (struct timezone *)0);
+       (void) fclose(din);
+       (void) getreply(0);
        if (bytes > 0 && verbose)
        if (bytes > 0 && verbose)
-               ptransfer("received", bytes, &start, &stop);
+               ptransfer("received", bytes, &start, &stop, local, remote);
+       if (oldtype) {
+               if (!debug) {
+                       verbose = 0;
+               }
+               switch (oldtype) {
+                       case TYPE_I:
+                               setbinary();
+                               break;
+                       case TYPE_E:
+                               setebcdic();
+                               break;
+                       case TYPE_L:
+                               settenex();
+                               break;
+               }
+               verbose = oldverbose;
+       }
        return;
        return;
-bad:
-       if (data >= 0)
-               (void) close(data), data = -1;
-       if (closefunc != NULL && fout != NULL)
+abort:
+
+/* if server command parser understands TELNET commands, abort using */
+/* recommended IP,SYNC sequence                                      */
+
+       gettimeofday(&stop, (struct timezone *)0);
+       if (oldintp) {
+               (void) signal(SIGPIPE, oldintr);
+       }
+       (void) signal(SIGINT,SIG_IGN);
+       if (oldtype) {
+               if (!debug) {
+                       verbose = 0;
+               }
+               switch (oldtype) {
+                       case TYPE_I:
+                               setbinary();
+                               break;
+                       case TYPE_E:
+                               setebcdic();
+                               break;
+                       case TYPE_L:
+                               settenex();
+                               break;
+               }
+               verbose = oldverbose;
+       }
+       if (!cpend) {
+               code = -1;
+               (void) signal(SIGINT,oldintr);
+               return;
+       }
+       if (telflag) {
+               char msg[2];
+
+               fprintf(cout,"%c%c",IAC,IP);
+               (void) fflush(cout); 
+               *msg = IAC;
+               *(msg+1) = DM;
+               if (send(fileno(cout),msg,2,MSG_OOB) != 2) {
+                       perror("abort");
+               }
+       }
+       fprintf(cout,"ABOR\r\n");
+       (void) fflush(cout);
+       mask = (1 << fileno(cin)) | (din ? (1 << fileno(din)) : 0);
+       if ((mask = empty(mask,10)) < 0) {
+               perror("abort");
+               code = -1;
+               lostpeer();
+       }
+       if (din && mask & (1 << fileno(din))) {
+               while ((c = read(fileno(din), buf, sizeof (buf))) > 0);
+       }
+       if ((c = getreply(0)) == ERROR) { /* needed for nic style abort */
+               if (data >= 0) {
+                       close(data);
+                       data = -1;
+               }
+               (void) getreply(0);
+       }
+       (void) getreply(0);
+       code = -1;
+       if (data >= 0) {
+               (void) close(data);
+               data = -1;
+       }
+       if (closefunc != NULL && fout != NULL) {
                (*closefunc)(fout);
                (*closefunc)(fout);
-       bytes = 0;      /* so we don't print a message if the transfer was aborted */
-       goto done;
+       }
+       if (din) {
+               (void) fclose(din);
+       }
+       if (bytes > 0 && verbose)
+               ptransfer("received", bytes, &start, &stop, local, remote);
+       (void) signal(SIGINT,oldintr);
 }
 
 /*
 }
 
 /*
@@ -501,7 +907,7 @@ static int sendport = -1;
 initconn()
 {
        register char *p, *a;
 initconn()
 {
        register char *p, *a;
-       int result, len;
+       int result, len, tmpno = 0;
        int on = 1;
 
 noport:
        int on = 1;
 
 noport:
@@ -513,11 +919,14 @@ noport:
        data = socket(AF_INET, SOCK_STREAM, 0);
        if (data < 0) {
                perror("ftp: socket");
        data = socket(AF_INET, SOCK_STREAM, 0);
        if (data < 0) {
                perror("ftp: socket");
+               if (tmpno) {
+                       sendport = 1;
+               }
                return (1);
        }
        if (!sendport)
                if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) < 0) {
                return (1);
        }
        if (!sendport)
                if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) < 0) {
-                       perror("ftp: setsockopt (reuse address)");
+                       perror("ftp: setsockopt (resuse address)");
                        goto bad;
                }
        if (bind(data, (char *)&data_addr, sizeof (data_addr), 0) < 0) {
                        goto bad;
                }
        if (bind(data, (char *)&data_addr, sizeof (data_addr), 0) < 0) {
@@ -534,7 +943,7 @@ noport:
        }
        if (listen(data, 1) < 0) {
                perror("ftp: listen");
        }
        if (listen(data, 1) < 0) {
                perror("ftp: listen");
-               goto bad;
+               
        }
        if (sendport) {
                a = (char *)&data_addr.sin_addr;
        }
        if (sendport) {
                a = (char *)&data_addr.sin_addr;
@@ -546,13 +955,20 @@ noport:
                      UC(p[0]), UC(p[1]));
                if (result == ERROR && sendport == -1) {
                        sendport = 0;
                      UC(p[0]), UC(p[1]));
                if (result == ERROR && sendport == -1) {
                        sendport = 0;
+                       tmpno = 1;
                        goto noport;
                }
                return (result != COMPLETE);
        }
                        goto noport;
                }
                return (result != COMPLETE);
        }
+       if (tmpno) {
+               sendport = 1;
+       }
        return (0);
 bad:
        (void) close(data), data = -1;
        return (0);
 bad:
        (void) close(data), data = -1;
+       if (tmpno) {
+               sendport = 1;
+       }
        return (1);
 }
 
        return (1);
 }
 
@@ -574,8 +990,8 @@ dataconn(mode)
        return (fdopen(data, mode));
 }
 
        return (fdopen(data, mode));
 }
 
-ptransfer(direction, bytes, t0, t1)
-       char *direction;
+ptransfer(direction, bytes, t0, t1, local, remote)
+       char *direction, *local, *remote;
        long bytes;
        struct timeval *t0, *t1;
 {
        long bytes;
        struct timeval *t0, *t1;
 {
@@ -586,6 +1002,12 @@ ptransfer(direction, bytes, t0, t1)
        s = td.tv_sec + (td.tv_usec / 1000000.);
 #define        nz(x)   ((x) == 0 ? 1 : (x))
        bs = bytes / nz(s);
        s = td.tv_sec + (td.tv_usec / 1000000.);
 #define        nz(x)   ((x) == 0 ? 1 : (x))
        bs = bytes / nz(s);
+       if (local && *local != '-') {
+               printf("local: %s ", local);
+       }
+       if (remote) {
+               printf("remote: %s\n", remote);
+       }
        printf("%ld bytes %s in %.2g seconds (%.2g Kbytes/s)\n",
                bytes, direction, s, bs / 1024.);
 }
        printf("%ld bytes %s in %.2g seconds (%.2g Kbytes/s)\n",
                bytes, direction, s, bs / 1024.);
 }
@@ -609,3 +1031,511 @@ tvsub(tdiff, t1, t0)
        if (tdiff->tv_usec < 0)
                tdiff->tv_sec--, tdiff->tv_usec += 1000000;
 }
        if (tdiff->tv_usec < 0)
                tdiff->tv_sec--, tdiff->tv_usec += 1000000;
 }
+
+psabort()
+{
+       extern int abrtflag;
+
+       abrtflag++;
+}
+
+pswitch(flag)
+       int flag;
+{
+       extern int proxy, abrtflag;
+       int (*oldintr)();
+       static struct comvars {
+               int connect;
+               char name[32];
+               struct sockaddr_in mctl;
+               struct sockaddr_in hctl;
+               FILE *in;
+               FILE *out;
+               int tflag;
+               int tpe;
+               int cpnd;
+               int sunqe;
+               int runqe;
+               int mcse;
+               int ntflg;
+               char nti[17];
+               char nto[17];
+               int mapflg;
+               char mi[MAXPATHLEN];
+               char mo[MAXPATHLEN];
+               } proxstruct, tmpstruct;
+       struct comvars *ip, *op;
+
+       abrtflag = 0;
+       oldintr = signal(SIGINT, psabort);
+       if (flag) {
+               if (proxy) {
+                       return;
+               }
+               ip = &tmpstruct;
+               op = &proxstruct;
+               proxy++;
+       }
+       else {
+               if (!proxy) {
+                       return;
+               }
+               ip = &proxstruct;
+               op = &tmpstruct;
+               proxy = 0;
+       }
+       ip->connect = connected;
+       connected = op->connect;
+       strncpy(ip->name, hostname, 31);
+       (ip->name)[strlen(ip->name)] = '\0';
+       hostname = op->name;
+       ip->hctl = hisctladdr;
+       hisctladdr = op->hctl;
+       ip->mctl = myctladdr;
+       myctladdr = op->mctl;
+       ip->in = cin;
+       cin = op->in;
+       ip->out = cout;
+       cout = op->out;
+       ip->tflag = telflag;
+       telflag = op->tflag;
+       ip->tpe = type;
+       type = op->tpe;
+       if (!type) {
+               type = 1;
+       }
+       ip->cpnd = cpend;
+       cpend = op->cpnd;
+       ip->sunqe = sunique;
+       sunique = op->sunqe;
+       ip->runqe = runique;
+       runique = op->runqe;
+       ip->mcse = mcase;
+       mcase = op->mcse;
+       ip->ntflg = ntflag;
+       ntflag = op->ntflg;
+       strncpy(ip->nti, ntin, 16);
+       (ip->nti)[strlen(ip->nti)] = '\0';
+       strcpy(ntin, op->nti);
+       strncpy(ip->nto, ntout, 16);
+       (ip->nto)[strlen(ip->nto)] = '\0';
+       strcpy(ntout, op->nto);
+       ip->mapflg = mapflag;
+       mapflag = op->mapflg;
+       strncpy(ip->mi, mapin, MAXPATHLEN - 1);
+       (ip->mi)[strlen(ip->mi)] = '\0';
+       strcpy(mapin, op->mi);
+       strncpy(ip->mo, mapout, MAXPATHLEN - 1);
+       (ip->mo)[strlen(ip->mo)] = '\0';
+       strcpy(mapout, op->mo);
+       (void) signal(SIGINT, oldintr);
+       if (abrtflag) {
+               abrtflag = 0;
+               (*oldintr)();
+               }
+}
+
+jmp_buf ptabort;
+int ptabflg;
+
+abortpt()
+{
+       printf("\n");
+       fflush(stdout);
+       ptabflg++;
+       mflag = 0;
+       abrtflag = 0;
+       longjmp(ptabort, 1);
+}
+
+proxtrans(cmd, local, remote)
+       char *cmd, *local, *remote;
+{
+       int (*oldintr)(), abortpt(), tmptype, oldtype = 0, secndflag = 0;
+       extern jmp_buf ptabort;
+       char *cmd2;
+       long mask;
+
+       if (strcmp(cmd, "RETR")) {
+               cmd2 = "RETR";
+       }
+       else {
+               cmd2 = runique ? "STOU" : "STOR";
+       }
+       if (command("PASV") != COMPLETE) {
+               printf("proxy server does not support third part transfers.\n");
+               return;
+       }
+       tmptype = type;
+       pswitch(0);
+       if (!connected) {
+               printf("No primary connection\n");
+               pswitch(1);
+               code = -1;
+               return;
+       }
+       if (type != tmptype) {
+               oldtype = type;
+               switch (tmptype) {
+                       case TYPE_A:
+                               setascii();
+                               break;
+                       case TYPE_I:
+                               setbinary();
+                               break;
+                       case TYPE_E:
+                               setebcdic();
+                               break;
+                       case TYPE_L:
+                               settenex();
+                               break;
+               }
+       }
+       if (command("PORT %s", pasv) != COMPLETE) {
+               switch (oldtype) {
+                       case 0:
+                               break;
+                       case TYPE_A:
+                               setascii();
+                               break;
+                       case TYPE_I:
+                               setbinary();
+                               break;
+                       case TYPE_E:
+                               setebcdic();
+                               break;
+                       case TYPE_L:
+                               settenex();
+                               break;
+               }
+               pswitch(1);
+               return;
+       }
+       if (setjmp(ptabort)) {
+               goto abort;
+       }
+       oldintr = signal(SIGINT, abortpt);
+       if (command("%s %s", cmd, remote) != PRELIM) {
+               (void) signal(SIGINT, oldintr);
+               switch (oldtype) {
+                       case 0:
+                               break;
+                       case TYPE_A:
+                               setascii();
+                               break;
+                       case TYPE_I:
+                               setbinary();
+                               break;
+                       case TYPE_E:
+                               setebcdic();
+                               break;
+                       case TYPE_L:
+                               settenex();
+                               break;
+               }
+               pswitch(1);
+               return;
+       }
+       sleep(2);
+       pswitch(1);
+       secndflag++;
+       if (command("%s %s", cmd2, local) != PRELIM) {
+               goto abort;
+       }
+       ptflag++;
+       (void) getreply(0);
+       pswitch(0);
+       (void) getreply(0);
+       (void) signal(SIGINT, oldintr);
+       switch (oldtype) {
+               case 0:
+                       break;
+               case TYPE_A:
+                       setascii();
+                       break;
+               case TYPE_I:
+                       setbinary();
+                       break;
+               case TYPE_E:
+                       setebcdic();
+                       break;
+               case TYPE_L:
+                       settenex();
+                       break;
+       }
+       pswitch(1);
+       ptflag = 0;
+       printf("local: %s remote: %s\n", local, remote);
+       return;
+abort:
+       (void) signal(SIGINT, SIG_IGN);
+       ptflag = 0;
+       if (strcmp(cmd, "RETR") && !proxy) {
+               pswitch(1);
+       }
+       else if (!strcmp(cmd, "RETR") && proxy) {
+               pswitch(0);
+       }
+       if (!cpend && !secndflag) {  /* only here if cmd = "STOR" (proxy=1) */
+               if (command("%s %s", cmd2, local) != PRELIM) {
+                       pswitch(0);
+                       switch (oldtype) {
+                               case 0:
+                                       break;
+                               case TYPE_A:
+                                       setascii();
+                                       break;
+                               case TYPE_I:
+                                       setbinary();
+                                       break;
+                               case TYPE_E:
+                                       setebcdic();
+                                       break;
+                               case TYPE_L:
+                                       settenex();
+                                       break;
+                       }
+                       if (cpend && telflag) {
+                               char msg[2];
+
+                               fprintf(cout,"%c%c",IAC,IP);
+                               (void) fflush(cout); 
+                               *msg = IAC;
+                               *(msg+1) = DM;
+                               if (send(fileno(cout),msg,2,MSG_OOB) != 2) {
+                                       perror("abort");
+                               }
+                       }
+                       if (cpend) {
+                               fprintf(cout,"ABOR\r\n");
+                               (void) fflush(cout);
+                               mask = 1 << fileno(cin);
+                               if ((mask = empty(mask,10)) < 0) {
+                                       perror("abort");
+                                       if (ptabflg) {
+                                               code = -1;
+                                       }
+                                       lostpeer();
+                               }
+                               (void) getreply(0);
+                               (void) getreply(0);
+                       }
+               }
+               pswitch(1);
+               if (ptabflg) {
+                       code = -1;
+               }
+               (void) signal(SIGINT, oldintr);
+               return;
+       }
+       if (cpend && telflag) {
+               char msg[2];
+
+               fprintf(cout,"%c%c",IAC,IP);
+               (void) fflush(cout); 
+               *msg = IAC;
+               *(msg+1) = DM;
+               if (send(fileno(cout),msg,2,MSG_OOB) != 2) {
+                       perror("abort");
+               }
+       }
+       if (cpend) {
+               fprintf(cout,"ABOR\r\n");
+               (void) fflush(cout);
+               mask = 1 << fileno(cin);
+               if ((mask = empty(mask,10)) < 0) {
+                       perror("abort");
+                       if (ptabflg) {
+                               code = -1;
+                       }
+                       lostpeer();
+               }
+               (void) getreply(0);
+               (void) getreply(0);
+       }
+       pswitch(!proxy);
+       if (!cpend && !secndflag) {  /* only if cmd = "RETR" (proxy=1) */
+               if (command("%s %s", cmd2, local) != PRELIM) {
+                       pswitch(0);
+                       switch (oldtype) {
+                               case 0:
+                                       break;
+                               case TYPE_A:
+                                       setascii();
+                                       break;
+                               case TYPE_I:
+                                       setbinary();
+                                       break;
+                               case TYPE_E:
+                                       setebcdic();
+                                       break;
+                               case TYPE_L:
+                                       settenex();
+                                       break;
+                       }
+                       if (cpend && telflag) {
+                               char msg[2];
+
+                               fprintf(cout,"%c%c",IAC,IP);
+                               (void) fflush(cout); 
+                               *msg = IAC;
+                               *(msg+1) = DM;
+                               if (send(fileno(cout),msg,2,MSG_OOB) != 2) {
+                                       perror("abort");
+                               }
+                       }
+                       if (cpend) {
+                               fprintf(cout,"ABOR\r\n");
+                               (void) fflush(cout);
+                               mask = 1 << fileno(cin);
+                               if ((mask = empty(mask,10)) < 0) {
+                                       perror("abort");
+                                       if (ptabflg) {
+                                               code = -1;
+                                       }
+                                       lostpeer();
+                               }
+                               (void) getreply(0);
+                               (void) getreply(0);
+                       }
+                       pswitch(1);
+                       if (ptabflg) {
+                               code = -1;
+                       }
+                       (void) signal(SIGINT, oldintr);
+                       return;
+               }
+       }
+       if (cpend && telflag) {
+               char msg[2];
+
+               fprintf(cout,"%c%c",IAC,IP);
+               (void) fflush(cout); 
+               *msg = IAC;
+               *(msg+1) = DM;
+               if (send(fileno(cout),msg,2,MSG_OOB) != 2) {
+                       perror("abort");
+               }
+       }
+       if (cpend) {
+               fprintf(cout,"ABOR\r\n");
+               (void) fflush(cout);
+               mask = 1 << fileno(cin);
+               if ((mask = empty(mask,10)) < 0) {
+                       perror("abort");
+                       if (ptabflg) {
+                               code = -1;
+                       }
+                       lostpeer();
+               }
+               (void) getreply(0);
+               (void) getreply(0);
+       }
+       pswitch(!proxy);
+       if (cpend) {
+               mask = 1 << fileno(cin);
+               if ((mask = empty(mask,10)) < 0) {
+                       perror("abort");
+                       if (ptabflg) {
+                               code = -1;
+                       }
+                       lostpeer();
+               }
+               (void) getreply(0);
+               (void) getreply(0);
+       }
+       if (proxy) {
+               pswitch(0);
+       }
+       switch (oldtype) {
+               case 0:
+                       break;
+               case TYPE_A:
+                       setascii();
+                       break;
+               case TYPE_I:
+                       setbinary();
+                       break;
+               case TYPE_E:
+                       setebcdic();
+                       break;
+               case TYPE_L:
+                       settenex();
+                       break;
+       }
+       pswitch(1);
+       if (ptabflg) {
+               code = -1;
+       }
+       (void) signal(SIGINT, oldintr);
+}
+
+reset()
+{
+       long mask;
+
+       mask = 1 << fileno(cin);
+       while (mask > 0) {
+               if ((mask = empty(mask,0)) < 0) {
+                       perror("reset");
+                       code = -1;
+                       lostpeer();
+               }
+               if (mask > 0) {
+                       (void) getreply(0);
+               }
+       }
+}
+
+char *
+gunique(local)
+       char *local;
+{
+       static char new[MAXPATHLEN];
+       char *cp = rindex(local, '/');
+       int d, count=0;
+       char ext = '1';
+
+       if (cp) {
+               *cp = '\0';
+       }
+       d = access(cp ? local : ".", 2);
+       if (cp) {
+               *cp = '/';
+       }
+       if (d < 0) {
+               perror(local);
+               return((char *) 0);
+       }
+       (void) strcpy(new, local);
+       cp = new + strlen(new);
+       *cp++ = '.';
+       while (!d) {
+               if (++count == 100) {
+                       printf("runique: can't find unique file name.\n");
+                       return((char *) 0);
+               }
+               *cp++ = ext;
+               *cp = '\0';
+               if (ext == '9') {
+                       ext = '0';
+               }
+               else {
+                       ext++;
+               }
+               if ((d = access(new, 0)) < 0) {
+                       break;
+               }
+               if (ext != '0') {
+                       cp--;
+               }
+               else if (*(cp - 2) == '.') {
+                       *(cp - 1) = '1';
+               }
+               else {
+                       *(cp - 2) = *(cp - 2) + 1;
+                       cp--;
+               }
+       }
+       return(new);
+}
index eb274ea..9f164a9 100644 (file)
@@ -1,9 +1,9 @@
 /*
 /*
- * Copyright (c) 1980 Regents of the University of California.
+ * Copyright (c) 1985 Regents of the University of California.
  * All rights reserved.  The Berkeley software License Agreement
  * specifies the terms and conditions for redistribution.
  *
  * All rights reserved.  The Berkeley software License Agreement
  * specifies the terms and conditions for redistribution.
  *
- *     @(#)ftp_var.h   5.1 (Berkeley) %G%
+ *     @(#)ftp_var.h   5.2 (Berkeley) %G%
  */
 
 /*
  */
 
 /*
@@ -24,7 +24,23 @@ int  debug;                  /* debugging level */
 int    bell;                   /* ring bell on cmd completion */
 int    doglob;                 /* glob local file names */
 int    autologin;              /* establish user account on connection */
 int    bell;                   /* ring bell on cmd completion */
 int    doglob;                 /* glob local file names */
 int    autologin;              /* establish user account on connection */
-
+int    proxy;                  /* proxy server connection active */
+int    proxflag;               /* proxy connection exists */
+int    sunique;                /* store files on server with unique name */
+int    runique;                /* store local files with unique name */
+int    mcase;                  /* map upper to lower case for mget names */
+int    ntflag;                 /* use ntin ntout tables for name translation */
+int    mapflag;                /* use mapin mapout templates on file names */
+int    code;                   /* return/reply code for ftp command */
+int    macroflg;               /* active macro */
+int    crflag;                 /* if 1, strip car. rets. on ascii gets */
+char   pasv[64];               /* passive port for proxy data connection */
+char   *altarg;                /* argv[1] with no shell-like preprocessing  */
+char   ntin[17];               /* input translation table */
+char   ntout[17];              /* output translation table */
+#include <sys/param.h>
+char   mapin[MAXPATHLEN];      /* input map template */
+char   mapout[MAXPATHLEN];     /* output map template */
 char   typename[32];           /* name of file transfer type */
 int    type;                   /* file transfer type */
 char   structname[32];         /* name of file transfer structure */
 char   typename[32];           /* name of file transfer type */
 int    type;                   /* file transfer type */
 char   structname[32];         /* name of file transfer structure */
@@ -49,6 +65,8 @@ char  argbuf[200];            /* argument storage buffer */
 char   *argbase;               /* current storage point in arg buffer */
 int    margc;                  /* count of arguments on input line */
 char   *margv[20];             /* args parsed from input line */
 char   *argbase;               /* current storage point in arg buffer */
 int    margc;                  /* count of arguments on input line */
 char   *margv[20];             /* args parsed from input line */
+int     cpend;                  /* flag: if != 0, then pending server reply */
+int    mflag;                  /* flag: if != 0, then active multi command */
 
 int    options;                /* used during socket creation */
 
 
 int    options;                /* used during socket creation */
 
@@ -60,9 +78,20 @@ struct cmd {
        char    *c_help;        /* help string */
        char    c_bell;         /* give bell when command completes */
        char    c_conn;         /* must be connected to use command */
        char    *c_help;        /* help string */
        char    c_bell;         /* give bell when command completes */
        char    c_conn;         /* must be connected to use command */
+       char    c_proxy;        /* proxy server may execute */
        int     (*c_handler)(); /* function to call */
 };
 
        int     (*c_handler)(); /* function to call */
 };
 
+struct macel {
+       char mac_name[9];       /* macro name */
+       char *mac_start;        /* start of macro in macbuf */
+       char *mac_end;          /* end of macro in macbuf */
+};
+
+int macnum;                    /* number of defined macros */
+struct macel macros[16], *macpt;
+char macbuf[4096];
+
 extern char *tail();
 extern char *index();
 extern char *rindex();
 extern char *tail();
 extern char *index();
 extern char *rindex();
index 3bca1fc..34eea80 100644 (file)
@@ -1,23 +1,23 @@
 /*
 /*
- * Copyright (c) 1983 Regents of the University of California.
+ * Copyright (c) 1985 Regents of the University of California.
  * All rights reserved.  The Berkeley software License Agreement
  * specifies the terms and conditions for redistribution.
  */
 
 #ifndef lint
 char copyright[] =
  * All rights reserved.  The Berkeley software License Agreement
  * specifies the terms and conditions for redistribution.
  */
 
 #ifndef lint
 char copyright[] =
-"@(#) Copyright (c) 1983 Regents of the University of California.\n\
+"@(#) Copyright (c) 1985 Regents of the University of California.\n\
  All rights reserved.\n";
 #endif not lint
 
 #ifndef lint
  All rights reserved.\n";
 #endif not lint
 
 #ifndef lint
-static char sccsid[] = "@(#)main.c     5.3 (Berkeley) %G%";
+static char sccsid[] = "@(#)main.c     5.4 (Berkeley) %G%";
 #endif not lint
 
 /*
  * FTP User Program -- Command Interface.
  */
 #endif not lint
 
 /*
  * FTP User Program -- Command Interface.
  */
-#include <sys/param.h>
+#include "ftp_var.h"
 #include <sys/socket.h>
 #include <sys/ioctl.h>
 
 #include <sys/socket.h>
 #include <sys/ioctl.h>
 
@@ -30,7 +30,6 @@ static char sccsid[] = "@(#)main.c    5.3 (Berkeley) %G%";
 #include <netdb.h>
 #include <pwd.h>
 
 #include <netdb.h>
 #include <pwd.h>
 
-#include "ftp_var.h"
 
 int    intr();
 int    lostpeer();
 
 int    intr();
 int    lostpeer();
@@ -101,12 +100,16 @@ main(argc, argv)
        strcpy(bytename, "8"), bytesize = 8;
        if (fromatty)
                verbose++;
        strcpy(bytename, "8"), bytesize = 8;
        if (fromatty)
                verbose++;
+       cpend = 0;           /* no pending replies */
+       proxy = 0;      /* proxy not active */
+       crflag = 1;    /* strip c.r. on ascii gets */
        /*
         * Set up the home directory in case we're globbing.
         */
        cp = getlogin();
        /*
         * Set up the home directory in case we're globbing.
         */
        cp = getlogin();
-       if (cp != NULL)
+       if (cp != NULL) {
                pw = getpwnam(cp);
                pw = getpwnam(cp);
+       }
        if (pw == NULL)
                pw = getpwuid(getuid());
        if (pw != NULL) {
        if (pw == NULL)
                pw = getpwuid(getuid());
        if (pw != NULL) {
@@ -155,7 +158,17 @@ lostpeer()
                }
                connected = 0;
        }
                }
                connected = 0;
        }
-       longjmp(toplevel, 1);
+       pswitch(1);
+       if (connected) {
+               if (cout != NULL) {
+                       shutdown(fileno(cout), 1+1);
+                       fclose(cout);
+                       cout = NULL;
+               }
+               connected = 0;
+       }
+       proxflag = 0;
+       pswitch(0);
 }
 
 char *
 }
 
 char *
@@ -194,15 +207,20 @@ cmdscanner(top)
                        fflush(stdout);
                }
                if (gets(line) == 0) {
                        fflush(stdout);
                }
                if (gets(line) == 0) {
-                       if (feof(stdin))
-                               quit();
+                       if (feof(stdin)) {
+                               if (!fromatty)
+                                       quit();
+                               clearerr(stdin);
+                               putchar('\n');
+                       }
                        break;
                }
                if (line[0] == 0)
                        break;
                makeargv();
                        break;
                }
                if (line[0] == 0)
                        break;
                makeargv();
-               if (margc == 0)
+               if (margc == 0) {
                        continue;
                        continue;
+               }
                c = getcmd(margv[0]);
                if (c == (struct cmd *)-1) {
                        printf("?Ambiguous command\n");
                c = getcmd(margv[0]);
                if (c == (struct cmd *)-1) {
                        printf("?Ambiguous command\n");
@@ -222,6 +240,8 @@ cmdscanner(top)
                if (c->c_handler != help)
                        break;
        }
                if (c->c_handler != help)
                        break;
        }
+       signal(SIGINT, intr);
+       signal(SIGPIPE, lostpeer);
 }
 
 struct cmd *
 }
 
 struct cmd *
@@ -256,6 +276,9 @@ getcmd(name)
 /*
  * Slice a string up into argc/argv.
  */
 /*
  * Slice a string up into argc/argv.
  */
+
+int slrflag;
+
 makeargv()
 {
        char **argp;
 makeargv()
 {
        char **argp;
@@ -265,23 +288,9 @@ makeargv()
        argp = margv;
        stringbase = line;              /* scan from first of buffer */
        argbase = argbuf;               /* store from first of buffer */
        argp = margv;
        stringbase = line;              /* scan from first of buffer */
        argbase = argbuf;               /* store from first of buffer */
-       while (*stringbase == ' ' || *stringbase == '\t')
-               stringbase++;           /* skip initial white space */
-       if (*stringbase == '!') {       /* handle shell escapes specially */
-               stringbase++;
-               *argp++ = "!";          /* command name is "!" */
+       slrflag = 0;
+       while (*argp++ = slurpstring())
                margc++;
                margc++;
-               while (*stringbase == ' ' || *stringbase == '\t')
-                       stringbase++;           /* skip white space */
-               if (*stringbase != '\0') {
-                       *argp++ = stringbase;   /* argument is entire command string */
-                       margc++;
-               }
-               *argp++ = NULL;
-       } else {
-               while (*argp++ = slurpstring())
-                       margc++;
-       }
 }
 
 /*
 }
 
 /*
@@ -297,6 +306,22 @@ slurpstring()
        register char *ap = argbase;
        char *tmp = argbase;            /* will return this if token found */
 
        register char *ap = argbase;
        char *tmp = argbase;            /* will return this if token found */
 
+       if (*sb == '!' || *sb == '$') { /* recognize ! as a token for shell */
+               switch (slrflag) {      /* and $ as token for macro invoke */
+                       case 0:
+                               slrflag++;
+                               stringbase++;
+                               return ((*sb == '!') ? "!" : "$");
+                               break;
+                       case 1:
+                               slrflag++;
+                               altarg = stringbase;
+                               break;
+                       default:
+                               break;
+               }
+       }
+
 S0:
        switch (*sb) {
 
 S0:
        switch (*sb) {
 
@@ -308,6 +333,17 @@ S0:
                sb++; goto S0;
 
        default:
                sb++; goto S0;
 
        default:
+               switch (slrflag) {
+                       case 0:
+                               slrflag++;
+                               break;
+                       case 1:
+                               slrflag++;
+                               altarg = sb;
+                               break;
+                       default:
+                               break;
+               }
                goto S1;
        }
 
                goto S1;
        }
 
@@ -363,8 +399,20 @@ OUT:
                *ap++ = '\0';
        argbase = ap;                   /* update storage pointer */
        stringbase = sb;                /* update scan pointer */
                *ap++ = '\0';
        argbase = ap;                   /* update storage pointer */
        stringbase = sb;                /* update scan pointer */
-       if (got_one)
+       if (got_one) {
                return(tmp);
                return(tmp);
+       }
+       switch (slrflag) {
+               case 0:
+                       slrflag++;
+                       break;
+               case 1:
+                       slrflag++;
+                       altarg = (char *) 0;
+                       break;
+               default:
+                       break;
+       }
        return((char *)0);
 }
 
        return((char *)0);
 }
 
@@ -381,7 +429,7 @@ help(argc, argv)
        register struct cmd *c;
 
        if (argc == 1) {
        register struct cmd *c;
 
        if (argc == 1) {
-               register int i, j, w;
+               register int i, j, w, k;
                int columns, width = 0, lines;
                extern int NCMDS;
 
                int columns, width = 0, lines;
                extern int NCMDS;
 
@@ -400,8 +448,14 @@ help(argc, argv)
                for (i = 0; i < lines; i++) {
                        for (j = 0; j < columns; j++) {
                                c = cmdtab + j * lines + i;
                for (i = 0; i < lines; i++) {
                        for (j = 0; j < columns; j++) {
                                c = cmdtab + j * lines + i;
-                               if (c->c_name)
+                               if (c->c_name && (!proxy || c->c_proxy)) {
                                        printf("%s", c->c_name);
                                        printf("%s", c->c_name);
+                               }
+                               else if (c->c_name) {
+                                       for (k=0; k < strlen(c->c_name); k++) {
+                                               putchar(' ');
+                                       }
+                               }
                                if (c + lines >= &cmdtab[NCMDS]) {
                                        printf("\n");
                                        break;
                                if (c + lines >= &cmdtab[NCMDS]) {
                                        printf("\n");
                                        break;