View | Details | Raw Unified | Return to bug 200 | Differences between
and this patch

Collapse All | Expand All

(-)sftp.c (-49 / +433 lines)
Lines 74-79 volatile sig_atomic_t interrupted = 0; Link Here
74
/* I wish qsort() took a separate ctx for the comparison function...*/
74
/* I wish qsort() took a separate ctx for the comparison function...*/
75
int sort_flag;
75
int sort_flag;
76
76
77
/* Context used for commandline completion */
78
struct complete_ctx {
79
	struct sftp_conn *conn;
80
	char **remote_pathp;
81
};
82
77
int remote_glob(struct sftp_conn *, const char *, int,
83
int remote_glob(struct sftp_conn *, const char *, int,
78
    int (*)(const char *, int), glob_t *); /* proto for sftp-glob.c */
84
    int (*)(const char *, int), glob_t *); /* proto for sftp-glob.c */
79
85
Lines 122-164 int remote_glob(struct sftp_conn *, cons Link Here
122
struct CMD {
128
struct CMD {
123
	const char *c;
129
	const char *c;
124
	const int n;
130
	const int n;
131
	const int t;
125
};
132
};
126
133
134
/* Type of completion */
135
#define NOARGS	0
136
#define REMOTE	1
137
#define LOCAL	2
138
127
static const struct CMD cmds[] = {
139
static const struct CMD cmds[] = {
128
	{ "bye",	I_QUIT },
140
	{ "bye",	I_QUIT,		NOARGS	},
129
	{ "cd",		I_CHDIR },
141
	{ "cd",		I_CHDIR,	REMOTE	},
130
	{ "chdir",	I_CHDIR },
142
	{ "chdir",	I_CHDIR,	REMOTE	},
131
	{ "chgrp",	I_CHGRP },
143
	{ "chgrp",	I_CHGRP,	REMOTE	},
132
	{ "chmod",	I_CHMOD },
144
	{ "chmod",	I_CHMOD,	REMOTE	},
133
	{ "chown",	I_CHOWN },
145
	{ "chown",	I_CHOWN,	REMOTE	},
134
	{ "df",		I_DF },
146
	{ "df",		I_DF,		REMOTE	},
135
	{ "dir",	I_LS },
147
	{ "dir",	I_LS,		REMOTE	},
136
	{ "exit",	I_QUIT },
148
	{ "exit",	I_QUIT,		NOARGS	},
137
	{ "get",	I_GET },
149
	{ "get",	I_GET,		REMOTE	},
138
	{ "mget",	I_GET },
150
	{ "help",	I_HELP,		NOARGS	},
139
	{ "help",	I_HELP },
151
	{ "lcd",	I_LCHDIR,	LOCAL	},
140
	{ "lcd",	I_LCHDIR },
152
	{ "lchdir",	I_LCHDIR,	LOCAL	},
141
	{ "lchdir",	I_LCHDIR },
153
	{ "lls",	I_LLS,		LOCAL	},
142
	{ "lls",	I_LLS },
154
	{ "lmkdir",	I_LMKDIR,	LOCAL	},
143
	{ "lmkdir",	I_LMKDIR },
155
	{ "ln",		I_SYMLINK,	REMOTE	},
144
	{ "ln",		I_SYMLINK },
156
	{ "lpwd",	I_LPWD,		LOCAL	},
145
	{ "lpwd",	I_LPWD },
157
	{ "ls",		I_LS,		REMOTE	},
146
	{ "ls",		I_LS },
158
	{ "lumask",	I_LUMASK,	NOARGS	},
147
	{ "lumask",	I_LUMASK },
159
	{ "mkdir",	I_MKDIR,	REMOTE	},
148
	{ "mkdir",	I_MKDIR },
160
	{ "progress",	I_PROGRESS,	NOARGS	},
149
	{ "progress",	I_PROGRESS },
161
	{ "put",	I_PUT,		LOCAL	},
150
	{ "put",	I_PUT },
162
	{ "pwd",	I_PWD,		REMOTE	},
151
	{ "mput",	I_PUT },
163
	{ "quit",	I_QUIT,		NOARGS	},
152
	{ "pwd",	I_PWD },
164
	{ "rename",	I_RENAME,	REMOTE	},
153
	{ "quit",	I_QUIT },
165
	{ "rm",		I_RM,		REMOTE	},
154
	{ "rename",	I_RENAME },
166
	{ "rmdir",	I_RMDIR,	REMOTE	},
155
	{ "rm",		I_RM },
167
	{ "symlink",	I_SYMLINK,	REMOTE	},
156
	{ "rmdir",	I_RMDIR },
168
	{ "version",	I_VERSION,	NOARGS	},
157
	{ "symlink",	I_SYMLINK },
169
	{ "!",		I_SHELL,	NOARGS	},
158
	{ "version",	I_VERSION },
170
	{ "?",		I_HELP,		NOARGS	},
159
	{ "!",		I_SHELL },
171
	{ NULL,		-1,		-1	}
160
	{ "?",		I_HELP },
161
	{ NULL,			-1}
162
};
172
};
163
173
164
int interactive_loop(struct sftp_conn *, char *file1, char *file2);
174
int interactive_loop(struct sftp_conn *, char *file1, char *file2);
Lines 909-920 undo_glob_escape(char *s) Link Here
909
 * Split a string into an argument vector using sh(1)-style quoting,
919
 * Split a string into an argument vector using sh(1)-style quoting,
910
 * comment and escaping rules, but with some tweaks to handle glob(3)
920
 * comment and escaping rules, but with some tweaks to handle glob(3)
911
 * wildcards.
921
 * wildcards.
922
 * The "sloppy" flag allows for recovery from missing terminating quote, for
923
 * use in parsing incomplete commandlines during tab autocompletion.
924
 *
912
 * Returns NULL on error or a NULL-terminated array of arguments.
925
 * Returns NULL on error or a NULL-terminated array of arguments.
926
 *
927
 * If "lastquote" is not NULL, the quoting character used for the last
928
 * argument is placed in *lastquote ("\0", "'" or "\"").
929
 * 
930
 * If "terminated" is not NULL, *terminated will be set to 1 when the
931
 * last argument's quote has been properly terminated or 0 otherwise.
932
 * This parameter is only of use if "sloppy" is set.
913
 */
933
 */
914
#define MAXARGS 	128
934
#define MAXARGS 	128
915
#define MAXARGLEN	8192
935
#define MAXARGLEN	8192
916
static char **
936
static char **
917
makeargv(const char *arg, int *argcp)
937
makeargv(const char *arg, int *argcp, int sloppy, char *lastquote,
938
    u_int *terminated)
918
{
939
{
919
	int argc, quot;
940
	int argc, quot;
920
	size_t i, j;
941
	size_t i, j;
Lines 928-933 makeargv(const char *arg, int *argcp) Link Here
928
		error("string too long");
949
		error("string too long");
929
		return NULL;
950
		return NULL;
930
	}
951
	}
952
	if (terminated != NULL)
953
		*terminated = 1;
954
	if (lastquote != NULL)
955
		*lastquote = '\0';
931
	state = MA_START;
956
	state = MA_START;
932
	i = j = 0;
957
	i = j = 0;
933
	for (;;) {
958
	for (;;) {
Lines 944-949 makeargv(const char *arg, int *argcp) Link Here
944
			if (state == MA_START) {
969
			if (state == MA_START) {
945
				argv[argc] = argvs + j;
970
				argv[argc] = argvs + j;
946
				state = q;
971
				state = q;
972
				if (lastquote != NULL)
973
					*lastquote = arg[i];
947
			} else if (state == MA_UNQUOTED) 
974
			} else if (state == MA_UNQUOTED) 
948
				state = q;
975
				state = q;
949
			else if (state == q)
976
			else if (state == q)
Lines 980-985 makeargv(const char *arg, int *argcp) Link Here
980
				if (state == MA_START) {
1007
				if (state == MA_START) {
981
					argv[argc] = argvs + j;
1008
					argv[argc] = argvs + j;
982
					state = MA_UNQUOTED;
1009
					state = MA_UNQUOTED;
1010
					if (lastquote != NULL)
1011
						*lastquote = '\0';
983
				}
1012
				}
984
				if (arg[i + 1] == '?' || arg[i + 1] == '[' ||
1013
				if (arg[i + 1] == '?' || arg[i + 1] == '[' ||
985
				    arg[i + 1] == '*' || arg[i + 1] == '\\') {
1014
				    arg[i + 1] == '*' || arg[i + 1] == '\\') {
Lines 1005-1010 makeargv(const char *arg, int *argcp) Link Here
1005
				goto string_done;
1034
				goto string_done;
1006
		} else if (arg[i] == '\0') {
1035
		} else if (arg[i] == '\0') {
1007
			if (state == MA_SQUOTE || state == MA_DQUOTE) {
1036
			if (state == MA_SQUOTE || state == MA_DQUOTE) {
1037
				if (sloppy) {
1038
					state = MA_UNQUOTED;
1039
					if (terminated != NULL)
1040
						*terminated = 0;
1041
					goto string_done;
1042
				}
1008
				error("Unterminated quoted argument");
1043
				error("Unterminated quoted argument");
1009
				return NULL;
1044
				return NULL;
1010
			}
1045
			}
Lines 1018-1023 makeargv(const char *arg, int *argcp) Link Here
1018
			if (state == MA_START) {
1053
			if (state == MA_START) {
1019
				argv[argc] = argvs + j;
1054
				argv[argc] = argvs + j;
1020
				state = MA_UNQUOTED;
1055
				state = MA_UNQUOTED;
1056
				if (lastquote != NULL)
1057
					*lastquote = '\0';
1021
			}
1058
			}
1022
			if ((state == MA_SQUOTE || state == MA_DQUOTE) &&
1059
			if ((state == MA_SQUOTE || state == MA_DQUOTE) &&
1023
			    (arg[i] == '?' || arg[i] == '[' || arg[i] == '*')) {
1060
			    (arg[i] == '?' || arg[i] == '[' || arg[i] == '*')) {
Lines 1040-1047 makeargv(const char *arg, int *argcp) Link Here
1040
}
1077
}
1041
1078
1042
static int
1079
static int
1043
parse_args(const char **cpp, int *pflag, int *rflag, int *lflag, int *iflag, int *hflag,
1080
parse_args(const char **cpp, int *pflag, int *rflag, int *lflag, int *iflag,
1044
    unsigned long *n_arg, char **path1, char **path2)
1081
    int *hflag, unsigned long *n_arg, char **path1, char **path2)
1045
{
1082
{
1046
	const char *cmd, *cp = *cpp;
1083
	const char *cmd, *cp = *cpp;
1047
	char *cp2, **argv;
1084
	char *cp2, **argv;
Lines 1063-1069 parse_args(const char **cpp, int *pflag, Link Here
1063
		cp++;
1100
		cp++;
1064
	}
1101
	}
1065
1102
1066
	if ((argv = makeargv(cp, &argc)) == NULL)
1103
	if ((argv = makeargv(cp, &argc, 0, NULL, NULL)) == NULL)
1067
		return -1;
1104
		return -1;
1068
1105
1069
	/* Figure out which command we have */
1106
	/* Figure out which command we have */
Lines 1443-1452 prompt(EditLine *el) Link Here
1443
	return ("sftp> ");
1480
	return ("sftp> ");
1444
}
1481
}
1445
1482
1483
/* Display entries in 'list' after skipping the first 'len' chars */
1484
static void
1485
complete_display(char **list, u_int len)
1486
{
1487
	u_int y, m = 0, width = 80, columns = 1, colspace = 0, llen;
1488
	struct winsize ws;
1489
	char *tmp;
1490
1491
	/* Count entries for sort and find longest */
1492
	for (y = 0; list[y]; y++) 
1493
		m = MAX(m, strlen(list[y]));
1494
1495
	if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1)
1496
		width = ws.ws_col;
1497
1498
	m = m > len ? m - len : 0;
1499
	columns = width / (m + 2);
1500
	columns = MAX(columns, 1);
1501
	colspace = width / columns;
1502
	colspace = MIN(colspace, width);
1503
1504
	printf("\n");
1505
	m = 1;
1506
	for (y = 0; list[y]; y++) {
1507
		llen = strlen(list[y]);
1508
		tmp = llen > len ? list[y] + len : "";
1509
		printf("%-*s", colspace, tmp);
1510
		if (m >= columns) {
1511
			printf("\n");
1512
			m = 1;
1513
		} else
1514
			m++;
1515
	}
1516
	printf("\n");
1517
}
1518
1519
/*
1520
 * Given a "list" of words that begin with a common prefix of "word",
1521
 * attempt to find an autocompletion to extends "word" by the next
1522
 * characters common to all entries in "list".
1523
 */
1524
static char *
1525
complete_ambiguous(const char *word, char **list, size_t count)
1526
{
1527
	if (word == NULL)
1528
		return NULL;
1529
1530
	if (count > 0) {
1531
		u_int y, matchlen = strlen(list[0]);
1532
1533
		/* Find length of common stem */
1534
		for (y = 1; list[y]; y++) {
1535
			u_int x;
1536
1537
			for (x = 0; x < matchlen; x++) 
1538
				if (list[0][x] != list[y][x]) 
1539
					break;
1540
1541
			matchlen = x;
1542
		}
1543
1544
		if (matchlen > strlen(word)) {
1545
			char *tmp = xstrdup(list[0]);
1546
1547
			tmp[matchlen] = NULL;
1548
			return tmp;
1549
		}
1550
	} 
1551
1552
	return xstrdup(word);
1553
}
1554
1555
/* Autocomplete a sftp command */
1556
static int
1557
complete_cmd_parse(EditLine *el, char *cmd, int lastarg, char quote,
1558
    int terminated)
1559
{
1560
	u_int y, count = 0, cmdlen, tmplen;
1561
	char *tmp, **list, argterm[3];
1562
	const LineInfo *lf;
1563
1564
	list = xcalloc((sizeof(cmds) / sizeof(*cmds)) + 1, sizeof(char *));
1565
1566
	/* No command specified: display all available commands */
1567
	if (cmd == NULL) {
1568
		for (y = 0; cmds[y].c; y++)
1569
			list[count++] = xstrdup(cmds[y].c);
1570
		
1571
		list[count] = NULL;
1572
		complete_display(list, 0);
1573
1574
		for (y = 0; list[y] != NULL; y++)  
1575
			xfree(list[y]);	
1576
		xfree(list);
1577
		return count;
1578
	}
1579
1580
	/* Prepare subset of commands that start with "cmd" */
1581
	cmdlen = strlen(cmd);
1582
	for (y = 0; cmds[y].c; y++)  {
1583
		if (!strncasecmp(cmd, cmds[y].c, cmdlen)) 
1584
			list[count++] = xstrdup(cmds[y].c);
1585
	}
1586
	list[count] = NULL;
1587
1588
	if (count == 0)
1589
		return 0;
1590
1591
	/* Complete ambigious command */
1592
	tmp = complete_ambiguous(cmd, list, count);
1593
	if (count > 1)
1594
		complete_display(list, 0);
1595
1596
	for (y = 0; list[y]; y++)  
1597
		xfree(list[y]);	
1598
	xfree(list);
1599
1600
	if (tmp != NULL) {
1601
		tmplen = strlen(tmp);
1602
		cmdlen = strlen(cmd);
1603
		/* If cmd may be extended then do so */
1604
		if (tmplen > cmdlen)
1605
			if (el_insertstr(el, tmp + cmdlen) == -1)
1606
				fatal("el_insertstr failed.");
1607
		lf = el_line(el);
1608
		/* Terminate argument cleanly */
1609
		if (count == 1) {
1610
			y = 0;
1611
			if (!terminated)
1612
				argterm[y++] = quote;
1613
			if (lastarg || *(lf->cursor) != ' ')
1614
				argterm[y++] = ' ';
1615
			argterm[y] = '\0';
1616
			if (y > 0 && el_insertstr(el, argterm) == -1)
1617
				fatal("el_insertstr failed.");
1618
		}
1619
		xfree(tmp);
1620
	}
1621
1622
	return count;
1623
}
1624
1625
/*
1626
 * Determine whether a particular sftp command's arguments (if any)
1627
 * represent local or remote files.
1628
 */
1629
static int
1630
complete_is_remote(char *cmd) {
1631
	int i;
1632
1633
	if (cmd == NULL)
1634
		return -1;
1635
1636
	for (i = 0; cmds[i].c; i++) {
1637
		if (!strncasecmp(cmd, cmds[i].c, strlen(cmds[i].c))) 
1638
			return cmds[i].t;
1639
	}
1640
1641
	return -1;
1642
}
1643
1644
/* Autocomplete a filename "file" */
1645
static int
1646
complete_match(EditLine *el, struct sftp_conn *conn, char *remote_path,
1647
    char *file, int remote, int lastarg, char quote, int terminated)
1648
{
1649
	glob_t g;
1650
	char *tmp, *tmp2, ins[3];
1651
	u_int i, hadglob, pwdlen, len, tmplen, filelen;
1652
	const LineInfo *lf;
1653
	
1654
	/* Glob from "file" location */
1655
	if (file == NULL)
1656
		tmp = xstrdup("*");
1657
	else
1658
		xasprintf(&tmp, "%s*", file);
1659
1660
	memset(&g, 0, sizeof(g));
1661
	if (remote != LOCAL) {
1662
		tmp = make_absolute(tmp, remote_path);
1663
		remote_glob(conn, tmp, GLOB_DOOFFS|GLOB_MARK, NULL, &g);
1664
	} else 
1665
		glob(tmp, GLOB_DOOFFS|GLOB_MARK, NULL, &g);
1666
	
1667
	/* Determine length of pwd so we can trim completion display */
1668
	for (hadglob = tmplen = pwdlen = 0; tmp[tmplen] != 0; tmplen++) {
1669
		/* Terminate counting on first unescaped glob metacharacter */
1670
		if (tmp[tmplen] == '*' || tmp[tmplen] == '?') {
1671
			if (tmp[tmplen] != '*' || tmp[tmplen + 1] != '\0')
1672
				hadglob = 1;
1673
			break;
1674
		}
1675
		if (tmp[tmplen] == '\\' && tmp[tmplen + 1] != '\0')
1676
			tmplen++;
1677
		if (tmp[tmplen] == '/')
1678
			pwdlen = tmplen + 1;	/* track last seen '/' */
1679
	}
1680
	xfree(tmp);
1681
1682
	if (g.gl_matchc == 0) 
1683
		goto out;
1684
1685
	if (g.gl_matchc > 1)
1686
		complete_display(g.gl_pathv, pwdlen);
1687
1688
	tmp = NULL;
1689
	/* Don't try to extend globs */
1690
	if (file == NULL || hadglob)
1691
		goto out;
1692
1693
	tmp2 = complete_ambiguous(file, g.gl_pathv, g.gl_matchc);
1694
	tmp = path_strip(tmp2, remote_path);
1695
	xfree(tmp2);
1696
1697
	if (tmp == NULL)
1698
		goto out;
1699
1700
	tmplen = strlen(tmp);
1701
	filelen = strlen(file);
1702
1703
	if (tmplen > filelen)  {
1704
		tmp2 = tmp + filelen;
1705
		len = strlen(tmp2); 
1706
		/* quote argument on way out */
1707
		for (i = 0; i < len; i++) {
1708
			ins[0] = '\\';
1709
			ins[1] = tmp2[i];
1710
			ins[2] = '\0';
1711
			switch (tmp2[i]) {
1712
			case '\'':
1713
			case '"':
1714
			case '\\':
1715
			case '\t':
1716
			case ' ':
1717
				if (quote == '\0' || tmp2[i] == quote) {
1718
					if (el_insertstr(el, ins) == -1)
1719
						fatal("el_insertstr "
1720
						    "failed.");
1721
					break;
1722
				}
1723
				/* FALLTHROUGH */
1724
			default:
1725
				if (el_insertstr(el, ins + 1) == -1)
1726
					fatal("el_insertstr failed.");
1727
				break;
1728
			}
1729
		}
1730
	}
1731
1732
	lf = el_line(el);
1733
	/*
1734
	 * XXX should we really extend here? the user may not be done if
1735
	 * the filename is a directory.
1736
	 */
1737
	if (g.gl_matchc == 1) {
1738
		i = 0;
1739
		if (!terminated)
1740
			ins[i++] = quote;
1741
		if (lastarg || *(lf->cursor) != ' ')
1742
			ins[i++] = ' ';
1743
		ins[i] = '\0';
1744
		if (i > 0 && el_insertstr(el, ins) == -1)
1745
			fatal("el_insertstr failed.");
1746
	}
1747
	xfree(tmp);
1748
1749
 out:
1750
	globfree(&g);
1751
	return g.gl_matchc;
1752
}
1753
1754
/* tab-completion hook function, called via libedit */
1755
static unsigned char
1756
complete(EditLine *el, int ch)
1757
{
1758
	char **argv, *line, quote; 
1759
	u_int argc, carg, cursor, len, terminated, ret = CC_ERROR;
1760
	const LineInfo *lf;
1761
	struct complete_ctx *complete_ctx;
1762
1763
	lf = el_line(el);
1764
	if (el_get(el, EL_CLIENTDATA, (void**)&complete_ctx) != 0)
1765
		fatal("%s: el_get failed", __func__);
1766
1767
	/* Figure out which argument the cursor points to */
1768
	cursor = lf->cursor - lf->buffer;
1769
	line = (char *)xmalloc(cursor + 1);
1770
	memcpy(line, lf->buffer, cursor);
1771
	line[cursor] = '\0';
1772
	argv = makeargv(line, &carg, 1, &quote, &terminated);
1773
	xfree(line);
1774
1775
	/* Get all the arguments on the line */
1776
	len = lf->lastchar - lf->buffer;
1777
	line = (char *)xmalloc(len + 1);
1778
	memcpy(line, lf->buffer, len);
1779
	line[len] = '\0';
1780
	argv = makeargv(line, &argc, 1, NULL, NULL);
1781
1782
	/* Ensure cursor is at EOL or a argument boundary */
1783
	if (line[cursor] != ' ' && line[cursor] != '\0' &&
1784
	    line[cursor] != '\n') {
1785
		xfree(line);
1786
		return ret;
1787
	}
1788
1789
	if (carg == 0) {
1790
		/* Show all available commands */
1791
		complete_cmd_parse(el, NULL, argc == carg, '\0', 1);
1792
		ret = CC_REDISPLAY;
1793
	} else if (carg == 1 && cursor > 0 && line[cursor - 1] != ' ')  {
1794
		/* Handle the command parsing */
1795
		if (complete_cmd_parse(el, argv[0], argc == carg,
1796
		    quote, terminated) != 0) 
1797
			ret = CC_REDISPLAY;
1798
	} else if (carg >= 1) {
1799
		/* Handle file parsing */
1800
		int remote = complete_is_remote(argv[0]);
1801
		char *filematch = NULL;
1802
1803
		if (carg > 1 && line[cursor-1] != ' ')
1804
			filematch = argv[carg - 1];
1805
1806
		if (remote != 0 &&
1807
		    complete_match(el, complete_ctx->conn,
1808
		    *complete_ctx->remote_pathp, filematch,
1809
		    remote, carg == argc, quote, terminated) != 0) 
1810
			ret = CC_REDISPLAY;
1811
	}
1812
1813
	xfree(line);	
1814
	return ret;
1815
}
1816
1446
int
1817
int
1447
interactive_loop(struct sftp_conn *conn, char *file1, char *file2)
1818
interactive_loop(struct sftp_conn *conn, char *file1, char *file2)
1448
{
1819
{
1449
	char *pwd;
1820
	char *remote_path;
1450
	char *dir = NULL;
1821
	char *dir = NULL;
1451
	char cmd[2048];
1822
	char cmd[2048];
1452
	int err, interactive;
1823
	int err, interactive;
Lines 1454-1459 interactive_loop(struct sftp_conn *conn, Link Here
1454
	History *hl = NULL;
1825
	History *hl = NULL;
1455
	HistEvent hev;
1826
	HistEvent hev;
1456
	extern char *__progname;
1827
	extern char *__progname;
1828
	struct complete_ctx complete_ctx;
1457
1829
1458
	if (!batchmode && isatty(STDIN_FILENO)) {
1830
	if (!batchmode && isatty(STDIN_FILENO)) {
1459
		if ((el = el_init(__progname, stdin, stdout, stderr)) == NULL)
1831
		if ((el = el_init(__progname, stdin, stdout, stderr)) == NULL)
Lines 1468-1489 interactive_loop(struct sftp_conn *conn, Link Here
1468
		el_set(el, EL_TERMINAL, NULL);
1840
		el_set(el, EL_TERMINAL, NULL);
1469
		el_set(el, EL_SIGNAL, 1);
1841
		el_set(el, EL_SIGNAL, 1);
1470
		el_source(el, NULL);
1842
		el_source(el, NULL);
1843
1844
		/* Tab Completion */
1845
		el_set(el, EL_ADDFN, "ftp-complete", 
1846
		    "Context senstive argument completion", complete);
1847
		complete_ctx.conn = conn;
1848
		complete_ctx.remote_pathp = &remote_path;
1849
		el_set(el, EL_CLIENTDATA, (void*)&complete_ctx);
1850
		el_set(el, EL_BIND, "^I", "ftp-complete", NULL);
1471
	}
1851
	}
1472
1852
1473
	pwd = do_realpath(conn, ".");
1853
	remote_path = do_realpath(conn, ".");
1474
	if (pwd == NULL)
1854
	if (remote_path == NULL)
1475
		fatal("Need cwd");
1855
		fatal("Need cwd");
1476
1856
1477
	if (file1 != NULL) {
1857
	if (file1 != NULL) {
1478
		dir = xstrdup(file1);
1858
		dir = xstrdup(file1);
1479
		dir = make_absolute(dir, pwd);
1859
		dir = make_absolute(dir, remote_path);
1480
1860
1481
		if (remote_is_dir(conn, dir) && file2 == NULL) {
1861
		if (remote_is_dir(conn, dir) && file2 == NULL) {
1482
			printf("Changing to: %s\n", dir);
1862
			printf("Changing to: %s\n", dir);
1483
			snprintf(cmd, sizeof cmd, "cd \"%s\"", dir);
1863
			snprintf(cmd, sizeof cmd, "cd \"%s\"", dir);
1484
			if (parse_dispatch_command(conn, cmd, &pwd, 1) != 0) {
1864
			if (parse_dispatch_command(conn, cmd,
1865
			    &remote_path, 1) != 0) {
1485
				xfree(dir);
1866
				xfree(dir);
1486
				xfree(pwd);
1867
				xfree(remote_path);
1487
				xfree(conn);
1868
				xfree(conn);
1488
				return (-1);
1869
				return (-1);
1489
			}
1870
			}
Lines 1494-1502 interactive_loop(struct sftp_conn *conn, Link Here
1494
				snprintf(cmd, sizeof cmd, "get %s %s", dir,
1875
				snprintf(cmd, sizeof cmd, "get %s %s", dir,
1495
				    file2);
1876
				    file2);
1496
1877
1497
			err = parse_dispatch_command(conn, cmd, &pwd, 1);
1878
			err = parse_dispatch_command(conn, cmd,
1879
			    &remote_path, 1);
1498
			xfree(dir);
1880
			xfree(dir);
1499
			xfree(pwd);
1881
			xfree(remote_path);
1500
			xfree(conn);
1882
			xfree(conn);
1501
			return (err);
1883
			return (err);
1502
		}
1884
		}
Lines 1530-1536 interactive_loop(struct sftp_conn *conn, Link Here
1530
					printf("\n");
1912
					printf("\n");
1531
			}
1913
			}
1532
		} else {
1914
		} else {
1533
			if ((line = el_gets(el, &count)) == NULL || count <= 0) {
1915
			if ((line = el_gets(el, &count)) == NULL ||
1916
			    count <= 0) {
1534
				printf("\n");
1917
				printf("\n");
1535
				break;
1918
				break;
1536
			}
1919
			}
Lines 1549-1559 interactive_loop(struct sftp_conn *conn, Link Here
1549
		interrupted = 0;
1932
		interrupted = 0;
1550
		signal(SIGINT, cmd_interrupt);
1933
		signal(SIGINT, cmd_interrupt);
1551
1934
1552
		err = parse_dispatch_command(conn, cmd, &pwd, batchmode);
1935
		err = parse_dispatch_command(conn, cmd, &remote_path,
1936
		    batchmode);
1553
		if (err != 0)
1937
		if (err != 0)
1554
			break;
1938
			break;
1555
	}
1939
	}
1556
	xfree(pwd);
1940
	xfree(remote_path);
1557
	xfree(conn);
1941
	xfree(conn);
1558
1942
1559
	if (el != NULL)
1943
	if (el != NULL)

Return to bug 200