110294Ssam #ifndef lint 2*12396Ssam static char sccsid[] = "@(#)cmds.c 4.6 (Berkeley) 05/11/83"; 310294Ssam #endif 410294Ssam 510294Ssam /* 610294Ssam * FTP User Program -- Command Routines. 710294Ssam */ 811353Ssam #include <sys/param.h> 910294Ssam #include <sys/socket.h> 1010294Ssam 11*12396Ssam #include <arpa/ftp.h> 12*12396Ssam 1310294Ssam #include <signal.h> 1410294Ssam #include <stdio.h> 1510294Ssam #include <errno.h> 1610294Ssam #include <netdb.h> 1711353Ssam #include <stat.h> 1810294Ssam 1910294Ssam #include "ftp_var.h" 2010294Ssam 2111353Ssam extern char *globerr; 2211353Ssam extern char **glob(); 2311756Ssam extern char *home; 2411353Ssam extern short gflag; 2511756Ssam extern char *remglob(); 2611756Ssam extern char *getenv(); 2711756Ssam extern char *index(); 2811756Ssam extern char *rindex(); 2910294Ssam 3010294Ssam /* 3110294Ssam * Connect to peer server and 3210294Ssam * auto-login, if possible. 3310294Ssam */ 3410294Ssam setpeer(argc, argv) 3510294Ssam int argc; 3610294Ssam char *argv[]; 3710294Ssam { 3810294Ssam struct hostent *host, *hookup(); 3910294Ssam int port; 4010294Ssam 4110294Ssam if (connected) { 4210294Ssam printf("Already connected to %s, use disconnect first.\n", 4310294Ssam hostname); 4410294Ssam return; 4510294Ssam } 4610294Ssam if (argc < 2) { 4710294Ssam strcat(line, " "); 4810294Ssam printf("(to) "); 4910294Ssam gets(&line[strlen(line)]); 5010294Ssam makeargv(); 5110294Ssam argc = margc; 5210294Ssam argv = margv; 5310294Ssam } 5410294Ssam if (argc > 3) { 5510294Ssam printf("usage: %s host-name [port]\n", argv[0]); 5610294Ssam return; 5710294Ssam } 5810294Ssam port = sp->s_port; 5910294Ssam if (argc > 2) { 6011218Ssam port = atoi(argv[2]); 6110294Ssam if (port <= 0) { 6211218Ssam printf("%s: bad port number-- %s\n", argv[1], argv[2]); 6311218Ssam printf ("usage: %s host-name [port]\n", argv[0]); 6410294Ssam return; 6510294Ssam } 6610294Ssam port = htons(port); 6710294Ssam } 6810294Ssam host = hookup(argv[1], port); 6910294Ssam if (host) { 7010294Ssam connected = 1; 7110294Ssam if (autologin) 7210294Ssam login(host); 7310294Ssam } 7410294Ssam } 7510294Ssam 7610294Ssam struct types { 7710294Ssam char *t_name; 7810294Ssam char *t_mode; 7910294Ssam int t_type; 8011218Ssam char *t_arg; 8110294Ssam } types[] = { 8211218Ssam { "ascii", "A", TYPE_A, 0 }, 8311218Ssam { "binary", "I", TYPE_I, 0 }, 8411218Ssam { "image", "I", TYPE_I, 0 }, 8511218Ssam { "ebcdic", "E", TYPE_E, 0 }, 8611218Ssam { "tenex", "L", TYPE_L, bytename }, 8710294Ssam 0 8810294Ssam }; 8910294Ssam 9010294Ssam /* 9110294Ssam * Set transfer type. 9210294Ssam */ 9310294Ssam settype(argc, argv) 9410294Ssam char *argv[]; 9510294Ssam { 9610294Ssam register struct types *p; 9711218Ssam int comret; 9810294Ssam 9910294Ssam if (argc > 2) { 10010294Ssam char *sep; 10110294Ssam 10210294Ssam printf("usage: %s [", argv[0]); 10310294Ssam sep = " "; 10410294Ssam for (p = types; p->t_name; p++) { 10510294Ssam printf("%s%s", sep, p->t_name); 10610294Ssam if (*sep == ' ') 10710294Ssam sep = " | "; 10810294Ssam } 10910294Ssam printf(" ]\n"); 11010294Ssam return; 11110294Ssam } 11210294Ssam if (argc < 2) { 11310294Ssam printf("Using %s mode to transfer files.\n", typename); 11410294Ssam return; 11510294Ssam } 11610294Ssam for (p = types; p->t_name; p++) 11710294Ssam if (strcmp(argv[1], p->t_name) == 0) 11810294Ssam break; 11910294Ssam if (p->t_name == 0) { 12010294Ssam printf("%s: unknown mode\n", argv[1]); 12110294Ssam return; 12210294Ssam } 12311218Ssam if ((p->t_arg != NULL) && (*(p->t_arg) != '\0')) 12411218Ssam comret = command ("TYPE %s %s", p->t_mode, p->t_arg); 12511218Ssam else 12611218Ssam comret = command("TYPE %s", p->t_mode); 12711218Ssam if (comret == COMPLETE) { 12810294Ssam strcpy(typename, p->t_name); 12910294Ssam type = p->t_type; 13010294Ssam } 13110294Ssam } 13210294Ssam 13310294Ssam /* 13410294Ssam * Set binary transfer type. 13510294Ssam */ 13610294Ssam /*VARARGS*/ 13710294Ssam setbinary() 13810294Ssam { 13910294Ssam 14010294Ssam call(settype, "type", "binary", 0); 14110294Ssam } 14210294Ssam 14310294Ssam /* 14410294Ssam * Set ascii transfer type. 14510294Ssam */ 14610294Ssam /*VARARGS*/ 14710294Ssam setascii() 14810294Ssam { 14910294Ssam 15010294Ssam call(settype, "type", "ascii", 0); 15110294Ssam } 15210294Ssam 15310294Ssam /* 15410294Ssam * Set tenex transfer type. 15510294Ssam */ 15610294Ssam /*VARARGS*/ 15710294Ssam settenex() 15810294Ssam { 15910294Ssam 16010294Ssam call(settype, "type", "tenex", 0); 16110294Ssam } 16210294Ssam 16310294Ssam /* 16410294Ssam * Set ebcdic transfer type. 16510294Ssam */ 16610294Ssam /*VARARGS*/ 16710294Ssam setebcdic() 16810294Ssam { 16910294Ssam 17010294Ssam call(settype, "type", "ebcdic", 0); 17110294Ssam } 17210294Ssam 17310294Ssam /* 17410294Ssam * Set file transfer mode. 17510294Ssam */ 17610294Ssam setmode(argc, argv) 17710294Ssam char *argv[]; 17810294Ssam { 17910294Ssam 18010294Ssam printf("We only support %s mode, sorry.\n", modename); 18110294Ssam } 18210294Ssam 18310294Ssam /* 18410294Ssam * Set file transfer format. 18510294Ssam */ 18610294Ssam setform(argc, argv) 18710294Ssam char *argv[]; 18810294Ssam { 18910294Ssam 19010294Ssam printf("We only support %s format, sorry.\n", formname); 19110294Ssam } 19210294Ssam 19310294Ssam /* 19410294Ssam * Set file transfer structure. 19510294Ssam */ 19610294Ssam setstruct(argc, argv) 19710294Ssam char *argv[]; 19810294Ssam { 19910294Ssam 20010294Ssam printf("We only support %s structure, sorry.\n", structname); 20110294Ssam } 20210294Ssam 20310294Ssam put(argc, argv) 20411756Ssam int argc; 20510294Ssam char *argv[]; 20610294Ssam { 20711650Ssam char *cmd; 20811650Ssam 20910294Ssam if (argc == 2) 21010294Ssam argc++, argv[2] = argv[1]; 21110294Ssam if (argc < 2) { 21210294Ssam strcat(line, " "); 21310294Ssam printf("(local-file) "); 21410294Ssam gets(&line[strlen(line)]); 21510294Ssam makeargv(); 21610294Ssam argc = margc; 21710294Ssam argv = margv; 21810294Ssam } 21910294Ssam if (argc < 2) { 22010294Ssam usage: 22110294Ssam printf("%s local-file remote-file\n", argv[0]); 22210294Ssam return; 22310294Ssam } 22410294Ssam if (argc < 3) { 22510294Ssam strcat(line, " "); 22610294Ssam printf("(remote-file) "); 22710294Ssam gets(&line[strlen(line)]); 22810294Ssam makeargv(); 22910294Ssam argc = margc; 23010294Ssam argv = margv; 23110294Ssam } 23210294Ssam if (argc < 3) 23310294Ssam goto usage; 23411353Ssam if (!globulize(&argv[1])) 23511353Ssam return; 23611756Ssam cmd = (argv[0][0] == 'a') ? "APPE" : "STOR"; 23711650Ssam sendrequest(cmd, argv[1], argv[2]); 23810294Ssam } 23910294Ssam 24010294Ssam /* 24111756Ssam * Send multiple files. 24210294Ssam */ 24311353Ssam mput(argc, argv) 24411353Ssam char *argv[]; 24511353Ssam { 24611650Ssam char **cpp, **gargs = NULL; 24711353Ssam 24811650Ssam if (argc < 2) { 24911650Ssam strcat(line, " "); 25011650Ssam printf("(local-files) "); 25111650Ssam gets(&line[strlen(line)]); 25211650Ssam makeargv(); 25311650Ssam argc = margc; 25411650Ssam argv = margv; 25511353Ssam } 25611353Ssam if (argc < 2) { 25711353Ssam printf("%s local-files\n", argv[0]); 25811353Ssam return; 25911353Ssam } 26011650Ssam cpp = argv + 1; 26111650Ssam if (doglob) { 26211650Ssam gargs = glob(cpp); 26311650Ssam if (globerr != NULL) { 26411650Ssam printf("%s\n", globerr); 26511650Ssam if (gargs) 26611650Ssam blkfree(gargs); 26711353Ssam return; 26811353Ssam } 26911353Ssam } 27011650Ssam if (gargs != NULL) 27111650Ssam cpp = gargs; 27211650Ssam for (; *cpp != NULL; cpp++) 27311650Ssam if (confirm(argv[0], *cpp)) 27411650Ssam sendrequest("STOR", *cpp, *cpp); 27511650Ssam if (gargs != NULL) 27611650Ssam blkfree(gargs); 27711353Ssam } 27811353Ssam 27911353Ssam /* 28011353Ssam * Receive one file. 28111353Ssam */ 28210294Ssam get(argc, argv) 28310294Ssam char *argv[]; 28410294Ssam { 28510294Ssam 28610294Ssam if (argc == 2) 28710294Ssam argc++, argv[2] = argv[1]; 28810294Ssam if (argc < 2) { 28910294Ssam strcat(line, " "); 29010294Ssam printf("(remote-file) "); 29110294Ssam gets(&line[strlen(line)]); 29210294Ssam makeargv(); 29310294Ssam argc = margc; 29410294Ssam argv = margv; 29510294Ssam } 29610294Ssam if (argc < 2) { 29710294Ssam usage: 29811353Ssam printf("%s remote-file [ local-file ]\n", argv[0]); 29910294Ssam return; 30010294Ssam } 30110294Ssam if (argc < 3) { 30210294Ssam strcat(line, " "); 30310294Ssam printf("(local-file) "); 30410294Ssam gets(&line[strlen(line)]); 30510294Ssam makeargv(); 30610294Ssam argc = margc; 30710294Ssam argv = margv; 30810294Ssam } 30910294Ssam if (argc < 3) 31010294Ssam goto usage; 31111353Ssam if (!globulize(&argv[2])) 31211353Ssam return; 31311650Ssam recvrequest("RETR", argv[2], argv[1], "w"); 31410294Ssam } 31510294Ssam 31611353Ssam /* 31711353Ssam * Get multiple files. 31811353Ssam */ 31911353Ssam mget(argc, argv) 32011353Ssam char *argv[]; 32111353Ssam { 32211756Ssam char *cp; 32311353Ssam 32411353Ssam if (argc < 2) { 32511353Ssam strcat(line, " "); 32611756Ssam printf("(remote-files) "); 32711353Ssam gets(&line[strlen(line)]); 32811353Ssam makeargv(); 32911353Ssam argc = margc; 33011353Ssam argv = margv; 33111353Ssam } 33211353Ssam if (argc < 2) { 33311650Ssam printf("%s remote-files\n", argv[0]); 33411353Ssam return; 33511353Ssam } 33611650Ssam while ((cp = remglob(argc, argv)) != NULL) 33711650Ssam if (confirm(argv[0], cp)) 33811650Ssam recvrequest("RETR", cp, cp, "w"); 33911650Ssam } 34011650Ssam 34111650Ssam char * 34211650Ssam remglob(argc, argv) 34311650Ssam char *argv[]; 34411650Ssam { 34511756Ssam char temp[16]; 34611650Ssam static char buf[MAXPATHLEN]; 34711650Ssam static FILE *ftemp = NULL; 34811650Ssam static char **args; 34911650Ssam int oldverbose; 35011756Ssam char *cp, *mode; 35111650Ssam 35211650Ssam if (!doglob) { 35311756Ssam if (args == NULL) 35411650Ssam args = argv; 35511650Ssam if ((cp = *++args) == NULL) 35611650Ssam args = NULL; 35711650Ssam return (cp); 35811353Ssam } 35911650Ssam if (ftemp == NULL) { 36011650Ssam strcpy(temp, "/tmp/ftpXXXXXX"); 36111650Ssam mktemp(temp); 36211650Ssam oldverbose = verbose, verbose = 0; 36311756Ssam for (mode = "w"; *++argv != NULL; mode = "a") 36411756Ssam recvrequest ("NLST", temp, *argv, mode); 36511650Ssam verbose = oldverbose; 36611650Ssam ftemp = fopen(temp, "r"); 36711650Ssam unlink(temp); 36811650Ssam if (ftemp == NULL) { 36911650Ssam printf("can't find list of remote files, oops\n"); 37011756Ssam return (NULL); 37111353Ssam } 37211353Ssam } 37311650Ssam if (fgets(buf, sizeof (buf), ftemp) == NULL) { 37411650Ssam fclose(ftemp), ftemp = NULL; 37511650Ssam return (NULL); 37611353Ssam } 37711650Ssam if ((cp = index(buf, '\n')) != NULL) 37811650Ssam *cp = '\0'; 37911650Ssam return (buf); 38011353Ssam } 38111353Ssam 38210294Ssam char * 38310294Ssam onoff(bool) 38410294Ssam int bool; 38510294Ssam { 38610294Ssam 38710294Ssam return (bool ? "on" : "off"); 38810294Ssam } 38910294Ssam 39010294Ssam /* 39110294Ssam * Show status. 39210294Ssam */ 39310294Ssam status(argc, argv) 39410294Ssam char *argv[]; 39510294Ssam { 39610294Ssam 39710294Ssam if (connected) 39810294Ssam printf("Connected to %s.\n", hostname); 39910294Ssam else 40010294Ssam printf("Not connected.\n"); 40110294Ssam printf("Mode: %s; Type: %s; Form: %s; Structure: %s\n", 40210294Ssam modename, typename, formname, structname); 40311353Ssam printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s\n", 40411353Ssam onoff(verbose), onoff(bell), onoff(interactive), 40511353Ssam onoff(doglob)); 40611650Ssam printf("Hash mark printing: %s; Use of PORT cmds: %s\n", 40711650Ssam onoff(hash), onoff(sendport)); 40810294Ssam } 40910294Ssam 41010294Ssam /* 41110294Ssam * Set beep on cmd completed mode. 41210294Ssam */ 41310294Ssam /*VARARGS*/ 41410294Ssam setbell() 41510294Ssam { 41610294Ssam 41710294Ssam bell = !bell; 41810294Ssam printf("Bell mode %s.\n", onoff(bell)); 41910294Ssam } 42010294Ssam 42110294Ssam /* 42210294Ssam * Turn on packet tracing. 42310294Ssam */ 42410294Ssam /*VARARGS*/ 42510294Ssam settrace() 42610294Ssam { 42710294Ssam 42810294Ssam trace = !trace; 42910294Ssam printf("Packet tracing %s.\n", onoff(trace)); 43010294Ssam } 43110294Ssam 43210294Ssam /* 43311650Ssam * Toggle hash mark printing during transfers. 43411650Ssam */ 43511650Ssam /*VARARGS*/ 43611650Ssam sethash() 43711650Ssam { 43811650Ssam 43911650Ssam hash = !hash; 44011650Ssam printf("Hash mark printing %s", onoff(hash)); 44111650Ssam if (hash) 44211650Ssam printf(" (%d bytes/hash mark)", BUFSIZ); 44311650Ssam printf(".\n"); 44411650Ssam } 44511650Ssam 44611650Ssam /* 44710294Ssam * Turn on printing of server echo's. 44810294Ssam */ 44910294Ssam /*VARARGS*/ 45010294Ssam setverbose() 45110294Ssam { 45210294Ssam 45310294Ssam verbose = !verbose; 45410294Ssam printf("Verbose mode %s.\n", onoff(verbose)); 45510294Ssam } 45610294Ssam 45710294Ssam /* 45811650Ssam * Toggle PORT cmd use before each data connection. 45911650Ssam */ 46011650Ssam /*VARARGS*/ 46111650Ssam setport() 46211650Ssam { 46311650Ssam 46411650Ssam sendport = !sendport; 46511650Ssam printf("Use of PORT cmds %s.\n", onoff(sendport)); 46611650Ssam } 46711650Ssam 46811650Ssam /* 46910294Ssam * Turn on interactive prompting 47010294Ssam * during mget, mput, and mdelete. 47110294Ssam */ 47210294Ssam /*VARARGS*/ 47310294Ssam setprompt() 47410294Ssam { 47510294Ssam 47610294Ssam interactive = !interactive; 47710294Ssam printf("Interactive mode %s.\n", onoff(interactive)); 47810294Ssam } 47910294Ssam 48010294Ssam /* 48111353Ssam * Toggle metacharacter interpretation 48211353Ssam * on local file names. 48311353Ssam */ 48411353Ssam /*VARARGS*/ 48511353Ssam setglob() 48611353Ssam { 48711353Ssam 48811353Ssam doglob = !doglob; 48911353Ssam printf("Globbing %s.\n", onoff(doglob)); 49011353Ssam } 49111353Ssam 49211353Ssam /* 49310294Ssam * Set debugging mode on/off and/or 49410294Ssam * set level of debugging. 49510294Ssam */ 49611756Ssam /*VARARGS*/ 49710294Ssam setdebug(argc, argv) 49810294Ssam char *argv[]; 49910294Ssam { 50010294Ssam int val; 50110294Ssam 50210294Ssam if (argc > 1) { 50310294Ssam val = atoi(argv[1]); 50410294Ssam if (val < 0) { 50510294Ssam printf("%s: bad debugging value.\n", argv[1]); 50610294Ssam return; 50710294Ssam } 50810294Ssam } else 50910294Ssam val = !debug; 51010294Ssam debug = val; 51110294Ssam if (debug) 51210294Ssam options |= SO_DEBUG; 51310294Ssam else 51410294Ssam options &= ~SO_DEBUG; 51510294Ssam printf("Debugging %s (debug=%d).\n", onoff(debug), debug); 51610294Ssam } 51710294Ssam 51810294Ssam /* 51910294Ssam * Set current working directory 52010294Ssam * on remote machine. 52110294Ssam */ 52210294Ssam cd(argc, argv) 52310294Ssam char *argv[]; 52410294Ssam { 52510294Ssam 52610294Ssam if (argc < 2) { 52710294Ssam strcat(line, " "); 52810294Ssam printf("(remote-directory) "); 52910294Ssam gets(&line[strlen(line)]); 53010294Ssam makeargv(); 53110294Ssam argc = margc; 53210294Ssam argv = margv; 53310294Ssam } 53410294Ssam if (argc < 2) { 53510294Ssam printf("%s remote-directory\n", argv[0]); 53610294Ssam return; 53710294Ssam } 53810294Ssam (void) command("CWD %s", argv[1]); 53910294Ssam } 54010294Ssam 54110294Ssam /* 54210294Ssam * Set current working directory 54310294Ssam * on local machine. 54410294Ssam */ 54510294Ssam lcd(argc, argv) 54610294Ssam char *argv[]; 54710294Ssam { 54811353Ssam char buf[MAXPATHLEN]; 54910294Ssam 55011353Ssam if (argc < 2) 55111353Ssam argc++, argv[1] = home; 55210294Ssam if (argc != 2) { 55310294Ssam printf("%s local-directory\n", argv[0]); 55410294Ssam return; 55510294Ssam } 55611353Ssam if (!globulize(&argv[1])) 55711353Ssam return; 55811353Ssam if (chdir(argv[1]) < 0) { 55910294Ssam perror(argv[1]); 56011353Ssam return; 56111353Ssam } 56211353Ssam printf("Local directory now %s\n", getwd(buf)); 56310294Ssam } 56410294Ssam 56510294Ssam /* 56610294Ssam * Delete a single file. 56710294Ssam */ 56810294Ssam delete(argc, argv) 56910294Ssam char *argv[]; 57010294Ssam { 57110294Ssam 57210294Ssam if (argc < 2) { 57310294Ssam strcat(line, " "); 57410294Ssam printf("(remote-file) "); 57510294Ssam gets(&line[strlen(line)]); 57610294Ssam makeargv(); 57710294Ssam argc = margc; 57810294Ssam argv = margv; 57910294Ssam } 58010294Ssam if (argc < 2) { 58110294Ssam printf("%s remote-file\n", argv[0]); 58210294Ssam return; 58310294Ssam } 58410294Ssam (void) command("DELE %s", argv[1]); 58510294Ssam } 58610294Ssam 58710294Ssam /* 58811650Ssam * Delete multiple files. 58911650Ssam */ 59011650Ssam mdelete(argc, argv) 59111650Ssam char *argv[]; 59211650Ssam { 59311650Ssam char *cp; 59411650Ssam 59511650Ssam if (argc < 2) { 59611650Ssam strcat(line, " "); 59711650Ssam printf("(remote-files) "); 59811650Ssam gets(&line[strlen(line)]); 59911650Ssam makeargv(); 60011650Ssam argc = margc; 60111650Ssam argv = margv; 60211650Ssam } 60311650Ssam if (argc < 2) { 60411650Ssam printf("%s remote-files\n", argv[0]); 60511650Ssam return; 60611650Ssam } 60711650Ssam while ((cp = remglob(argc, argv)) != NULL) 60811650Ssam if (confirm(argv[0], cp)) 60911650Ssam (void) command("DELE %s", cp); 61011650Ssam } 61111756Ssam 61211650Ssam /* 61310294Ssam * Rename a remote file. 61410294Ssam */ 61510294Ssam renamefile(argc, argv) 61610294Ssam char *argv[]; 61710294Ssam { 61810294Ssam 61910294Ssam if (argc < 2) { 62010294Ssam strcat(line, " "); 62110294Ssam printf("(from-name) "); 62210294Ssam gets(&line[strlen(line)]); 62310294Ssam makeargv(); 62410294Ssam argc = margc; 62510294Ssam argv = margv; 62610294Ssam } 62710294Ssam if (argc < 2) { 62810294Ssam usage: 62910294Ssam printf("%s from-name to-name\n", argv[0]); 63010294Ssam return; 63110294Ssam } 63210294Ssam if (argc < 3) { 63310294Ssam strcat(line, " "); 63410294Ssam printf("(to-name) "); 63510294Ssam gets(&line[strlen(line)]); 63610294Ssam makeargv(); 63710294Ssam argc = margc; 63810294Ssam argv = margv; 63910294Ssam } 64010294Ssam if (argc < 3) 64110294Ssam goto usage; 64210294Ssam if (command("RNFR %s", argv[1]) == CONTINUE) 64310294Ssam (void) command("RNTO %s", argv[2]); 64410294Ssam } 64510294Ssam 64610294Ssam /* 64710294Ssam * Get a directory listing 64810294Ssam * of remote files. 64910294Ssam */ 65010294Ssam ls(argc, argv) 65110294Ssam char *argv[]; 65210294Ssam { 65311756Ssam char *cmd; 65410294Ssam 65510294Ssam if (argc < 2) 65610294Ssam argc++, argv[1] = NULL; 65710294Ssam if (argc < 3) 65810294Ssam argc++, argv[2] = "-"; 65911756Ssam if (argc > 3) { 66011756Ssam printf("usage: %s remote-directory local-file\n", argv[0]); 66111756Ssam return; 66211756Ssam } 66310294Ssam cmd = argv[0][0] == 'l' ? "NLST" : "LIST"; 66411353Ssam if (strcmp(argv[2], "-") && !globulize(&argv[2])) 66511353Ssam return; 66611756Ssam recvrequest(cmd, argv[2], argv[1], "w"); 66710294Ssam } 66810294Ssam 66910294Ssam /* 67011756Ssam * Get a directory listing 67111756Ssam * of multiple remote files. 67211756Ssam */ 67311756Ssam mls(argc, argv) 67411756Ssam char *argv[]; 67511756Ssam { 67611756Ssam char *cmd, *mode; 67711756Ssam int i, dest; 67811756Ssam 67911756Ssam if (argc < 2) 68011756Ssam argc++, argv[1] = NULL; 68111756Ssam if (argc < 3) 68211756Ssam argc++, argv[2] = "-"; 68311756Ssam dest = argc - 1; 68411756Ssam cmd = argv[0][1] == 'l' ? "NLST" : "LIST"; 68511756Ssam if (strcmp(argv[dest], "-") != 0) 68611756Ssam if (globulize(&argv[dest]) && confirm("local-file", argv[dest])) 68711756Ssam return; 68811756Ssam for (i = 1, mode = "w"; i < dest; i++, mode = "a") 68911756Ssam recvrequest(cmd, argv[dest], argv[i], mode); 69011756Ssam } 69111756Ssam 69211756Ssam /* 69310294Ssam * Do a shell escape 69410294Ssam */ 69510294Ssam shell(argc, argv) 69610294Ssam char *argv[]; 69710294Ssam { 69811756Ssam int pid, status, (*old1)(), (*old2)(); 69911756Ssam char shellnam[40], *shell, *namep; 70011756Ssam char **cpp, **gargs; 70110294Ssam 70211756Ssam old1 = signal (SIGINT, SIG_IGN); 70311756Ssam old2 = signal (SIGQUIT, SIG_IGN); 70411756Ssam if ((pid = fork()) == 0) { 70511756Ssam for (pid = 3; pid < 20; pid++) 70611756Ssam close(pid); 70711756Ssam signal(SIGINT, SIG_DFL); 70811756Ssam signal(SIGQUIT, SIG_DFL); 70911756Ssam if (argc <= 1) { 71011756Ssam shell = getenv("SHELL"); 71111756Ssam if (shell == NULL) 71211756Ssam shell = "/bin/sh"; 71311756Ssam namep = rindex(shell,'/'); 71411756Ssam if (namep == NULL) 71511756Ssam namep = shell; 71611756Ssam strcpy(shellnam,"-"); 71711756Ssam strcat(shellnam, ++namep); 71811756Ssam if (strcmp(namep, "sh") != 0) 71911756Ssam shellnam[0] = '+'; 72011756Ssam if (debug) { 72111756Ssam printf ("%s\n", shell); 72211756Ssam fflush (stdout); 72311756Ssam } 72411756Ssam execl(shell, shellnam, 0); 72511756Ssam perror(shell); 72611756Ssam exit(1); 72711756Ssam } 72811756Ssam cpp = &argv[1]; 72911756Ssam if (argc > 2) { 73011756Ssam if ((gargs = glob(cpp)) != NULL) 73111756Ssam cpp = gargs; 73211756Ssam if (globerr != NULL) { 73311756Ssam printf("%s\n", globerr); 73411756Ssam exit(1); 73511756Ssam } 73611756Ssam } 73711756Ssam if (debug) { 73811756Ssam register char **zip = cpp; 73911756Ssam 74011756Ssam printf("%s", *zip); 74111756Ssam while (*++zip != NULL) 74211756Ssam printf(" %s", *zip); 74311756Ssam printf("\n"); 74411756Ssam fflush(stdout); 74511756Ssam } 74611756Ssam execvp(argv[1], cpp); 74711756Ssam perror(argv[1]); 74811756Ssam exit(1); 74911756Ssam } 75011756Ssam if (pid > 0) 75111756Ssam while (wait(&status) != pid) 75211756Ssam ; 75311756Ssam signal(SIGINT, old1); 75411756Ssam signal(SIGQUIT, old2); 75511756Ssam if (pid == -1) 75611756Ssam perror("Try again later"); 75711756Ssam return (0); 75810294Ssam } 75910294Ssam 76010294Ssam /* 76110294Ssam * Send new user information (re-login) 76210294Ssam */ 76310294Ssam user(argc, argv) 76410294Ssam int argc; 76510294Ssam char **argv; 76610294Ssam { 76710294Ssam char acct[80], *getpass(); 76810294Ssam int n; 76910294Ssam 77010294Ssam if (argc < 2) { 77110294Ssam strcat(line, " "); 77210294Ssam printf("(username) "); 77310294Ssam gets(&line[strlen(line)]); 77410294Ssam makeargv(); 77510294Ssam argc = margc; 77610294Ssam argv = margv; 77710294Ssam } 77810294Ssam if (argc > 4) { 77910294Ssam printf("usage: %s username [password] [account]\n", argv[0]); 78011756Ssam return (0); 78110294Ssam } 78210294Ssam n = command("USER %s", argv[1]); 78310294Ssam if (n == CONTINUE) { 78410294Ssam if (argc < 3 ) 78510294Ssam argv[2] = getpass("Password: "), argc++; 78610294Ssam n = command("PASS %s", argv[2]); 78710294Ssam } 78810294Ssam if (n == CONTINUE) { 78910294Ssam if (argc < 4) { 79010294Ssam printf("Account: "); (void) fflush(stdout); 79110294Ssam (void) fgets(acct, sizeof(acct) - 1, stdin); 79210294Ssam acct[strlen(acct) - 1] = '\0'; 79310294Ssam argv[3] = acct; argc++; 79410294Ssam } 79510294Ssam n = command("ACCT %s", acct); 79610294Ssam } 79710294Ssam if (n != COMPLETE) { 79810294Ssam fprintf(stderr, "Login failed.\n"); 79910294Ssam return (0); 80010294Ssam } 80110294Ssam return (1); 80210294Ssam } 80310294Ssam 80410294Ssam /* 80510294Ssam * Print working directory. 80610294Ssam */ 80710294Ssam /*VARARGS*/ 80810294Ssam pwd() 80910294Ssam { 81011756Ssam 81110294Ssam (void) command("XPWD"); 81210294Ssam } 81310294Ssam 81410294Ssam /* 81510294Ssam * Make a directory. 81610294Ssam */ 81710294Ssam makedir(argc, argv) 81810294Ssam char *argv[]; 81910294Ssam { 82010294Ssam 82110294Ssam if (argc < 2) { 82210294Ssam strcat(line, " "); 82310294Ssam printf("(directory-name) "); 82410294Ssam gets(&line[strlen(line)]); 82510294Ssam makeargv(); 82610294Ssam argc = margc; 82710294Ssam argv = margv; 82810294Ssam } 82910294Ssam if (argc < 2) { 83010294Ssam printf("%s directory-name\n", argv[0]); 83110294Ssam return; 83210294Ssam } 83310294Ssam (void) command("XMKD %s", argv[1]); 83410294Ssam } 83510294Ssam 83610294Ssam /* 83710294Ssam * Remove a directory. 83810294Ssam */ 83910294Ssam removedir(argc, argv) 84010294Ssam char *argv[]; 84110294Ssam { 84210294Ssam 84310294Ssam if (argc < 2) { 84410294Ssam strcat(line, " "); 84510294Ssam printf("(directory-name) "); 84610294Ssam gets(&line[strlen(line)]); 84710294Ssam makeargv(); 84810294Ssam argc = margc; 84910294Ssam argv = margv; 85010294Ssam } 85110294Ssam if (argc < 2) { 85210294Ssam printf("%s directory-name\n", argv[0]); 85310294Ssam return; 85410294Ssam } 85510294Ssam (void) command("XRMD %s", argv[1]); 85610294Ssam } 85710294Ssam 85810294Ssam /* 85910294Ssam * Send a line, verbatim, to the remote machine. 86010294Ssam */ 86110294Ssam quote(argc, argv) 86210294Ssam char *argv[]; 86310294Ssam { 86410294Ssam int i; 86510294Ssam char buf[BUFSIZ]; 86610294Ssam 86710294Ssam if (argc < 2) { 86810294Ssam strcat(line, " "); 86910294Ssam printf("(command line to send) "); 87010294Ssam gets(&line[strlen(line)]); 87110294Ssam makeargv(); 87210294Ssam argc = margc; 87310294Ssam argv = margv; 87410294Ssam } 87510294Ssam if (argc < 2) { 87610294Ssam printf("usage: %s line-to-send\n", argv[0]); 87710294Ssam return; 87810294Ssam } 87910294Ssam strcpy(buf, argv[1]); 88010294Ssam for (i = 2; i < argc; i++) { 88110294Ssam strcat(buf, " "); 88210294Ssam strcat(buf, argv[i]); 88310294Ssam } 88410294Ssam (void) command(buf); 88510294Ssam } 88610294Ssam 88710294Ssam /* 88810294Ssam * Ask the other side for help. 88910294Ssam */ 89010294Ssam rmthelp(argc, argv) 89110294Ssam char *argv[]; 89210294Ssam { 89310294Ssam int oldverbose = verbose; 89410294Ssam 89510294Ssam verbose = 1; 89610294Ssam (void) command(argc == 1 ? "HELP" : "HELP %s", argv[1]); 89710294Ssam verbose = oldverbose; 89810294Ssam } 89910294Ssam 90010294Ssam /* 90110294Ssam * Terminate session and exit. 90210294Ssam */ 90310294Ssam /*VARARGS*/ 90410294Ssam quit() 90510294Ssam { 90610294Ssam 90710294Ssam disconnect(); 90810294Ssam exit(0); 90910294Ssam } 91010294Ssam 91110294Ssam /* 91210294Ssam * Terminate session, but don't exit. 91310294Ssam */ 91410294Ssam disconnect() 91510294Ssam { 91610294Ssam extern FILE *cout; 91710294Ssam extern int data; 91810294Ssam 91910294Ssam if (!connected) 92010294Ssam return; 92110294Ssam (void) command("QUIT"); 92210294Ssam (void) fclose(cout); 92310294Ssam cout = NULL; 92410294Ssam connected = 0; 92510294Ssam data = -1; 92610294Ssam } 92711353Ssam 92811650Ssam confirm(cmd, file) 92911353Ssam char *cmd, *file; 93011353Ssam { 93111353Ssam char line[BUFSIZ]; 93211353Ssam 93311353Ssam if (!interactive) 93411650Ssam return (1); 93511353Ssam printf("%s %s? ", cmd, file); 93611353Ssam fflush(stdout); 93711353Ssam gets(line); 93811650Ssam return (*line != 'n' && *line != 'N'); 93911353Ssam } 94011353Ssam 94111353Ssam fatal(msg) 94211353Ssam char *msg; 94311353Ssam { 94411353Ssam 94511353Ssam fprintf(stderr, "ftp: %s\n"); 94611353Ssam exit(1); 94711353Ssam } 94811353Ssam 94911353Ssam /* 95011353Ssam * Glob a local file name specification with 95111353Ssam * the expectation of a single return value. 95211353Ssam * Can't control multiple values being expanded 95311353Ssam * from the expression, we return only the first. 95411353Ssam */ 95511353Ssam globulize(cpp) 95611353Ssam char **cpp; 95711353Ssam { 95811353Ssam char **globbed; 95911353Ssam 96011353Ssam if (!doglob) 96111353Ssam return (1); 96211353Ssam globbed = glob(*cpp); 96311353Ssam if (globerr != NULL) { 96411353Ssam printf("%s: %s\n", *cpp, globerr); 96511353Ssam if (globbed) 96611353Ssam blkfree(globbed); 96711353Ssam return (0); 96811353Ssam } 96911353Ssam if (globbed) { 97011353Ssam *cpp = *globbed++; 97111353Ssam /* don't waste too much memory */ 97211353Ssam if (*globbed) 97311353Ssam blkfree(globbed); 97411353Ssam } 97511353Ssam return (1); 97611353Ssam } 977