mat: add matrix operations
[transsip-mirror.git] / src / cli.c
blob089de603f82d154a265a450fdc857132bc6086b2
1 /*
2 * transsip - the telephony toolkit
3 * By Daniel Borkmann <daniel@transsip.org>
4 * Copyright 2011, 2012 Daniel Borkmann <dborkma@tik.ee.ethz.ch>
5 * Subject to the GPL, version 2.
6 */
8 #include <stdio.h>
9 #include <unistd.h>
10 #include <signal.h>
11 #include <string.h>
12 #include <errno.h>
13 #include <readline/readline.h>
14 #include <readline/history.h>
15 #include <ctype.h>
17 #include "clicmds.h"
18 #include "xmalloc.h"
19 #include "xutils.h"
20 #include "built_in.h"
21 #include "call_notifier.h"
22 #include "die.h"
24 #define MAX_MENU_ELEMS 100
25 #define FETCH_LIST 0
26 #define FETCH_ELEM 1
28 static int exit_val = 0;
30 volatile sig_atomic_t quit = 0;
32 static char *prompt = NULL;
34 static size_t prompt_len = 256;
36 extern volatile sig_atomic_t stun_done;
38 extern int print_stun_probe(char *server, int sport, int tport);
40 extern void init_cli_cmds(int ti, int to);
42 static struct shell_cmd show_node[] = {
43 { "settings", cmd_help, "Show settings", NULL, },
44 { "pubkey", cmd_help, "Show my public key", NULL, },
45 { "contacts", cmd_help, "Show my contacts", NULL, },
46 { NULL, NULL, NULL, NULL, },
49 static struct shell_cmd import_node[] = {
50 { "contact", cmd_help, "Import a contact user/pubkey", NULL, },
51 { NULL, NULL, NULL, NULL, },
54 static struct shell_cmd cmd_tree[] = {
55 { "help", cmd_help, "Show help", NULL, },
56 { "quit", cmd_quit, "Exit shell", NULL, },
57 { "call", cmd_call, "Perform a call", NULL, },
58 { "hangup", cmd_hangup, "Hangup the current call", NULL, },
59 { "take", cmd_take, "Take a call", NULL, },
60 { "show", NULL, "Show information", show_node, },
61 { "import", NULL, "Import things", import_node, },
62 { NULL, NULL, NULL, NULL, },
65 static void fetch_user(char *user, size_t len)
67 int ret = getlogin_r(user, len);
68 if (ret)
69 strlcpy(user, "anon", len);
70 user[len - 1] = 0;
73 static void fetch_host(char *host, size_t len)
75 int ret = gethostname(host, len);
76 if (ret)
77 strlcpy(host, "local", len);
78 host[len - 1] = 0;
81 static void setup_prompt(char *prompt, size_t len, char *state)
83 char user[64], host[64];
85 fetch_user(user, sizeof(user));
86 fetch_host(host, sizeof(host));
88 memset(prompt, 0, len);
89 slprintf(prompt, len, "\r%s@%s:%s> ", user, host, state);
92 static void find_list(struct shell_cmd **list, const char *token)
94 int i;
95 char *cmd;
97 for (i = 0; (cmd = (*list)[i].name); ++i) {
98 if (strncmp(cmd, token, min(strlen(token), strlen(cmd))))
99 continue;
100 if (strlen(cmd) != strlen(token))
101 continue;
102 if ((*list)[i].sub_cmd != NULL)
103 (*list) = (*list)[i].sub_cmd;
104 break;
108 static struct shell_cmd *find_elem(struct shell_cmd *list, const char *token)
110 int i;
111 char *cmd;
112 struct shell_cmd *elem;
114 if (!list || !token)
115 return NULL;
117 for (i = 0, elem = NULL; (cmd = list[i].name); ++i) {
118 if (strncmp(cmd, token, min(strlen(token), strlen(cmd))))
119 continue;
120 elem = &list[i];
123 return elem;
126 static char *get_next_token(char *line, int *off)
128 int i = *off;
129 char *token;
131 while (line[i] && isspace(line[i]))
132 i++;
133 token = line + i;
134 while (line[i] && !isspace(line[i]))
135 i++;
136 if (line[i])
137 line[i++] = '\0';
138 *off = i;
140 return token;
143 static struct shell_cmd *walk_commands(char *line_buffer, int len, int ret)
145 int off = 0;
146 char *token, *line;
147 struct shell_cmd *list, *elem = NULL;
149 list = cmd_tree;
150 line = xmalloc(len + 1);
151 strlcpy(line, line_buffer, len + 1);
153 while (list && len > 0) {
154 token = get_next_token(line, &off);
155 if (strlen(token) == 0)
156 break;
158 find_list(&list, token);
159 elem = find_elem(list, token);
160 if (elem) {
161 if (strlen(elem->name) == strlen(token))
162 list = NULL;
163 break;
167 xfree(line);
168 return (ret == FETCH_ELEM ? elem : list);
171 static char **__cmd_complete_line(const char *text, char *line_buffer, int point)
173 int i, j, wlen;
174 char *word, *cmd, **list;
175 struct shell_cmd *curr;
177 word = line_buffer + point - strlen(text);
178 curr = walk_commands(line_buffer, strlen(line_buffer), FETCH_LIST);
179 if (!curr)
180 return NULL;
182 wlen = strlen(word);
183 list = xzmalloc(MAX_MENU_ELEMS * sizeof(*list));
185 for (i = j = 0; (cmd = curr[j].name); ++j)
186 if (strncmp(cmd, word, min(wlen, strlen(cmd))) == 0)
187 list[i++] = xstrdup(curr[j].name);
189 return list;
192 static char *cmd_line_completion(const char *text, int matches,
193 char *line_buffer, int point)
195 static char **list = NULL;
196 static int i;
197 char *curr = NULL;
199 if (matches == 0) {
200 if (list) {
201 xfree(list);
202 list = NULL;
205 i = 0;
206 list = __cmd_complete_line(text, line_buffer, point);
209 if (list) {
210 curr = list[i];
211 if (curr)
212 ++i;
215 return curr;
218 char *cmd_completion(const char *text, int matches)
220 return cmd_line_completion(text, matches, rl_line_buffer, rl_point);
223 static int process_command(char *line)
225 int i = 0;
226 char *token, *ptr;
227 struct shell_cmd *curr;
229 curr = walk_commands(line, strlen(line), FETCH_ELEM);
230 if (!curr || curr->callback == NULL)
231 goto err;
233 ptr = strstr(line, curr->name);
234 if (ptr == NULL)
235 goto err;
236 ptr += strlen(curr->name);
238 while (ptr[i] && isspace(ptr[i]))
239 i++;
240 token = ptr + i;
242 return curr->callback(token);
243 err:
244 printf("Ooops, bad command! Try `help` for more information.\n");
245 return -EINVAL;
248 void clear_term(int signal)
250 if (rl_end)
251 rl_kill_line(-1, 0);
252 rl_crlf();
253 rl_refresh_line(0, 0);
254 rl_free_line_state();
257 static void setup_readline(void)
259 rl_readline_name = "transsip";
260 rl_completion_entry_function = cmd_completion;
261 rl_catch_signals = 0;
262 rl_catch_sigwinch = 1;
263 rl_set_signals();
265 register_signal(SIGINT, clear_term);
268 static char *strip_white(char *line)
270 char *l, *t;
272 for (l = line; isspace(*l); l++)
274 if (*l == 0)
275 return l;
277 t = l + strlen(l) - 1;
278 while (t > l && isspace(*t))
279 t--;
280 *++t = '\0';
282 return l;
285 static int call_event_hook_handle_changed(int num)
287 switch (num) {
288 case CALL_STATE_MACHINE_IDLE:
289 setup_prompt(prompt, prompt_len, "idle");
290 break;
291 case CALL_STATE_MACHINE_CALLIN:
292 setup_prompt(prompt, prompt_len, "call-in");
293 break;
294 case CALL_STATE_MACHINE_CALLOUT:
295 setup_prompt(prompt, prompt_len, "call-out");
296 break;
297 case CALL_STATE_MACHINE_SPEAKING:
298 setup_prompt(prompt, prompt_len, "speaking");
299 break;
300 default:
301 break;
304 return 0;
307 static int call_event_hook(const struct event_block *self,
308 unsigned long event, const void *arg)
310 int ret = 0;
312 switch (event) {
313 case CALL_STATE_MACHINE_CHANGED: {
314 int num = *(int *) arg;
315 ret = call_event_hook_handle_changed(num);
316 break; }
317 default:
318 break;
321 return ret;
324 struct event_block call_event = {
325 .prio = PRIO_MEDIUM,
326 .hook = call_event_hook,
329 static inline void print_shell_header(void)
331 printf("\n%s%s%s shell\n\n", colorize_start(bold),
332 PROGNAME_STRING " " VERSION_STRING, colorize_end());
335 static inline void init_stun(void)
337 int ret = print_stun_probe("stunserver.org", 3478, 30111);
338 if (ret < 0)
339 printf("STUN failed!\n");
340 stun_done = 1;
341 fflush(stdout);
344 int cmd_help(char *args)
346 struct shell_cmd *cmd;
347 int i, entries = (sizeof(cmd_tree) / sizeof(cmd_tree[0])) - 1;
349 if (!*args) {
350 for (i = 0; i < entries; ++i)
351 printf("%s - %s\n", cmd_tree[i].name, cmd_tree[i].doc);
352 return 0;
355 cmd = walk_commands(args, strlen(args), FETCH_ELEM);
356 if (!cmd || !cmd->doc || !cmd->name)
357 return -EINVAL;
359 printf("%s - %s\n", cmd->name, cmd->doc);
360 return 0;
363 int cmd_quit(char *args)
365 quit = 1;
366 return 0;
369 void enter_shell_loop(int ti, int to)
371 char *line, *cmd;
373 init_cli_cmds(ti, to);
375 prompt = xzmalloc(prompt_len);
376 setup_prompt(prompt, prompt_len, "idle");
377 setup_readline();
379 print_shell_header();
380 init_stun();
382 register_call_notifier(&call_event);
384 while (!quit) {
385 line = readline(prompt);
386 if (!line) {
387 printf("\n");
388 cmd_quit(NULL);
389 break;
392 cmd = strip_white(line);
393 if (*cmd) {
394 add_history(cmd);
395 exit_val = process_command(cmd);
398 xfree(line);
401 xfree(prompt);
402 printf("\n");