110294Ssam #ifndef lint 2*11756Ssam static char sccsid[] = "@(#)cmds.c 4.5 (Berkeley) 03/29/83"; 310294Ssam #endif 410294Ssam 510294Ssam /* 610294Ssam * FTP User Program -- Command Routines. 710294Ssam */ 811353Ssam #include <sys/param.h> 910294Ssam #include <sys/socket.h> 1010294Ssam 1110294Ssam #include <signal.h> 1210294Ssam #include <stdio.h> 1310294Ssam #include <errno.h> 1410294Ssam #include <netdb.h> 1511353Ssam #include <stat.h> 1610294Ssam 1710294Ssam #include "ftp.h" 1810294Ssam #include "ftp_var.h" 1910294Ssam 2011353Ssam extern char *globerr; 2111353Ssam extern char **glob(); 22*11756Ssam extern char *home; 2311353Ssam extern short gflag; 24*11756Ssam extern char *remglob(); 25*11756Ssam extern char *getenv(); 26*11756Ssam extern char *index(); 27*11756Ssam extern char *rindex(); 2810294Ssam 2910294Ssam /* 3010294Ssam * Connect to peer server and 3110294Ssam * auto-login, if possible. 3210294Ssam */ 3310294Ssam setpeer(argc, argv) 3410294Ssam int argc; 3510294Ssam char *argv[]; 3610294Ssam { 3710294Ssam struct hostent *host, *hookup(); 3810294Ssam int port; 3910294Ssam 4010294Ssam if (connected) { 4110294Ssam printf("Already connected to %s, use disconnect first.\n", 4210294Ssam hostname); 4310294Ssam return; 4410294Ssam } 4510294Ssam if (argc < 2) { 4610294Ssam strcat(line, " "); 4710294Ssam printf("(to) "); 4810294Ssam gets(&line[strlen(line)]); 4910294Ssam makeargv(); 5010294Ssam argc = margc; 5110294Ssam argv = margv; 5210294Ssam } 5310294Ssam if (argc > 3) { 5410294Ssam printf("usage: %s host-name [port]\n", argv[0]); 5510294Ssam return; 5610294Ssam } 5710294Ssam port = sp->s_port; 5810294Ssam if (argc > 2) { 5911218Ssam port = atoi(argv[2]); 6010294Ssam if (port <= 0) { 6111218Ssam printf("%s: bad port number-- %s\n", argv[1], argv[2]); 6211218Ssam printf ("usage: %s host-name [port]\n", argv[0]); 6310294Ssam return; 6410294Ssam } 6510294Ssam port = htons(port); 6610294Ssam } 6710294Ssam host = hookup(argv[1], port); 6810294Ssam if (host) { 6910294Ssam connected = 1; 7010294Ssam if (autologin) 7110294Ssam login(host); 7210294Ssam } 7310294Ssam } 7410294Ssam 7510294Ssam struct types { 7610294Ssam char *t_name; 7710294Ssam char *t_mode; 7810294Ssam int t_type; 7911218Ssam char *t_arg; 8010294Ssam } types[] = { 8111218Ssam { "ascii", "A", TYPE_A, 0 }, 8211218Ssam { "binary", "I", TYPE_I, 0 }, 8311218Ssam { "image", "I", TYPE_I, 0 }, 8411218Ssam { "ebcdic", "E", TYPE_E, 0 }, 8511218Ssam { "tenex", "L", TYPE_L, bytename }, 8610294Ssam 0 8710294Ssam }; 8810294Ssam 8910294Ssam /* 9010294Ssam * Set transfer type. 9110294Ssam */ 9210294Ssam settype(argc, argv) 9310294Ssam char *argv[]; 9410294Ssam { 9510294Ssam register struct types *p; 9611218Ssam int comret; 9710294Ssam 9810294Ssam if (argc > 2) { 9910294Ssam char *sep; 10010294Ssam 10110294Ssam printf("usage: %s [", argv[0]); 10210294Ssam sep = " "; 10310294Ssam for (p = types; p->t_name; p++) { 10410294Ssam printf("%s%s", sep, p->t_name); 10510294Ssam if (*sep == ' ') 10610294Ssam sep = " | "; 10710294Ssam } 10810294Ssam printf(" ]\n"); 10910294Ssam return; 11010294Ssam } 11110294Ssam if (argc < 2) { 11210294Ssam printf("Using %s mode to transfer files.\n", typename); 11310294Ssam return; 11410294Ssam } 11510294Ssam for (p = types; p->t_name; p++) 11610294Ssam if (strcmp(argv[1], p->t_name) == 0) 11710294Ssam break; 11810294Ssam if (p->t_name == 0) { 11910294Ssam printf("%s: unknown mode\n", argv[1]); 12010294Ssam return; 12110294Ssam } 12211218Ssam if ((p->t_arg != NULL) && (*(p->t_arg) != '\0')) 12311218Ssam comret = command ("TYPE %s %s", p->t_mode, p->t_arg); 12411218Ssam else 12511218Ssam comret = command("TYPE %s", p->t_mode); 12611218Ssam if (comret == COMPLETE) { 12710294Ssam strcpy(typename, p->t_name); 12810294Ssam type = p->t_type; 12910294Ssam } 13010294Ssam } 13110294Ssam 13210294Ssam /* 13310294Ssam * Set binary transfer type. 13410294Ssam */ 13510294Ssam /*VARARGS*/ 13610294Ssam setbinary() 13710294Ssam { 13810294Ssam 13910294Ssam call(settype, "type", "binary", 0); 14010294Ssam } 14110294Ssam 14210294Ssam /* 14310294Ssam * Set ascii transfer type. 14410294Ssam */ 14510294Ssam /*VARARGS*/ 14610294Ssam setascii() 14710294Ssam { 14810294Ssam 14910294Ssam call(settype, "type", "ascii", 0); 15010294Ssam } 15110294Ssam 15210294Ssam /* 15310294Ssam * Set tenex transfer type. 15410294Ssam */ 15510294Ssam /*VARARGS*/ 15610294Ssam settenex() 15710294Ssam { 15810294Ssam 15910294Ssam call(settype, "type", "tenex", 0); 16010294Ssam } 16110294Ssam 16210294Ssam /* 16310294Ssam * Set ebcdic transfer type. 16410294Ssam */ 16510294Ssam /*VARARGS*/ 16610294Ssam setebcdic() 16710294Ssam { 16810294Ssam 16910294Ssam call(settype, "type", "ebcdic", 0); 17010294Ssam } 17110294Ssam 17210294Ssam /* 17310294Ssam * Set file transfer mode. 17410294Ssam */ 17510294Ssam setmode(argc, argv) 17610294Ssam char *argv[]; 17710294Ssam { 17810294Ssam 17910294Ssam printf("We only support %s mode, sorry.\n", modename); 18010294Ssam } 18110294Ssam 18210294Ssam /* 18310294Ssam * Set file transfer format. 18410294Ssam */ 18510294Ssam setform(argc, argv) 18610294Ssam char *argv[]; 18710294Ssam { 18810294Ssam 18910294Ssam printf("We only support %s format, sorry.\n", formname); 19010294Ssam } 19110294Ssam 19210294Ssam /* 19310294Ssam * Set file transfer structure. 19410294Ssam */ 19510294Ssam setstruct(argc, argv) 19610294Ssam char *argv[]; 19710294Ssam { 19810294Ssam 19910294Ssam printf("We only support %s structure, sorry.\n", structname); 20010294Ssam } 20110294Ssam 20210294Ssam put(argc, argv) 203*11756Ssam int argc; 20410294Ssam char *argv[]; 20510294Ssam { 20611650Ssam char *cmd; 20711650Ssam 20810294Ssam if (argc == 2) 20910294Ssam argc++, argv[2] = argv[1]; 21010294Ssam if (argc < 2) { 21110294Ssam strcat(line, " "); 21210294Ssam printf("(local-file) "); 21310294Ssam gets(&line[strlen(line)]); 21410294Ssam makeargv(); 21510294Ssam argc = margc; 21610294Ssam argv = margv; 21710294Ssam } 21810294Ssam if (argc < 2) { 21910294Ssam usage: 22010294Ssam printf("%s local-file remote-file\n", argv[0]); 22110294Ssam return; 22210294Ssam } 22310294Ssam if (argc < 3) { 22410294Ssam strcat(line, " "); 22510294Ssam printf("(remote-file) "); 22610294Ssam gets(&line[strlen(line)]); 22710294Ssam makeargv(); 22810294Ssam argc = margc; 22910294Ssam argv = margv; 23010294Ssam } 23110294Ssam if (argc < 3) 23210294Ssam goto usage; 23311353Ssam if (!globulize(&argv[1])) 23411353Ssam return; 235*11756Ssam cmd = (argv[0][0] == 'a') ? "APPE" : "STOR"; 23611650Ssam sendrequest(cmd, argv[1], argv[2]); 23710294Ssam } 23810294Ssam 23910294Ssam /* 240*11756Ssam * Send multiple files. 24110294Ssam */ 24211353Ssam mput(argc, argv) 24311353Ssam char *argv[]; 24411353Ssam { 24511650Ssam char **cpp, **gargs = NULL; 24611353Ssam 24711650Ssam if (argc < 2) { 24811650Ssam strcat(line, " "); 24911650Ssam printf("(local-files) "); 25011650Ssam gets(&line[strlen(line)]); 25111650Ssam makeargv(); 25211650Ssam argc = margc; 25311650Ssam argv = margv; 25411353Ssam } 25511353Ssam if (argc < 2) { 25611353Ssam printf("%s local-files\n", argv[0]); 25711353Ssam return; 25811353Ssam } 25911650Ssam cpp = argv + 1; 26011650Ssam if (doglob) { 26111650Ssam gargs = glob(cpp); 26211650Ssam if (globerr != NULL) { 26311650Ssam printf("%s\n", globerr); 26411650Ssam if (gargs) 26511650Ssam blkfree(gargs); 26611353Ssam return; 26711353Ssam } 26811353Ssam } 26911650Ssam if (gargs != NULL) 27011650Ssam cpp = gargs; 27111650Ssam for (; *cpp != NULL; cpp++) 27211650Ssam if (confirm(argv[0], *cpp)) 27311650Ssam sendrequest("STOR", *cpp, *cpp); 27411650Ssam if (gargs != NULL) 27511650Ssam blkfree(gargs); 27611353Ssam } 27711353Ssam 27811353Ssam /* 27911353Ssam * Receive one file. 28011353Ssam */ 28110294Ssam get(argc, argv) 28210294Ssam char *argv[]; 28310294Ssam { 28410294Ssam 28510294Ssam if (argc == 2) 28610294Ssam argc++, argv[2] = argv[1]; 28710294Ssam if (argc < 2) { 28810294Ssam strcat(line, " "); 28910294Ssam printf("(remote-file) "); 29010294Ssam gets(&line[strlen(line)]); 29110294Ssam makeargv(); 29210294Ssam argc = margc; 29310294Ssam argv = margv; 29410294Ssam } 29510294Ssam if (argc < 2) { 29610294Ssam usage: 29711353Ssam printf("%s remote-file [ local-file ]\n", argv[0]); 29810294Ssam return; 29910294Ssam } 30010294Ssam if (argc < 3) { 30110294Ssam strcat(line, " "); 30210294Ssam printf("(local-file) "); 30310294Ssam gets(&line[strlen(line)]); 30410294Ssam makeargv(); 30510294Ssam argc = margc; 30610294Ssam argv = margv; 30710294Ssam } 30810294Ssam if (argc < 3) 30910294Ssam goto usage; 31011353Ssam if (!globulize(&argv[2])) 31111353Ssam return; 31211650Ssam recvrequest("RETR", argv[2], argv[1], "w"); 31310294Ssam } 31410294Ssam 31511353Ssam /* 31611353Ssam * Get multiple files. 31711353Ssam */ 31811353Ssam mget(argc, argv) 31911353Ssam char *argv[]; 32011353Ssam { 321*11756Ssam char *cp; 32211353Ssam 32311353Ssam if (argc < 2) { 32411353Ssam strcat(line, " "); 325*11756Ssam printf("(remote-files) "); 32611353Ssam gets(&line[strlen(line)]); 32711353Ssam makeargv(); 32811353Ssam argc = margc; 32911353Ssam argv = margv; 33011353Ssam } 33111353Ssam if (argc < 2) { 33211650Ssam printf("%s remote-files\n", argv[0]); 33311353Ssam return; 33411353Ssam } 33511650Ssam while ((cp = remglob(argc, argv)) != NULL) 33611650Ssam if (confirm(argv[0], cp)) 33711650Ssam recvrequest("RETR", cp, cp, "w"); 33811650Ssam } 33911650Ssam 34011650Ssam char * 34111650Ssam remglob(argc, argv) 34211650Ssam char *argv[]; 34311650Ssam { 344*11756Ssam char temp[16]; 34511650Ssam static char buf[MAXPATHLEN]; 34611650Ssam static FILE *ftemp = NULL; 34711650Ssam static char **args; 34811650Ssam int oldverbose; 349*11756Ssam char *cp, *mode; 35011650Ssam 35111650Ssam if (!doglob) { 352*11756Ssam if (args == NULL) 35311650Ssam args = argv; 35411650Ssam if ((cp = *++args) == NULL) 35511650Ssam args = NULL; 35611650Ssam return (cp); 35711353Ssam } 35811650Ssam if (ftemp == NULL) { 35911650Ssam strcpy(temp, "/tmp/ftpXXXXXX"); 36011650Ssam mktemp(temp); 36111650Ssam oldverbose = verbose, verbose = 0; 362*11756Ssam for (mode = "w"; *++argv != NULL; mode = "a") 363*11756Ssam recvrequest ("NLST", temp, *argv, mode); 36411650Ssam verbose = oldverbose; 36511650Ssam ftemp = fopen(temp, "r"); 36611650Ssam unlink(temp); 36711650Ssam if (ftemp == NULL) { 36811650Ssam printf("can't find list of remote files, oops\n"); 369*11756Ssam return (NULL); 37011353Ssam } 37111353Ssam } 37211650Ssam if (fgets(buf, sizeof (buf), ftemp) == NULL) { 37311650Ssam fclose(ftemp), ftemp = NULL; 37411650Ssam return (NULL); 37511353Ssam } 37611650Ssam if ((cp = index(buf, '\n')) != NULL) 37711650Ssam *cp = '\0'; 37811650Ssam return (buf); 37911353Ssam } 38011353Ssam 38110294Ssam char * 38210294Ssam onoff(bool) 38310294Ssam int bool; 38410294Ssam { 38510294Ssam 38610294Ssam return (bool ? "on" : "off"); 38710294Ssam } 38810294Ssam 38910294Ssam /* 39010294Ssam * Show status. 39110294Ssam */ 39210294Ssam status(argc, argv) 39310294Ssam char *argv[]; 39410294Ssam { 39510294Ssam 39610294Ssam if (connected) 39710294Ssam printf("Connected to %s.\n", hostname); 39810294Ssam else 39910294Ssam printf("Not connected.\n"); 40010294Ssam printf("Mode: %s; Type: %s; Form: %s; Structure: %s\n", 40110294Ssam modename, typename, formname, structname); 40211353Ssam printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s\n", 40311353Ssam onoff(verbose), onoff(bell), onoff(interactive), 40411353Ssam onoff(doglob)); 40511650Ssam printf("Hash mark printing: %s; Use of PORT cmds: %s\n", 40611650Ssam onoff(hash), onoff(sendport)); 40710294Ssam } 40810294Ssam 40910294Ssam /* 41010294Ssam * Set beep on cmd completed mode. 41110294Ssam */ 41210294Ssam /*VARARGS*/ 41310294Ssam setbell() 41410294Ssam { 41510294Ssam 41610294Ssam bell = !bell; 41710294Ssam printf("Bell mode %s.\n", onoff(bell)); 41810294Ssam } 41910294Ssam 42010294Ssam /* 42110294Ssam * Turn on packet tracing. 42210294Ssam */ 42310294Ssam /*VARARGS*/ 42410294Ssam settrace() 42510294Ssam { 42610294Ssam 42710294Ssam trace = !trace; 42810294Ssam printf("Packet tracing %s.\n", onoff(trace)); 42910294Ssam } 43010294Ssam 43110294Ssam /* 43211650Ssam * Toggle hash mark printing during transfers. 43311650Ssam */ 43411650Ssam /*VARARGS*/ 43511650Ssam sethash() 43611650Ssam { 43711650Ssam 43811650Ssam hash = !hash; 43911650Ssam printf("Hash mark printing %s", onoff(hash)); 44011650Ssam if (hash) 44111650Ssam printf(" (%d bytes/hash mark)", BUFSIZ); 44211650Ssam printf(".\n"); 44311650Ssam } 44411650Ssam 44511650Ssam /* 44610294Ssam * Turn on printing of server echo's. 44710294Ssam */ 44810294Ssam /*VARARGS*/ 44910294Ssam setverbose() 45010294Ssam { 45110294Ssam 45210294Ssam verbose = !verbose; 45310294Ssam printf("Verbose mode %s.\n", onoff(verbose)); 45410294Ssam } 45510294Ssam 45610294Ssam /* 45711650Ssam * Toggle PORT cmd use before each data connection. 45811650Ssam */ 45911650Ssam /*VARARGS*/ 46011650Ssam setport() 46111650Ssam { 46211650Ssam 46311650Ssam sendport = !sendport; 46411650Ssam printf("Use of PORT cmds %s.\n", onoff(sendport)); 46511650Ssam } 46611650Ssam 46711650Ssam /* 46810294Ssam * Turn on interactive prompting 46910294Ssam * during mget, mput, and mdelete. 47010294Ssam */ 47110294Ssam /*VARARGS*/ 47210294Ssam setprompt() 47310294Ssam { 47410294Ssam 47510294Ssam interactive = !interactive; 47610294Ssam printf("Interactive mode %s.\n", onoff(interactive)); 47710294Ssam } 47810294Ssam 47910294Ssam /* 48011353Ssam * Toggle metacharacter interpretation 48111353Ssam * on local file names. 48211353Ssam */ 48311353Ssam /*VARARGS*/ 48411353Ssam setglob() 48511353Ssam { 48611353Ssam 48711353Ssam doglob = !doglob; 48811353Ssam printf("Globbing %s.\n", onoff(doglob)); 48911353Ssam } 49011353Ssam 49111353Ssam /* 49210294Ssam * Set debugging mode on/off and/or 49310294Ssam * set level of debugging. 49410294Ssam */ 495*11756Ssam /*VARARGS*/ 49610294Ssam setdebug(argc, argv) 49710294Ssam char *argv[]; 49810294Ssam { 49910294Ssam int val; 50010294Ssam 50110294Ssam if (argc > 1) { 50210294Ssam val = atoi(argv[1]); 50310294Ssam if (val < 0) { 50410294Ssam printf("%s: bad debugging value.\n", argv[1]); 50510294Ssam return; 50610294Ssam } 50710294Ssam } else 50810294Ssam val = !debug; 50910294Ssam debug = val; 51010294Ssam if (debug) 51110294Ssam options |= SO_DEBUG; 51210294Ssam else 51310294Ssam options &= ~SO_DEBUG; 51410294Ssam printf("Debugging %s (debug=%d).\n", onoff(debug), debug); 51510294Ssam } 51610294Ssam 51710294Ssam /* 51810294Ssam * Set current working directory 51910294Ssam * on remote machine. 52010294Ssam */ 52110294Ssam cd(argc, argv) 52210294Ssam char *argv[]; 52310294Ssam { 52410294Ssam 52510294Ssam if (argc < 2) { 52610294Ssam strcat(line, " "); 52710294Ssam printf("(remote-directory) "); 52810294Ssam gets(&line[strlen(line)]); 52910294Ssam makeargv(); 53010294Ssam argc = margc; 53110294Ssam argv = margv; 53210294Ssam } 53310294Ssam if (argc < 2) { 53410294Ssam printf("%s remote-directory\n", argv[0]); 53510294Ssam return; 53610294Ssam } 53710294Ssam (void) command("CWD %s", argv[1]); 53810294Ssam } 53910294Ssam 54010294Ssam /* 54110294Ssam * Set current working directory 54210294Ssam * on local machine. 54310294Ssam */ 54410294Ssam lcd(argc, argv) 54510294Ssam char *argv[]; 54610294Ssam { 54711353Ssam char buf[MAXPATHLEN]; 54810294Ssam 54911353Ssam if (argc < 2) 55011353Ssam argc++, argv[1] = home; 55110294Ssam if (argc != 2) { 55210294Ssam printf("%s local-directory\n", argv[0]); 55310294Ssam return; 55410294Ssam } 55511353Ssam if (!globulize(&argv[1])) 55611353Ssam return; 55711353Ssam if (chdir(argv[1]) < 0) { 55810294Ssam perror(argv[1]); 55911353Ssam return; 56011353Ssam } 56111353Ssam printf("Local directory now %s\n", getwd(buf)); 56210294Ssam } 56310294Ssam 56410294Ssam /* 56510294Ssam * Delete a single file. 56610294Ssam */ 56710294Ssam delete(argc, argv) 56810294Ssam char *argv[]; 56910294Ssam { 57010294Ssam 57110294Ssam if (argc < 2) { 57210294Ssam strcat(line, " "); 57310294Ssam printf("(remote-file) "); 57410294Ssam gets(&line[strlen(line)]); 57510294Ssam makeargv(); 57610294Ssam argc = margc; 57710294Ssam argv = margv; 57810294Ssam } 57910294Ssam if (argc < 2) { 58010294Ssam printf("%s remote-file\n", argv[0]); 58110294Ssam return; 58210294Ssam } 58310294Ssam (void) command("DELE %s", argv[1]); 58410294Ssam } 58510294Ssam 58610294Ssam /* 58711650Ssam * Delete multiple files. 58811650Ssam */ 58911650Ssam mdelete(argc, argv) 59011650Ssam char *argv[]; 59111650Ssam { 59211650Ssam char *cp; 59311650Ssam 59411650Ssam if (argc < 2) { 59511650Ssam strcat(line, " "); 59611650Ssam printf("(remote-files) "); 59711650Ssam gets(&line[strlen(line)]); 59811650Ssam makeargv(); 59911650Ssam argc = margc; 60011650Ssam argv = margv; 60111650Ssam } 60211650Ssam if (argc < 2) { 60311650Ssam printf("%s remote-files\n", argv[0]); 60411650Ssam return; 60511650Ssam } 60611650Ssam while ((cp = remglob(argc, argv)) != NULL) 60711650Ssam if (confirm(argv[0], cp)) 60811650Ssam (void) command("DELE %s", cp); 60911650Ssam } 610*11756Ssam 61111650Ssam /* 61210294Ssam * Rename a remote file. 61310294Ssam */ 61410294Ssam renamefile(argc, argv) 61510294Ssam char *argv[]; 61610294Ssam { 61710294Ssam 61810294Ssam if (argc < 2) { 61910294Ssam strcat(line, " "); 62010294Ssam printf("(from-name) "); 62110294Ssam gets(&line[strlen(line)]); 62210294Ssam makeargv(); 62310294Ssam argc = margc; 62410294Ssam argv = margv; 62510294Ssam } 62610294Ssam if (argc < 2) { 62710294Ssam usage: 62810294Ssam printf("%s from-name to-name\n", argv[0]); 62910294Ssam return; 63010294Ssam } 63110294Ssam if (argc < 3) { 63210294Ssam strcat(line, " "); 63310294Ssam printf("(to-name) "); 63410294Ssam gets(&line[strlen(line)]); 63510294Ssam makeargv(); 63610294Ssam argc = margc; 63710294Ssam argv = margv; 63810294Ssam } 63910294Ssam if (argc < 3) 64010294Ssam goto usage; 64110294Ssam if (command("RNFR %s", argv[1]) == CONTINUE) 64210294Ssam (void) command("RNTO %s", argv[2]); 64310294Ssam } 64410294Ssam 64510294Ssam /* 64610294Ssam * Get a directory listing 64710294Ssam * of remote files. 64810294Ssam */ 64910294Ssam ls(argc, argv) 65010294Ssam char *argv[]; 65110294Ssam { 652*11756Ssam char *cmd; 65310294Ssam 65410294Ssam if (argc < 2) 65510294Ssam argc++, argv[1] = NULL; 65610294Ssam if (argc < 3) 65710294Ssam argc++, argv[2] = "-"; 658*11756Ssam if (argc > 3) { 659*11756Ssam printf("usage: %s remote-directory local-file\n", argv[0]); 660*11756Ssam return; 661*11756Ssam } 66210294Ssam cmd = argv[0][0] == 'l' ? "NLST" : "LIST"; 66311353Ssam if (strcmp(argv[2], "-") && !globulize(&argv[2])) 66411353Ssam return; 665*11756Ssam recvrequest(cmd, argv[2], argv[1], "w"); 66610294Ssam } 66710294Ssam 66810294Ssam /* 669*11756Ssam * Get a directory listing 670*11756Ssam * of multiple remote files. 671*11756Ssam */ 672*11756Ssam mls(argc, argv) 673*11756Ssam char *argv[]; 674*11756Ssam { 675*11756Ssam char *cmd, *mode; 676*11756Ssam int i, dest; 677*11756Ssam 678*11756Ssam if (argc < 2) 679*11756Ssam argc++, argv[1] = NULL; 680*11756Ssam if (argc < 3) 681*11756Ssam argc++, argv[2] = "-"; 682*11756Ssam dest = argc - 1; 683*11756Ssam cmd = argv[0][1] == 'l' ? "NLST" : "LIST"; 684*11756Ssam if (strcmp(argv[dest], "-") != 0) 685*11756Ssam if (globulize(&argv[dest]) && confirm("local-file", argv[dest])) 686*11756Ssam return; 687*11756Ssam for (i = 1, mode = "w"; i < dest; i++, mode = "a") 688*11756Ssam recvrequest(cmd, argv[dest], argv[i], mode); 689*11756Ssam } 690*11756Ssam 691*11756Ssam /* 69210294Ssam * Do a shell escape 69310294Ssam */ 69410294Ssam shell(argc, argv) 69510294Ssam char *argv[]; 69610294Ssam { 697*11756Ssam int pid, status, (*old1)(), (*old2)(); 698*11756Ssam char shellnam[40], *shell, *namep; 699*11756Ssam char **cpp, **gargs; 70010294Ssam 701*11756Ssam old1 = signal (SIGINT, SIG_IGN); 702*11756Ssam old2 = signal (SIGQUIT, SIG_IGN); 703*11756Ssam if ((pid = fork()) == 0) { 704*11756Ssam for (pid = 3; pid < 20; pid++) 705*11756Ssam close(pid); 706*11756Ssam signal(SIGINT, SIG_DFL); 707*11756Ssam signal(SIGQUIT, SIG_DFL); 708*11756Ssam if (argc <= 1) { 709*11756Ssam shell = getenv("SHELL"); 710*11756Ssam if (shell == NULL) 711*11756Ssam shell = "/bin/sh"; 712*11756Ssam namep = rindex(shell,'/'); 713*11756Ssam if (namep == NULL) 714*11756Ssam namep = shell; 715*11756Ssam strcpy(shellnam,"-"); 716*11756Ssam strcat(shellnam, ++namep); 717*11756Ssam if (strcmp(namep, "sh") != 0) 718*11756Ssam shellnam[0] = '+'; 719*11756Ssam if (debug) { 720*11756Ssam printf ("%s\n", shell); 721*11756Ssam fflush (stdout); 722*11756Ssam } 723*11756Ssam execl(shell, shellnam, 0); 724*11756Ssam perror(shell); 725*11756Ssam exit(1); 726*11756Ssam } 727*11756Ssam cpp = &argv[1]; 728*11756Ssam if (argc > 2) { 729*11756Ssam if ((gargs = glob(cpp)) != NULL) 730*11756Ssam cpp = gargs; 731*11756Ssam if (globerr != NULL) { 732*11756Ssam printf("%s\n", globerr); 733*11756Ssam exit(1); 734*11756Ssam } 735*11756Ssam } 736*11756Ssam if (debug) { 737*11756Ssam register char **zip = cpp; 738*11756Ssam 739*11756Ssam printf("%s", *zip); 740*11756Ssam while (*++zip != NULL) 741*11756Ssam printf(" %s", *zip); 742*11756Ssam printf("\n"); 743*11756Ssam fflush(stdout); 744*11756Ssam } 745*11756Ssam execvp(argv[1], cpp); 746*11756Ssam perror(argv[1]); 747*11756Ssam exit(1); 748*11756Ssam } 749*11756Ssam if (pid > 0) 750*11756Ssam while (wait(&status) != pid) 751*11756Ssam ; 752*11756Ssam signal(SIGINT, old1); 753*11756Ssam signal(SIGQUIT, old2); 754*11756Ssam if (pid == -1) 755*11756Ssam perror("Try again later"); 756*11756Ssam return (0); 75710294Ssam } 75810294Ssam 75910294Ssam /* 76010294Ssam * Send new user information (re-login) 76110294Ssam */ 76210294Ssam user(argc, argv) 76310294Ssam int argc; 76410294Ssam char **argv; 76510294Ssam { 76610294Ssam char acct[80], *getpass(); 76710294Ssam int n; 76810294Ssam 76910294Ssam if (argc < 2) { 77010294Ssam strcat(line, " "); 77110294Ssam printf("(username) "); 77210294Ssam gets(&line[strlen(line)]); 77310294Ssam makeargv(); 77410294Ssam argc = margc; 77510294Ssam argv = margv; 77610294Ssam } 77710294Ssam if (argc > 4) { 77810294Ssam printf("usage: %s username [password] [account]\n", argv[0]); 779*11756Ssam return (0); 78010294Ssam } 78110294Ssam n = command("USER %s", argv[1]); 78210294Ssam if (n == CONTINUE) { 78310294Ssam if (argc < 3 ) 78410294Ssam argv[2] = getpass("Password: "), argc++; 78510294Ssam n = command("PASS %s", argv[2]); 78610294Ssam } 78710294Ssam if (n == CONTINUE) { 78810294Ssam if (argc < 4) { 78910294Ssam printf("Account: "); (void) fflush(stdout); 79010294Ssam (void) fgets(acct, sizeof(acct) - 1, stdin); 79110294Ssam acct[strlen(acct) - 1] = '\0'; 79210294Ssam argv[3] = acct; argc++; 79310294Ssam } 79410294Ssam n = command("ACCT %s", acct); 79510294Ssam } 79610294Ssam if (n != COMPLETE) { 79710294Ssam fprintf(stderr, "Login failed.\n"); 79810294Ssam return (0); 79910294Ssam } 80010294Ssam return (1); 80110294Ssam } 80210294Ssam 80310294Ssam /* 80410294Ssam * Print working directory. 80510294Ssam */ 80610294Ssam /*VARARGS*/ 80710294Ssam pwd() 80810294Ssam { 809*11756Ssam 81010294Ssam (void) command("XPWD"); 81110294Ssam } 81210294Ssam 81310294Ssam /* 81410294Ssam * Make a directory. 81510294Ssam */ 81610294Ssam makedir(argc, argv) 81710294Ssam char *argv[]; 81810294Ssam { 81910294Ssam 82010294Ssam if (argc < 2) { 82110294Ssam strcat(line, " "); 82210294Ssam printf("(directory-name) "); 82310294Ssam gets(&line[strlen(line)]); 82410294Ssam makeargv(); 82510294Ssam argc = margc; 82610294Ssam argv = margv; 82710294Ssam } 82810294Ssam if (argc < 2) { 82910294Ssam printf("%s directory-name\n", argv[0]); 83010294Ssam return; 83110294Ssam } 83210294Ssam (void) command("XMKD %s", argv[1]); 83310294Ssam } 83410294Ssam 83510294Ssam /* 83610294Ssam * Remove a directory. 83710294Ssam */ 83810294Ssam removedir(argc, argv) 83910294Ssam char *argv[]; 84010294Ssam { 84110294Ssam 84210294Ssam if (argc < 2) { 84310294Ssam strcat(line, " "); 84410294Ssam printf("(directory-name) "); 84510294Ssam gets(&line[strlen(line)]); 84610294Ssam makeargv(); 84710294Ssam argc = margc; 84810294Ssam argv = margv; 84910294Ssam } 85010294Ssam if (argc < 2) { 85110294Ssam printf("%s directory-name\n", argv[0]); 85210294Ssam return; 85310294Ssam } 85410294Ssam (void) command("XRMD %s", argv[1]); 85510294Ssam } 85610294Ssam 85710294Ssam /* 85810294Ssam * Send a line, verbatim, to the remote machine. 85910294Ssam */ 86010294Ssam quote(argc, argv) 86110294Ssam char *argv[]; 86210294Ssam { 86310294Ssam int i; 86410294Ssam char buf[BUFSIZ]; 86510294Ssam 86610294Ssam if (argc < 2) { 86710294Ssam strcat(line, " "); 86810294Ssam printf("(command line to send) "); 86910294Ssam gets(&line[strlen(line)]); 87010294Ssam makeargv(); 87110294Ssam argc = margc; 87210294Ssam argv = margv; 87310294Ssam } 87410294Ssam if (argc < 2) { 87510294Ssam printf("usage: %s line-to-send\n", argv[0]); 87610294Ssam return; 87710294Ssam } 87810294Ssam strcpy(buf, argv[1]); 87910294Ssam for (i = 2; i < argc; i++) { 88010294Ssam strcat(buf, " "); 88110294Ssam strcat(buf, argv[i]); 88210294Ssam } 88310294Ssam (void) command(buf); 88410294Ssam } 88510294Ssam 88610294Ssam /* 88710294Ssam * Ask the other side for help. 88810294Ssam */ 88910294Ssam rmthelp(argc, argv) 89010294Ssam char *argv[]; 89110294Ssam { 89210294Ssam int oldverbose = verbose; 89310294Ssam 89410294Ssam verbose = 1; 89510294Ssam (void) command(argc == 1 ? "HELP" : "HELP %s", argv[1]); 89610294Ssam verbose = oldverbose; 89710294Ssam } 89810294Ssam 89910294Ssam /* 90010294Ssam * Terminate session and exit. 90110294Ssam */ 90210294Ssam /*VARARGS*/ 90310294Ssam quit() 90410294Ssam { 90510294Ssam 90610294Ssam disconnect(); 90710294Ssam exit(0); 90810294Ssam } 90910294Ssam 91010294Ssam /* 91110294Ssam * Terminate session, but don't exit. 91210294Ssam */ 91310294Ssam disconnect() 91410294Ssam { 91510294Ssam extern FILE *cout; 91610294Ssam extern int data; 91710294Ssam 91810294Ssam if (!connected) 91910294Ssam return; 92010294Ssam (void) command("QUIT"); 92110294Ssam (void) fclose(cout); 92210294Ssam cout = NULL; 92310294Ssam connected = 0; 92410294Ssam data = -1; 92510294Ssam } 92611353Ssam 92711650Ssam confirm(cmd, file) 92811353Ssam char *cmd, *file; 92911353Ssam { 93011353Ssam char line[BUFSIZ]; 93111353Ssam 93211353Ssam if (!interactive) 93311650Ssam return (1); 93411353Ssam printf("%s %s? ", cmd, file); 93511353Ssam fflush(stdout); 93611353Ssam gets(line); 93711650Ssam return (*line != 'n' && *line != 'N'); 93811353Ssam } 93911353Ssam 94011353Ssam fatal(msg) 94111353Ssam char *msg; 94211353Ssam { 94311353Ssam 94411353Ssam fprintf(stderr, "ftp: %s\n"); 94511353Ssam exit(1); 94611353Ssam } 94711353Ssam 94811353Ssam /* 94911353Ssam * Glob a local file name specification with 95011353Ssam * the expectation of a single return value. 95111353Ssam * Can't control multiple values being expanded 95211353Ssam * from the expression, we return only the first. 95311353Ssam */ 95411353Ssam globulize(cpp) 95511353Ssam char **cpp; 95611353Ssam { 95711353Ssam char **globbed; 95811353Ssam 95911353Ssam if (!doglob) 96011353Ssam return (1); 96111353Ssam globbed = glob(*cpp); 96211353Ssam if (globerr != NULL) { 96311353Ssam printf("%s: %s\n", *cpp, globerr); 96411353Ssam if (globbed) 96511353Ssam blkfree(globbed); 96611353Ssam return (0); 96711353Ssam } 96811353Ssam if (globbed) { 96911353Ssam *cpp = *globbed++; 97011353Ssam /* don't waste too much memory */ 97111353Ssam if (*globbed) 97211353Ssam blkfree(globbed); 97311353Ssam } 97411353Ssam return (1); 97511353Ssam } 976