2 * Copyright (c) 1985, 1989, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * FTP User Program -- Command Routines.
39 RCSID("$Id: cmds.c 15673 2005-07-19 18:19:33Z lha $");
41 typedef void (*sighand)(int);
48 * `Another' gets another argument, and stores the new argc and argv.
49 * It reverts to the top level (via main.c's intr()) on EOF/error.
51 * Returns false if no new arguments have been added.
54 another(int *pargc, char ***pargv, char *prompt)
56 int len = strlen(line), ret;
58 if (len >= sizeof(line) - 3) {
59 printf("sorry, arguments too long\n");
62 printf("(%s) ", prompt);
64 if (fgets(&line[len], sizeof(line) - len, stdin) == NULL)
66 len += strlen(&line[len]);
67 if (len > 0 && line[len - 1] == '\n')
77 * Connect to peer server and
78 * auto-login, if possible.
81 setpeer(int argc, char **argv)
88 printf("Already connected to %s, use close first.\n",
94 another(&argc, &argv, "to");
95 if (argc < 2 || argc > 3) {
96 printf("usage: %s host-name [port]\n", argv[0]);
100 sp = getservbyname("ftp", "tcp");
102 errx(1, "You bastard. You removed ftp/tcp from services");
105 sp = getservbyname(argv[2], "tcp");
111 port = strtol(argv[2], &ep, 0);
113 printf("%s: bad port number-- %s\n",
115 printf ("usage: %s host-name [port]\n",
123 host = hookup(argv[1], port);
129 * Set up defaults for FTP.
131 strlcpy(typename, "ascii", sizeof(typename));
134 strlcpy(formname, "non-print", sizeof(formname));
136 strlcpy(modename, "stream", sizeof(modename));
138 strlcpy(structname, "file", sizeof(structname));
140 strlcpy(bytename, "8", sizeof(bytename));
145 #if (defined(unix) || defined(__unix__) || defined(__unix) || defined(_AIX) || defined(_CRAY) || defined(__NetBSD__) || defined(__APPLE__)) && NBBY == 8
147 * this ifdef is to keep someone form "porting" this to an incompatible
148 * system and not checking this out. This way they have to think about it.
153 if (command("SYST") == COMPLETE && overbose && strlen(reply_string) > 4) {
156 cp = strdup(reply_string + 4);
158 errx(1, "strdup: out of memory");
161 p = strchr(cp, '\r');
168 printf("Remote system type is %s.\n", cp);
171 if (!strncmp(reply_string, "215 UNIX Type: L8", 17)) {
177 * Set type to 0 (not specified by user),
178 * meaning binary by default, but don't bother
179 * telling server. We can use binary
180 * for text files unless changed by the user.
183 strlcpy(typename, "binary", sizeof(typename));
185 printf("Using %s mode to transfer files.\n",
193 !strncmp(reply_string, "215 TOPS20", 10))
195 "Remember to set tenex mode when transfering binary files from this machine.\n");
208 { "ascii", "A", TYPE_A, 0 },
209 { "binary", "I", TYPE_I, 0 },
210 { "image", "I", TYPE_I, 0 },
211 { "ebcdic", "E", TYPE_E, 0 },
212 { "tenex", "L", TYPE_L, bytename },
220 settype(int argc, char **argv)
228 printf("usage: %s [", argv[0]);
230 for (p = types; p->t_name; p++) {
231 printf("%s%s", sep, p->t_name);
239 printf("Using %s mode to transfer files.\n", typename);
243 for (p = types; p->t_name; p++)
244 if (strcmp(argv[1], p->t_name) == 0)
246 if (p->t_name == 0) {
247 printf("%s: unknown mode\n", argv[1]);
251 if ((p->t_arg != NULL) && (*(p->t_arg) != '\0'))
252 comret = command ("TYPE %s %s", p->t_mode, p->t_arg);
254 comret = command("TYPE %s", p->t_mode);
255 if (comret == COMPLETE) {
256 strlcpy(typename, p->t_name, sizeof(typename));
257 curtype = type = p->t_type;
262 * Internal form of settype; changes current type in use with server
263 * without changing our notion of the type for data transfers.
264 * Used to change to and from ascii for listings.
267 changetype(int newtype, int show)
270 int comret, oldverbose = verbose;
274 if (newtype == curtype)
276 if (debug == 0 && show == 0)
278 for (p = types; p->t_name; p++)
279 if (newtype == p->t_type)
281 if (p->t_name == 0) {
282 printf("ftp: internal error: unknown type %d\n", newtype);
285 if (newtype == TYPE_L && bytename[0] != '\0')
286 comret = command("TYPE %s %s", p->t_mode, bytename);
288 comret = command("TYPE %s", p->t_mode);
289 if (comret == COMPLETE)
291 verbose = oldverbose;
301 * Set binary transfer type.
305 setbinary(int argc, char **argv)
313 * Set ascii transfer type.
317 setascii(int argc, char **argv)
325 * Set tenex transfer type.
329 settenex(int argc, char **argv)
337 * Set file transfer mode.
341 setftmode(int argc, char **argv)
344 printf("We only support %s mode, sorry.\n", modename);
349 * Set file transfer format.
353 setform(int argc, char **argv)
356 printf("We only support %s format, sorry.\n", formname);
361 * Set file transfer structure.
365 setstruct(int argc, char **argv)
368 printf("We only support %s structure, sorry.\n", structname);
373 * Send a single file.
376 put(int argc, char **argv)
380 char *oldargv1, *oldargv2;
387 if (argc < 2 && !another(&argc, &argv, "local-file"))
389 if (argc < 3 && !another(&argc, &argv, "remote-file")) {
391 printf("usage: %s local-file remote-file\n", argv[0]);
397 if (!globulize(&argv[1])) {
402 * If "globulize" modifies argv[1], and argv[2] is a copy of
403 * the old argv[1], make it a copy of the new argv[1].
405 if (argv[1] != oldargv1 && argv[2] == oldargv1) {
408 cmd = (argv[0][0] == 'a') ? "APPE" : ((sunique) ? "STOU" : "STOR");
410 argv[2] = dotrans(argv[2]);
412 if (loc && mapflag) {
413 argv[2] = domap(argv[2]);
415 sendrequest(cmd, argv[1], argv[2],
416 curtype == TYPE_I ? "rb" : "r",
417 argv[1] != oldargv1 || argv[2] != oldargv2);
428 if (mflag && fromatty) {
429 ointer = interactive;
431 if (confirm("Continue with", mname)) {
432 interactive = ointer;
435 interactive = ointer;
442 * Send multiple files.
445 mput(int argc, char **argv)
448 RETSIGTYPE (*oldintr)(int);
452 if (argc < 2 && !another(&argc, &argv, "local-files")) {
453 printf("usage: %s local-files\n", argv[0]);
459 oldintr = signal(SIGINT, mabort);
462 char *cp, *tp2, tmpbuf[MaxPathLen];
464 while ((cp = remglob(argv,0)) != NULL) {
469 if (mflag && confirm(argv[0], cp)) {
472 while (*tp && !islower((unsigned char)*tp)) {
478 while ((*tp2 = *tp) != '\0') {
479 if (isupper((unsigned char)*tp2)) {
480 *tp2 = 'a' + *tp2 - 'A';
494 sendrequest((sunique) ? "STOU" : "STOR",
496 curtype == TYPE_I ? "rb" : "r",
497 cp != tp || !interactive);
498 if (!mflag && fromatty) {
499 ointer = interactive;
501 if (confirm("Continue with","mput")) {
504 interactive = ointer;
508 signal(SIGINT, oldintr);
512 for (i = 1; i < argc; i++) {
518 if (mflag && confirm(argv[0], argv[i])) {
519 tp = (ntflag) ? dotrans(argv[i]) : argv[i];
520 tp = (mapflag) ? domap(tp) : tp;
521 sendrequest((sunique) ? "STOU" : "STOR",
523 curtype == TYPE_I ? "rb" : "r",
524 tp, tp != argv[i] || !interactive);
525 if (!mflag && fromatty) {
526 ointer = interactive;
528 if (confirm("Continue with","mput")) {
531 interactive = ointer;
537 memset(&gl, 0, sizeof(gl));
538 flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE;
539 if (glob(argv[i], flags, NULL, &gl) || gl.gl_pathc == 0) {
540 warnx("%s: not found", argv[i]);
544 for (cpp = gl.gl_pathv; cpp && *cpp != NULL; cpp++) {
545 if (mflag && confirm(argv[0], *cpp)) {
546 tp = (ntflag) ? dotrans(*cpp) : *cpp;
547 tp = (mapflag) ? domap(tp) : tp;
548 sendrequest((sunique) ? "STOU" : "STOR",
550 curtype == TYPE_I ? "rb" : "r",
551 *cpp != tp || !interactive);
552 if (!mflag && fromatty) {
553 ointer = interactive;
555 if (confirm("Continue with","mput")) {
558 interactive = ointer;
564 signal(SIGINT, oldintr);
569 reget(int argc, char **argv)
571 getit(argc, argv, 1, curtype == TYPE_I ? "r+wb" : "r+w");
575 get(int argc, char **argv)
580 if (curtype == TYPE_I)
585 if (curtype == TYPE_I)
591 getit(argc, argv, 0, filemode);
598 getit(int argc, char **argv, int restartit, char *filemode)
602 char *oldargv1, *oldargv2;
610 if ((argc < 2 && !another(&argc, &argv, "remote-file")) ||
611 (argc < 3 && !another(&argc, &argv, "local-file"))) {
612 printf("usage: %s remote-file [ local-file ]\n", argv[0]);
618 if (!globulize(&argv[2])) {
623 char *tp = argv[1], *tp2, tmpbuf[MaxPathLen];
625 while (*tp && !islower((unsigned char)*tp)) {
631 while ((*tp2 = *tp) != '\0') {
632 if (isupper((unsigned char)*tp2)) {
633 *tp2 = 'a' + *tp2 - 'A';
642 argv[2] = dotrans(argv[2]);
644 argv[2] = domap(argv[2]);
649 ret = stat(argv[2], &stbuf);
650 if (restartit == 1) {
652 warn("local: %s", argv[2]);
655 restart_point = stbuf.st_size;
656 } else if (ret == 0) {
659 int yy, mo, day, hour, min, sec;
661 time_t mtime = stbuf.st_mtime;
666 cmdret = command("MDTM %s", argv[1]);
668 if (cmdret != COMPLETE) {
669 printf("%s\n", reply_string);
672 if (sscanf(reply_string,
673 "%*s %04d%02d%02d%02d%02d%02d",
674 &yy, &mo, &day, &hour, &min, &sec)
676 printf ("bad MDTM result\n");
684 if ((tm->tm_year > yy) ||
685 (tm->tm_year == yy &&
688 tm->tm_mday > day) ||
689 (tm->tm_mday == day &&
690 tm->tm_hour > hour) ||
691 (tm->tm_hour == hour &&
693 (tm->tm_min == min &&
699 recvrequest("RETR", argv[2], argv[1], filemode,
700 argv[1] != oldargv1 || argv[2] != oldargv2, local_given);
706 suspicious_filename(const char *fn)
708 return strstr(fn, "../") != NULL || *fn == '/';
712 * Get multiple files.
715 mget(int argc, char **argv)
719 char *cp, *tp, *tp2, tmpbuf[MaxPathLen];
721 if (argc < 2 && !another(&argc, &argv, "remote-files")) {
722 printf("usage: %s remote-files\n", argv[0]);
728 oldintr = signal(SIGINT, mabort);
730 while ((cp = remglob(argv,proxy)) != NULL) {
735 if (mflag && suspicious_filename(cp))
736 printf("*** Suspicious filename: %s\n", cp);
737 if (mflag && confirm(argv[0], cp)) {
740 for (tp2 = tmpbuf;(ch = (unsigned char)*tp++);)
741 *tp2++ = tolower(ch);
751 recvrequest("RETR", tp, cp,
752 curtype == TYPE_I ? "wb" : "w",
753 tp != cp || !interactive, 0);
754 if (!mflag && fromatty) {
755 ointer = interactive;
757 if (confirm("Continue with","mget")) {
760 interactive = ointer;
764 signal(SIGINT,oldintr);
769 remglob(char **argv, int doswitch)
772 static char buf[MaxPathLen];
773 static FILE *ftemp = NULL;
775 int oldverbose, oldhash;
793 if ((cp = *++args) == NULL)
799 strlcpy(temp, _PATH_TMP_XXX, sizeof(temp));
802 warn("unable to create temporary file %s", temp);
806 oldverbose = verbose, verbose = 0;
807 oldhash = hash, hash = 0;
811 for (filemode = "w"; *++argv != NULL; filemode = "a")
812 recvrequest ("NLST", temp, *argv, filemode, 0, 0);
816 verbose = oldverbose; hash = oldhash;
817 ftemp = fopen(temp, "r");
820 printf("can't find list of remote files, oops\n");
824 while(fgets(buf, sizeof (buf), ftemp)) {
825 if ((cp = strchr(buf, '\n')) != NULL)
827 if(!interactive && suspicious_filename(buf)){
828 printf("Ignoring remote globbed file `%s'\n", buf);
842 return (bool ? "on" : "off");
850 status(int argc, char **argv)
855 printf("Connected to %s.\n", hostname);
857 printf("Not connected.\n");
861 printf("Connected for proxy commands to %s.\n", hostname);
864 printf("No proxy connection.\n");
869 printf("Mode: %s; Type: %s; Form: %s; Structure: %s\n",
870 modename, typename, formname, structname);
871 printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s\n",
872 onoff(verbose), onoff(bell), onoff(interactive),
874 printf("Store unique: %s; Receive unique: %s\n", onoff(sunique),
876 printf("Case: %s; CR stripping: %s\n",onoff(mcase),onoff(crflag));
878 printf("Ntrans: (in) %s (out) %s\n", ntin,ntout);
881 printf("Ntrans: off\n");
884 printf("Nmap: (in) %s (out) %s\n", mapin, mapout);
887 printf("Nmap: off\n");
889 printf("Hash mark printing: %s; Use of PORT cmds: %s\n",
890 onoff(hash), onoff(sendport));
893 for (i=0; i<macnum; i++) {
894 printf("\t%s\n",macros[i].mac_name);
901 * Set beep on cmd completed mode.
905 setbell(int argc, char **argv)
909 printf("Bell mode %s.\n", onoff(bell));
914 * Turn on packet tracing.
918 settrace(int argc, char **argv)
922 printf("Packet tracing %s.\n", onoff(trace));
927 * Toggle hash mark printing during transfers.
931 sethash(int argc, char **argv)
935 printf("Hash mark printing %s", onoff(hash));
938 printf(" (%d bytes/hash mark)", 1024);
943 * Turn on printing of server echo's.
947 setverbose(int argc, char **argv)
951 printf("Verbose mode %s.\n", onoff(verbose));
956 * Toggle PORT cmd use before each data connection.
960 setport(int argc, char **argv)
963 sendport = !sendport;
964 printf("Use of PORT cmds %s.\n", onoff(sendport));
969 * Turn on interactive prompting
970 * during mget, mput, and mdelete.
974 setprompt(int argc, char **argv)
977 interactive = !interactive;
978 printf("Interactive mode %s.\n", onoff(interactive));
983 * Toggle metacharacter interpretation
984 * on local file names.
988 setglob(int argc, char **argv)
992 printf("Globbing %s.\n", onoff(doglob));
997 * Set debugging mode on/off and/or
998 * set level of debugging.
1002 setdebug(int argc, char **argv)
1007 val = atoi(argv[1]);
1009 printf("%s: bad debugging value.\n", argv[1]);
1017 options |= SO_DEBUG;
1019 options &= ~SO_DEBUG;
1020 printf("Debugging %s (debug=%d).\n", onoff(debug), debug);
1025 * Set current working directory
1026 * on remote machine.
1029 cd(int argc, char **argv)
1032 if (argc < 2 && !another(&argc, &argv, "remote-directory")) {
1033 printf("usage: %s remote-directory\n", argv[0]);
1037 if (command("CWD %s", argv[1]) == ERROR && code == 500) {
1039 printf("CWD command not recognized, trying XCWD\n");
1040 command("XCWD %s", argv[1]);
1045 * Set current working directory
1049 lcd(int argc, char **argv)
1051 char buf[MaxPathLen];
1054 argc++, argv[1] = home;
1056 printf("usage: %s local-directory\n", argv[0]);
1060 if (!globulize(&argv[1])) {
1064 if (chdir(argv[1]) < 0) {
1065 warn("local: %s", argv[1]);
1069 if (getcwd(buf, sizeof(buf)) != NULL)
1070 printf("Local directory now %s\n", buf);
1072 warnx("getwd: %s", buf);
1077 * Delete a single file.
1080 delete(int argc, char **argv)
1083 if (argc < 2 && !another(&argc, &argv, "remote-file")) {
1084 printf("usage: %s remote-file\n", argv[0]);
1088 command("DELE %s", argv[1]);
1092 * Delete multiple files.
1095 mdelete(int argc, char **argv)
1101 if (argc < 2 && !another(&argc, &argv, "remote-files")) {
1102 printf("usage: %s remote-files\n", argv[0]);
1108 oldintr = signal(SIGINT, mabort);
1110 while ((cp = remglob(argv,0)) != NULL) {
1115 if (mflag && confirm(argv[0], cp)) {
1116 command("DELE %s", cp);
1117 if (!mflag && fromatty) {
1118 ointer = interactive;
1120 if (confirm("Continue with", "mdelete")) {
1123 interactive = ointer;
1127 signal(SIGINT, oldintr);
1132 * Rename a remote file.
1135 renamefile(int argc, char **argv)
1138 if (argc < 2 && !another(&argc, &argv, "from-name"))
1140 if (argc < 3 && !another(&argc, &argv, "to-name")) {
1142 printf("%s from-name to-name\n", argv[0]);
1146 if (command("RNFR %s", argv[1]) == CONTINUE)
1147 command("RNTO %s", argv[2]);
1151 * Get a directory listing
1155 ls(int argc, char **argv)
1160 argc++, argv[1] = NULL;
1162 argc++, argv[2] = "-";
1164 printf("usage: %s remote-directory local-file\n", argv[0]);
1168 cmd = argv[0][0] == 'n' ? "NLST" : "LIST";
1169 if (strcmp(argv[2], "-") && !globulize(&argv[2])) {
1173 if (strcmp(argv[2], "-") && *argv[2] != '|')
1174 if (!globulize(&argv[2]) || !confirm("output to local-file:",
1179 recvrequest(cmd, argv[2], argv[1], "w", 0, 1);
1183 * Get a directory listing
1184 * of multiple remote files.
1187 mls(int argc, char **argv)
1191 char *cmd, filemode[2], *dest;
1193 if (argc < 2 && !another(&argc, &argv, "remote-files"))
1195 if (argc < 3 && !another(&argc, &argv, "local-file")) {
1197 printf("usage: %s remote-files local-file\n", argv[0]);
1201 dest = argv[argc - 1];
1202 argv[argc - 1] = NULL;
1203 if (strcmp(dest, "-") && *dest != '|')
1204 if (!globulize(&dest) ||
1205 !confirm("output to local-file:", dest)) {
1209 cmd = argv[0][1] == 'l' ? "NLST" : "LIST";
1212 oldintr = signal(SIGINT, mabort);
1215 for (i = 1; mflag && i < argc-1; ++i) {
1216 *filemode = (i == 1) ? 'w' : 'a';
1217 recvrequest(cmd, dest, argv[i], filemode, 0, 1);
1218 if (!mflag && fromatty) {
1219 ointer = interactive;
1221 if (confirm("Continue with", argv[0])) {
1224 interactive = ointer;
1227 signal(SIGINT, oldintr);
1236 shell(int argc, char **argv)
1239 RETSIGTYPE (*old1)(int), (*old2)(int);
1240 char shellnam[40], *shellpath, *namep;
1243 old1 = signal (SIGINT, SIG_IGN);
1244 old2 = signal (SIGQUIT, SIG_IGN);
1245 if ((pid = fork()) == 0) {
1246 for (pid = 3; pid < 20; pid++)
1248 signal(SIGINT, SIG_DFL);
1249 signal(SIGQUIT, SIG_DFL);
1250 shellpath = getenv("SHELL");
1251 if (shellpath == NULL)
1252 shellpath = _PATH_BSHELL;
1253 namep = strrchr(shellpath, '/');
1256 snprintf (shellnam, sizeof(shellnam),
1258 if (strcmp(namep, "sh") != 0)
1261 printf ("%s\n", shellpath);
1265 execl(shellpath,shellnam,"-c",altarg,(char *)0);
1268 execl(shellpath,shellnam,(char *)0);
1270 warn("%s", shellpath);
1275 while (waitpid(-1, &waitstatus, 0) != pid)
1277 signal(SIGINT, old1);
1278 signal(SIGQUIT, old2);
1280 warn("%s", "Try again later");
1289 * Send new user information (re-login)
1292 user(int argc, char **argv)
1299 another(&argc, &argv, "username");
1300 if (argc < 2 || argc > 4) {
1301 printf("usage: %s username [password] [account]\n", argv[0]);
1305 n = command("USER %s", argv[1]);
1306 if (n == CONTINUE) {
1308 UI_UTIL_read_pw_string (tmp,
1314 n = command("PASS %s", argv[2]);
1316 if (n == CONTINUE) {
1318 printf("Account: "); fflush(stdout);
1319 fgets(acctstr, sizeof(acctstr) - 1, stdin);
1320 acctstr[strcspn(acctstr, "\r\n")] = '\0';
1321 argv[3] = acctstr; argc++;
1323 n = command("ACCT %s", argv[3]);
1326 if (n != COMPLETE) {
1327 fprintf(stdout, "Login failed.\n");
1330 if (!aflag && argc == 4) {
1331 command("ACCT %s", argv[3]);
1336 * Print working directory.
1340 pwd(int argc, char **argv)
1342 int oldverbose = verbose;
1345 * If we aren't verbose, this doesn't do anything!
1348 if (command("PWD") == ERROR && code == 500) {
1349 printf("PWD command not recognized, trying XPWD\n");
1352 verbose = oldverbose;
1359 makedir(int argc, char **argv)
1362 if (argc < 2 && !another(&argc, &argv, "directory-name")) {
1363 printf("usage: %s directory-name\n", argv[0]);
1367 if (command("MKD %s", argv[1]) == ERROR && code == 500) {
1369 printf("MKD command not recognized, trying XMKD\n");
1370 command("XMKD %s", argv[1]);
1375 * Remove a directory.
1378 removedir(int argc, char **argv)
1381 if (argc < 2 && !another(&argc, &argv, "directory-name")) {
1382 printf("usage: %s directory-name\n", argv[0]);
1386 if (command("RMD %s", argv[1]) == ERROR && code == 500) {
1388 printf("RMD command not recognized, trying XRMD\n");
1389 command("XRMD %s", argv[1]);
1394 * Send a line, verbatim, to the remote machine.
1397 quote(int argc, char **argv)
1400 if (argc < 2 && !another(&argc, &argv, "command line to send")) {
1401 printf("usage: %s line-to-send\n", argv[0]);
1405 quote1("", argc, argv);
1409 * Send a SITE command to the remote machine. The line
1410 * is sent verbatim to the remote machine, except that the
1411 * word "SITE" is added at the front.
1414 site(int argc, char **argv)
1417 if (argc < 2 && !another(&argc, &argv, "arguments to SITE command")) {
1418 printf("usage: %s line-to-send\n", argv[0]);
1422 quote1("SITE ", argc, argv);
1426 * Turn argv[1..argc) into a space-separated string, then prepend initial text.
1427 * Send the result as a one-line command and get response.
1430 quote1(char *initial, int argc, char **argv)
1433 char buf[BUFSIZ]; /* must be >= sizeof(line) */
1435 strlcpy(buf, initial, sizeof(buf));
1436 for(i = 1; i < argc; i++) {
1438 strlcat(buf, " ", sizeof(buf));
1439 strlcat(buf, argv[i], sizeof(buf));
1441 if (command("%s", buf) == PRELIM) {
1442 while (getreply(0) == PRELIM)
1448 do_chmod(int argc, char **argv)
1451 if (argc < 2 && !another(&argc, &argv, "mode"))
1453 if (argc < 3 && !another(&argc, &argv, "file-name")) {
1455 printf("usage: %s mode file-name\n", argv[0]);
1459 command("SITE CHMOD %s %s", argv[1], argv[2]);
1463 do_umask(int argc, char **argv)
1465 int oldverbose = verbose;
1468 command(argc == 1 ? "SITE UMASK" : "SITE UMASK %s", argv[1]);
1469 verbose = oldverbose;
1473 ftp_idle(int argc, char **argv)
1475 int oldverbose = verbose;
1478 command(argc == 1 ? "SITE IDLE" : "SITE IDLE %s", argv[1]);
1479 verbose = oldverbose;
1483 * Ask the other side for help.
1486 rmthelp(int argc, char **argv)
1488 int oldverbose = verbose;
1491 command(argc == 1 ? "HELP" : "HELP %s", argv[1]);
1492 verbose = oldverbose;
1496 * Terminate session and exit.
1500 quit(int argc, char **argv)
1513 * Terminate session, but don't exit.
1516 disconnect(int argc, char **argv)
1535 confirm(char *cmd, char *file)
1541 printf("%s %s? ", cmd, file);
1543 if (fgets(buf, sizeof buf, stdin) == NULL)
1545 return (*buf == 'y' || *buf == 'Y');
1556 * Glob a local file name specification with
1557 * the expectation of a single return value.
1558 * Can't control multiple values being expanded
1559 * from the expression, we return only the first.
1562 globulize(char **cpp)
1570 flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE;
1571 memset(&gl, 0, sizeof(gl));
1572 if (glob(*cpp, flags, NULL, &gl) ||
1574 warnx("%s: not found", *cpp);
1578 *cpp = strdup(gl.gl_pathv[0]); /* XXX - wasted memory */
1584 account(int argc, char **argv)
1591 strlcpy (acctstr, *argv, sizeof(acctstr));
1595 strlcat(acctstr, *argv, sizeof(acctstr));
1599 UI_UTIL_read_pw_string(acctstr, sizeof(acctstr), "Account:", 0);
1601 command("ACCT %s", acctstr);
1620 longjmp(abortprox,1);
1624 doproxy(int argc, char **argv)
1627 RETSIGTYPE (*oldintr)(int);
1629 if (argc < 2 && !another(&argc, &argv, "command")) {
1630 printf("usage: %s command\n", argv[0]);
1634 c = getcmd(argv[1]);
1635 if (c == (struct cmd *) -1) {
1636 printf("?Ambiguous command\n");
1642 printf("?Invalid command\n");
1648 printf("?Invalid proxy command\n");
1653 if (setjmp(abortprox)) {
1657 oldintr = signal(SIGINT, proxabort);
1659 if (c->c_conn && !connected) {
1660 printf("Not connected\n");
1663 signal(SIGINT, oldintr);
1667 (*c->c_handler)(argc-1, argv+1);
1675 signal(SIGINT, oldintr);
1679 setcase(int argc, char **argv)
1683 printf("Case mapping %s.\n", onoff(mcase));
1688 setcr(int argc, char **argv)
1692 printf("Carriage Return stripping %s.\n", onoff(crflag));
1697 setntrans(int argc, char **argv)
1701 printf("Ntrans off.\n");
1707 strlcpy (ntin, argv[1], 17);
1712 strlcpy (ntout, argv[2], 17);
1718 static char new[MaxPathLen];
1719 char *cp1, *cp2 = new;
1720 int i, ostop, found;
1722 for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++)
1724 for (cp1 = name; *cp1; cp1++) {
1726 for (i = 0; *(ntin + i) && i < 16; i++) {
1727 if (*cp1 == *(ntin + i)) {
1730 *cp2++ = *(ntout + i);
1744 setnmap(int argc, char **argv)
1750 printf("Nmap off.\n");
1754 if (argc < 3 && !another(&argc, &argv, "mapout")) {
1755 printf("Usage: %s [mapin mapout]\n",argv[0]);
1761 cp = strchr(altarg, ' ');
1766 cp = strchr(altarg, ' ');
1769 strlcpy(mapin, altarg, MaxPathLen);
1770 while (*++cp == ' ')
1772 strlcpy(mapout, cp, MaxPathLen);
1778 static char new[MaxPathLen];
1779 char *cp1 = name, *cp2 = mapin;
1780 char *tp[9], *te[9];
1781 int i, toks[9], toknum = 0, match = 1;
1783 for (i=0; i < 9; ++i) {
1786 while (match && *cp1 && *cp2) {
1789 if (*++cp2 != *cp1) {
1794 if (*(cp2+1) >= '1' && (*cp2+1) <= '9') {
1795 if (*cp1 != *(++cp2+1)) {
1796 toks[toknum = *cp2 - '1']++;
1798 while (*++cp1 && *(cp2+1)
1812 if (match && *cp1) {
1815 if (match && *cp2) {
1819 if (!match && *cp1) /* last token mismatch */
1836 if (*++cp2 == '$' && isdigit((unsigned char)*(cp2+1))) {
1837 if (*++cp2 == '0') {
1845 else if (toks[toknum = *cp2 - '1']) {
1846 char *cp3 = tp[toknum];
1848 while (cp3 != te[toknum]) {
1855 while (*cp2 && *cp2 != ',' &&
1860 else if (*cp2 == '$' &&
1861 isdigit((unsigned char)*(cp2+1))) {
1862 if (*++cp2 == '0') {
1869 else if (toks[toknum =
1871 char *cp3=tp[toknum];
1884 printf("nmap: unbalanced brackets\n");
1891 while (*++cp2 && *cp2 != ']') {
1892 if (*cp2 == '\\' && *(cp2 + 1)) {
1897 printf("nmap: unbalanced brackets\n");
1913 if (isdigit((unsigned char)*(cp2 + 1))) {
1914 if (*++cp2 == '0') {
1921 else if (toks[toknum = *cp2 - '1']) {
1922 char *cp3 = tp[toknum];
1924 while (cp3 != te[toknum]) {
1930 /* intentional drop through */
1945 setpassive(int argc, char **argv)
1948 passivemode = !passivemode;
1949 printf("Passive mode %s.\n", onoff(passivemode));
1954 setsunique(int argc, char **argv)
1958 printf("Store unique %s.\n", onoff(sunique));
1963 setrunique(int argc, char **argv)
1967 printf("Receive unique %s.\n", onoff(runique));
1971 /* change directory to perent directory */
1973 cdup(int argc, char **argv)
1976 if (command("CDUP") == ERROR && code == 500) {
1978 printf("CDUP command not recognized, trying XCUP\n");
1983 /* restart transfer at specific point */
1985 restart(int argc, char **argv)
1989 printf("restart: offset not specified\n");
1991 restart_point = atol(argv[1]);
1992 printf("restarting at %ld. %s\n", (long)restart_point,
1993 "execute get, put or append to initiate transfer");
1997 /* show remote system type */
1999 syst(int argc, char **argv)
2006 macdef(int argc, char **argv)
2012 printf("Limit of 16 macros have already been defined\n");
2016 if (argc < 2 && !another(&argc, &argv, "macro name")) {
2017 printf("Usage: %s macro_name\n",argv[0]);
2022 printf("Enter macro line by line, terminating it with a null line\n");
2024 strlcpy(macros[macnum].mac_name,
2026 sizeof(macros[macnum].mac_name));
2028 macros[macnum].mac_start = macbuf;
2031 macros[macnum].mac_start = macros[macnum - 1].mac_end + 1;
2033 tmp = macros[macnum].mac_start;
2034 while (tmp != macbuf+4096) {
2035 if ((c = getchar()) == EOF) {
2036 printf("macdef:end of file encountered\n");
2040 if ((*tmp = c) == '\n') {
2041 if (tmp == macros[macnum].mac_start) {
2042 macros[macnum++].mac_end = tmp;
2046 if (*(tmp-1) == '\0') {
2047 macros[macnum++].mac_end = tmp - 1;
2056 while ((c = getchar()) != '\n' && c != EOF)
2058 if (c == EOF || getchar() == '\n') {
2059 printf("Macro not defined - 4k buffer exceeded\n");
2067 * get size of file on remote machine
2070 sizecmd(int argc, char **argv)
2073 if (argc < 2 && !another(&argc, &argv, "filename")) {
2074 printf("usage: %s filename\n", argv[0]);
2078 command("SIZE %s", argv[1]);
2082 * get last modification time of file on remote machine
2085 modtime(int argc, char **argv)
2089 if (argc < 2 && !another(&argc, &argv, "filename")) {
2090 printf("usage: %s filename\n", argv[0]);
2097 if (command("MDTM %s", argv[1]) == COMPLETE) {
2098 int yy, mo, day, hour, min, sec;
2099 sscanf(reply_string, "%*s %04d%02d%02d%02d%02d%02d", &yy, &mo,
2100 &day, &hour, &min, &sec);
2101 /* might want to print this in local time */
2102 printf("%s\t%02d/%02d/%04d %02d:%02d:%02d GMT\n", argv[1],
2103 mo, day, yy, hour, min, sec);
2105 printf("%s\n", reply_string);
2110 * show status on reomte machine
2113 rmtstatus(int argc, char **argv)
2116 command(argc > 1 ? "STAT %s" : "STAT" , argv[1]);
2120 * get file if modtime is more recent than current file
2123 newer(int argc, char **argv)
2126 if (getit(argc, argv, -1, curtype == TYPE_I ? "wb" : "w"))
2127 printf("Local file \"%s\" is newer than remote file \"%s\"\n",
2132 klist(int argc, char **argv)
2136 printf("usage: %s\n", argv[0]);
2141 ret = command("SITE KLIST");
2142 code = (ret == COMPLETE);