110294Ssam #ifndef lint 2*13613Ssam static char sccsid[] = "@(#)cmds.c 4.8 (Berkeley) 07/02/83"; 310294Ssam #endif 410294Ssam 510294Ssam /* 610294Ssam * FTP User Program -- Command Routines. 710294Ssam */ 811353Ssam #include <sys/param.h> 9*13613Ssam #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)); 41113212Ssam printf("Hash mark printing: %s; Use of PORT cmds: %s; Linger: %s\n", 41213212Ssam onoff(hash), onoff(sendport), onoff(linger)); 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 /* 52413212Ssam * Set linger on data connections on/off. 52513212Ssam */ 52613212Ssam /*VARARGS*/ 52713212Ssam setlinger(argc, argv) 52813212Ssam char *argv[]; 52913212Ssam { 53013212Ssam 53113212Ssam if (argc == 1) 53213212Ssam linger = !linger; 53313212Ssam else 53413212Ssam linger = atoi(argv[1]); 53513212Ssam if (argc == 1 || linger == 0) { 53613212Ssam printf("Linger on data connection close %s.\n", onoff(linger)); 53713212Ssam return; 53813212Ssam } 53913212Ssam printf("Will linger for %d seconds on close of data connections.\n", 54013212Ssam linger); 54113212Ssam } 54213212Ssam 54313212Ssam /* 54410294Ssam * Set current working directory 54510294Ssam * on remote machine. 54610294Ssam */ 54710294Ssam cd(argc, argv) 54810294Ssam char *argv[]; 54910294Ssam { 55010294Ssam 55110294Ssam if (argc < 2) { 55210294Ssam strcat(line, " "); 55310294Ssam printf("(remote-directory) "); 55410294Ssam gets(&line[strlen(line)]); 55510294Ssam makeargv(); 55610294Ssam argc = margc; 55710294Ssam argv = margv; 55810294Ssam } 55910294Ssam if (argc < 2) { 56010294Ssam printf("%s remote-directory\n", argv[0]); 56110294Ssam return; 56210294Ssam } 56310294Ssam (void) command("CWD %s", argv[1]); 56410294Ssam } 56510294Ssam 56610294Ssam /* 56710294Ssam * Set current working directory 56810294Ssam * on local machine. 56910294Ssam */ 57010294Ssam lcd(argc, argv) 57110294Ssam char *argv[]; 57210294Ssam { 57311353Ssam char buf[MAXPATHLEN]; 57410294Ssam 57511353Ssam if (argc < 2) 57611353Ssam argc++, argv[1] = home; 57710294Ssam if (argc != 2) { 57810294Ssam printf("%s local-directory\n", argv[0]); 57910294Ssam return; 58010294Ssam } 58111353Ssam if (!globulize(&argv[1])) 58211353Ssam return; 58311353Ssam if (chdir(argv[1]) < 0) { 58410294Ssam perror(argv[1]); 58511353Ssam return; 58611353Ssam } 58711353Ssam printf("Local directory now %s\n", getwd(buf)); 58810294Ssam } 58910294Ssam 59010294Ssam /* 59110294Ssam * Delete a single file. 59210294Ssam */ 59310294Ssam delete(argc, argv) 59410294Ssam char *argv[]; 59510294Ssam { 59610294Ssam 59710294Ssam if (argc < 2) { 59810294Ssam strcat(line, " "); 59910294Ssam printf("(remote-file) "); 60010294Ssam gets(&line[strlen(line)]); 60110294Ssam makeargv(); 60210294Ssam argc = margc; 60310294Ssam argv = margv; 60410294Ssam } 60510294Ssam if (argc < 2) { 60610294Ssam printf("%s remote-file\n", argv[0]); 60710294Ssam return; 60810294Ssam } 60910294Ssam (void) command("DELE %s", argv[1]); 61010294Ssam } 61110294Ssam 61210294Ssam /* 61311650Ssam * Delete multiple files. 61411650Ssam */ 61511650Ssam mdelete(argc, argv) 61611650Ssam char *argv[]; 61711650Ssam { 61811650Ssam char *cp; 61911650Ssam 62011650Ssam if (argc < 2) { 62111650Ssam strcat(line, " "); 62211650Ssam printf("(remote-files) "); 62311650Ssam gets(&line[strlen(line)]); 62411650Ssam makeargv(); 62511650Ssam argc = margc; 62611650Ssam argv = margv; 62711650Ssam } 62811650Ssam if (argc < 2) { 62911650Ssam printf("%s remote-files\n", argv[0]); 63011650Ssam return; 63111650Ssam } 63211650Ssam while ((cp = remglob(argc, argv)) != NULL) 63311650Ssam if (confirm(argv[0], cp)) 63411650Ssam (void) command("DELE %s", cp); 63511650Ssam } 63611756Ssam 63711650Ssam /* 63810294Ssam * Rename a remote file. 63910294Ssam */ 64010294Ssam renamefile(argc, argv) 64110294Ssam char *argv[]; 64210294Ssam { 64310294Ssam 64410294Ssam if (argc < 2) { 64510294Ssam strcat(line, " "); 64610294Ssam printf("(from-name) "); 64710294Ssam gets(&line[strlen(line)]); 64810294Ssam makeargv(); 64910294Ssam argc = margc; 65010294Ssam argv = margv; 65110294Ssam } 65210294Ssam if (argc < 2) { 65310294Ssam usage: 65410294Ssam printf("%s from-name to-name\n", argv[0]); 65510294Ssam return; 65610294Ssam } 65710294Ssam if (argc < 3) { 65810294Ssam strcat(line, " "); 65910294Ssam printf("(to-name) "); 66010294Ssam gets(&line[strlen(line)]); 66110294Ssam makeargv(); 66210294Ssam argc = margc; 66310294Ssam argv = margv; 66410294Ssam } 66510294Ssam if (argc < 3) 66610294Ssam goto usage; 66710294Ssam if (command("RNFR %s", argv[1]) == CONTINUE) 66810294Ssam (void) command("RNTO %s", argv[2]); 66910294Ssam } 67010294Ssam 67110294Ssam /* 67210294Ssam * Get a directory listing 67310294Ssam * of remote files. 67410294Ssam */ 67510294Ssam ls(argc, argv) 67610294Ssam char *argv[]; 67710294Ssam { 67811756Ssam char *cmd; 67910294Ssam 68010294Ssam if (argc < 2) 68110294Ssam argc++, argv[1] = NULL; 68210294Ssam if (argc < 3) 68310294Ssam argc++, argv[2] = "-"; 68411756Ssam if (argc > 3) { 68511756Ssam printf("usage: %s remote-directory local-file\n", argv[0]); 68611756Ssam return; 68711756Ssam } 68810294Ssam cmd = argv[0][0] == 'l' ? "NLST" : "LIST"; 68911353Ssam if (strcmp(argv[2], "-") && !globulize(&argv[2])) 69011353Ssam return; 69111756Ssam recvrequest(cmd, argv[2], argv[1], "w"); 69210294Ssam } 69310294Ssam 69410294Ssam /* 69511756Ssam * Get a directory listing 69611756Ssam * of multiple remote files. 69711756Ssam */ 69811756Ssam mls(argc, argv) 69911756Ssam char *argv[]; 70011756Ssam { 70113212Ssam char *cmd, *mode, *cp, *dest; 70211756Ssam 70313212Ssam if (argc < 2) { 70413212Ssam strcat(line, " "); 70513212Ssam printf("(remote-files) "); 70613212Ssam gets(&line[strlen(line)]); 70713212Ssam makeargv(); 70813212Ssam argc = margc; 70913212Ssam argv = margv; 71013212Ssam } 71113212Ssam if (argc < 3) { 71213212Ssam strcat(line, " "); 71313212Ssam printf("(local-file) "); 71413212Ssam gets(&line[strlen(line)]); 71513212Ssam makeargv(); 71613212Ssam argc = margc; 71713212Ssam argv = margv; 71813212Ssam } 71913212Ssam if (argc < 3) { 72013212Ssam printf("%s remote-files local-file\n", argv[0]); 72113212Ssam return; 72213212Ssam } 72313212Ssam dest = argv[argc - 1]; 72413212Ssam argv[argc - 1] = NULL; 72513212Ssam if (strcmp(dest, "-")) 72613212Ssam if (globulize(&dest) && confirm("local-file", dest)) 72713212Ssam return; 72811756Ssam cmd = argv[0][1] == 'l' ? "NLST" : "LIST"; 72913212Ssam for (mode = "w"; cp = remglob(argc, argv); mode = "a") 73013212Ssam if (confirm(argv[0], cp)) 73113212Ssam recvrequest(cmd, dest, cp, mode); 73211756Ssam } 73311756Ssam 73411756Ssam /* 73510294Ssam * Do a shell escape 73610294Ssam */ 73710294Ssam shell(argc, argv) 73810294Ssam char *argv[]; 73910294Ssam { 74011756Ssam int pid, status, (*old1)(), (*old2)(); 74111756Ssam char shellnam[40], *shell, *namep; 74211756Ssam char **cpp, **gargs; 74310294Ssam 74411756Ssam old1 = signal (SIGINT, SIG_IGN); 74511756Ssam old2 = signal (SIGQUIT, SIG_IGN); 74611756Ssam if ((pid = fork()) == 0) { 74711756Ssam for (pid = 3; pid < 20; pid++) 74811756Ssam close(pid); 74911756Ssam signal(SIGINT, SIG_DFL); 75011756Ssam signal(SIGQUIT, SIG_DFL); 75111756Ssam if (argc <= 1) { 75211756Ssam shell = getenv("SHELL"); 75311756Ssam if (shell == NULL) 75411756Ssam shell = "/bin/sh"; 75511756Ssam namep = rindex(shell,'/'); 75611756Ssam if (namep == NULL) 75711756Ssam namep = shell; 75811756Ssam strcpy(shellnam,"-"); 75911756Ssam strcat(shellnam, ++namep); 76011756Ssam if (strcmp(namep, "sh") != 0) 76111756Ssam shellnam[0] = '+'; 76211756Ssam if (debug) { 76311756Ssam printf ("%s\n", shell); 76411756Ssam fflush (stdout); 76511756Ssam } 76611756Ssam execl(shell, shellnam, 0); 76711756Ssam perror(shell); 76811756Ssam exit(1); 76911756Ssam } 77011756Ssam cpp = &argv[1]; 77111756Ssam if (argc > 2) { 77211756Ssam if ((gargs = glob(cpp)) != NULL) 77311756Ssam cpp = gargs; 77411756Ssam if (globerr != NULL) { 77511756Ssam printf("%s\n", globerr); 77611756Ssam exit(1); 77711756Ssam } 77811756Ssam } 77911756Ssam if (debug) { 78011756Ssam register char **zip = cpp; 78111756Ssam 78211756Ssam printf("%s", *zip); 78311756Ssam while (*++zip != NULL) 78411756Ssam printf(" %s", *zip); 78511756Ssam printf("\n"); 78611756Ssam fflush(stdout); 78711756Ssam } 78811756Ssam execvp(argv[1], cpp); 78911756Ssam perror(argv[1]); 79011756Ssam exit(1); 79111756Ssam } 79211756Ssam if (pid > 0) 79311756Ssam while (wait(&status) != pid) 79411756Ssam ; 79511756Ssam signal(SIGINT, old1); 79611756Ssam signal(SIGQUIT, old2); 79711756Ssam if (pid == -1) 79811756Ssam perror("Try again later"); 79911756Ssam return (0); 80010294Ssam } 80110294Ssam 80210294Ssam /* 80310294Ssam * Send new user information (re-login) 80410294Ssam */ 80510294Ssam user(argc, argv) 80610294Ssam int argc; 80710294Ssam char **argv; 80810294Ssam { 80910294Ssam char acct[80], *getpass(); 81010294Ssam int n; 81110294Ssam 81210294Ssam if (argc < 2) { 81310294Ssam strcat(line, " "); 81410294Ssam printf("(username) "); 81510294Ssam gets(&line[strlen(line)]); 81610294Ssam makeargv(); 81710294Ssam argc = margc; 81810294Ssam argv = margv; 81910294Ssam } 82010294Ssam if (argc > 4) { 82110294Ssam printf("usage: %s username [password] [account]\n", argv[0]); 82211756Ssam return (0); 82310294Ssam } 82410294Ssam n = command("USER %s", argv[1]); 82510294Ssam if (n == CONTINUE) { 82610294Ssam if (argc < 3 ) 82710294Ssam argv[2] = getpass("Password: "), argc++; 82810294Ssam n = command("PASS %s", argv[2]); 82910294Ssam } 83010294Ssam if (n == CONTINUE) { 83110294Ssam if (argc < 4) { 83210294Ssam printf("Account: "); (void) fflush(stdout); 83310294Ssam (void) fgets(acct, sizeof(acct) - 1, stdin); 83410294Ssam acct[strlen(acct) - 1] = '\0'; 83510294Ssam argv[3] = acct; argc++; 83610294Ssam } 83710294Ssam n = command("ACCT %s", acct); 83810294Ssam } 83910294Ssam if (n != COMPLETE) { 84010294Ssam fprintf(stderr, "Login failed.\n"); 84110294Ssam return (0); 84210294Ssam } 84310294Ssam return (1); 84410294Ssam } 84510294Ssam 84610294Ssam /* 84710294Ssam * Print working directory. 84810294Ssam */ 84910294Ssam /*VARARGS*/ 85010294Ssam pwd() 85110294Ssam { 85211756Ssam 85310294Ssam (void) command("XPWD"); 85410294Ssam } 85510294Ssam 85610294Ssam /* 85710294Ssam * Make a directory. 85810294Ssam */ 85910294Ssam makedir(argc, argv) 86010294Ssam char *argv[]; 86110294Ssam { 86210294Ssam 86310294Ssam if (argc < 2) { 86410294Ssam strcat(line, " "); 86510294Ssam printf("(directory-name) "); 86610294Ssam gets(&line[strlen(line)]); 86710294Ssam makeargv(); 86810294Ssam argc = margc; 86910294Ssam argv = margv; 87010294Ssam } 87110294Ssam if (argc < 2) { 87210294Ssam printf("%s directory-name\n", argv[0]); 87310294Ssam return; 87410294Ssam } 87510294Ssam (void) command("XMKD %s", argv[1]); 87610294Ssam } 87710294Ssam 87810294Ssam /* 87910294Ssam * Remove a directory. 88010294Ssam */ 88110294Ssam removedir(argc, argv) 88210294Ssam char *argv[]; 88310294Ssam { 88410294Ssam 88510294Ssam if (argc < 2) { 88610294Ssam strcat(line, " "); 88710294Ssam printf("(directory-name) "); 88810294Ssam gets(&line[strlen(line)]); 88910294Ssam makeargv(); 89010294Ssam argc = margc; 89110294Ssam argv = margv; 89210294Ssam } 89310294Ssam if (argc < 2) { 89410294Ssam printf("%s directory-name\n", argv[0]); 89510294Ssam return; 89610294Ssam } 89710294Ssam (void) command("XRMD %s", argv[1]); 89810294Ssam } 89910294Ssam 90010294Ssam /* 90110294Ssam * Send a line, verbatim, to the remote machine. 90210294Ssam */ 90310294Ssam quote(argc, argv) 90410294Ssam char *argv[]; 90510294Ssam { 90610294Ssam int i; 90710294Ssam char buf[BUFSIZ]; 90810294Ssam 90910294Ssam if (argc < 2) { 91010294Ssam strcat(line, " "); 91110294Ssam printf("(command line to send) "); 91210294Ssam gets(&line[strlen(line)]); 91310294Ssam makeargv(); 91410294Ssam argc = margc; 91510294Ssam argv = margv; 91610294Ssam } 91710294Ssam if (argc < 2) { 91810294Ssam printf("usage: %s line-to-send\n", argv[0]); 91910294Ssam return; 92010294Ssam } 92110294Ssam strcpy(buf, argv[1]); 92210294Ssam for (i = 2; i < argc; i++) { 92310294Ssam strcat(buf, " "); 92410294Ssam strcat(buf, argv[i]); 92510294Ssam } 92610294Ssam (void) command(buf); 92710294Ssam } 92810294Ssam 92910294Ssam /* 93010294Ssam * Ask the other side for help. 93110294Ssam */ 93210294Ssam rmthelp(argc, argv) 93310294Ssam char *argv[]; 93410294Ssam { 93510294Ssam int oldverbose = verbose; 93610294Ssam 93710294Ssam verbose = 1; 93810294Ssam (void) command(argc == 1 ? "HELP" : "HELP %s", argv[1]); 93910294Ssam verbose = oldverbose; 94010294Ssam } 94110294Ssam 94210294Ssam /* 94310294Ssam * Terminate session and exit. 94410294Ssam */ 94510294Ssam /*VARARGS*/ 94610294Ssam quit() 94710294Ssam { 94810294Ssam 94910294Ssam disconnect(); 95010294Ssam exit(0); 95110294Ssam } 95210294Ssam 95310294Ssam /* 95410294Ssam * Terminate session, but don't exit. 95510294Ssam */ 95610294Ssam disconnect() 95710294Ssam { 95810294Ssam extern FILE *cout; 95910294Ssam extern int data; 96010294Ssam 96110294Ssam if (!connected) 96210294Ssam return; 96310294Ssam (void) command("QUIT"); 96410294Ssam (void) fclose(cout); 96510294Ssam cout = NULL; 96610294Ssam connected = 0; 96710294Ssam data = -1; 96810294Ssam } 96911353Ssam 97011650Ssam confirm(cmd, file) 97111353Ssam char *cmd, *file; 97211353Ssam { 97311353Ssam char line[BUFSIZ]; 97411353Ssam 97511353Ssam if (!interactive) 97611650Ssam return (1); 97711353Ssam printf("%s %s? ", cmd, file); 97811353Ssam fflush(stdout); 97911353Ssam gets(line); 98011650Ssam return (*line != 'n' && *line != 'N'); 98111353Ssam } 98211353Ssam 98311353Ssam fatal(msg) 98411353Ssam char *msg; 98511353Ssam { 98611353Ssam 98711353Ssam fprintf(stderr, "ftp: %s\n"); 98811353Ssam exit(1); 98911353Ssam } 99011353Ssam 99111353Ssam /* 99211353Ssam * Glob a local file name specification with 99311353Ssam * the expectation of a single return value. 99411353Ssam * Can't control multiple values being expanded 99511353Ssam * from the expression, we return only the first. 99611353Ssam */ 99711353Ssam globulize(cpp) 99811353Ssam char **cpp; 99911353Ssam { 100011353Ssam char **globbed; 100111353Ssam 100211353Ssam if (!doglob) 100311353Ssam return (1); 100411353Ssam globbed = glob(*cpp); 100511353Ssam if (globerr != NULL) { 100611353Ssam printf("%s: %s\n", *cpp, globerr); 100711353Ssam if (globbed) 100811353Ssam blkfree(globbed); 100911353Ssam return (0); 101011353Ssam } 101111353Ssam if (globbed) { 101211353Ssam *cpp = *globbed++; 101311353Ssam /* don't waste too much memory */ 101411353Ssam if (*globbed) 101511353Ssam blkfree(globbed); 101611353Ssam } 101711353Ssam return (1); 101811353Ssam } 1019