minor fixes from ut-sally
[unix-history] / usr / src / usr.bin / ftp / cmds.c
index 6d5f9af..03daee1 100644 (file)
@@ -1,22 +1,30 @@
 #ifndef lint
 #ifndef lint
-static char sccsid[] = "@(#)cmds.c     4.1 (Berkeley) %G%";
+static char sccsid[] = "@(#)cmds.c     4.11 (Berkeley) %G%";
 #endif
 
 /*
  * FTP User Program -- Command Routines.
  */
 #endif
 
 /*
  * FTP User Program -- Command Routines.
  */
-#include <sys/types.h>
+#include <sys/param.h>
 #include <sys/socket.h>
 
 #include <sys/socket.h>
 
+#include <arpa/ftp.h>
+
 #include <signal.h>
 #include <stdio.h>
 #include <errno.h>
 #include <netdb.h>
 
 #include <signal.h>
 #include <stdio.h>
 #include <errno.h>
 #include <netdb.h>
 
-#include "ftp.h"
 #include "ftp_var.h"
 
 #include "ftp_var.h"
 
-int    autologin = 1;
+extern char *globerr;
+extern char **glob();
+extern char *home;
+extern short gflag;
+extern char *remglob();
+extern char *getenv();
+extern char *index();
+extern char *rindex();
 
 /*
  * Connect to peer server and
 
 /*
  * Connect to peer server and
@@ -48,9 +56,10 @@ setpeer(argc, argv)
        }
        port = sp->s_port;
        if (argc > 2) {
        }
        port = sp->s_port;
        if (argc > 2) {
-               port = atoi(argv[1]);
+               port = atoi(argv[2]);
                if (port <= 0) {
                if (port <= 0) {
-                       printf("%s: bad port number.\n", argv[1]);
+                       printf("%s: bad port number-- %s\n", argv[1], argv[2]);
+                       printf ("usage: %s host-name [port]\n", argv[0]);
                        return;
                }
                port = htons(port);
                        return;
                }
                port = htons(port);
@@ -67,12 +76,13 @@ struct      types {
        char    *t_name;
        char    *t_mode;
        int     t_type;
        char    *t_name;
        char    *t_mode;
        int     t_type;
+       char    *t_arg;
 } types[] = {
 } types[] = {
-       { "ascii",      "A",    TYPE_A },
-       { "binary",     "I",    TYPE_I },
-       { "image",      "I",    TYPE_I },
-       { "ebcdic",     "E",    TYPE_E },
-       { "tenex",      "L",    TYPE_L },
+       { "ascii",      "A",    TYPE_A, 0 },
+       { "binary",     "I",    TYPE_I, 0 },
+       { "image",      "I",    TYPE_I, 0 },
+       { "ebcdic",     "E",    TYPE_E, 0 },
+       { "tenex",      "L",    TYPE_L, bytename },
        0
 };
 
        0
 };
 
@@ -83,6 +93,7 @@ settype(argc, argv)
        char *argv[];
 {
        register struct types *p;
        char *argv[];
 {
        register struct types *p;
+       int comret;
 
        if (argc > 2) {
                char *sep;
 
        if (argc > 2) {
                char *sep;
@@ -108,7 +119,11 @@ settype(argc, argv)
                printf("%s: unknown mode\n", argv[1]);
                return;
        }
                printf("%s: unknown mode\n", argv[1]);
                return;
        }
-       if (command("TYPE %s", p->t_mode) == COMPLETE) {
+       if ((p->t_arg != NULL) && (*(p->t_arg) != '\0'))
+               comret = command ("TYPE %s %s", p->t_mode, p->t_arg);
+       else
+               comret = command("TYPE %s", p->t_mode);
+       if (comret == COMPLETE) {
                strcpy(typename, p->t_name);
                type = p->t_type;
        }
                strcpy(typename, p->t_name);
                type = p->t_type;
        }
@@ -188,16 +203,11 @@ setstruct(argc, argv)
  * Send a single file.
  */
 put(argc, argv)
  * Send a single file.
  */
 put(argc, argv)
+       int argc;
        char *argv[];
 {
        char *argv[];
 {
-       int fd;
-       register int n, addr;
-       register char *cp, *targ;
+       char *cmd;
 
 
-       if (!connected) {
-               printf("Not connected.\n");
-               return;
-       }
        if (argc == 2)
                argc++, argv[2] = argv[1];
        if (argc < 2) {
        if (argc == 2)
                argc++, argv[2] = argv[1];
        if (argc < 2) {
@@ -223,24 +233,62 @@ usage:
        }
        if (argc < 3) 
                goto usage;
        }
        if (argc < 3) 
                goto usage;
-       sendrequest("STOR", argv[1], argv[2]);
+       if (!globulize(&argv[1]))
+               return;
+       cmd = (argv[0][0] == 'a') ? "APPE" : "STOR";
+       sendrequest(cmd, argv[1], argv[2]);
 }
 
 /*
 }
 
 /*
- * Receive a single file.
+ * Send multiple files.
  */
  */
-get(argc, argv)
+mput(argc, argv)
        char *argv[];
 {
        char *argv[];
 {
-       int fd;
-       register int n, addr;
-       register char *cp;
-       char *src;
+       register int i;
 
 
-       if (!connected) {
-               printf("Not connected.\n");
+       if (argc < 2) {
+               strcat(line, " ");
+               printf("(local-files) ");
+               gets(&line[strlen(line)]);
+               makeargv();
+               argc = margc;
+               argv = margv;
+       }
+       if (argc < 2) {
+               printf("%s local-files\n", argv[0]);
                return;
        }
                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]);
+                       continue;
+               }
+               gargs = glob(argv[i]);
+               if (globerr != NULL) {
+                       printf("%s\n", globerr);
+                       if (gargs)
+                               blkfree(gargs);
+                       continue;
+               }
+               for (cpp = gargs; cpp && *cpp != NULL; cpp++)
+                       if (confirm(argv[0], *cpp))
+                               sendrequest("STOR", *cpp, *cpp);
+               if (gargs != NULL)
+                       blkfree(gargs);
+       }
+}
+
+/*
+ * Receive one file.
+ */
+get(argc, argv)
+       char *argv[];
+{
+
        if (argc == 2)
                argc++, argv[2] = argv[1];
        if (argc < 2) {
        if (argc == 2)
                argc++, argv[2] = argv[1];
        if (argc < 2) {
@@ -253,7 +301,7 @@ get(argc, argv)
        }
        if (argc < 2) {
 usage:
        }
        if (argc < 2) {
 usage:
-               printf("%s remote-file local-file\n", argv[0]);
+               printf("%s remote-file [ local-file ]\n", argv[0]);
                return;
        }
        if (argc < 3) {
                return;
        }
        if (argc < 3) {
@@ -266,7 +314,76 @@ usage:
        }
        if (argc < 3) 
                goto usage;
        }
        if (argc < 3) 
                goto usage;
-       recvrequest("RETR", argv[2], argv[1]);
+       if (!globulize(&argv[2]))
+               return;
+       recvrequest("RETR", argv[2], argv[1], "w");
+}
+
+/*
+ * Get multiple files.
+ */
+mget(argc, argv)
+       char *argv[];
+{
+       char *cp;
+
+       if (argc < 2) {
+               strcat(line, " ");
+               printf("(remote-files) ");
+               gets(&line[strlen(line)]);
+               makeargv();
+               argc = margc;
+               argv = margv;
+       }
+       if (argc < 2) {
+               printf("%s remote-files\n", argv[0]);
+               return;
+       }
+       while ((cp = remglob(argc, argv)) != NULL)
+               if (confirm(argv[0], cp))
+                       recvrequest("RETR", cp, cp, "w");
+}
+
+char *
+remglob(argc, argv)
+       char *argv[];
+{
+       char temp[16];
+       static char buf[MAXPATHLEN];
+       static FILE *ftemp = NULL;
+       static char **args;
+       int oldverbose, oldhash;
+       char *cp, *mode;
+
+       if (!doglob) {
+               if (args == NULL)
+                       args = argv;
+               if ((cp = *++args) == NULL)
+                       args = NULL;
+               return (cp);
+       }
+       if (ftemp == NULL) {
+               strcpy(temp, "/tmp/ftpXXXXXX");
+               mktemp(temp);
+               oldverbose = verbose, verbose = 0;
+               oldhash = hash, hash = 0;
+               for (mode = "w"; *++argv != NULL; mode = "a")
+                       recvrequest ("NLST", temp, *argv, mode);
+               verbose = oldverbose; hash = oldhash;
+               ftemp = fopen(temp, "r");
+               unlink(temp);
+               if (ftemp == NULL) {
+                       printf("can't find list of remote files, oops\n");
+                       return (NULL);
+               }
+       }
+       if (fgets(buf, sizeof (buf), ftemp) == NULL) {
+               fclose(ftemp), ftemp = NULL;
+               return (NULL);
+       }
+       if ((cp = index(buf, '\n')) != NULL)
+               *cp = '\0';
+       return (buf);
 }
 
 char *
 }
 
 char *
@@ -290,8 +407,11 @@ status(argc, argv)
                printf("Not connected.\n");
        printf("Mode: %s; Type: %s; Form: %s; Structure: %s\n",
                modename, typename, formname, structname);
                printf("Not connected.\n");
        printf("Mode: %s; Type: %s; Form: %s; Structure: %s\n",
                modename, typename, formname, structname);
-       printf("Verbose: %s; Bell: %s; Prompting: %s\n", 
-               onoff(verbose), onoff(bell), onoff(interactive));
+       printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s\n", 
+               onoff(verbose), onoff(bell), onoff(interactive),
+               onoff(doglob));
+       printf("Hash mark printing: %s; Use of PORT cmds: %s\n",
+               onoff(hash), onoff(sendport));
 }
 
 /*
 }
 
 /*
@@ -316,6 +436,20 @@ settrace()
        printf("Packet tracing %s.\n", onoff(trace));
 }
 
        printf("Packet tracing %s.\n", onoff(trace));
 }
 
+/*
+ * Toggle hash mark printing during transfers.
+ */
+/*VARARGS*/
+sethash()
+{
+
+       hash = !hash;
+       printf("Hash mark printing %s", onoff(hash));
+       if (hash)
+               printf(" (%d bytes/hash mark)", BUFSIZ);
+       printf(".\n");
+}
+
 /*
  * Turn on printing of server echo's.
  */
 /*
  * Turn on printing of server echo's.
  */
@@ -327,6 +461,17 @@ setverbose()
        printf("Verbose mode %s.\n", onoff(verbose));
 }
 
        printf("Verbose mode %s.\n", onoff(verbose));
 }
 
+/*
+ * Toggle PORT cmd use before each data connection.
+ */
+/*VARARGS*/
+setport()
+{
+
+       sendport = !sendport;
+       printf("Use of PORT cmds %s.\n", onoff(sendport));
+}
+
 /*
  * Turn on interactive prompting
  * during mget, mput, and mdelete.
 /*
  * Turn on interactive prompting
  * during mget, mput, and mdelete.
@@ -339,6 +484,18 @@ setprompt()
        printf("Interactive mode %s.\n", onoff(interactive));
 }
 
        printf("Interactive mode %s.\n", onoff(interactive));
 }
 
+/*
+ * Toggle metacharacter interpretation
+ * on local file names.
+ */
+/*VARARGS*/
+setglob()
+{
+       
+       doglob = !doglob;
+       printf("Globbing %s.\n", onoff(doglob));
+}
+
 /*
  * Set debugging mode on/off and/or
  * set level of debugging.
 /*
  * Set debugging mode on/off and/or
  * set level of debugging.
@@ -373,10 +530,6 @@ cd(argc, argv)
        char *argv[];
 {
 
        char *argv[];
 {
 
-       if (!connected) {
-               printf("Not connected.\n");
-               return;
-       }
        if (argc < 2) {
                strcat(line, " ");
                printf("(remote-directory) ");
        if (argc < 2) {
                strcat(line, " ");
                printf("(remote-directory) ");
@@ -392,8 +545,6 @@ cd(argc, argv)
        (void) command("CWD %s", argv[1]);
 }
 
        (void) command("CWD %s", argv[1]);
 }
 
-#include <pwd.h>
-
 /*
  * Set current working directory
  * on local machine.
 /*
  * Set current working directory
  * on local machine.
@@ -401,26 +552,21 @@ cd(argc, argv)
 lcd(argc, argv)
        char *argv[];
 {
 lcd(argc, argv)
        char *argv[];
 {
-       static struct passwd *pw = NULL;
+       char buf[MAXPATHLEN];
 
 
-       if (argc < 2) {
-               if (pw == NULL) {
-                       pw = getpwnam(getlogin());
-                       if (pw == NULL)
-                               pw = getpwuid(getuid());
-               }
-               if (pw == NULL) {
-                       printf("ftp: can't find home directory.\n");
-                       return;
-               }
-               argc++, argv[1] = pw->pw_dir;
-       }
+       if (argc < 2)
+               argc++, argv[1] = home;
        if (argc != 2) {
                printf("%s local-directory\n", argv[0]);
                return;
        }
        if (argc != 2) {
                printf("%s local-directory\n", argv[0]);
                return;
        }
-       if (chdir(argv[1]) < 0)
+       if (!globulize(&argv[1]))
+               return;
+       if (chdir(argv[1]) < 0) {
                perror(argv[1]);
                perror(argv[1]);
+               return;
+       }
+       printf("Local directory now %s\n", getwd(buf));
 }
 
 /*
 }
 
 /*
@@ -445,6 +591,31 @@ delete(argc, argv)
        (void) command("DELE %s", argv[1]);
 }
 
        (void) command("DELE %s", argv[1]);
 }
 
+/*
+ * Delete multiple files.
+ */
+mdelete(argc, argv)
+       char *argv[];
+{
+       char *cp;
+
+       if (argc < 2) {
+               strcat(line, " ");
+               printf("(remote-files) ");
+               gets(&line[strlen(line)]);
+               makeargv();
+               argc = margc;
+               argv = margv;
+       }
+       if (argc < 2) {
+               printf("%s remote-files\n", argv[0]);
+               return;
+       }
+       while ((cp = remglob(argc, argv)) != NULL)
+               if (confirm(argv[0], cp))
+                       (void) command("DELE %s", cp);
+}
+
 /*
  * Rename a remote file.
  */
 /*
  * Rename a remote file.
  */
@@ -497,7 +668,49 @@ ls(argc, argv)
                return;
        }
        cmd = argv[0][0] == 'l' ? "NLST" : "LIST";
                return;
        }
        cmd = argv[0][0] == 'l' ? "NLST" : "LIST";
-       recvrequest(cmd, argv[2], argv[1]);
+       if (strcmp(argv[2], "-") && !globulize(&argv[2]))
+               return;
+       recvrequest(cmd, argv[2], argv[1], "w");
+}
+
+/*
+ * Get a directory listing
+ * of multiple remote files.
+ */
+mls(argc, argv)
+       char *argv[];
+{
+       char *cmd, *mode, *cp, *dest;
+
+       if (argc < 2) {
+               strcat(line, " ");
+               printf("(remote-files) ");
+               gets(&line[strlen(line)]);
+               makeargv();
+               argc = margc;
+               argv = margv;
+       }
+       if (argc < 3) {
+               strcat(line, " ");
+               printf("(local-file) ");
+               gets(&line[strlen(line)]);
+               makeargv();
+               argc = margc;
+               argv = margv;
+       }
+       if (argc < 3) {
+               printf("%s remote-files local-file\n", argv[0]);
+               return;
+       }
+       dest = argv[argc - 1];
+       argv[argc - 1] = NULL;
+       if (strcmp(dest, "-"))
+               if (!globulize(&dest) || !confirm("local-file", dest))
+                       return;
+       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);
 }
 
 /*
 }
 
 /*
@@ -506,8 +719,66 @@ ls(argc, argv)
 shell(argc, argv)
        char *argv[];
 {
 shell(argc, argv)
        char *argv[];
 {
-
-       printf("Sorry, this function is unimplemented.\n");
+       int pid, status, (*old1)(), (*old2)();
+       char shellnam[40], *shell, *namep;
+       char **cpp, **gargs;
+
+       old1 = signal (SIGINT, SIG_IGN);
+       old2 = signal (SIGQUIT, SIG_IGN);
+       if ((pid = fork()) == 0) {
+               for (pid = 3; pid < 20; pid++)
+                       close(pid);
+               signal(SIGINT, SIG_DFL);
+               signal(SIGQUIT, SIG_DFL);
+               if (argc <= 1) {
+                       shell = getenv("SHELL");
+                       if (shell == NULL)
+                               shell = "/bin/sh";
+                       namep = rindex(shell,'/');
+                       if (namep == NULL)
+                               namep = shell;
+                       strcpy(shellnam,"-");
+                       strcat(shellnam, ++namep);
+                       if (strcmp(namep, "sh") != 0)
+                               shellnam[0] = '+';
+                       if (debug) {
+                               printf ("%s\n", shell);
+                               fflush (stdout);
+                       }
+                       execl(shell, shellnam, 0);
+                       perror(shell);
+                       exit(1);
+               }
+               cpp = &argv[1];
+               if (argc > 2) {
+                       if ((gargs = glob(cpp)) != NULL)
+                               cpp = gargs;
+                       if (globerr != NULL) {
+                               printf("%s\n", globerr);
+                               exit(1);
+                       }
+               }
+               if (debug) {
+                       register char **zip = cpp;
+
+                       printf("%s", *zip);
+                       while (*++zip != NULL)
+                               printf(" %s", *zip);
+                       printf("\n");
+                       fflush(stdout);
+               }
+               execvp(argv[1], cpp);
+               perror(argv[1]);
+               exit(1);
+       }
+       if (pid > 0)
+               while (wait(&status) != pid)
+                       ;
+       signal(SIGINT, old1);
+       signal(SIGQUIT, old2);
+       if (pid == -1)
+               perror("Try again later");
+       return (0);
 }
 
 /*
 }
 
 /*
@@ -530,7 +801,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]);
-               return;
+               return (0);
        }
        n = command("USER %s", argv[1]);
        if (n == CONTINUE) {
        }
        n = command("USER %s", argv[1]);
        if (n == CONTINUE) {
@@ -560,10 +831,7 @@ user(argc, argv)
 /*VARARGS*/
 pwd()
 {
 /*VARARGS*/
 pwd()
 {
-       if (!connected) {
-               printf("Not connected.\n");
-               return;
-       }
+
        (void) command("XPWD");
 }
 
        (void) command("XPWD");
 }
 
@@ -660,7 +928,8 @@ rmthelp(argc, argv)
 quit()
 {
 
 quit()
 {
 
-       disconnect();
+       if (connected)
+               disconnect();
        exit(0);
 }
 
        exit(0);
 }
 
@@ -680,3 +949,53 @@ disconnect()
        connected = 0;
        data = -1;
 }
        connected = 0;
        data = -1;
 }
+
+confirm(cmd, file)
+       char *cmd, *file;
+{
+       char line[BUFSIZ];
+
+       if (!interactive)
+               return (1);
+       printf("%s %s? ", cmd, file);
+       fflush(stdout);
+       gets(line);
+       return (*line != 'n' && *line != 'N');
+}
+
+fatal(msg)
+       char *msg;
+{
+
+       fprintf(stderr, "ftp: %s\n");
+       exit(1);
+}
+
+/*
+ * Glob a local file name specification with
+ * the expectation of a single return value.
+ * Can't control multiple values being expanded
+ * from the expression, we return only the first.
+ */
+globulize(cpp)
+       char **cpp;
+{
+       char **globbed;
+
+       if (!doglob)
+               return (1);
+       globbed = glob(*cpp);
+       if (globerr != NULL) {
+               printf("%s: %s\n", *cpp, globerr);
+               if (globbed)
+                       blkfree(globbed);
+               return (0);
+       }
+       if (globbed) {
+               *cpp = *globbed++;
+               /* don't waste too much memory */
+               if (*globbed)
+                       blkfree(globbed);
+       }
+       return (1);
+}