Bugzilla – Attachment 1428 Details for
Bug 200
readline support for sftp
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Final Version
sftp-tab.patch (text/plain), 9.05 KB, created by
Ben Lindstrom
on 2007-12-30 12:16:11 AEDT
(
hide
)
Description:
Final Version
Filename:
MIME Type:
Creator:
Ben Lindstrom
Created:
2007-12-30 12:16:11 AEDT
Size:
9.05 KB
patch
obsolete
>## Version 5 - OpenSSH SFTP patch - 12/11/2007 ># ># This is a complete sftp patch. It must be applied to the --current ># version of sftp. Any other version isn't support. The tab completion ># matches openbsd's sftp in behavior. ># >Index: sftp.c >=================================================================== >RCS file: /cvs/src/usr.bin/ssh/sftp.c,v >retrieving revision 1.97 >diff -u -r1.97 sftp.c >--- sftp.c 24 Oct 2007 03:30:02 -0000 1.97 >+++ sftp.c 12 Dec 2007 03:19:32 -0000 >@@ -71,6 +71,12 @@ > int remote_glob(struct sftp_conn *, const char *, int, > int (*)(const char *, int), glob_t *); /* proto for sftp-glob.c */ > >+/* sftp connection structure */ >+struct sftp_conn *conn; >+ >+/* sftp remote path */ >+char *remote_path; >+ > /* Separators for interactive commands */ > #define WHITESPACE " \t\r\n" > >@@ -115,42 +121,49 @@ > struct CMD { > const char *c; > const int n; >+ const int t; > }; > >+/* Type of completion */ >+#define NOARGS 0 >+#define REMOTE 1 >+#define LOCAL 2 >+ >+ > static const struct CMD cmds[] = { >- { "bye", I_QUIT }, >- { "cd", I_CHDIR }, >- { "chdir", I_CHDIR }, >- { "chgrp", I_CHGRP }, >- { "chmod", I_CHMOD }, >- { "chown", I_CHOWN }, >- { "dir", I_LS }, >- { "exit", I_QUIT }, >- { "get", I_GET }, >- { "mget", I_GET }, >- { "help", I_HELP }, >- { "lcd", I_LCHDIR }, >- { "lchdir", I_LCHDIR }, >- { "lls", I_LLS }, >- { "lmkdir", I_LMKDIR }, >- { "ln", I_SYMLINK }, >- { "lpwd", I_LPWD }, >- { "ls", I_LS }, >- { "lumask", I_LUMASK }, >- { "mkdir", I_MKDIR }, >- { "progress", I_PROGRESS }, >- { "put", I_PUT }, >- { "mput", I_PUT }, >- { "pwd", I_PWD }, >- { "quit", I_QUIT }, >- { "rename", I_RENAME }, >- { "rm", I_RM }, >- { "rmdir", I_RMDIR }, >- { "symlink", I_SYMLINK }, >- { "version", I_VERSION }, >- { "!", I_SHELL }, >- { "?", I_HELP }, >- { NULL, -1} >+ { "bye", I_QUIT, NOARGS }, >+ { "cd", I_CHDIR, REMOTE }, >+ { "chdir", I_CHDIR, REMOTE }, >+ { "chgrp", I_CHGRP, REMOTE }, >+ { "chmod", I_CHMOD, REMOTE }, >+ { "chown", I_CHOWN, REMOTE }, >+ { "dir", I_LS, REMOTE }, >+ { "exit", I_QUIT, NOARGS }, >+ { "get", I_GET, REMOTE }, >+ { "mget", I_GET, REMOTE }, >+ { "help", I_HELP, NOARGS }, >+ { "lcd", I_LCHDIR, LOCAL }, >+ { "lchdir", I_LCHDIR, LOCAL }, >+ { "lls", I_LLS, LOCAL }, >+ { "lmkdir", I_LMKDIR, LOCAL }, >+ { "ln", I_SYMLINK, REMOTE }, >+ { "lpwd", I_LPWD, LOCAL }, >+ { "ls", I_LS, REMOTE }, >+ { "lumask", I_LUMASK, NOARGS }, >+ { "mkdir", I_MKDIR, REMOTE }, >+ { "progress", I_PROGRESS, NOARGS }, >+ { "put", I_PUT, LOCAL }, >+ { "mput", I_PUT, LOCAL }, >+ { "pwd", I_PWD, REMOTE }, >+ { "quit", I_QUIT, NOARGS }, >+ { "rename", I_RENAME, REMOTE }, >+ { "rm", I_RM, REMOTE }, >+ { "rmdir", I_RMDIR, REMOTE }, >+ { "symlink", I_SYMLINK, REMOTE }, >+ { "version", I_VERSION, NOARGS }, >+ { "!", I_SHELL, NOARGS }, >+ { "?", I_HELP, NOARGS }, >+ { NULL, -1, -1} > }; > > int interactive_loop(int fd_in, int fd_out, char *file1, char *file2); >@@ -1344,13 +1357,237 @@ > return ("sftp> "); > } > >+void >+complete_display(char **list, u_int len) >+{ >+ u_int y, m = 0, width = 80, columns = 1, colspace = 0; >+ struct winsize ws; >+ >+ /* Count entries for sort and find longest filename */ >+ for (y = 0; list[y]; y++) >+ m = MAX(m, strlen(list[y])); >+ >+ if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1) >+ width = ws.ws_col; >+ >+ m -= len; >+ columns = width / (m + 2); >+ columns = MAX(columns, 1); >+ colspace = width / columns; >+ colspace = MIN(colspace, width); >+ >+ printf("\n"); >+ m = 1; >+ for (y = 0; list[y]; y++) { >+ char *tmp = list[y]; >+ >+ tmp += len; >+ printf("%-*s", colspace, tmp); >+ if (m >= columns) { >+ printf("\n"); >+ m = 1; >+ } else >+ m++; >+ } >+ printf("\n"); >+} >+ >+char * >+complete_ambiguous(const char *word, char **list, size_t count) >+{ >+ if (word == NULL) >+ return (NULL); >+ >+ if (count > 0) { >+ u_int y, matchlen = strlen(list[0]); >+ >+ for (y = 1; list[y]; y++) { >+ int x; >+ >+ for (x = 0; x < matchlen; x++) >+ if (list[0][x] != list[y][x]) >+ break; >+ >+ matchlen = x; >+ } >+ >+ if (matchlen > strlen(word)) { >+ char *tmp = xstrdup(list[0]); >+ >+ tmp[matchlen] = NULL; >+ return (tmp); >+ } >+ } >+ >+ return (xstrdup(word)); >+} >+ >+ >+int >+complete_cmd_parse(EditLine *el, char *cmd) >+{ >+ u_int y, count = 0, cmdlen; >+ char **list; >+ >+ if (cmd == NULL) >+ return (0); >+ >+ list = xcalloc((sizeof(cmds) / sizeof(*cmds)), sizeof(char *)); >+ cmdlen = strlen(cmd); >+ for (y = 0; cmds[y].c; y++) { >+ if (!strncasecmp(cmd, cmds[y].c, cmdlen)) >+ list[count++] = xstrdup(cmds[y].c); >+ >+ list[count] = NULL; >+ } >+ >+ if (count > 0) { >+ char *tmp = complete_ambiguous(cmd, list, count); >+ >+ if (count > 1) >+ complete_display(list, 0); >+ >+ for (y = 1; list[y]; y++) >+ xfree(list[y]); >+ xfree(list); >+ >+ if (tmp != NULL) { >+ if (strlen(tmp) > strlen(cmd)) >+ if (el_insertstr(el, tmp + strlen(cmd)) == -1) >+ fatal("el_insertstr failed."); >+ >+ xfree(tmp); >+ } >+ } >+ >+ return (count); >+} >+ >+int >+complete_is_remote(char *cmd) { >+ int i; >+ >+ if (cmd == NULL) >+ return (-1); >+ >+ for (i = 0; cmds[i].c; i++) { >+ size_t cmdlen = strlen(cmds[i].c); >+ >+ if (!strncasecmp(cmd, cmds[i].c, cmdlen)) >+ return cmds[i].t; >+ } >+ >+ return (-1); >+} >+ >+int >+complete_match(EditLine *el, char *file, int remote) >+{ >+ glob_t g; >+ char *tmp, *tmp2, *pwd; >+ u_int len; >+ >+ if (file == NULL) >+ return (0); >+ >+ len = strlen(file) + 2; /* NULL + Wildcard */ >+ tmp = xmalloc(len); >+ snprintf(tmp, len, "%s*", file); >+ >+ memset(&g, 0, sizeof(g)); >+ if (remote != LOCAL) { >+ tmp = make_absolute(tmp, remote_path); >+ remote_glob(conn, tmp, 0, NULL, &g); >+ } else >+ glob(tmp, GLOB_DOOFFS, NULL, &g); >+ >+ xfree(tmp); >+ >+ if (g.gl_matchc == 0) >+ return (0); >+ >+ tmp2 = complete_ambiguous(file, g.gl_pathv, g.gl_matchc); >+ tmp = path_strip(tmp2, remote_path); >+ xfree(tmp2); >+ >+ if (g.gl_matchc > 1) { >+ char *pwd = strrchr(g.gl_pathv[0], '/'); >+ u_int len = 0; >+ >+ if (pwd != NULL) >+ len = strlen(g.gl_pathv[0]) - strlen(pwd) + 1; >+ >+ complete_display(g.gl_pathv, len); >+ } >+ >+ globfree(&g); >+ if (tmp != NULL) { >+ if (strlen(tmp) > strlen(file)) { >+ char *ap, *tmp2 = tmp + strlen(file); >+ u_int len = strlen(tmp2); >+ >+ while ((ap = strsep(&tmp2, " ")) != NULL) { >+ if (strlen(ap) > 0) { >+ if (el_insertstr(el, ap) == -1) >+ fatal("el_insertstr failed."); >+ len -= strlen(ap); >+ } >+ if (len > 0) { >+ len--; >+ if (el_insertstr(el, "\\ ") == -1) >+ fatal("el_insertstr failed."); >+ } >+ } >+ } >+ >+ xfree(tmp); >+ } >+ >+ return (g.gl_matchc); >+} >+ >+unsigned char >+complete(EditLine *el, int ch) >+{ >+ char **argv, *line; >+ u_int x, argc, carg, len, ret = CC_ERROR; >+ const LineInfo *lf; >+ >+ lf = el_line(el); >+ >+ /* Figure out which argument we are on */ >+ len = lf->cursor - lf->buffer + 1; >+ line = (char *)xmalloc(len); >+ strlcpy(line, lf->buffer, len); >+ argv = makeargv(line, &carg); >+ xfree(line); >+ >+ /* now get the real argument */ >+ len = lf->lastchar - lf->buffer + 1; >+ line = (char *)xmalloc(len); >+ strlcpy(line, lf->buffer, len); >+ argv = makeargv(line, &argc); >+ xfree(line); >+ >+ if (carg == 1) { /* Handle the command parsing */ >+ if (complete_cmd_parse(el, argv[0]) != 0) >+ ret = CC_REDISPLAY; >+ } else if (carg > 1) { /* Handle file parsing */ >+ int remote = complete_is_remote(argv[0]); >+ >+ if (remote != 0 && complete_match(el, argv[carg - 1], >+ remote) != 0) >+ ret = CC_REDISPLAY; >+ } >+ >+ return (ret); >+} >+ > int > interactive_loop(int fd_in, int fd_out, char *file1, char *file2) > { >- char *pwd; > char *dir = NULL; > char cmd[2048]; >- struct sftp_conn *conn; > int err, interactive; > EditLine *el = NULL; > History *hl = NULL; >@@ -1370,26 +1607,31 @@ > el_set(el, EL_TERMINAL, NULL); > el_set(el, EL_SIGNAL, 1); > el_source(el, NULL); >+ >+ /* Tab Completion */ >+ el_set(el, EL_ADDFN, "ftp-complete", >+ "Context senstive argument completion", complete); >+ el_set(el, EL_BIND, "^I", "ftp-complete", NULL); > } > > conn = do_init(fd_in, fd_out, copy_buffer_len, num_requests); > if (conn == NULL) > fatal("Couldn't initialise connection to server"); > >- pwd = do_realpath(conn, "."); >- if (pwd == NULL) >+ remote_path = do_realpath(conn, "."); >+ if (remote_path == NULL) > fatal("Need cwd"); > > if (file1 != NULL) { > dir = xstrdup(file1); >- dir = make_absolute(dir, pwd); >+ dir = make_absolute(dir, remote_path); > > if (remote_is_dir(conn, dir) && file2 == NULL) { > printf("Changing to: %s\n", dir); > snprintf(cmd, sizeof cmd, "cd \"%s\"", dir); >- if (parse_dispatch_command(conn, cmd, &pwd, 1) != 0) { >+ if (parse_dispatch_command(conn, cmd, &remote_path, 1) != 0) { > xfree(dir); >- xfree(pwd); >+ xfree(remote_path); > xfree(conn); > return (-1); > } >@@ -1400,9 +1642,9 @@ > snprintf(cmd, sizeof cmd, "get %s %s", dir, > file2); > >- err = parse_dispatch_command(conn, cmd, &pwd, 1); >+ err = parse_dispatch_command(conn, cmd, &remote_path, 1); > xfree(dir); >- xfree(pwd); >+ xfree(remote_path); > xfree(conn); > return (err); > } >@@ -1455,11 +1697,11 @@ > interrupted = 0; > signal(SIGINT, cmd_interrupt); > >- err = parse_dispatch_command(conn, cmd, &pwd, batchmode); >+ err = parse_dispatch_command(conn, cmd, &remote_path, batchmode); > if (err != 0) > break; > } >- xfree(pwd); >+ xfree(remote_path); > xfree(conn); > > if (el != NULL)
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 200
:
59
| 1428 |
1743