1*21737Sdist /* 2*21737Sdist * Copyright (c) 1983 Regents of the University of California. 3*21737Sdist * All rights reserved. The Berkeley software License Agreement 4*21737Sdist * specifies the terms and conditions for redistribution. 5*21737Sdist */ 6*21737Sdist 710294Ssam #ifndef lint 8*21737Sdist static char sccsid[] = "@(#)cmds.c 5.1 (Berkeley) 05/31/85"; 9*21737Sdist #endif not lint 1010294Ssam 1110294Ssam /* 1210294Ssam * FTP User Program -- Command Routines. 1310294Ssam */ 1411353Ssam #include <sys/param.h> 1510294Ssam #include <sys/socket.h> 1610294Ssam 1712396Ssam #include <arpa/ftp.h> 1812396Ssam 1910294Ssam #include <signal.h> 2010294Ssam #include <stdio.h> 2110294Ssam #include <errno.h> 2210294Ssam #include <netdb.h> 2310294Ssam 2410294Ssam #include "ftp_var.h" 2510294Ssam 2611353Ssam extern char *globerr; 2711353Ssam extern char **glob(); 2811756Ssam extern char *home; 2911353Ssam extern short gflag; 3011756Ssam extern char *remglob(); 3111756Ssam extern char *getenv(); 3211756Ssam extern char *index(); 3311756Ssam extern char *rindex(); 3410294Ssam 3510294Ssam /* 3610294Ssam * Connect to peer server and 3710294Ssam * auto-login, if possible. 3810294Ssam */ 3910294Ssam setpeer(argc, argv) 4010294Ssam int argc; 4110294Ssam char *argv[]; 4210294Ssam { 4310294Ssam struct hostent *host, *hookup(); 4410294Ssam int port; 4510294Ssam 4610294Ssam if (connected) { 4710294Ssam printf("Already connected to %s, use disconnect first.\n", 4810294Ssam hostname); 4910294Ssam return; 5010294Ssam } 5110294Ssam if (argc < 2) { 5210294Ssam strcat(line, " "); 5310294Ssam printf("(to) "); 5410294Ssam gets(&line[strlen(line)]); 5510294Ssam makeargv(); 5610294Ssam argc = margc; 5710294Ssam argv = margv; 5810294Ssam } 5910294Ssam if (argc > 3) { 6010294Ssam printf("usage: %s host-name [port]\n", argv[0]); 6110294Ssam return; 6210294Ssam } 6310294Ssam port = sp->s_port; 6410294Ssam if (argc > 2) { 6511218Ssam port = atoi(argv[2]); 6610294Ssam if (port <= 0) { 6711218Ssam printf("%s: bad port number-- %s\n", argv[1], argv[2]); 6811218Ssam printf ("usage: %s host-name [port]\n", argv[0]); 6910294Ssam return; 7010294Ssam } 7110294Ssam port = htons(port); 7210294Ssam } 7310294Ssam host = hookup(argv[1], port); 7410294Ssam if (host) { 7510294Ssam connected = 1; 7610294Ssam if (autologin) 7710294Ssam login(host); 7810294Ssam } 7910294Ssam } 8010294Ssam 8110294Ssam struct types { 8210294Ssam char *t_name; 8310294Ssam char *t_mode; 8410294Ssam int t_type; 8511218Ssam char *t_arg; 8610294Ssam } types[] = { 8711218Ssam { "ascii", "A", TYPE_A, 0 }, 8811218Ssam { "binary", "I", TYPE_I, 0 }, 8911218Ssam { "image", "I", TYPE_I, 0 }, 9011218Ssam { "ebcdic", "E", TYPE_E, 0 }, 9111218Ssam { "tenex", "L", TYPE_L, bytename }, 9210294Ssam 0 9310294Ssam }; 9410294Ssam 9510294Ssam /* 9610294Ssam * Set transfer type. 9710294Ssam */ 9810294Ssam settype(argc, argv) 9910294Ssam char *argv[]; 10010294Ssam { 10110294Ssam register struct types *p; 10211218Ssam int comret; 10310294Ssam 10410294Ssam if (argc > 2) { 10510294Ssam char *sep; 10610294Ssam 10710294Ssam printf("usage: %s [", argv[0]); 10810294Ssam sep = " "; 10910294Ssam for (p = types; p->t_name; p++) { 11010294Ssam printf("%s%s", sep, p->t_name); 11110294Ssam if (*sep == ' ') 11210294Ssam sep = " | "; 11310294Ssam } 11410294Ssam printf(" ]\n"); 11510294Ssam return; 11610294Ssam } 11710294Ssam if (argc < 2) { 11810294Ssam printf("Using %s mode to transfer files.\n", typename); 11910294Ssam return; 12010294Ssam } 12110294Ssam for (p = types; p->t_name; p++) 12210294Ssam if (strcmp(argv[1], p->t_name) == 0) 12310294Ssam break; 12410294Ssam if (p->t_name == 0) { 12510294Ssam printf("%s: unknown mode\n", argv[1]); 12610294Ssam return; 12710294Ssam } 12811218Ssam if ((p->t_arg != NULL) && (*(p->t_arg) != '\0')) 12911218Ssam comret = command ("TYPE %s %s", p->t_mode, p->t_arg); 13011218Ssam else 13111218Ssam comret = command("TYPE %s", p->t_mode); 13211218Ssam if (comret == COMPLETE) { 13310294Ssam strcpy(typename, p->t_name); 13410294Ssam type = p->t_type; 13510294Ssam } 13610294Ssam } 13710294Ssam 13810294Ssam /* 13910294Ssam * Set binary transfer type. 14010294Ssam */ 14110294Ssam /*VARARGS*/ 14210294Ssam setbinary() 14310294Ssam { 14410294Ssam 14510294Ssam call(settype, "type", "binary", 0); 14610294Ssam } 14710294Ssam 14810294Ssam /* 14910294Ssam * Set ascii transfer type. 15010294Ssam */ 15110294Ssam /*VARARGS*/ 15210294Ssam setascii() 15310294Ssam { 15410294Ssam 15510294Ssam call(settype, "type", "ascii", 0); 15610294Ssam } 15710294Ssam 15810294Ssam /* 15910294Ssam * Set tenex transfer type. 16010294Ssam */ 16110294Ssam /*VARARGS*/ 16210294Ssam settenex() 16310294Ssam { 16410294Ssam 16510294Ssam call(settype, "type", "tenex", 0); 16610294Ssam } 16710294Ssam 16810294Ssam /* 16910294Ssam * Set ebcdic transfer type. 17010294Ssam */ 17110294Ssam /*VARARGS*/ 17210294Ssam setebcdic() 17310294Ssam { 17410294Ssam 17510294Ssam call(settype, "type", "ebcdic", 0); 17610294Ssam } 17710294Ssam 17810294Ssam /* 17910294Ssam * Set file transfer mode. 18010294Ssam */ 18110294Ssam setmode(argc, argv) 18210294Ssam char *argv[]; 18310294Ssam { 18410294Ssam 18510294Ssam printf("We only support %s mode, sorry.\n", modename); 18610294Ssam } 18710294Ssam 18810294Ssam /* 18910294Ssam * Set file transfer format. 19010294Ssam */ 19110294Ssam setform(argc, argv) 19210294Ssam char *argv[]; 19310294Ssam { 19410294Ssam 19510294Ssam printf("We only support %s format, sorry.\n", formname); 19610294Ssam } 19710294Ssam 19810294Ssam /* 19910294Ssam * Set file transfer structure. 20010294Ssam */ 20110294Ssam setstruct(argc, argv) 20210294Ssam char *argv[]; 20310294Ssam { 20410294Ssam 20510294Ssam printf("We only support %s structure, sorry.\n", structname); 20610294Ssam } 20710294Ssam 20818286Sralph /* 20918286Sralph * Send a single file. 21018286Sralph */ 21110294Ssam put(argc, argv) 21211756Ssam int argc; 21310294Ssam char *argv[]; 21410294Ssam { 21511650Ssam char *cmd; 21611650Ssam 21710294Ssam if (argc == 2) 21810294Ssam argc++, argv[2] = argv[1]; 21910294Ssam if (argc < 2) { 22010294Ssam strcat(line, " "); 22110294Ssam printf("(local-file) "); 22210294Ssam gets(&line[strlen(line)]); 22310294Ssam makeargv(); 22410294Ssam argc = margc; 22510294Ssam argv = margv; 22610294Ssam } 22710294Ssam if (argc < 2) { 22810294Ssam usage: 22910294Ssam printf("%s local-file remote-file\n", argv[0]); 23010294Ssam return; 23110294Ssam } 23210294Ssam if (argc < 3) { 23310294Ssam strcat(line, " "); 23410294Ssam printf("(remote-file) "); 23510294Ssam gets(&line[strlen(line)]); 23610294Ssam makeargv(); 23710294Ssam argc = margc; 23810294Ssam argv = margv; 23910294Ssam } 24010294Ssam if (argc < 3) 24110294Ssam goto usage; 24211353Ssam if (!globulize(&argv[1])) 24311353Ssam return; 24411756Ssam cmd = (argv[0][0] == 'a') ? "APPE" : "STOR"; 24511650Ssam sendrequest(cmd, argv[1], argv[2]); 24610294Ssam } 24710294Ssam 24810294Ssam /* 24911756Ssam * Send multiple files. 25010294Ssam */ 25111353Ssam mput(argc, argv) 25211353Ssam char *argv[]; 25311353Ssam { 25413212Ssam register int i; 25511353Ssam 25611650Ssam if (argc < 2) { 25711650Ssam strcat(line, " "); 25811650Ssam printf("(local-files) "); 25911650Ssam gets(&line[strlen(line)]); 26011650Ssam makeargv(); 26111650Ssam argc = margc; 26211650Ssam argv = margv; 26311353Ssam } 26411353Ssam if (argc < 2) { 26511353Ssam printf("%s local-files\n", argv[0]); 26611353Ssam return; 26711353Ssam } 26813212Ssam for (i = 1; i < argc; i++) { 26913212Ssam register char **cpp, **gargs; 27013212Ssam 27113212Ssam if (!doglob) { 27213212Ssam if (confirm(argv[0], argv[i])) 27313212Ssam sendrequest("STOR", argv[i], argv[i]); 27413212Ssam continue; 27513212Ssam } 27613212Ssam gargs = glob(argv[i]); 27711650Ssam if (globerr != NULL) { 27811650Ssam printf("%s\n", globerr); 27911650Ssam if (gargs) 28011650Ssam blkfree(gargs); 28113212Ssam continue; 28211353Ssam } 28313212Ssam for (cpp = gargs; cpp && *cpp != NULL; cpp++) 28413212Ssam if (confirm(argv[0], *cpp)) 28513212Ssam sendrequest("STOR", *cpp, *cpp); 28613212Ssam if (gargs != NULL) 28713212Ssam blkfree(gargs); 28811353Ssam } 28911353Ssam } 29011353Ssam 29111353Ssam /* 29211353Ssam * Receive one file. 29311353Ssam */ 29410294Ssam get(argc, argv) 29510294Ssam char *argv[]; 29610294Ssam { 29710294Ssam 29810294Ssam if (argc == 2) 29910294Ssam argc++, argv[2] = argv[1]; 30010294Ssam if (argc < 2) { 30110294Ssam strcat(line, " "); 30210294Ssam printf("(remote-file) "); 30310294Ssam gets(&line[strlen(line)]); 30410294Ssam makeargv(); 30510294Ssam argc = margc; 30610294Ssam argv = margv; 30710294Ssam } 30810294Ssam if (argc < 2) { 30910294Ssam usage: 31011353Ssam printf("%s remote-file [ local-file ]\n", argv[0]); 31110294Ssam return; 31210294Ssam } 31310294Ssam if (argc < 3) { 31410294Ssam strcat(line, " "); 31510294Ssam printf("(local-file) "); 31610294Ssam gets(&line[strlen(line)]); 31710294Ssam makeargv(); 31810294Ssam argc = margc; 31910294Ssam argv = margv; 32010294Ssam } 32110294Ssam if (argc < 3) 32210294Ssam goto usage; 32311353Ssam if (!globulize(&argv[2])) 32411353Ssam return; 32511650Ssam recvrequest("RETR", argv[2], argv[1], "w"); 32610294Ssam } 32710294Ssam 32811353Ssam /* 32911353Ssam * Get multiple files. 33011353Ssam */ 33111353Ssam mget(argc, argv) 33211353Ssam char *argv[]; 33311353Ssam { 33411756Ssam char *cp; 33511353Ssam 33611353Ssam if (argc < 2) { 33711353Ssam strcat(line, " "); 33811756Ssam printf("(remote-files) "); 33911353Ssam gets(&line[strlen(line)]); 34011353Ssam makeargv(); 34111353Ssam argc = margc; 34211353Ssam argv = margv; 34311353Ssam } 34411353Ssam if (argc < 2) { 34511650Ssam printf("%s remote-files\n", argv[0]); 34611353Ssam return; 34711353Ssam } 34811650Ssam while ((cp = remglob(argc, argv)) != NULL) 34911650Ssam if (confirm(argv[0], cp)) 35011650Ssam recvrequest("RETR", cp, cp, "w"); 35111650Ssam } 35211650Ssam 35311650Ssam char * 35411650Ssam remglob(argc, argv) 35511650Ssam char *argv[]; 35611650Ssam { 35711756Ssam char temp[16]; 35811650Ssam static char buf[MAXPATHLEN]; 35911650Ssam static FILE *ftemp = NULL; 36011650Ssam static char **args; 36113212Ssam int oldverbose, oldhash; 36211756Ssam char *cp, *mode; 36311650Ssam 36411650Ssam if (!doglob) { 36511756Ssam if (args == NULL) 36611650Ssam args = argv; 36711650Ssam if ((cp = *++args) == NULL) 36811650Ssam args = NULL; 36911650Ssam return (cp); 37011353Ssam } 37111650Ssam if (ftemp == NULL) { 37211650Ssam strcpy(temp, "/tmp/ftpXXXXXX"); 37311650Ssam mktemp(temp); 37411650Ssam oldverbose = verbose, verbose = 0; 37513212Ssam oldhash = hash, hash = 0; 37611756Ssam for (mode = "w"; *++argv != NULL; mode = "a") 37711756Ssam recvrequest ("NLST", temp, *argv, mode); 37813212Ssam verbose = oldverbose; hash = oldhash; 37911650Ssam ftemp = fopen(temp, "r"); 38011650Ssam unlink(temp); 38111650Ssam if (ftemp == NULL) { 38211650Ssam printf("can't find list of remote files, oops\n"); 38311756Ssam return (NULL); 38411353Ssam } 38511353Ssam } 38611650Ssam if (fgets(buf, sizeof (buf), ftemp) == NULL) { 38711650Ssam fclose(ftemp), ftemp = NULL; 38811650Ssam return (NULL); 38911353Ssam } 39011650Ssam if ((cp = index(buf, '\n')) != NULL) 39111650Ssam *cp = '\0'; 39211650Ssam return (buf); 39311353Ssam } 39411353Ssam 39510294Ssam char * 39610294Ssam onoff(bool) 39710294Ssam int bool; 39810294Ssam { 39910294Ssam 40010294Ssam return (bool ? "on" : "off"); 40110294Ssam } 40210294Ssam 40310294Ssam /* 40410294Ssam * Show status. 40510294Ssam */ 40610294Ssam status(argc, argv) 40710294Ssam char *argv[]; 40810294Ssam { 40910294Ssam 41010294Ssam if (connected) 41110294Ssam printf("Connected to %s.\n", hostname); 41210294Ssam else 41310294Ssam printf("Not connected.\n"); 41410294Ssam printf("Mode: %s; Type: %s; Form: %s; Structure: %s\n", 41510294Ssam modename, typename, formname, structname); 41611353Ssam printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s\n", 41711353Ssam onoff(verbose), onoff(bell), onoff(interactive), 41811353Ssam onoff(doglob)); 41914143Ssam printf("Hash mark printing: %s; Use of PORT cmds: %s\n", 42014143Ssam onoff(hash), onoff(sendport)); 42110294Ssam } 42210294Ssam 42310294Ssam /* 42410294Ssam * Set beep on cmd completed mode. 42510294Ssam */ 42610294Ssam /*VARARGS*/ 42710294Ssam setbell() 42810294Ssam { 42910294Ssam 43010294Ssam bell = !bell; 43110294Ssam printf("Bell mode %s.\n", onoff(bell)); 43210294Ssam } 43310294Ssam 43410294Ssam /* 43510294Ssam * Turn on packet tracing. 43610294Ssam */ 43710294Ssam /*VARARGS*/ 43810294Ssam settrace() 43910294Ssam { 44010294Ssam 44110294Ssam trace = !trace; 44210294Ssam printf("Packet tracing %s.\n", onoff(trace)); 44310294Ssam } 44410294Ssam 44510294Ssam /* 44611650Ssam * Toggle hash mark printing during transfers. 44711650Ssam */ 44811650Ssam /*VARARGS*/ 44911650Ssam sethash() 45011650Ssam { 45111650Ssam 45211650Ssam hash = !hash; 45311650Ssam printf("Hash mark printing %s", onoff(hash)); 45411650Ssam if (hash) 45511650Ssam printf(" (%d bytes/hash mark)", BUFSIZ); 45611650Ssam printf(".\n"); 45711650Ssam } 45811650Ssam 45911650Ssam /* 46010294Ssam * Turn on printing of server echo's. 46110294Ssam */ 46210294Ssam /*VARARGS*/ 46310294Ssam setverbose() 46410294Ssam { 46510294Ssam 46610294Ssam verbose = !verbose; 46710294Ssam printf("Verbose mode %s.\n", onoff(verbose)); 46810294Ssam } 46910294Ssam 47010294Ssam /* 47111650Ssam * Toggle PORT cmd use before each data connection. 47211650Ssam */ 47311650Ssam /*VARARGS*/ 47411650Ssam setport() 47511650Ssam { 47611650Ssam 47711650Ssam sendport = !sendport; 47811650Ssam printf("Use of PORT cmds %s.\n", onoff(sendport)); 47911650Ssam } 48011650Ssam 48111650Ssam /* 48210294Ssam * Turn on interactive prompting 48310294Ssam * during mget, mput, and mdelete. 48410294Ssam */ 48510294Ssam /*VARARGS*/ 48610294Ssam setprompt() 48710294Ssam { 48810294Ssam 48910294Ssam interactive = !interactive; 49010294Ssam printf("Interactive mode %s.\n", onoff(interactive)); 49110294Ssam } 49210294Ssam 49310294Ssam /* 49411353Ssam * Toggle metacharacter interpretation 49511353Ssam * on local file names. 49611353Ssam */ 49711353Ssam /*VARARGS*/ 49811353Ssam setglob() 49911353Ssam { 50011353Ssam 50111353Ssam doglob = !doglob; 50211353Ssam printf("Globbing %s.\n", onoff(doglob)); 50311353Ssam } 50411353Ssam 50511353Ssam /* 50610294Ssam * Set debugging mode on/off and/or 50710294Ssam * set level of debugging. 50810294Ssam */ 50911756Ssam /*VARARGS*/ 51010294Ssam setdebug(argc, argv) 51110294Ssam char *argv[]; 51210294Ssam { 51310294Ssam int val; 51410294Ssam 51510294Ssam if (argc > 1) { 51610294Ssam val = atoi(argv[1]); 51710294Ssam if (val < 0) { 51810294Ssam printf("%s: bad debugging value.\n", argv[1]); 51910294Ssam return; 52010294Ssam } 52110294Ssam } else 52210294Ssam val = !debug; 52310294Ssam debug = val; 52410294Ssam if (debug) 52510294Ssam options |= SO_DEBUG; 52610294Ssam else 52710294Ssam options &= ~SO_DEBUG; 52810294Ssam printf("Debugging %s (debug=%d).\n", onoff(debug), debug); 52910294Ssam } 53010294Ssam 53110294Ssam /* 53210294Ssam * Set current working directory 53310294Ssam * on remote machine. 53410294Ssam */ 53510294Ssam cd(argc, argv) 53610294Ssam char *argv[]; 53710294Ssam { 53810294Ssam 53910294Ssam if (argc < 2) { 54010294Ssam strcat(line, " "); 54110294Ssam printf("(remote-directory) "); 54210294Ssam gets(&line[strlen(line)]); 54310294Ssam makeargv(); 54410294Ssam argc = margc; 54510294Ssam argv = margv; 54610294Ssam } 54710294Ssam if (argc < 2) { 54810294Ssam printf("%s remote-directory\n", argv[0]); 54910294Ssam return; 55010294Ssam } 55110294Ssam (void) command("CWD %s", argv[1]); 55210294Ssam } 55310294Ssam 55410294Ssam /* 55510294Ssam * Set current working directory 55610294Ssam * on local machine. 55710294Ssam */ 55810294Ssam lcd(argc, argv) 55910294Ssam char *argv[]; 56010294Ssam { 56111353Ssam char buf[MAXPATHLEN]; 56210294Ssam 56311353Ssam if (argc < 2) 56411353Ssam argc++, argv[1] = home; 56510294Ssam if (argc != 2) { 56610294Ssam printf("%s local-directory\n", argv[0]); 56710294Ssam return; 56810294Ssam } 56911353Ssam if (!globulize(&argv[1])) 57011353Ssam return; 57111353Ssam if (chdir(argv[1]) < 0) { 57210294Ssam perror(argv[1]); 57311353Ssam return; 57411353Ssam } 57511353Ssam printf("Local directory now %s\n", getwd(buf)); 57610294Ssam } 57710294Ssam 57810294Ssam /* 57910294Ssam * Delete a single file. 58010294Ssam */ 58110294Ssam delete(argc, argv) 58210294Ssam char *argv[]; 58310294Ssam { 58410294Ssam 58510294Ssam if (argc < 2) { 58610294Ssam strcat(line, " "); 58710294Ssam printf("(remote-file) "); 58810294Ssam gets(&line[strlen(line)]); 58910294Ssam makeargv(); 59010294Ssam argc = margc; 59110294Ssam argv = margv; 59210294Ssam } 59310294Ssam if (argc < 2) { 59410294Ssam printf("%s remote-file\n", argv[0]); 59510294Ssam return; 59610294Ssam } 59710294Ssam (void) command("DELE %s", argv[1]); 59810294Ssam } 59910294Ssam 60010294Ssam /* 60111650Ssam * Delete multiple files. 60211650Ssam */ 60311650Ssam mdelete(argc, argv) 60411650Ssam char *argv[]; 60511650Ssam { 60611650Ssam char *cp; 60711650Ssam 60811650Ssam if (argc < 2) { 60911650Ssam strcat(line, " "); 61011650Ssam printf("(remote-files) "); 61111650Ssam gets(&line[strlen(line)]); 61211650Ssam makeargv(); 61311650Ssam argc = margc; 61411650Ssam argv = margv; 61511650Ssam } 61611650Ssam if (argc < 2) { 61711650Ssam printf("%s remote-files\n", argv[0]); 61811650Ssam return; 61911650Ssam } 62011650Ssam while ((cp = remglob(argc, argv)) != NULL) 62111650Ssam if (confirm(argv[0], cp)) 62211650Ssam (void) command("DELE %s", cp); 62311650Ssam } 62411756Ssam 62511650Ssam /* 62610294Ssam * Rename a remote file. 62710294Ssam */ 62810294Ssam renamefile(argc, argv) 62910294Ssam char *argv[]; 63010294Ssam { 63110294Ssam 63210294Ssam if (argc < 2) { 63310294Ssam strcat(line, " "); 63410294Ssam printf("(from-name) "); 63510294Ssam gets(&line[strlen(line)]); 63610294Ssam makeargv(); 63710294Ssam argc = margc; 63810294Ssam argv = margv; 63910294Ssam } 64010294Ssam if (argc < 2) { 64110294Ssam usage: 64210294Ssam printf("%s from-name to-name\n", argv[0]); 64310294Ssam return; 64410294Ssam } 64510294Ssam if (argc < 3) { 64610294Ssam strcat(line, " "); 64710294Ssam printf("(to-name) "); 64810294Ssam gets(&line[strlen(line)]); 64910294Ssam makeargv(); 65010294Ssam argc = margc; 65110294Ssam argv = margv; 65210294Ssam } 65310294Ssam if (argc < 3) 65410294Ssam goto usage; 65510294Ssam if (command("RNFR %s", argv[1]) == CONTINUE) 65610294Ssam (void) command("RNTO %s", argv[2]); 65710294Ssam } 65810294Ssam 65910294Ssam /* 66010294Ssam * Get a directory listing 66110294Ssam * of remote files. 66210294Ssam */ 66310294Ssam ls(argc, argv) 66410294Ssam char *argv[]; 66510294Ssam { 66611756Ssam char *cmd; 66710294Ssam 66810294Ssam if (argc < 2) 66910294Ssam argc++, argv[1] = NULL; 67010294Ssam if (argc < 3) 67110294Ssam argc++, argv[2] = "-"; 67211756Ssam if (argc > 3) { 67311756Ssam printf("usage: %s remote-directory local-file\n", argv[0]); 67411756Ssam return; 67511756Ssam } 67610294Ssam cmd = argv[0][0] == 'l' ? "NLST" : "LIST"; 67711353Ssam if (strcmp(argv[2], "-") && !globulize(&argv[2])) 67811353Ssam return; 67911756Ssam recvrequest(cmd, argv[2], argv[1], "w"); 68010294Ssam } 68110294Ssam 68210294Ssam /* 68311756Ssam * Get a directory listing 68411756Ssam * of multiple remote files. 68511756Ssam */ 68611756Ssam mls(argc, argv) 68711756Ssam char *argv[]; 68811756Ssam { 68913212Ssam char *cmd, *mode, *cp, *dest; 69011756Ssam 69113212Ssam if (argc < 2) { 69213212Ssam strcat(line, " "); 69313212Ssam printf("(remote-files) "); 69413212Ssam gets(&line[strlen(line)]); 69513212Ssam makeargv(); 69613212Ssam argc = margc; 69713212Ssam argv = margv; 69813212Ssam } 69913212Ssam if (argc < 3) { 70013212Ssam strcat(line, " "); 70113212Ssam printf("(local-file) "); 70213212Ssam gets(&line[strlen(line)]); 70313212Ssam makeargv(); 70413212Ssam argc = margc; 70513212Ssam argv = margv; 70613212Ssam } 70713212Ssam if (argc < 3) { 70813212Ssam printf("%s remote-files local-file\n", argv[0]); 70913212Ssam return; 71013212Ssam } 71113212Ssam dest = argv[argc - 1]; 71213212Ssam argv[argc - 1] = NULL; 71313212Ssam if (strcmp(dest, "-")) 71416324Sralph if (!globulize(&dest) || !confirm("local-file", dest)) 71513212Ssam return; 71611756Ssam cmd = argv[0][1] == 'l' ? "NLST" : "LIST"; 71713212Ssam for (mode = "w"; cp = remglob(argc, argv); mode = "a") 71813212Ssam if (confirm(argv[0], cp)) 71913212Ssam recvrequest(cmd, dest, cp, mode); 72011756Ssam } 72111756Ssam 72211756Ssam /* 72310294Ssam * Do a shell escape 72410294Ssam */ 72510294Ssam shell(argc, argv) 72610294Ssam char *argv[]; 72710294Ssam { 72811756Ssam int pid, status, (*old1)(), (*old2)(); 72911756Ssam char shellnam[40], *shell, *namep; 73011756Ssam char **cpp, **gargs; 73110294Ssam 73211756Ssam old1 = signal (SIGINT, SIG_IGN); 73311756Ssam old2 = signal (SIGQUIT, SIG_IGN); 73411756Ssam if ((pid = fork()) == 0) { 73511756Ssam for (pid = 3; pid < 20; pid++) 73611756Ssam close(pid); 73711756Ssam signal(SIGINT, SIG_DFL); 73811756Ssam signal(SIGQUIT, SIG_DFL); 73911756Ssam if (argc <= 1) { 74011756Ssam shell = getenv("SHELL"); 74111756Ssam if (shell == NULL) 74211756Ssam shell = "/bin/sh"; 74311756Ssam namep = rindex(shell,'/'); 74411756Ssam if (namep == NULL) 74511756Ssam namep = shell; 74611756Ssam strcpy(shellnam,"-"); 74711756Ssam strcat(shellnam, ++namep); 74811756Ssam if (strcmp(namep, "sh") != 0) 74911756Ssam shellnam[0] = '+'; 75011756Ssam if (debug) { 75111756Ssam printf ("%s\n", shell); 75211756Ssam fflush (stdout); 75311756Ssam } 75411756Ssam execl(shell, shellnam, 0); 75511756Ssam perror(shell); 75611756Ssam exit(1); 75711756Ssam } 75811756Ssam cpp = &argv[1]; 75911756Ssam if (argc > 2) { 76011756Ssam if ((gargs = glob(cpp)) != NULL) 76111756Ssam cpp = gargs; 76211756Ssam if (globerr != NULL) { 76311756Ssam printf("%s\n", globerr); 76411756Ssam exit(1); 76511756Ssam } 76611756Ssam } 76711756Ssam if (debug) { 76811756Ssam register char **zip = cpp; 76911756Ssam 77011756Ssam printf("%s", *zip); 77111756Ssam while (*++zip != NULL) 77211756Ssam printf(" %s", *zip); 77311756Ssam printf("\n"); 77411756Ssam fflush(stdout); 77511756Ssam } 77611756Ssam execvp(argv[1], cpp); 77711756Ssam perror(argv[1]); 77811756Ssam exit(1); 77911756Ssam } 78011756Ssam if (pid > 0) 78111756Ssam while (wait(&status) != pid) 78211756Ssam ; 78311756Ssam signal(SIGINT, old1); 78411756Ssam signal(SIGQUIT, old2); 78511756Ssam if (pid == -1) 78611756Ssam perror("Try again later"); 78711756Ssam return (0); 78810294Ssam } 78910294Ssam 79010294Ssam /* 79110294Ssam * Send new user information (re-login) 79210294Ssam */ 79310294Ssam user(argc, argv) 79410294Ssam int argc; 79510294Ssam char **argv; 79610294Ssam { 79710294Ssam char acct[80], *getpass(); 79810294Ssam int n; 79910294Ssam 80010294Ssam if (argc < 2) { 80110294Ssam strcat(line, " "); 80210294Ssam printf("(username) "); 80310294Ssam gets(&line[strlen(line)]); 80410294Ssam makeargv(); 80510294Ssam argc = margc; 80610294Ssam argv = margv; 80710294Ssam } 80810294Ssam if (argc > 4) { 80910294Ssam printf("usage: %s username [password] [account]\n", argv[0]); 81011756Ssam return (0); 81110294Ssam } 81210294Ssam n = command("USER %s", argv[1]); 81310294Ssam if (n == CONTINUE) { 81410294Ssam if (argc < 3 ) 81510294Ssam argv[2] = getpass("Password: "), argc++; 81610294Ssam n = command("PASS %s", argv[2]); 81710294Ssam } 81810294Ssam if (n == CONTINUE) { 81910294Ssam if (argc < 4) { 82010294Ssam printf("Account: "); (void) fflush(stdout); 82110294Ssam (void) fgets(acct, sizeof(acct) - 1, stdin); 82210294Ssam acct[strlen(acct) - 1] = '\0'; 82310294Ssam argv[3] = acct; argc++; 82410294Ssam } 82510294Ssam n = command("ACCT %s", acct); 82610294Ssam } 82710294Ssam if (n != COMPLETE) { 82810294Ssam fprintf(stderr, "Login failed.\n"); 82910294Ssam return (0); 83010294Ssam } 83110294Ssam return (1); 83210294Ssam } 83310294Ssam 83410294Ssam /* 83510294Ssam * Print working directory. 83610294Ssam */ 83710294Ssam /*VARARGS*/ 83810294Ssam pwd() 83910294Ssam { 84011756Ssam 84110294Ssam (void) command("XPWD"); 84210294Ssam } 84310294Ssam 84410294Ssam /* 84510294Ssam * Make a directory. 84610294Ssam */ 84710294Ssam makedir(argc, argv) 84810294Ssam char *argv[]; 84910294Ssam { 85010294Ssam 85110294Ssam if (argc < 2) { 85210294Ssam strcat(line, " "); 85310294Ssam printf("(directory-name) "); 85410294Ssam gets(&line[strlen(line)]); 85510294Ssam makeargv(); 85610294Ssam argc = margc; 85710294Ssam argv = margv; 85810294Ssam } 85910294Ssam if (argc < 2) { 86010294Ssam printf("%s directory-name\n", argv[0]); 86110294Ssam return; 86210294Ssam } 86310294Ssam (void) command("XMKD %s", argv[1]); 86410294Ssam } 86510294Ssam 86610294Ssam /* 86710294Ssam * Remove a directory. 86810294Ssam */ 86910294Ssam removedir(argc, argv) 87010294Ssam char *argv[]; 87110294Ssam { 87210294Ssam 87310294Ssam if (argc < 2) { 87410294Ssam strcat(line, " "); 87510294Ssam printf("(directory-name) "); 87610294Ssam gets(&line[strlen(line)]); 87710294Ssam makeargv(); 87810294Ssam argc = margc; 87910294Ssam argv = margv; 88010294Ssam } 88110294Ssam if (argc < 2) { 88210294Ssam printf("%s directory-name\n", argv[0]); 88310294Ssam return; 88410294Ssam } 88510294Ssam (void) command("XRMD %s", argv[1]); 88610294Ssam } 88710294Ssam 88810294Ssam /* 88910294Ssam * Send a line, verbatim, to the remote machine. 89010294Ssam */ 89110294Ssam quote(argc, argv) 89210294Ssam char *argv[]; 89310294Ssam { 89410294Ssam int i; 89510294Ssam char buf[BUFSIZ]; 89610294Ssam 89710294Ssam if (argc < 2) { 89810294Ssam strcat(line, " "); 89910294Ssam printf("(command line to send) "); 90010294Ssam gets(&line[strlen(line)]); 90110294Ssam makeargv(); 90210294Ssam argc = margc; 90310294Ssam argv = margv; 90410294Ssam } 90510294Ssam if (argc < 2) { 90610294Ssam printf("usage: %s line-to-send\n", argv[0]); 90710294Ssam return; 90810294Ssam } 90910294Ssam strcpy(buf, argv[1]); 91010294Ssam for (i = 2; i < argc; i++) { 91110294Ssam strcat(buf, " "); 91210294Ssam strcat(buf, argv[i]); 91310294Ssam } 91410294Ssam (void) command(buf); 91510294Ssam } 91610294Ssam 91710294Ssam /* 91810294Ssam * Ask the other side for help. 91910294Ssam */ 92010294Ssam rmthelp(argc, argv) 92110294Ssam char *argv[]; 92210294Ssam { 92310294Ssam int oldverbose = verbose; 92410294Ssam 92510294Ssam verbose = 1; 92610294Ssam (void) command(argc == 1 ? "HELP" : "HELP %s", argv[1]); 92710294Ssam verbose = oldverbose; 92810294Ssam } 92910294Ssam 93010294Ssam /* 93110294Ssam * Terminate session and exit. 93210294Ssam */ 93310294Ssam /*VARARGS*/ 93410294Ssam quit() 93510294Ssam { 93610294Ssam 93718286Sralph if (connected) 93818286Sralph disconnect(); 93910294Ssam exit(0); 94010294Ssam } 94110294Ssam 94210294Ssam /* 94310294Ssam * Terminate session, but don't exit. 94410294Ssam */ 94510294Ssam disconnect() 94610294Ssam { 94710294Ssam extern FILE *cout; 94810294Ssam extern int data; 94910294Ssam 95010294Ssam if (!connected) 95110294Ssam return; 95210294Ssam (void) command("QUIT"); 95310294Ssam (void) fclose(cout); 95410294Ssam cout = NULL; 95510294Ssam connected = 0; 95610294Ssam data = -1; 95710294Ssam } 95811353Ssam 95911650Ssam confirm(cmd, file) 96011353Ssam char *cmd, *file; 96111353Ssam { 96211353Ssam char line[BUFSIZ]; 96311353Ssam 96411353Ssam if (!interactive) 96511650Ssam return (1); 96611353Ssam printf("%s %s? ", cmd, file); 96711353Ssam fflush(stdout); 96811353Ssam gets(line); 96911650Ssam return (*line != 'n' && *line != 'N'); 97011353Ssam } 97111353Ssam 97211353Ssam fatal(msg) 97311353Ssam char *msg; 97411353Ssam { 97511353Ssam 97611353Ssam fprintf(stderr, "ftp: %s\n"); 97711353Ssam exit(1); 97811353Ssam } 97911353Ssam 98011353Ssam /* 98111353Ssam * Glob a local file name specification with 98211353Ssam * the expectation of a single return value. 98311353Ssam * Can't control multiple values being expanded 98411353Ssam * from the expression, we return only the first. 98511353Ssam */ 98611353Ssam globulize(cpp) 98711353Ssam char **cpp; 98811353Ssam { 98911353Ssam char **globbed; 99011353Ssam 99111353Ssam if (!doglob) 99211353Ssam return (1); 99311353Ssam globbed = glob(*cpp); 99411353Ssam if (globerr != NULL) { 99511353Ssam printf("%s: %s\n", *cpp, globerr); 99611353Ssam if (globbed) 99711353Ssam blkfree(globbed); 99811353Ssam return (0); 99911353Ssam } 100011353Ssam if (globbed) { 100111353Ssam *cpp = *globbed++; 100211353Ssam /* don't waste too much memory */ 100311353Ssam if (*globbed) 100411353Ssam blkfree(globbed); 100511353Ssam } 100611353Ssam return (1); 100711353Ssam } 1008