|
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) |