110294Ssam #ifndef lint 2*14143Ssam static char sccsid[] = "@(#)cmds.c 4.9 (Berkeley) 07/26/83"; 310294Ssam #endif 410294Ssam 510294Ssam /* 610294Ssam * FTP User Program -- Command Routines. 710294Ssam */ 811353Ssam #include <sys/param.h> 913613Ssam #include <sys/stat.h> 1010294Ssam #include <sys/socket.h> 1110294Ssam 1212396Ssam #include <arpa/ftp.h> 1312396Ssam 1410294Ssam #include <signal.h> 1510294Ssam #include <stdio.h> 1610294Ssam #include <errno.h> 1710294Ssam #include <netdb.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 { 24613212Ssam register int i; 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 } 26013212Ssam for (i = 1; i < argc; i++) { 26113212Ssam register char **cpp, **gargs; 26213212Ssam 26313212Ssam if (!doglob) { 26413212Ssam if (confirm(argv[0], argv[i])) 26513212Ssam sendrequest("STOR", argv[i], argv[i]); 26613212Ssam continue; 26713212Ssam } 26813212Ssam gargs = glob(argv[i]); 26911650Ssam if (globerr != NULL) { 27011650Ssam printf("%s\n", globerr); 27111650Ssam if (gargs) 27211650Ssam blkfree(gargs); 27313212Ssam continue; 27411353Ssam } 27513212Ssam for (cpp = gargs; cpp && *cpp != NULL; cpp++) 27613212Ssam if (confirm(argv[0], *cpp)) 27713212Ssam sendrequest("STOR", *cpp, *cpp); 27813212Ssam if (gargs != NULL) 27913212Ssam blkfree(gargs); 28011353Ssam } 28111353Ssam } 28211353Ssam 28311353Ssam /* 28411353Ssam * Receive one file. 28511353Ssam */ 28610294Ssam get(argc, argv) 28710294Ssam char *argv[]; 28810294Ssam { 28910294Ssam 29010294Ssam if (argc == 2) 29110294Ssam argc++, argv[2] = argv[1]; 29210294Ssam if (argc < 2) { 29310294Ssam strcat(line, " "); 29410294Ssam printf("(remote-file) "); 29510294Ssam gets(&line[strlen(line)]); 29610294Ssam makeargv(); 29710294Ssam argc = margc; 29810294Ssam argv = margv; 29910294Ssam } 30010294Ssam if (argc < 2) { 30110294Ssam usage: 30211353Ssam printf("%s remote-file [ local-file ]\n", argv[0]); 30310294Ssam return; 30410294Ssam } 30510294Ssam if (argc < 3) { 30610294Ssam strcat(line, " "); 30710294Ssam printf("(local-file) "); 30810294Ssam gets(&line[strlen(line)]); 30910294Ssam makeargv(); 31010294Ssam argc = margc; 31110294Ssam argv = margv; 31210294Ssam } 31310294Ssam if (argc < 3) 31410294Ssam goto usage; 31511353Ssam if (!globulize(&argv[2])) 31611353Ssam return; 31711650Ssam recvrequest("RETR", argv[2], argv[1], "w"); 31810294Ssam } 31910294Ssam 32011353Ssam /* 32111353Ssam * Get multiple files. 32211353Ssam */ 32311353Ssam mget(argc, argv) 32411353Ssam char *argv[]; 32511353Ssam { 32611756Ssam char *cp; 32711353Ssam 32811353Ssam if (argc < 2) { 32911353Ssam strcat(line, " "); 33011756Ssam printf("(remote-files) "); 33111353Ssam gets(&line[strlen(line)]); 33211353Ssam makeargv(); 33311353Ssam argc = margc; 33411353Ssam argv = margv; 33511353Ssam } 33611353Ssam if (argc < 2) { 33711650Ssam printf("%s remote-files\n", argv[0]); 33811353Ssam return; 33911353Ssam } 34011650Ssam while ((cp = remglob(argc, argv)) != NULL) 34111650Ssam if (confirm(argv[0], cp)) 34211650Ssam recvrequest("RETR", cp, cp, "w"); 34311650Ssam } 34411650Ssam 34511650Ssam char * 34611650Ssam remglob(argc, argv) 34711650Ssam char *argv[]; 34811650Ssam { 34911756Ssam char temp[16]; 35011650Ssam static char buf[MAXPATHLEN]; 35111650Ssam static FILE *ftemp = NULL; 35211650Ssam static char **args; 35313212Ssam int oldverbose, oldhash; 35411756Ssam char *cp, *mode; 35511650Ssam 35611650Ssam if (!doglob) { 35711756Ssam if (args == NULL) 35811650Ssam args = argv; 35911650Ssam if ((cp = *++args) == NULL) 36011650Ssam args = NULL; 36111650Ssam return (cp); 36211353Ssam } 36311650Ssam if (ftemp == NULL) { 36411650Ssam strcpy(temp, "/tmp/ftpXXXXXX"); 36511650Ssam mktemp(temp); 36611650Ssam oldverbose = verbose, verbose = 0; 36713212Ssam oldhash = hash, hash = 0; 36811756Ssam for (mode = "w"; *++argv != NULL; mode = "a") 36911756Ssam recvrequest ("NLST", temp, *argv, mode); 37013212Ssam verbose = oldverbose; hash = oldhash; 37111650Ssam ftemp = fopen(temp, "r"); 37211650Ssam unlink(temp); 37311650Ssam if (ftemp == NULL) { 37411650Ssam printf("can't find list of remote files, oops\n"); 37511756Ssam return (NULL); 37611353Ssam } 37711353Ssam } 37811650Ssam if (fgets(buf, sizeof (buf), ftemp) == NULL) { 37911650Ssam fclose(ftemp), ftemp = NULL; 38011650Ssam return (NULL); 38111353Ssam } 38211650Ssam if ((cp = index(buf, '\n')) != NULL) 38311650Ssam *cp = '\0'; 38411650Ssam return (buf); 38511353Ssam } 38611353Ssam 38710294Ssam char * 38810294Ssam onoff(bool) 38910294Ssam int bool; 39010294Ssam { 39110294Ssam 39210294Ssam return (bool ? "on" : "off"); 39310294Ssam } 39410294Ssam 39510294Ssam /* 39610294Ssam * Show status. 39710294Ssam */ 39810294Ssam status(argc, argv) 39910294Ssam char *argv[]; 40010294Ssam { 40110294Ssam 40210294Ssam if (connected) 40310294Ssam printf("Connected to %s.\n", hostname); 40410294Ssam else 40510294Ssam printf("Not connected.\n"); 40610294Ssam printf("Mode: %s; Type: %s; Form: %s; Structure: %s\n", 40710294Ssam modename, typename, formname, structname); 40811353Ssam printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s\n", 40911353Ssam onoff(verbose), onoff(bell), onoff(interactive), 41011353Ssam onoff(doglob)); 411*14143Ssam printf("Hash mark printing: %s; Use of PORT cmds: %s\n", 412*14143Ssam onoff(hash), onoff(sendport)); 41310294Ssam } 41410294Ssam 41510294Ssam /* 41610294Ssam * Set beep on cmd completed mode. 41710294Ssam */ 41810294Ssam /*VARARGS*/ 41910294Ssam setbell() 42010294Ssam { 42110294Ssam 42210294Ssam bell = !bell; 42310294Ssam printf("Bell mode %s.\n", onoff(bell)); 42410294Ssam } 42510294Ssam 42610294Ssam /* 42710294Ssam * Turn on packet tracing. 42810294Ssam */ 42910294Ssam /*VARARGS*/ 43010294Ssam settrace() 43110294Ssam { 43210294Ssam 43310294Ssam trace = !trace; 43410294Ssam printf("Packet tracing %s.\n", onoff(trace)); 43510294Ssam } 43610294Ssam 43710294Ssam /* 43811650Ssam * Toggle hash mark printing during transfers. 43911650Ssam */ 44011650Ssam /*VARARGS*/ 44111650Ssam sethash() 44211650Ssam { 44311650Ssam 44411650Ssam hash = !hash; 44511650Ssam printf("Hash mark printing %s", onoff(hash)); 44611650Ssam if (hash) 44711650Ssam printf(" (%d bytes/hash mark)", BUFSIZ); 44811650Ssam printf(".\n"); 44911650Ssam } 45011650Ssam 45111650Ssam /* 45210294Ssam * Turn on printing of server echo's. 45310294Ssam */ 45410294Ssam /*VARARGS*/ 45510294Ssam setverbose() 45610294Ssam { 45710294Ssam 45810294Ssam verbose = !verbose; 45910294Ssam printf("Verbose mode %s.\n", onoff(verbose)); 46010294Ssam } 46110294Ssam 46210294Ssam /* 46311650Ssam * Toggle PORT cmd use before each data connection. 46411650Ssam */ 46511650Ssam /*VARARGS*/ 46611650Ssam setport() 46711650Ssam { 46811650Ssam 46911650Ssam sendport = !sendport; 47011650Ssam printf("Use of PORT cmds %s.\n", onoff(sendport)); 47111650Ssam } 47211650Ssam 47311650Ssam /* 47410294Ssam * Turn on interactive prompting 47510294Ssam * during mget, mput, and mdelete. 47610294Ssam */ 47710294Ssam /*VARARGS*/ 47810294Ssam setprompt() 47910294Ssam { 48010294Ssam 48110294Ssam interactive = !interactive; 48210294Ssam printf("Interactive mode %s.\n", onoff(interactive)); 48310294Ssam } 48410294Ssam 48510294Ssam /* 48611353Ssam * Toggle metacharacter interpretation 48711353Ssam * on local file names. 48811353Ssam */ 48911353Ssam /*VARARGS*/ 49011353Ssam setglob() 49111353Ssam { 49211353Ssam 49311353Ssam doglob = !doglob; 49411353Ssam printf("Globbing %s.\n", onoff(doglob)); 49511353Ssam } 49611353Ssam 49711353Ssam /* 49810294Ssam * Set debugging mode on/off and/or 49910294Ssam * set level of debugging. 50010294Ssam */ 50111756Ssam /*VARARGS*/ 50210294Ssam setdebug(argc, argv) 50310294Ssam char *argv[]; 50410294Ssam { 50510294Ssam int val; 50610294Ssam 50710294Ssam if (argc > 1) { 50810294Ssam val = atoi(argv[1]); 50910294Ssam if (val < 0) { 51010294Ssam printf("%s: bad debugging value.\n", argv[1]); 51110294Ssam return; 51210294Ssam } 51310294Ssam } else 51410294Ssam val = !debug; 51510294Ssam debug = val; 51610294Ssam if (debug) 51710294Ssam options |= SO_DEBUG; 51810294Ssam else 51910294Ssam options &= ~SO_DEBUG; 52010294Ssam printf("Debugging %s (debug=%d).\n", onoff(debug), debug); 52110294Ssam } 52210294Ssam 52310294Ssam /* 52410294Ssam * Set current working directory 52510294Ssam * on remote machine. 52610294Ssam */ 52710294Ssam cd(argc, argv) 52810294Ssam char *argv[]; 52910294Ssam { 53010294Ssam 53110294Ssam if (argc < 2) { 53210294Ssam strcat(line, " "); 53310294Ssam printf("(remote-directory) "); 53410294Ssam gets(&line[strlen(line)]); 53510294Ssam makeargv(); 53610294Ssam argc = margc; 53710294Ssam argv = margv; 53810294Ssam } 53910294Ssam if (argc < 2) { 54010294Ssam printf("%s remote-directory\n", argv[0]); 54110294Ssam return; 54210294Ssam } 54310294Ssam (void) command("CWD %s", argv[1]); 54410294Ssam } 54510294Ssam 54610294Ssam /* 54710294Ssam * Set current working directory 54810294Ssam * on local machine. 54910294Ssam */ 55010294Ssam lcd(argc, argv) 55110294Ssam char *argv[]; 55210294Ssam { 55311353Ssam char buf[MAXPATHLEN]; 55410294Ssam 55511353Ssam if (argc < 2) 55611353Ssam argc++, argv[1] = home; 55710294Ssam if (argc != 2) { 55810294Ssam printf("%s local-directory\n", argv[0]); 55910294Ssam return; 56010294Ssam } 56111353Ssam if (!globulize(&argv[1])) 56211353Ssam return; 56311353Ssam if (chdir(argv[1]) < 0) { 56410294Ssam perror(argv[1]); 56511353Ssam return; 56611353Ssam } 56711353Ssam printf("Local directory now %s\n", getwd(buf)); 56810294Ssam } 56910294Ssam 57010294Ssam /* 57110294Ssam * Delete a single file. 57210294Ssam */ 57310294Ssam delete(argc, argv) 57410294Ssam char *argv[]; 57510294Ssam { 57610294Ssam 57710294Ssam if (argc < 2) { 57810294Ssam strcat(line, " "); 57910294Ssam printf("(remote-file) "); 58010294Ssam gets(&line[strlen(line)]); 58110294Ssam makeargv(); 58210294Ssam argc = margc; 58310294Ssam argv = margv; 58410294Ssam } 58510294Ssam if (argc < 2) { 58610294Ssam printf("%s remote-file\n", argv[0]); 58710294Ssam return; 58810294Ssam } 58910294Ssam (void) command("DELE %s", argv[1]); 59010294Ssam } 59110294Ssam 59210294Ssam /* 59311650Ssam * Delete multiple files. 59411650Ssam */ 59511650Ssam mdelete(argc, argv) 59611650Ssam char *argv[]; 59711650Ssam { 59811650Ssam char *cp; 59911650Ssam 60011650Ssam if (argc < 2) { 60111650Ssam strcat(line, " "); 60211650Ssam printf("(remote-files) "); 60311650Ssam gets(&line[strlen(line)]); 60411650Ssam makeargv(); 60511650Ssam argc = margc; 60611650Ssam argv = margv; 60711650Ssam } 60811650Ssam if (argc < 2) { 60911650Ssam printf("%s remote-files\n", argv[0]); 61011650Ssam return; 61111650Ssam } 61211650Ssam while ((cp = remglob(argc, argv)) != NULL) 61311650Ssam if (confirm(argv[0], cp)) 61411650Ssam (void) command("DELE %s", cp); 61511650Ssam } 61611756Ssam 61711650Ssam /* 61810294Ssam * Rename a remote file. 61910294Ssam */ 62010294Ssam renamefile(argc, argv) 62110294Ssam char *argv[]; 62210294Ssam { 62310294Ssam 62410294Ssam if (argc < 2) { 62510294Ssam strcat(line, " "); 62610294Ssam printf("(from-name) "); 62710294Ssam gets(&line[strlen(line)]); 62810294Ssam makeargv(); 62910294Ssam argc = margc; 63010294Ssam argv = margv; 63110294Ssam } 63210294Ssam if (argc < 2) { 63310294Ssam usage: 63410294Ssam printf("%s from-name to-name\n", argv[0]); 63510294Ssam return; 63610294Ssam } 63710294Ssam if (argc < 3) { 63810294Ssam strcat(line, " "); 63910294Ssam printf("(to-name) "); 64010294Ssam gets(&line[strlen(line)]); 64110294Ssam makeargv(); 64210294Ssam argc = margc; 64310294Ssam argv = margv; 64410294Ssam } 64510294Ssam if (argc < 3) 64610294Ssam goto usage; 64710294Ssam if (command("RNFR %s", argv[1]) == CONTINUE) 64810294Ssam (void) command("RNTO %s", argv[2]); 64910294Ssam } 65010294Ssam 65110294Ssam /* 65210294Ssam * Get a directory listing 65310294Ssam * of remote files. 65410294Ssam */ 65510294Ssam ls(argc, argv) 65610294Ssam char *argv[]; 65710294Ssam { 65811756Ssam char *cmd; 65910294Ssam 66010294Ssam if (argc < 2) 66110294Ssam argc++, argv[1] = NULL; 66210294Ssam if (argc < 3) 66310294Ssam argc++, argv[2] = "-"; 66411756Ssam if (argc > 3) { 66511756Ssam printf("usage: %s remote-directory local-file\n", argv[0]); 66611756Ssam return; 66711756Ssam } 66810294Ssam cmd = argv[0][0] == 'l' ? "NLST" : "LIST"; 66911353Ssam if (strcmp(argv[2], "-") && !globulize(&argv[2])) 67011353Ssam return; 67111756Ssam recvrequest(cmd, argv[2], argv[1], "w"); 67210294Ssam } 67310294Ssam 67410294Ssam /* 67511756Ssam * Get a directory listing 67611756Ssam * of multiple remote files. 67711756Ssam */ 67811756Ssam mls(argc, argv) 67911756Ssam char *argv[]; 68011756Ssam { 68113212Ssam char *cmd, *mode, *cp, *dest; 68211756Ssam 68313212Ssam if (argc < 2) { 68413212Ssam strcat(line, " "); 68513212Ssam printf("(remote-files) "); 68613212Ssam gets(&line[strlen(line)]); 68713212Ssam makeargv(); 68813212Ssam argc = margc; 68913212Ssam argv = margv; 69013212Ssam } 69113212Ssam if (argc < 3) { 69213212Ssam strcat(line, " "); 69313212Ssam printf("(local-file) "); 69413212Ssam gets(&line[strlen(line)]); 69513212Ssam makeargv(); 69613212Ssam argc = margc; 69713212Ssam argv = margv; 69813212Ssam } 69913212Ssam if (argc < 3) { 70013212Ssam printf("%s remote-files local-file\n", argv[0]); 70113212Ssam return; 70213212Ssam } 70313212Ssam dest = argv[argc - 1]; 70413212Ssam argv[argc - 1] = NULL; 70513212Ssam if (strcmp(dest, "-")) 70613212Ssam if (globulize(&dest) && confirm("local-file", dest)) 70713212Ssam return; 70811756Ssam cmd = argv[0][1] == 'l' ? "NLST" : "LIST"; 70913212Ssam for (mode = "w"; cp = remglob(argc, argv); mode = "a") 71013212Ssam if (confirm(argv[0], cp)) 71113212Ssam recvrequest(cmd, dest, cp, mode); 71211756Ssam } 71311756Ssam 71411756Ssam /* 71510294Ssam * Do a shell escape 71610294Ssam */ 71710294Ssam shell(argc, argv) 71810294Ssam char *argv[]; 71910294Ssam { 72011756Ssam int pid, status, (*old1)(), (*old2)(); 72111756Ssam char shellnam[40], *shell, *namep; 72211756Ssam char **cpp, **gargs; 72310294Ssam 72411756Ssam old1 = signal (SIGINT, SIG_IGN); 72511756Ssam old2 = signal (SIGQUIT, SIG_IGN); 72611756Ssam if ((pid = fork()) == 0) { 72711756Ssam for (pid = 3; pid < 20; pid++) 72811756Ssam close(pid); 72911756Ssam signal(SIGINT, SIG_DFL); 73011756Ssam signal(SIGQUIT, SIG_DFL); 73111756Ssam if (argc <= 1) { 73211756Ssam shell = getenv("SHELL"); 73311756Ssam if (shell == NULL) 73411756Ssam shell = "/bin/sh"; 73511756Ssam namep = rindex(shell,'/'); 73611756Ssam if (namep == NULL) 73711756Ssam namep = shell; 73811756Ssam strcpy(shellnam,"-"); 73911756Ssam strcat(shellnam, ++namep); 74011756Ssam if (strcmp(namep, "sh") != 0) 74111756Ssam shellnam[0] = '+'; 74211756Ssam if (debug) { 74311756Ssam printf ("%s\n", shell); 74411756Ssam fflush (stdout); 74511756Ssam } 74611756Ssam execl(shell, shellnam, 0); 74711756Ssam perror(shell); 74811756Ssam exit(1); 74911756Ssam } 75011756Ssam cpp = &argv[1]; 75111756Ssam if (argc > 2) { 75211756Ssam if ((gargs = glob(cpp)) != NULL) 75311756Ssam cpp = gargs; 75411756Ssam if (globerr != NULL) { 75511756Ssam printf("%s\n", globerr); 75611756Ssam exit(1); 75711756Ssam } 75811756Ssam } 75911756Ssam if (debug) { 76011756Ssam register char **zip = cpp; 76111756Ssam 76211756Ssam printf("%s", *zip); 76311756Ssam while (*++zip != NULL) 76411756Ssam printf(" %s", *zip); 76511756Ssam printf("\n"); 76611756Ssam fflush(stdout); 76711756Ssam } 76811756Ssam execvp(argv[1], cpp); 76911756Ssam perror(argv[1]); 77011756Ssam exit(1); 77111756Ssam } 77211756Ssam if (pid > 0) 77311756Ssam while (wait(&status) != pid) 77411756Ssam ; 77511756Ssam signal(SIGINT, old1); 77611756Ssam signal(SIGQUIT, old2); 77711756Ssam if (pid == -1) 77811756Ssam perror("Try again later"); 77911756Ssam return (0); 78010294Ssam } 78110294Ssam 78210294Ssam /* 78310294Ssam * Send new user information (re-login) 78410294Ssam */ 78510294Ssam user(argc, argv) 78610294Ssam int argc; 78710294Ssam char **argv; 78810294Ssam { 78910294Ssam char acct[80], *getpass(); 79010294Ssam int n; 79110294Ssam 79210294Ssam if (argc < 2) { 79310294Ssam strcat(line, " "); 79410294Ssam printf("(username) "); 79510294Ssam gets(&line[strlen(line)]); 79610294Ssam makeargv(); 79710294Ssam argc = margc; 79810294Ssam argv = margv; 79910294Ssam } 80010294Ssam if (argc > 4) { 80110294Ssam printf("usage: %s username [password] [account]\n", argv[0]); 80211756Ssam return (0); 80310294Ssam } 80410294Ssam n = command("USER %s", argv[1]); 80510294Ssam if (n == CONTINUE) { 80610294Ssam if (argc < 3 ) 80710294Ssam argv[2] = getpass("Password: "), argc++; 80810294Ssam n = command("PASS %s", argv[2]); 80910294Ssam } 81010294Ssam if (n == CONTINUE) { 81110294Ssam if (argc < 4) { 81210294Ssam printf("Account: "); (void) fflush(stdout); 81310294Ssam (void) fgets(acct, sizeof(acct) - 1, stdin); 81410294Ssam acct[strlen(acct) - 1] = '\0'; 81510294Ssam argv[3] = acct; argc++; 81610294Ssam } 81710294Ssam n = command("ACCT %s", acct); 81810294Ssam } 81910294Ssam if (n != COMPLETE) { 82010294Ssam fprintf(stderr, "Login failed.\n"); 82110294Ssam return (0); 82210294Ssam } 82310294Ssam return (1); 82410294Ssam } 82510294Ssam 82610294Ssam /* 82710294Ssam * Print working directory. 82810294Ssam */ 82910294Ssam /*VARARGS*/ 83010294Ssam pwd() 83110294Ssam { 83211756Ssam 83310294Ssam (void) command("XPWD"); 83410294Ssam } 83510294Ssam 83610294Ssam /* 83710294Ssam * Make a directory. 83810294Ssam */ 83910294Ssam makedir(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("XMKD %s", argv[1]); 85610294Ssam } 85710294Ssam 85810294Ssam /* 85910294Ssam * Remove a directory. 86010294Ssam */ 86110294Ssam removedir(argc, argv) 86210294Ssam char *argv[]; 86310294Ssam { 86410294Ssam 86510294Ssam if (argc < 2) { 86610294Ssam strcat(line, " "); 86710294Ssam printf("(directory-name) "); 86810294Ssam gets(&line[strlen(line)]); 86910294Ssam makeargv(); 87010294Ssam argc = margc; 87110294Ssam argv = margv; 87210294Ssam } 87310294Ssam if (argc < 2) { 87410294Ssam printf("%s directory-name\n", argv[0]); 87510294Ssam return; 87610294Ssam } 87710294Ssam (void) command("XRMD %s", argv[1]); 87810294Ssam } 87910294Ssam 88010294Ssam /* 88110294Ssam * Send a line, verbatim, to the remote machine. 88210294Ssam */ 88310294Ssam quote(argc, argv) 88410294Ssam char *argv[]; 88510294Ssam { 88610294Ssam int i; 88710294Ssam char buf[BUFSIZ]; 88810294Ssam 88910294Ssam if (argc < 2) { 89010294Ssam strcat(line, " "); 89110294Ssam printf("(command line to send) "); 89210294Ssam gets(&line[strlen(line)]); 89310294Ssam makeargv(); 89410294Ssam argc = margc; 89510294Ssam argv = margv; 89610294Ssam } 89710294Ssam if (argc < 2) { 89810294Ssam printf("usage: %s line-to-send\n", argv[0]); 89910294Ssam return; 90010294Ssam } 90110294Ssam strcpy(buf, argv[1]); 90210294Ssam for (i = 2; i < argc; i++) { 90310294Ssam strcat(buf, " "); 90410294Ssam strcat(buf, argv[i]); 90510294Ssam } 90610294Ssam (void) command(buf); 90710294Ssam } 90810294Ssam 90910294Ssam /* 91010294Ssam * Ask the other side for help. 91110294Ssam */ 91210294Ssam rmthelp(argc, argv) 91310294Ssam char *argv[]; 91410294Ssam { 91510294Ssam int oldverbose = verbose; 91610294Ssam 91710294Ssam verbose = 1; 91810294Ssam (void) command(argc == 1 ? "HELP" : "HELP %s", argv[1]); 91910294Ssam verbose = oldverbose; 92010294Ssam } 92110294Ssam 92210294Ssam /* 92310294Ssam * Terminate session and exit. 92410294Ssam */ 92510294Ssam /*VARARGS*/ 92610294Ssam quit() 92710294Ssam { 92810294Ssam 92910294Ssam disconnect(); 93010294Ssam exit(0); 93110294Ssam } 93210294Ssam 93310294Ssam /* 93410294Ssam * Terminate session, but don't exit. 93510294Ssam */ 93610294Ssam disconnect() 93710294Ssam { 93810294Ssam extern FILE *cout; 93910294Ssam extern int data; 94010294Ssam 94110294Ssam if (!connected) 94210294Ssam return; 94310294Ssam (void) command("QUIT"); 94410294Ssam (void) fclose(cout); 94510294Ssam cout = NULL; 94610294Ssam connected = 0; 94710294Ssam data = -1; 94810294Ssam } 94911353Ssam 95011650Ssam confirm(cmd, file) 95111353Ssam char *cmd, *file; 95211353Ssam { 95311353Ssam char line[BUFSIZ]; 95411353Ssam 95511353Ssam if (!interactive) 95611650Ssam return (1); 95711353Ssam printf("%s %s? ", cmd, file); 95811353Ssam fflush(stdout); 95911353Ssam gets(line); 96011650Ssam return (*line != 'n' && *line != 'N'); 96111353Ssam } 96211353Ssam 96311353Ssam fatal(msg) 96411353Ssam char *msg; 96511353Ssam { 96611353Ssam 96711353Ssam fprintf(stderr, "ftp: %s\n"); 96811353Ssam exit(1); 96911353Ssam } 97011353Ssam 97111353Ssam /* 97211353Ssam * Glob a local file name specification with 97311353Ssam * the expectation of a single return value. 97411353Ssam * Can't control multiple values being expanded 97511353Ssam * from the expression, we return only the first. 97611353Ssam */ 97711353Ssam globulize(cpp) 97811353Ssam char **cpp; 97911353Ssam { 98011353Ssam char **globbed; 98111353Ssam 98211353Ssam if (!doglob) 98311353Ssam return (1); 98411353Ssam globbed = glob(*cpp); 98511353Ssam if (globerr != NULL) { 98611353Ssam printf("%s: %s\n", *cpp, globerr); 98711353Ssam if (globbed) 98811353Ssam blkfree(globbed); 98911353Ssam return (0); 99011353Ssam } 99111353Ssam if (globbed) { 99211353Ssam *cpp = *globbed++; 99311353Ssam /* don't waste too much memory */ 99411353Ssam if (*globbed) 99511353Ssam blkfree(globbed); 99611353Ssam } 99711353Ssam return (1); 99811353Ssam } 999