reenabled stun probe
[transsip.git] / src / cli.c
blob2d150164eaa4cc622fae83cc0e5f3db2f4944de9
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <signal.h>
4 #include <string.h>
5 #include <errno.h>
6 #include <readline/readline.h>
7 #include <readline/history.h>
8 #include <ctype.h>
10 #include "clicmds.h"
11 #include "xmalloc.h"
12 #include "xutils.h"
13 #include "built-in.h"
14 #include "die.h"
16 #define FETCH_LIST 0
17 #define FETCH_ELEM 1
19 static int exit_val = 0;
21 sig_atomic_t quit = 0;
23 extern sig_atomic_t stun_done;
25 extern void print_stun_probe(char *server, int sport, int tport);
27 static void fetch_user(char *user, size_t len)
29 int ret = getlogin_r(user, len);
30 if (ret)
31 strlcpy(user, "anon", len);
32 user[len - 1] = 0;
35 static void fetch_host(char *host, size_t len)
37 int ret = gethostname(host, len);
38 if (ret)
39 strlcpy(host, "local", len);
40 host[len - 1] = 0;
43 static void setup_prompt(char *prompt, size_t len)
45 char user[64], host[64];
47 fetch_user(user, sizeof(user));
48 fetch_host(host, sizeof(host));
50 memset(prompt, 0, len);
51 slprintf(prompt, len, "%s@%s> ", user, host);
54 static void find_list(struct shell_cmd **list, const char *token)
56 int i;
57 char *cmd;
59 for (i = 0; (cmd = (*list)[i].name); ++i) {
60 if (strncmp(cmd, token, min(strlen(token), strlen(cmd))))
61 continue;
62 if (strlen(cmd) != strlen(token))
63 continue;
64 if ((*list)[i].sub_cmd != NULL)
65 (*list) = (*list)[i].sub_cmd;
66 break;
70 static struct shell_cmd *find_elem(struct shell_cmd *list, const char *token)
72 int i;
73 char *cmd;
74 struct shell_cmd *elem;
76 if (!list || !token)
77 return NULL;
79 for (i = 0, elem = NULL; (cmd = list[i].name); ++i) {
80 if (strncmp(cmd, token, min(strlen(token), strlen(cmd))))
81 continue;
82 elem = &list[i];
85 return elem;
88 static char *get_next_token(char *line, int *off)
90 int i = *off;
91 char *token;
93 while (line[i] && isspace(line[i]))
94 i++;
95 token = line + i;
96 while (line[i] && !isspace(line[i]))
97 i++;
98 if (line[i])
99 line[i++] = '\0';
100 *off = i;
102 return token;
105 static struct shell_cmd *walk_commands(char *line_buffer, int len, int ret)
107 int off = 0;
108 char *token, *line;
109 struct shell_cmd *list, *elem = NULL;
111 list = cmd_tree;
112 line = xmalloc(len + 1);
113 strlcpy(line, line_buffer, len + 1);
115 while (list && len > 0) {
116 token = get_next_token(line, &off);
117 if (strlen(token) == 0)
118 break;
120 find_list(&list, token);
121 elem = find_elem(list, token);
122 if (elem) {
123 if (strlen(elem->name) == strlen(token))
124 list = NULL;
125 break;
129 xfree(line);
130 return (ret == FETCH_ELEM ? elem : list);
133 static char **__cmd_complete_line(const char *text, char *line_buffer, int point)
135 int i, j, wlen;
136 char *word, *cmd, **list;
137 struct shell_cmd *curr;
139 word = line_buffer + point - strlen(text);
140 curr = walk_commands(line_buffer, strlen(line_buffer), FETCH_LIST);
141 if (!curr)
142 return NULL;
144 wlen = strlen(word);
145 list = xzmalloc(MAX_MENU_ELEMS * sizeof(*list));
147 for (i = j = 0; (cmd = curr[j].name); ++j)
148 if (strncmp(cmd, word, min(wlen, strlen(cmd))) == 0)
149 list[i++] = xstrdup(curr[j].name);
151 return list;
154 static char *cmd_line_completion(const char *text, int matches,
155 char *line_buffer, int point)
157 static char **list = NULL;
158 static int i;
159 char *curr = NULL;
161 if (matches == 0) {
162 if (list) {
163 xfree(list);
164 list = NULL;
167 i = 0;
168 list = __cmd_complete_line(text, line_buffer, point);
171 if (list) {
172 curr = list[i];
173 if (curr)
174 ++i;
177 return curr;
180 char *cmd_completion(const char *text, int matches)
182 return cmd_line_completion(text, matches, rl_line_buffer, rl_point);
185 static int process_command(char *line)
187 int i = 0;
188 char *token, *ptr;
189 struct shell_cmd *curr;
191 curr = walk_commands(line, strlen(line), FETCH_ELEM);
192 if (!curr || curr->callback == NULL)
193 goto err;
195 ptr = strstr(line, curr->name);
196 if (ptr == NULL)
197 goto err;
198 ptr += strlen(curr->name);
200 while (ptr[i] && isspace(ptr[i]))
201 i++;
202 token = ptr + i;
204 return curr->callback(token);
205 err:
206 printf("Ooops, bad command! Try `help` for more information.\n");
207 return -EINVAL;
210 void clear_term(int signal)
212 if (rl_end)
213 rl_kill_line(-1, 0);
214 rl_crlf();
215 rl_refresh_line(0, 0);
216 rl_free_line_state();
219 static void setup_readline(void)
221 rl_readline_name = "transsip";
222 rl_completion_entry_function = cmd_completion;
223 rl_catch_signals = 0;
224 rl_catch_sigwinch = 1;
225 rl_set_signals();
227 register_signal(SIGINT, clear_term);
230 static char *strip_white(char *line)
232 char *l, *t;
234 for (l = line; isspace(*l); l++)
236 if (*l == 0)
237 return l;
239 t = l + strlen(l) - 1;
240 while (t > l && isspace(*t))
241 t--;
242 *++t = '\0';
244 return l;
247 static int tsocki, tsocko;
249 void enter_shell_loop(int __tsocki, int __tsocko)
251 char *prompt;
252 char *line, *cmd;
253 size_t prompt_len = 256;
255 tsocki = __tsocki;
256 tsocko = __tsocko;
258 prompt = xzmalloc(prompt_len);
259 setup_prompt(prompt, prompt_len);
260 setup_readline();
262 printf("\n%s%s%s shell\n\n", colorize_start(bold),
263 PROGNAME_STRING " " VERSION_STRING, colorize_end());
264 print_stun_probe("stunserver.org", 3478, 30111);
265 stun_done = 1;
266 fflush(stdout);
268 while (!quit) {
269 line = readline(prompt);
270 if (!line) {
271 printf("\n");
272 break;
275 cmd = strip_white(line);
276 if (*cmd) {
277 add_history(cmd);
278 exit_val = process_command(cmd);
281 xfree(line);
284 xfree(prompt);
285 printf("\n");
288 int cmd_help(char *args)
290 struct shell_cmd *cmd;
291 int i, entries = (sizeof(cmd_tree) / sizeof(cmd_tree[0])) - 1;
293 if (!*args) {
294 for (i = 0; i < entries; ++i)
295 printf("%s - %s\n", cmd_tree[i].name, cmd_tree[i].doc);
296 return 0;
299 cmd = walk_commands(args, strlen(args), FETCH_ELEM);
300 if (!cmd || !cmd->doc || !cmd->name)
301 return -EINVAL;
303 printf("%s - %s\n", cmd->name, cmd->doc);
304 return 0;
307 int cmd_quit(char *args)
309 quit = 1;
310 return 0;
313 int cmd_stat(char *args)
315 printf("%d\n", exit_val);
316 return 0;
319 int cmd_call(char *arg)
321 int argc;
322 ssize_t ret;
323 char **argv = strntoargv(arg, strlen(arg), &argc);
324 struct cli_pkt cpkt;
326 if (argc != 2) {
327 whine("Missing arguments: call <ipv4/ipv6/host> <port>\n");
328 xfree(argv);
329 return -EINVAL;
331 if (strlen(argv[0]) > ADDRSIZ || strlen(argv[1]) > PORTSIZ) {
332 whine("Arguments too long!\n");
333 xfree(argv);
334 return -EINVAL;
337 memset(&cpkt, 0, sizeof(cpkt));
338 cpkt.ring = 1;
339 strlcpy(cpkt.address, argv[0], sizeof(cpkt.address));
340 strlcpy(cpkt.port, argv[1], sizeof(cpkt.port));
342 ret = write(tsocko, &cpkt, sizeof(cpkt));
343 ret = write(tsocko, &cpkt, sizeof(cpkt)); //XXX
344 if (ret != sizeof(cpkt)) {
345 whine("Error notifying thread!\n");
346 return -EIO;
349 printf("Calling ... hang up the line with: hangup\n");
351 xfree(argv);
352 return 0;
355 int cmd_hangup(char *arg)
357 ssize_t ret;
358 struct cli_pkt cpkt;
360 memset(&cpkt, 0, sizeof(cpkt));
361 cpkt.fin = 1;
363 ret = write(tsocko, &cpkt, sizeof(cpkt));
364 if (ret != sizeof(cpkt)) {
365 whine("Error notifying thread!\n");
366 return -EIO;
369 return 0;
372 int cmd_take(char *arg)
374 ssize_t ret;
375 struct cli_pkt cpkt;
377 memset(&cpkt, 0, sizeof(cpkt));
378 cpkt.take = 1;
380 ret = write(tsocko, &cpkt, sizeof(cpkt));
381 if (ret != sizeof(cpkt)) {
382 whine("Error notifying thread!\n");
383 return -EIO;
386 return 0;