Blame


1 d3e1ab0c 2022-11-24 op /*
2 d3e1ab0c 2022-11-24 op * Copyright (c) 2022 Omar Polo <op@omarpolo.com>
3 d3e1ab0c 2022-11-24 op *
4 d3e1ab0c 2022-11-24 op * Permission to use, copy, modify, and distribute this software for any
5 d3e1ab0c 2022-11-24 op * purpose with or without fee is hereby granted, provided that the above
6 d3e1ab0c 2022-11-24 op * copyright notice and this permission notice appear in all copies.
7 d3e1ab0c 2022-11-24 op *
8 d3e1ab0c 2022-11-24 op * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 d3e1ab0c 2022-11-24 op * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 d3e1ab0c 2022-11-24 op * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 d3e1ab0c 2022-11-24 op * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 d3e1ab0c 2022-11-24 op * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 d3e1ab0c 2022-11-24 op * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 d3e1ab0c 2022-11-24 op * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 d3e1ab0c 2022-11-24 op */
16 d3e1ab0c 2022-11-24 op
17 d3e1ab0c 2022-11-24 op #include "compat.h"
18 d3e1ab0c 2022-11-24 op
19 d3e1ab0c 2022-11-24 op #if !HAVE_READLINE
20 d3e1ab0c 2022-11-24 op
21 d3e1ab0c 2022-11-24 op #include <stdio.h>
22 d3e1ab0c 2022-11-24 op #include <string.h>
23 d3e1ab0c 2022-11-24 op
24 d3e1ab0c 2022-11-24 op char *
25 d3e1ab0c 2022-11-24 op readline(const char *prompt)
26 d3e1ab0c 2022-11-24 op {
27 d3e1ab0c 2022-11-24 op char *ch, *line = NULL;
28 d3e1ab0c 2022-11-24 op size_t linesize = 0;
29 d3e1ab0c 2022-11-24 op ssize_t linelen;
30 d3e1ab0c 2022-11-24 op
31 d3e1ab0c 2022-11-24 op printf("%s", prompt);
32 d3e1ab0c 2022-11-24 op fflush(stdout);
33 d3e1ab0c 2022-11-24 op
34 d3e1ab0c 2022-11-24 op linelen = getline(&line, &linesize, stdin);
35 d3e1ab0c 2022-11-24 op if (linelen == -1)
36 d3e1ab0c 2022-11-24 op return NULL;
37 d3e1ab0c 2022-11-24 op
38 d3e1ab0c 2022-11-24 op if ((ch = strchr(line, '\n')) != NULL)
39 d3e1ab0c 2022-11-24 op *ch = '\0';
40 d3e1ab0c 2022-11-24 op return line;
41 d3e1ab0c 2022-11-24 op }
42 d3e1ab0c 2022-11-24 op
43 d3e1ab0c 2022-11-24 op void
44 d3e1ab0c 2022-11-24 op add_history(const char *line)
45 d3e1ab0c 2022-11-24 op {
46 d3e1ab0c 2022-11-24 op return;
47 d3e1ab0c 2022-11-24 op }
48 d3e1ab0c 2022-11-24 op
49 d3e1ab0c 2022-11-24 op void
50 d3e1ab0c 2022-11-24 op compl_setup(void)
51 d3e1ab0c 2022-11-24 op {
52 d3e1ab0c 2022-11-24 op return;
53 d3e1ab0c 2022-11-24 op }
54 d3e1ab0c 2022-11-24 op
55 d3e1ab0c 2022-11-24 op #else /* HAVE_READLINE */
56 d3e1ab0c 2022-11-24 op
57 d3e1ab0c 2022-11-24 op #include <ctype.h>
58 65b37bc8 2022-12-21 op #include <libgen.h>
59 d3e1ab0c 2022-11-24 op #include <limits.h>
60 d3e1ab0c 2022-11-24 op #include <stdio.h>
61 d3e1ab0c 2022-11-24 op #include <stdlib.h>
62 d3e1ab0c 2022-11-24 op #include <string.h>
63 d3e1ab0c 2022-11-24 op
64 d3e1ab0c 2022-11-24 op #include <readline/readline.h>
65 d3e1ab0c 2022-11-24 op #include <readline/history.h>
66 d3e1ab0c 2022-11-24 op
67 d3e1ab0c 2022-11-24 op #include "kami.h"
68 d3e1ab0c 2022-11-24 op #include "kamiftp.h"
69 d3e1ab0c 2022-11-24 op
70 d3e1ab0c 2022-11-24 op struct compl_state {
71 d3e1ab0c 2022-11-24 op size_t size;
72 d3e1ab0c 2022-11-24 op size_t len;
73 d3e1ab0c 2022-11-24 op char **entries;
74 d3e1ab0c 2022-11-24 op };
75 d3e1ab0c 2022-11-24 op
76 d3e1ab0c 2022-11-24 op static struct compl_state compl_state;
77 d3e1ab0c 2022-11-24 op static char compl_prfx[PATH_MAX];
78 d3e1ab0c 2022-11-24 op
79 d3e1ab0c 2022-11-24 op static void
80 d3e1ab0c 2022-11-24 op compl_state_reset(void)
81 d3e1ab0c 2022-11-24 op {
82 d3e1ab0c 2022-11-24 op size_t i;
83 d3e1ab0c 2022-11-24 op
84 d3e1ab0c 2022-11-24 op for (i = 0; i < compl_state.len; ++i)
85 d3e1ab0c 2022-11-24 op free(compl_state.entries[i]);
86 d3e1ab0c 2022-11-24 op free(compl_state.entries);
87 d3e1ab0c 2022-11-24 op
88 e3644194 2022-12-21 op memset(&compl_state, 0, sizeof(compl_state));
89 d3e1ab0c 2022-11-24 op }
90 d3e1ab0c 2022-11-24 op
91 d3e1ab0c 2022-11-24 op static int
92 d3e1ab0c 2022-11-24 op compl_add_entry(const struct np_stat *st)
93 d3e1ab0c 2022-11-24 op {
94 d3e1ab0c 2022-11-24 op const char *sufx = "";
95 d3e1ab0c 2022-11-24 op char *dup;
96 d3e1ab0c 2022-11-24 op
97 d3e1ab0c 2022-11-24 op if (compl_state.len == compl_state.size) {
98 d3e1ab0c 2022-11-24 op size_t newsz = compl_state.size * 1.5;
99 d3e1ab0c 2022-11-24 op void *t;
100 d3e1ab0c 2022-11-24 op
101 e3644194 2022-12-21 op if (newsz == 0)
102 e3644194 2022-12-21 op newsz = 16;
103 e3644194 2022-12-21 op
104 e3644194 2022-12-21 op /* one for the NULL entry at the end */
105 d3e1ab0c 2022-11-24 op t = recallocarray(compl_state.entries, compl_state.size,
106 e3644194 2022-12-21 op newsz + 1, sizeof(char *));
107 d3e1ab0c 2022-11-24 op if (t == NULL)
108 d3e1ab0c 2022-11-24 op return -1;
109 d3e1ab0c 2022-11-24 op compl_state.entries = t;
110 d3e1ab0c 2022-11-24 op compl_state.size = newsz;
111 d3e1ab0c 2022-11-24 op }
112 d3e1ab0c 2022-11-24 op
113 d3e1ab0c 2022-11-24 op if (st->qid.type & QTDIR)
114 d3e1ab0c 2022-11-24 op sufx = "/";
115 d3e1ab0c 2022-11-24 op
116 d3e1ab0c 2022-11-24 op if (asprintf(&dup, "%s%s%s", compl_prfx, st->name, sufx) == -1)
117 d3e1ab0c 2022-11-24 op return -1;
118 d3e1ab0c 2022-11-24 op compl_state.entries[compl_state.len++] = dup;
119 d3e1ab0c 2022-11-24 op return 0;
120 d3e1ab0c 2022-11-24 op }
121 d3e1ab0c 2022-11-24 op
122 d3e1ab0c 2022-11-24 op static void
123 d3e1ab0c 2022-11-24 op cleanword(char *buf, int brkspc)
124 d3e1ab0c 2022-11-24 op {
125 d3e1ab0c 2022-11-24 op char *cmd;
126 d3e1ab0c 2022-11-24 op int escape, quote;
127 d3e1ab0c 2022-11-24 op
128 d3e1ab0c 2022-11-24 op while (brkspc && isspace((unsigned char)*buf))
129 d3e1ab0c 2022-11-24 op memmove(buf, buf + 1, strlen(buf));
130 d3e1ab0c 2022-11-24 op
131 d3e1ab0c 2022-11-24 op escape = quote = 0;
132 d3e1ab0c 2022-11-24 op for (cmd = buf; *cmd != '\0'; ++cmd) {
133 d3e1ab0c 2022-11-24 op if (escape) {
134 d3e1ab0c 2022-11-24 op escape = 0;
135 d3e1ab0c 2022-11-24 op continue;
136 d3e1ab0c 2022-11-24 op }
137 d3e1ab0c 2022-11-24 op if (*cmd == '\\')
138 d3e1ab0c 2022-11-24 op goto skip;
139 d3e1ab0c 2022-11-24 op if (*cmd == quote) {
140 d3e1ab0c 2022-11-24 op quote = 0;
141 d3e1ab0c 2022-11-24 op goto skip;
142 d3e1ab0c 2022-11-24 op }
143 d3e1ab0c 2022-11-24 op if (*cmd == '\'' || *cmd == '"') {
144 d3e1ab0c 2022-11-24 op quote = *cmd;
145 d3e1ab0c 2022-11-24 op goto skip;
146 d3e1ab0c 2022-11-24 op }
147 d3e1ab0c 2022-11-24 op if (quote)
148 d3e1ab0c 2022-11-24 op continue;
149 d3e1ab0c 2022-11-24 op if (brkspc && isspace((unsigned char)*cmd))
150 d3e1ab0c 2022-11-24 op break;
151 d3e1ab0c 2022-11-24 op continue;
152 d3e1ab0c 2022-11-24 op
153 d3e1ab0c 2022-11-24 op skip:
154 d3e1ab0c 2022-11-24 op memmove(cmd, cmd + 1, strlen(cmd));
155 d3e1ab0c 2022-11-24 op cmd--;
156 d3e1ab0c 2022-11-24 op }
157 d3e1ab0c 2022-11-24 op *cmd = '\0';
158 d3e1ab0c 2022-11-24 op }
159 d3e1ab0c 2022-11-24 op
160 d3e1ab0c 2022-11-24 op static int
161 d3e1ab0c 2022-11-24 op tellcmd(char *buf)
162 d3e1ab0c 2022-11-24 op {
163 d3e1ab0c 2022-11-24 op size_t i;
164 d3e1ab0c 2022-11-24 op
165 d3e1ab0c 2022-11-24 op cleanword(buf, 1);
166 d3e1ab0c 2022-11-24 op for (i = 0; i < nitems(cmds); ++i) {
167 d3e1ab0c 2022-11-24 op if (!strcmp(cmds[i].name, buf))
168 d3e1ab0c 2022-11-24 op return cmds[i].cmdtype;
169 d3e1ab0c 2022-11-24 op }
170 d3e1ab0c 2022-11-24 op
171 d3e1ab0c 2022-11-24 op return CMD_UNKNOWN;
172 d3e1ab0c 2022-11-24 op }
173 d3e1ab0c 2022-11-24 op
174 d3e1ab0c 2022-11-24 op static int
175 d3e1ab0c 2022-11-24 op tell_argno(const char *cmd, int *cmdtype)
176 d3e1ab0c 2022-11-24 op {
177 d3e1ab0c 2022-11-24 op char cmd0[64]; /* plenty of space */
178 d3e1ab0c 2022-11-24 op const char *start = cmd;
179 d3e1ab0c 2022-11-24 op int escape, quote;
180 d3e1ab0c 2022-11-24 op int argno = 0;
181 d3e1ab0c 2022-11-24 op
182 d3e1ab0c 2022-11-24 op *cmdtype = CMD_UNKNOWN;
183 d3e1ab0c 2022-11-24 op
184 d3e1ab0c 2022-11-24 op /* find which argument needs to be completed */
185 d3e1ab0c 2022-11-24 op while (*cmd) {
186 d3e1ab0c 2022-11-24 op while (isspace((unsigned char)*cmd))
187 d3e1ab0c 2022-11-24 op cmd++;
188 d3e1ab0c 2022-11-24 op if (*cmd == '\0')
189 d3e1ab0c 2022-11-24 op break;
190 d3e1ab0c 2022-11-24 op
191 d3e1ab0c 2022-11-24 op escape = quote = 0;
192 d3e1ab0c 2022-11-24 op for (; *cmd; ++cmd) {
193 d3e1ab0c 2022-11-24 op if (escape) {
194 d3e1ab0c 2022-11-24 op escape = 0;
195 d3e1ab0c 2022-11-24 op continue;
196 d3e1ab0c 2022-11-24 op }
197 d3e1ab0c 2022-11-24 op if (*cmd == '\\') {
198 d3e1ab0c 2022-11-24 op escape = 1;
199 d3e1ab0c 2022-11-24 op continue;
200 d3e1ab0c 2022-11-24 op }
201 d3e1ab0c 2022-11-24 op if (*cmd == quote) {
202 d3e1ab0c 2022-11-24 op quote = 0;
203 d3e1ab0c 2022-11-24 op continue;
204 d3e1ab0c 2022-11-24 op }
205 d3e1ab0c 2022-11-24 op if (*cmd == '\'' || *cmd == '\"') {
206 d3e1ab0c 2022-11-24 op quote = *cmd;
207 d3e1ab0c 2022-11-24 op continue;
208 d3e1ab0c 2022-11-24 op }
209 d3e1ab0c 2022-11-24 op if (quote)
210 d3e1ab0c 2022-11-24 op continue;
211 d3e1ab0c 2022-11-24 op if (isspace((unsigned char)*cmd))
212 d3e1ab0c 2022-11-24 op break;
213 d3e1ab0c 2022-11-24 op }
214 d3e1ab0c 2022-11-24 op if (isspace((unsigned char)*cmd))
215 d3e1ab0c 2022-11-24 op argno++;
216 d3e1ab0c 2022-11-24 op
217 d3e1ab0c 2022-11-24 op if (argno == 1 && strlcpy(cmd0, start, sizeof(cmd0)) <
218 d3e1ab0c 2022-11-24 op sizeof(cmd0))
219 d3e1ab0c 2022-11-24 op *cmdtype = tellcmd(cmd0);
220 d3e1ab0c 2022-11-24 op }
221 d3e1ab0c 2022-11-24 op
222 d3e1ab0c 2022-11-24 op return argno;
223 d3e1ab0c 2022-11-24 op }
224 d3e1ab0c 2022-11-24 op
225 d3e1ab0c 2022-11-24 op static char *
226 d3e1ab0c 2022-11-24 op ftp_cmdname_generator(const char *text, int state)
227 d3e1ab0c 2022-11-24 op {
228 d3e1ab0c 2022-11-24 op static size_t i, len;
229 d3e1ab0c 2022-11-24 op struct cmd *cmd;
230 d3e1ab0c 2022-11-24 op
231 d3e1ab0c 2022-11-24 op if (state == 0) {
232 d3e1ab0c 2022-11-24 op i = 0;
233 d3e1ab0c 2022-11-24 op len = strlen(text);
234 d3e1ab0c 2022-11-24 op }
235 d3e1ab0c 2022-11-24 op
236 d3e1ab0c 2022-11-24 op while (i < nitems(cmds)) {
237 d3e1ab0c 2022-11-24 op cmd = &cmds[i++];
238 d3e1ab0c 2022-11-24 op if (strncmp(text, cmd->name, len) == 0)
239 d3e1ab0c 2022-11-24 op return strdup(cmd->name);
240 d3e1ab0c 2022-11-24 op }
241 d3e1ab0c 2022-11-24 op
242 d3e1ab0c 2022-11-24 op return NULL;
243 d3e1ab0c 2022-11-24 op }
244 d3e1ab0c 2022-11-24 op
245 d3e1ab0c 2022-11-24 op static char *
246 d3e1ab0c 2022-11-24 op ftp_bool_generator(const char *text, int state)
247 d3e1ab0c 2022-11-24 op {
248 d3e1ab0c 2022-11-24 op static const char *toks[] = { "on", "off" };
249 d3e1ab0c 2022-11-24 op static size_t i, len;
250 d3e1ab0c 2022-11-24 op const char *tok;
251 d3e1ab0c 2022-11-24 op
252 d3e1ab0c 2022-11-24 op if (state == 0) {
253 d3e1ab0c 2022-11-24 op i = 0;
254 d3e1ab0c 2022-11-24 op len = strlen(text);
255 d3e1ab0c 2022-11-24 op }
256 d3e1ab0c 2022-11-24 op
257 d3e1ab0c 2022-11-24 op while ((tok = toks[i++]) != NULL) {
258 d3e1ab0c 2022-11-24 op if (strncmp(text, tok, len) == 0)
259 d3e1ab0c 2022-11-24 op return strdup(tok);
260 d3e1ab0c 2022-11-24 op }
261 d3e1ab0c 2022-11-24 op return NULL;
262 d3e1ab0c 2022-11-24 op }
263 d3e1ab0c 2022-11-24 op
264 d3e1ab0c 2022-11-24 op static char *
265 d3e1ab0c 2022-11-24 op ftp_dirent_generator(const char *text, int state)
266 d3e1ab0c 2022-11-24 op {
267 d3e1ab0c 2022-11-24 op static size_t i, len;
268 d3e1ab0c 2022-11-24 op const char *entry;
269 d3e1ab0c 2022-11-24 op
270 d3e1ab0c 2022-11-24 op if (state == 0) {
271 d3e1ab0c 2022-11-24 op i = 0;
272 d3e1ab0c 2022-11-24 op len = strlen(text);
273 d3e1ab0c 2022-11-24 op }
274 d3e1ab0c 2022-11-24 op
275 d3e1ab0c 2022-11-24 op while (i < compl_state.len) {
276 d3e1ab0c 2022-11-24 op entry = compl_state.entries[i++];
277 d3e1ab0c 2022-11-24 op if (strncmp(text, entry, len) == 0)
278 d3e1ab0c 2022-11-24 op return strdup(entry);
279 d3e1ab0c 2022-11-24 op }
280 d3e1ab0c 2022-11-24 op return NULL;
281 65b37bc8 2022-12-21 op }
282 65b37bc8 2022-12-21 op
283 65b37bc8 2022-12-21 op static inline void
284 65b37bc8 2022-12-21 op set_compl_prfx(const char *path)
285 65b37bc8 2022-12-21 op {
286 65b37bc8 2022-12-21 op if (!strcmp(path, "."))
287 65b37bc8 2022-12-21 op strlcpy(compl_prfx, "", sizeof(compl_prfx));
288 65b37bc8 2022-12-21 op else
289 65b37bc8 2022-12-21 op strlcpy(compl_prfx, path, sizeof(compl_prfx));
290 65b37bc8 2022-12-21 op }
291 65b37bc8 2022-12-21 op
292 65b37bc8 2022-12-21 op static inline void
293 65b37bc8 2022-12-21 op inplace_dirname(char *path, size_t len)
294 65b37bc8 2022-12-21 op {
295 65b37bc8 2022-12-21 op char *t;
296 65b37bc8 2022-12-21 op
297 65b37bc8 2022-12-21 op if ((t = strrchr(path, '/')) == NULL)
298 65b37bc8 2022-12-21 op strlcpy(path, ".", len);
299 65b37bc8 2022-12-21 op else
300 65b37bc8 2022-12-21 op t[1] = '\0';
301 d3e1ab0c 2022-11-24 op }
302 d3e1ab0c 2022-11-24 op
303 d3e1ab0c 2022-11-24 op static char **
304 d3e1ab0c 2022-11-24 op ftp_remote_files(const char *text, int start, int end)
305 d3e1ab0c 2022-11-24 op {
306 847e80dc 2022-12-21 op char *t, dir[PATH_MAX];
307 d3e1ab0c 2022-11-24 op
308 847e80dc 2022-12-21 op strlcpy(dir, text, sizeof(dir));
309 847e80dc 2022-12-21 op cleanword(dir, 0);
310 d3e1ab0c 2022-11-24 op
311 847e80dc 2022-12-21 op if (!strcmp(dir, "..")) {
312 d3e1ab0c 2022-11-24 op char **cs;
313 d3e1ab0c 2022-11-24 op if ((cs = calloc(2, sizeof(*cs))) == NULL)
314 d3e1ab0c 2022-11-24 op return NULL;
315 d3e1ab0c 2022-11-24 op cs[0] = strdup("../");
316 d3e1ab0c 2022-11-24 op return cs;
317 d3e1ab0c 2022-11-24 op }
318 d3e1ab0c 2022-11-24 op
319 847e80dc 2022-12-21 op t = dir;
320 847e80dc 2022-12-21 op if (!strncmp(t, "./", 2)) {
321 847e80dc 2022-12-21 op t++;
322 847e80dc 2022-12-21 op while (*t == '/')
323 847e80dc 2022-12-21 op t++;
324 847e80dc 2022-12-21 op memmove(dir, t, strlen(t) + 1);
325 65b37bc8 2022-12-21 op }
326 d3e1ab0c 2022-11-24 op
327 65b37bc8 2022-12-21 op if (*dir && dir[strlen(dir) - 1] != '/')
328 65b37bc8 2022-12-21 op strlcat(dir, "/", sizeof(dir));
329 d3e1ab0c 2022-11-24 op
330 65b37bc8 2022-12-21 op set_compl_prfx(dir);
331 d3e1ab0c 2022-11-24 op compl_state_reset();
332 65b37bc8 2022-12-21 op if (dir_listing(dir, compl_add_entry, 0) == -1) {
333 65b37bc8 2022-12-21 op if (*dir)
334 65b37bc8 2022-12-21 op dir[strlen(dir) - 1] = '\0';
335 65b37bc8 2022-12-21 op inplace_dirname(dir, sizeof(dir));
336 65b37bc8 2022-12-21 op set_compl_prfx(dir);
337 65b37bc8 2022-12-21 op
338 65b37bc8 2022-12-21 op compl_state_reset();
339 65b37bc8 2022-12-21 op if (dir_listing(dir, compl_add_entry, 0) == -1)
340 65b37bc8 2022-12-21 op return NULL;
341 65b37bc8 2022-12-21 op }
342 65b37bc8 2022-12-21 op
343 d3e1ab0c 2022-11-24 op return rl_completion_matches(text, ftp_dirent_generator);
344 d3e1ab0c 2022-11-24 op }
345 d3e1ab0c 2022-11-24 op
346 d3e1ab0c 2022-11-24 op static char **
347 d3e1ab0c 2022-11-24 op ftp_completion(const char *text, int start, int end)
348 d3e1ab0c 2022-11-24 op {
349 d3e1ab0c 2022-11-24 op int argno, cmdtype;
350 d3e1ab0c 2022-11-24 op char *line;
351 d3e1ab0c 2022-11-24 op
352 d3e1ab0c 2022-11-24 op /* don't fall back on the default completion system by default */
353 d3e1ab0c 2022-11-24 op rl_attempted_completion_over = 1;
354 4c9b5bd4 2022-12-21 op
355 4c9b5bd4 2022-12-21 op /* append a space after selecting a command */
356 4c9b5bd4 2022-12-21 op rl_completion_append_character = ' ';
357 d3e1ab0c 2022-11-24 op
358 d3e1ab0c 2022-11-24 op if ((line = rl_copy_text(0, start)) == NULL)
359 d3e1ab0c 2022-11-24 op return NULL;
360 d3e1ab0c 2022-11-24 op
361 d3e1ab0c 2022-11-24 op argno = tell_argno(line, &cmdtype);
362 d3e1ab0c 2022-11-24 op free(line);
363 d3e1ab0c 2022-11-24 op if (argno == 0)
364 d3e1ab0c 2022-11-24 op return rl_completion_matches(text, ftp_cmdname_generator);
365 d3e1ab0c 2022-11-24 op
366 4c9b5bd4 2022-12-21 op /* but not for file completions */
367 4c9b5bd4 2022-12-21 op rl_completion_append_character = '\0';
368 4c9b5bd4 2022-12-21 op
369 d3e1ab0c 2022-11-24 op switch (cmdtype) {
370 d3e1ab0c 2022-11-24 op case CMD_BELL:
371 d3e1ab0c 2022-11-24 op case CMD_HEXDUMP:
372 d3e1ab0c 2022-11-24 op case CMD_VERBOSE:
373 d3e1ab0c 2022-11-24 op if (argno != 1)
374 d3e1ab0c 2022-11-24 op return NULL;
375 d3e1ab0c 2022-11-24 op return rl_completion_matches(text, ftp_bool_generator);
376 d3e1ab0c 2022-11-24 op
377 d3e1ab0c 2022-11-24 op case CMD_BYE:
378 d3e1ab0c 2022-11-24 op case CMD_LPWD:
379 d3e1ab0c 2022-11-24 op /* no args */
380 d3e1ab0c 2022-11-24 op return NULL;
381 d3e1ab0c 2022-11-24 op
382 d3e1ab0c 2022-11-24 op case CMD_CD:
383 d3e1ab0c 2022-11-24 op case CMD_EDIT:
384 d3e1ab0c 2022-11-24 op case CMD_LS:
385 d3e1ab0c 2022-11-24 op case CMD_PAGE:
386 d3e1ab0c 2022-11-24 op if (argno != 1)
387 d3e1ab0c 2022-11-24 op return NULL;
388 d3e1ab0c 2022-11-24 op /* fallthrough */
389 d3e1ab0c 2022-11-24 op case CMD_RM:
390 d3e1ab0c 2022-11-24 op return ftp_remote_files(text, start, end);
391 d3e1ab0c 2022-11-24 op
392 d3e1ab0c 2022-11-24 op case CMD_GET:
393 d3e1ab0c 2022-11-24 op if (argno > 2)
394 d3e1ab0c 2022-11-24 op return NULL;
395 d3e1ab0c 2022-11-24 op if (argno == 2)
396 d3e1ab0c 2022-11-24 op return ftp_remote_files(text, start, end);
397 d3e1ab0c 2022-11-24 op /* try local */
398 d3e1ab0c 2022-11-24 op rl_attempted_completion_over = 0;
399 d3e1ab0c 2022-11-24 op return NULL;
400 d3e1ab0c 2022-11-24 op
401 d3e1ab0c 2022-11-24 op case CMD_LCD:
402 d3e1ab0c 2022-11-24 op if (argno != 1)
403 d3e1ab0c 2022-11-24 op return NULL;
404 d3e1ab0c 2022-11-24 op /* try local */
405 d3e1ab0c 2022-11-24 op rl_attempted_completion_over = 0;
406 d3e1ab0c 2022-11-24 op return NULL;
407 d3e1ab0c 2022-11-24 op
408 d3e1ab0c 2022-11-24 op case CMD_PIPE:
409 d3e1ab0c 2022-11-24 op if (argno > 2)
410 d3e1ab0c 2022-11-24 op return NULL;
411 d3e1ab0c 2022-11-24 op if (argno == 1)
412 d3e1ab0c 2022-11-24 op return ftp_remote_files(text, start, end);
413 d3e1ab0c 2022-11-24 op /* try local */
414 d3e1ab0c 2022-11-24 op rl_attempted_completion_over = 0;
415 d3e1ab0c 2022-11-24 op return NULL;
416 d3e1ab0c 2022-11-24 op
417 d3e1ab0c 2022-11-24 op case CMD_PUT:
418 d3e1ab0c 2022-11-24 op if (argno > 2)
419 d3e1ab0c 2022-11-24 op return NULL;
420 d3e1ab0c 2022-11-24 op if (argno == 1) {
421 d3e1ab0c 2022-11-24 op /* try local */
422 d3e1ab0c 2022-11-24 op rl_attempted_completion_over = 0;
423 d3e1ab0c 2022-11-24 op return NULL;
424 d3e1ab0c 2022-11-24 op }
425 d3e1ab0c 2022-11-24 op return ftp_remote_files(text, start, end);
426 d3e1ab0c 2022-11-24 op
427 d3e1ab0c 2022-11-24 op case CMD_RENAME:
428 d3e1ab0c 2022-11-24 op if (argno > 2)
429 d3e1ab0c 2022-11-24 op return NULL;
430 d3e1ab0c 2022-11-24 op return ftp_remote_files(text, start, end);
431 d3e1ab0c 2022-11-24 op }
432 d3e1ab0c 2022-11-24 op
433 d3e1ab0c 2022-11-24 op return NULL;
434 d3e1ab0c 2022-11-24 op }
435 d3e1ab0c 2022-11-24 op
436 d3e1ab0c 2022-11-24 op static int
437 d3e1ab0c 2022-11-24 op ftp_quoted(char *line, int index)
438 d3e1ab0c 2022-11-24 op {
439 d3e1ab0c 2022-11-24 op if (index > 0 && line[index - 1] == '\\')
440 d3e1ab0c 2022-11-24 op return !ftp_quoted(line, index - 1);
441 d3e1ab0c 2022-11-24 op return 0;
442 d3e1ab0c 2022-11-24 op }
443 d3e1ab0c 2022-11-24 op
444 d3e1ab0c 2022-11-24 op void
445 d3e1ab0c 2022-11-24 op compl_setup(void)
446 d3e1ab0c 2022-11-24 op {
447 d3e1ab0c 2022-11-24 op rl_attempted_completion_function = ftp_completion;
448 d3e1ab0c 2022-11-24 op rl_completer_word_break_characters = "\t ";
449 d3e1ab0c 2022-11-24 op rl_completer_quote_characters = "\"'";
450 d3e1ab0c 2022-11-24 op rl_char_is_quoted_p = ftp_quoted;
451 d3e1ab0c 2022-11-24 op }
452 d3e1ab0c 2022-11-24 op
453 d3e1ab0c 2022-11-24 op #endif