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

Collapse All | Expand All

(-)sftp.c (-44 / +286 lines)
Lines 71-76 Link Here
71
int remote_glob(struct sftp_conn *, const char *, int,
71
int remote_glob(struct sftp_conn *, const char *, int,
72
    int (*)(const char *, int), glob_t *); /* proto for sftp-glob.c */
72
    int (*)(const char *, int), glob_t *); /* proto for sftp-glob.c */
73
73
74
/* sftp connection structure */
75
struct sftp_conn *conn;
76
77
/* sftp remote path */
78
char *remote_path;
79
74
/* Separators for interactive commands */
80
/* Separators for interactive commands */
75
#define WHITESPACE " \t\r\n"
81
#define WHITESPACE " \t\r\n"
76
82
Lines 115-156 Link Here
115
struct CMD {
121
struct CMD {
116
	const char *c;
122
	const char *c;
117
	const int n;
123
	const int n;
124
	const int t;
118
};
125
};
119
126
127
/* Type of completion */
128
#define NOARGS 		0
129
#define REMOTE 		1
130
#define LOCAL		2
131
132
120
static const struct CMD cmds[] = {
133
static const struct CMD cmds[] = {
121
	{ "bye",	I_QUIT },
134
	{ "bye",	I_QUIT, 	NOARGS },
122
	{ "cd",		I_CHDIR },
135
	{ "cd",		I_CHDIR,	REMOTE },
123
	{ "chdir",	I_CHDIR },
136
	{ "chdir",	I_CHDIR,	REMOTE },
124
	{ "chgrp",	I_CHGRP },
137
	{ "chgrp",	I_CHGRP,	REMOTE },
125
	{ "chmod",	I_CHMOD },
138
	{ "chmod",	I_CHMOD,	REMOTE },
126
	{ "chown",	I_CHOWN },
139
	{ "chown",	I_CHOWN,	REMOTE },
127
	{ "dir",	I_LS },
140
	{ "dir",	I_LS,		REMOTE },
128
	{ "exit",	I_QUIT },
141
	{ "exit",	I_QUIT,		NOARGS },
129
	{ "get",	I_GET },
142
	{ "get",	I_GET,		REMOTE },
130
	{ "mget",	I_GET },
143
	{ "mget",	I_GET,		REMOTE },
131
	{ "help",	I_HELP },
144
	{ "help",	I_HELP,		NOARGS },
132
	{ "lcd",	I_LCHDIR },
145
	{ "lcd",	I_LCHDIR,	LOCAL },
133
	{ "lchdir",	I_LCHDIR },
146
	{ "lchdir",	I_LCHDIR,	LOCAL },
134
	{ "lls",	I_LLS },
147
	{ "lls",	I_LLS,		LOCAL },
135
	{ "lmkdir",	I_LMKDIR },
148
	{ "lmkdir",	I_LMKDIR,	LOCAL  },
136
	{ "ln",		I_SYMLINK },
149
	{ "ln",		I_SYMLINK,	REMOTE },
137
	{ "lpwd",	I_LPWD },
150
	{ "lpwd",	I_LPWD,		LOCAL },
138
	{ "ls",		I_LS },
151
	{ "ls",		I_LS, 		REMOTE },
139
	{ "lumask",	I_LUMASK },
152
	{ "lumask",	I_LUMASK,	NOARGS },
140
	{ "mkdir",	I_MKDIR },
153
	{ "mkdir",	I_MKDIR,	REMOTE },
141
	{ "progress",	I_PROGRESS },
154
	{ "progress",	I_PROGRESS,	NOARGS },
142
	{ "put",	I_PUT },
155
	{ "put",	I_PUT,		LOCAL },
143
	{ "mput",	I_PUT },
156
	{ "mput",	I_PUT,		LOCAL },
144
	{ "pwd",	I_PWD },
157
	{ "pwd",	I_PWD,		REMOTE },
145
	{ "quit",	I_QUIT },
158
	{ "quit",	I_QUIT,		NOARGS },
146
	{ "rename",	I_RENAME },
159
	{ "rename",	I_RENAME,	REMOTE },
147
	{ "rm",		I_RM },
160
	{ "rm",		I_RM,		REMOTE },
148
	{ "rmdir",	I_RMDIR },
161
	{ "rmdir",	I_RMDIR,	REMOTE },
149
	{ "symlink",	I_SYMLINK },
162
	{ "symlink",	I_SYMLINK,	REMOTE },
150
	{ "version",	I_VERSION },
163
	{ "version",	I_VERSION,	NOARGS },
151
	{ "!",		I_SHELL },
164
	{ "!",		I_SHELL,	NOARGS },
152
	{ "?",		I_HELP },
165
	{ "?",		I_HELP,		NOARGS },
153
	{ NULL,			-1}
166
	{ NULL,		-1,		-1}
154
};
167
};
155
168
156
int interactive_loop(int fd_in, int fd_out, char *file1, char *file2);
169
int interactive_loop(int fd_in, int fd_out, char *file1, char *file2);
Lines 1344-1356 Link Here
1344
	return ("sftp> ");
1357
	return ("sftp> ");
1345
}
1358
}
1346
1359
1360
void
1361
complete_display(char **list, u_int len)
1362
{
1363
	u_int y, m = 0, width = 80, columns = 1, colspace = 0;
1364
	struct winsize ws;
1365
1366
	/* Count entries for sort and find longest filename */
1367
	for (y = 0; list[y]; y++) 
1368
		m = MAX(m, strlen(list[y]));
1369
1370
	if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1)
1371
		width = ws.ws_col;
1372
1373
	m -= len;
1374
	columns = width / (m + 2);
1375
	columns = MAX(columns, 1);
1376
	colspace = width / columns;
1377
	colspace = MIN(colspace, width);
1378
1379
	printf("\n");
1380
	m = 1;
1381
	for (y = 0; list[y]; y++) {
1382
		char *tmp = list[y];
1383
1384
		tmp += len;
1385
		printf("%-*s", colspace, tmp);
1386
		if (m >= columns) {
1387
			printf("\n");
1388
			m = 1;
1389
		} else
1390
			m++;
1391
	}
1392
	printf("\n");
1393
}
1394
1395
char *
1396
complete_ambiguous(const char *word, char **list, size_t count)
1397
{
1398
	if (word == NULL)
1399
		return (NULL);
1400
1401
	if (count > 0) {
1402
		u_int y, matchlen = strlen(list[0]);
1403
1404
		for (y = 1; list[y]; y++) {
1405
			int x;
1406
1407
			for (x = 0; x < matchlen; x++) 
1408
				if (list[0][x] != list[y][x]) 
1409
					break;
1410
1411
			matchlen = x;
1412
		}
1413
1414
		if (matchlen > strlen(word)) {
1415
			char *tmp = xstrdup(list[0]);
1416
1417
			tmp[matchlen] = NULL;
1418
			return (tmp);
1419
		}
1420
	} 
1421
1422
	return (xstrdup(word));
1423
}
1424
1425
1426
int
1427
complete_cmd_parse(EditLine *el, char *cmd)
1428
{
1429
	u_int y, count = 0, cmdlen;
1430
	char **list;
1431
1432
	if (cmd == NULL)
1433
		return (0);
1434
1435
	list = xcalloc((sizeof(cmds) / sizeof(*cmds)), sizeof(char *));
1436
	cmdlen = strlen(cmd);
1437
	for (y = 0; cmds[y].c; y++)  {
1438
		if (!strncasecmp(cmd, cmds[y].c, cmdlen)) 
1439
			list[count++] = xstrdup(cmds[y].c);
1440
1441
		list[count] = NULL;
1442
	}
1443
1444
	if (count > 0) {
1445
		char *tmp = complete_ambiguous(cmd, list, count);
1446
1447
		if (count > 1)
1448
			complete_display(list, 0);
1449
1450
		for (y = 1; list[y]; y++)  
1451
			xfree(list[y]);	
1452
		xfree(list);
1453
1454
		if (tmp != NULL) {
1455
			if (strlen(tmp) > strlen(cmd)) 
1456
				if (el_insertstr(el, tmp + strlen(cmd)) == -1)
1457
					fatal("el_insertstr failed.");
1458
1459
			xfree(tmp);
1460
		}
1461
	}
1462
1463
	return (count);
1464
}
1465
1466
int
1467
complete_is_remote(char *cmd) {
1468
	int i;
1469
1470
	if (cmd == NULL)
1471
		return (-1);
1472
1473
	for (i = 0; cmds[i].c; i++) {
1474
		size_t cmdlen = strlen(cmds[i].c);
1475
1476
		if (!strncasecmp(cmd, cmds[i].c, cmdlen)) 
1477
			return cmds[i].t;
1478
	}
1479
1480
	return (-1);
1481
}
1482
1483
int
1484
complete_match(EditLine *el, char *file, int remote)
1485
{
1486
	glob_t g;
1487
	char *tmp, *tmp2, *pwd;
1488
	u_int len;
1489
1490
	if (file == NULL)
1491
		return (0);
1492
1493
	len = strlen(file) + 2;  /* NULL + Wildcard */
1494
	tmp = xmalloc(len);
1495
	snprintf(tmp, len, "%s*",  file);
1496
1497
	memset(&g, 0, sizeof(g));
1498
	if (remote != LOCAL) {
1499
		tmp = make_absolute(tmp, remote_path);
1500
		remote_glob(conn, tmp, 0, NULL, &g);
1501
	} else 
1502
		glob(tmp, GLOB_DOOFFS, NULL, &g);
1503
	
1504
	xfree(tmp);
1505
1506
	if (g.gl_matchc == 0) 
1507
		return (0);
1508
1509
	tmp2 = complete_ambiguous(file, g.gl_pathv, g.gl_matchc);
1510
	tmp = path_strip(tmp2, remote_path);
1511
	xfree(tmp2);
1512
1513
	if (g.gl_matchc > 1) {
1514
		char *pwd = strrchr(g.gl_pathv[0], '/');
1515
		u_int len = 0;
1516
1517
		if (pwd != NULL)
1518
			len = strlen(g.gl_pathv[0]) - strlen(pwd) + 1;
1519
1520
		complete_display(g.gl_pathv, len);
1521
	}
1522
1523
	globfree(&g);
1524
	if (tmp != NULL) {
1525
		if (strlen(tmp) > strlen(file))  {
1526
			char *ap, *tmp2 = tmp + strlen(file);
1527
			u_int len = strlen(tmp2); 
1528
1529
			while ((ap = strsep(&tmp2, " ")) != NULL) {
1530
				if (strlen(ap) > 0) {
1531
					if (el_insertstr(el, ap) == -1)
1532
						fatal("el_insertstr failed.");
1533
					len -= strlen(ap);
1534
				}
1535
				if (len > 0) {
1536
					len--;
1537
					if (el_insertstr(el, "\\ ") == -1)
1538
						fatal("el_insertstr failed.");
1539
				}
1540
			}
1541
		}
1542
1543
		xfree(tmp);
1544
	}
1545
1546
	return (g.gl_matchc);
1547
}
1548
1549
unsigned char
1550
complete(EditLine *el, int ch)
1551
{
1552
	char **argv, *line;
1553
	u_int x, argc, carg, len, ret = CC_ERROR;
1554
	const LineInfo *lf;
1555
1556
	lf = el_line(el);
1557
1558
	/* Figure out which argument we are on */
1559
	len = lf->cursor - lf->buffer + 1;
1560
	line = (char *)xmalloc(len);
1561
	strlcpy(line, lf->buffer, len);
1562
	argv = makeargv(line, &carg);
1563
	xfree(line);
1564
1565
	/* now get the real argument */
1566
	len = lf->lastchar - lf->buffer + 1;
1567
	line = (char *)xmalloc(len);
1568
	strlcpy(line, lf->buffer, len);
1569
	argv = makeargv(line, &argc);
1570
	xfree(line);
1571
1572
	if (carg == 1) {  /* Handle the command parsing */
1573
		if (complete_cmd_parse(el, argv[0]) != 0) 
1574
			ret = CC_REDISPLAY;
1575
	} else if (carg > 1) { /* Handle file parsing */
1576
		int remote = complete_is_remote(argv[0]);
1577
1578
		if (remote != 0 && complete_match(el, argv[carg - 1], 
1579
		    remote) != 0) 
1580
			ret = CC_REDISPLAY;
1581
	}
1582
1583
	return (ret);
1584
}
1585
1347
int
1586
int
1348
interactive_loop(int fd_in, int fd_out, char *file1, char *file2)
1587
interactive_loop(int fd_in, int fd_out, char *file1, char *file2)
1349
{
1588
{
1350
	char *pwd;
1351
	char *dir = NULL;
1589
	char *dir = NULL;
1352
	char cmd[2048];
1590
	char cmd[2048];
1353
	struct sftp_conn *conn;
1354
	int err, interactive;
1591
	int err, interactive;
1355
	EditLine *el = NULL;
1592
	EditLine *el = NULL;
1356
	History *hl = NULL;
1593
	History *hl = NULL;
Lines 1370-1395 Link Here
1370
		el_set(el, EL_TERMINAL, NULL);
1607
		el_set(el, EL_TERMINAL, NULL);
1371
		el_set(el, EL_SIGNAL, 1);
1608
		el_set(el, EL_SIGNAL, 1);
1372
		el_source(el, NULL);
1609
		el_source(el, NULL);
1610
1611
		/* Tab Completion */
1612
		el_set(el, EL_ADDFN, "ftp-complete", 
1613
		    "Context senstive argument completion", complete);
1614
		el_set(el, EL_BIND, "^I", "ftp-complete", NULL);
1373
	}
1615
	}
1374
1616
1375
	conn = do_init(fd_in, fd_out, copy_buffer_len, num_requests);
1617
	conn = do_init(fd_in, fd_out, copy_buffer_len, num_requests);
1376
	if (conn == NULL)
1618
	if (conn == NULL)
1377
		fatal("Couldn't initialise connection to server");
1619
		fatal("Couldn't initialise connection to server");
1378
1620
1379
	pwd = do_realpath(conn, ".");
1621
	remote_path = do_realpath(conn, ".");
1380
	if (pwd == NULL)
1622
	if (remote_path == NULL)
1381
		fatal("Need cwd");
1623
		fatal("Need cwd");
1382
1624
1383
	if (file1 != NULL) {
1625
	if (file1 != NULL) {
1384
		dir = xstrdup(file1);
1626
		dir = xstrdup(file1);
1385
		dir = make_absolute(dir, pwd);
1627
		dir = make_absolute(dir, remote_path);
1386
1628
1387
		if (remote_is_dir(conn, dir) && file2 == NULL) {
1629
		if (remote_is_dir(conn, dir) && file2 == NULL) {
1388
			printf("Changing to: %s\n", dir);
1630
			printf("Changing to: %s\n", dir);
1389
			snprintf(cmd, sizeof cmd, "cd \"%s\"", dir);
1631
			snprintf(cmd, sizeof cmd, "cd \"%s\"", dir);
1390
			if (parse_dispatch_command(conn, cmd, &pwd, 1) != 0) {
1632
			if (parse_dispatch_command(conn, cmd, &remote_path, 1) != 0) {
1391
				xfree(dir);
1633
				xfree(dir);
1392
				xfree(pwd);
1634
				xfree(remote_path);
1393
				xfree(conn);
1635
				xfree(conn);
1394
				return (-1);
1636
				return (-1);
1395
			}
1637
			}
Lines 1400-1408 Link Here
1400
				snprintf(cmd, sizeof cmd, "get %s %s", dir,
1642
				snprintf(cmd, sizeof cmd, "get %s %s", dir,
1401
				    file2);
1643
				    file2);
1402
1644
1403
			err = parse_dispatch_command(conn, cmd, &pwd, 1);
1645
			err = parse_dispatch_command(conn, cmd, &remote_path, 1);
1404
			xfree(dir);
1646
			xfree(dir);
1405
			xfree(pwd);
1647
			xfree(remote_path);
1406
			xfree(conn);
1648
			xfree(conn);
1407
			return (err);
1649
			return (err);
1408
		}
1650
		}
Lines 1455-1465 Link Here
1455
		interrupted = 0;
1697
		interrupted = 0;
1456
		signal(SIGINT, cmd_interrupt);
1698
		signal(SIGINT, cmd_interrupt);
1457
1699
1458
		err = parse_dispatch_command(conn, cmd, &pwd, batchmode);
1700
		err = parse_dispatch_command(conn, cmd, &remote_path, batchmode);
1459
		if (err != 0)
1701
		if (err != 0)
1460
			break;
1702
			break;
1461
	}
1703
	}
1462
	xfree(pwd);
1704
	xfree(remote_path);
1463
	xfree(conn);
1705
	xfree(conn);
1464
1706
1465
	if (el != NULL)
1707
	if (el != NULL)

Return to bug 200