alsa: changed ret values
[transsip.git] / src / cli.c
blob42a97dc52d41d45c7c149828b570992710d39286
1 /*
2 * transsip - the telephony network
3 * By Daniel Borkmann <daniel@transsip.org>
4 * Copyright 2011, 2012 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,
5 * Swiss federal institute of technology (ETH Zurich)
6 * Subject to the GPL, version 2.
7 */
9 #include <stdio.h>
10 #include <unistd.h>
11 #include <signal.h>
12 #include <string.h>
13 #include <errno.h>
14 #include <readline/readline.h>
15 #include <readline/history.h>
16 #include <ctype.h>
18 #include "clicmds.h"
19 #include "xmalloc.h"
20 #include "xutils.h"
21 #include "built-in.h"
22 #include "call-notifier.h"
23 #include "die.h"
25 #define FETCH_LIST 0
26 #define FETCH_ELEM 1
28 static int exit_val = 0, tsocki, tsocko;
29 sig_atomic_t quit = 0;
30 static char *prompt = NULL;
31 static size_t prompt_len = 256;
33 extern sig_atomic_t stun_done;
34 extern int print_stun_probe(char *server, int sport, int tport);
36 static void fetch_user(char *user, size_t len)
38 int ret = getlogin_r(user, len);
39 if (ret)
40 strlcpy(user, "anon", len);
41 user[len - 1] = 0;
44 static void fetch_host(char *host, size_t len)
46 int ret = gethostname(host, len);
47 if (ret)
48 strlcpy(host, "local", len);
49 host[len - 1] = 0;
52 static void setup_prompt(char *prompt, size_t len, char *state)
54 char user[64], host[64];
56 fetch_user(user, sizeof(user));
57 fetch_host(host, sizeof(host));
59 memset(prompt, 0, len);
60 slprintf(prompt, len, "\r%s@%s:%s> ", user, host, state);
63 static void find_list(struct shell_cmd **list, const char *token)
65 int i;
66 char *cmd;
68 for (i = 0; (cmd = (*list)[i].name); ++i) {
69 if (strncmp(cmd, token, min(strlen(token), strlen(cmd))))
70 continue;
71 if (strlen(cmd) != strlen(token))
72 continue;
73 if ((*list)[i].sub_cmd != NULL)
74 (*list) = (*list)[i].sub_cmd;
75 break;
79 static struct shell_cmd *find_elem(struct shell_cmd *list, const char *token)
81 int i;
82 char *cmd;
83 struct shell_cmd *elem;
85 if (!list || !token)
86 return NULL;
88 for (i = 0, elem = NULL; (cmd = list[i].name); ++i) {
89 if (strncmp(cmd, token, min(strlen(token), strlen(cmd))))
90 continue;
91 elem = &list[i];
94 return elem;
97 static char *get_next_token(char *line, int *off)
99 int i = *off;
100 char *token;
102 while (line[i] && isspace(line[i]))
103 i++;
104 token = line + i;
105 while (line[i] && !isspace(line[i]))
106 i++;
107 if (line[i])
108 line[i++] = '\0';
109 *off = i;
111 return token;
114 static struct shell_cmd *walk_commands(char *line_buffer, int len, int ret)
116 int off = 0;
117 char *token, *line;
118 struct shell_cmd *list, *elem = NULL;
120 list = cmd_tree;
121 line = xmalloc(len + 1);
122 strlcpy(line, line_buffer, len + 1);
124 while (list && len > 0) {
125 token = get_next_token(line, &off);
126 if (strlen(token) == 0)
127 break;
129 find_list(&list, token);
130 elem = find_elem(list, token);
131 if (elem) {
132 if (strlen(elem->name) == strlen(token))
133 list = NULL;
134 break;
138 xfree(line);
139 return (ret == FETCH_ELEM ? elem : list);
142 static char **__cmd_complete_line(const char *text, char *line_buffer, int point)
144 int i, j, wlen;
145 char *word, *cmd, **list;
146 struct shell_cmd *curr;
148 word = line_buffer + point - strlen(text);
149 curr = walk_commands(line_buffer, strlen(line_buffer), FETCH_LIST);
150 if (!curr)
151 return NULL;
153 wlen = strlen(word);
154 list = xzmalloc(MAX_MENU_ELEMS * sizeof(*list));
156 for (i = j = 0; (cmd = curr[j].name); ++j)
157 if (strncmp(cmd, word, min(wlen, strlen(cmd))) == 0)
158 list[i++] = xstrdup(curr[j].name);
160 return list;
163 static char *cmd_line_completion(const char *text, int matches,
164 char *line_buffer, int point)
166 static char **list = NULL;
167 static int i;
168 char *curr = NULL;
170 if (matches == 0) {
171 if (list) {
172 xfree(list);
173 list = NULL;
176 i = 0;
177 list = __cmd_complete_line(text, line_buffer, point);
180 if (list) {
181 curr = list[i];
182 if (curr)
183 ++i;
186 return curr;
189 char *cmd_completion(const char *text, int matches)
191 return cmd_line_completion(text, matches, rl_line_buffer, rl_point);
194 static int process_command(char *line)
196 int i = 0;
197 char *token, *ptr;
198 struct shell_cmd *curr;
200 curr = walk_commands(line, strlen(line), FETCH_ELEM);
201 if (!curr || curr->callback == NULL)
202 goto err;
204 ptr = strstr(line, curr->name);
205 if (ptr == NULL)
206 goto err;
207 ptr += strlen(curr->name);
209 while (ptr[i] && isspace(ptr[i]))
210 i++;
211 token = ptr + i;
213 return curr->callback(token);
214 err:
215 printf("Ooops, bad command! Try `help` for more information.\n");
216 return -EINVAL;
219 void clear_term(int signal)
221 if (rl_end)
222 rl_kill_line(-1, 0);
223 rl_crlf();
224 rl_refresh_line(0, 0);
225 rl_free_line_state();
228 static void setup_readline(void)
230 rl_readline_name = "transsip";
231 rl_completion_entry_function = cmd_completion;
232 rl_catch_signals = 0;
233 rl_catch_sigwinch = 1;
234 rl_set_signals();
236 register_signal(SIGINT, clear_term);
239 static char *strip_white(char *line)
241 char *l, *t;
243 for (l = line; isspace(*l); l++)
245 if (*l == 0)
246 return l;
248 t = l + strlen(l) - 1;
249 while (t > l && isspace(*t))
250 t--;
251 *++t = '\0';
253 return l;
256 static int call_event_hook_handle_changed(int num)
258 switch (num) {
259 case CALL_STATE_MACHINE_IDLE:
260 setup_prompt(prompt, prompt_len, "idle");
261 break;
262 case CALL_STATE_MACHINE_CALLIN:
263 setup_prompt(prompt, prompt_len, "call-in");
264 break;
265 case CALL_STATE_MACHINE_CALLOUT:
266 setup_prompt(prompt, prompt_len, "call-out");
267 break;
268 case CALL_STATE_MACHINE_SPEAKING:
269 setup_prompt(prompt, prompt_len, "speaking");
270 break;
271 default:
272 break;
275 return 0;
278 static int call_event_hook(const struct event_block *self,
279 unsigned long event, const void *arg)
281 int ret = 0;
283 switch (event) {
284 case CALL_STATE_MACHINE_CHANGED: {
285 int num = *(int *) arg;
286 ret = call_event_hook_handle_changed(num);
287 break; }
288 default:
289 break;
292 return ret;
295 struct event_block call_event = {
296 .prio = PRIO_MEDIUM,
297 .hook = call_event_hook,
300 static inline void print_shell_header(void)
302 printf("\n%s%s%s shell\n\n", colorize_start(bold),
303 PROGNAME_STRING " " VERSION_STRING, colorize_end());
306 static inline void init_stun(void)
308 int ret = print_stun_probe("stunserver.org", 3478, 30111);
309 if (ret < 0)
310 printf("STUN failed!\n");
311 stun_done = 1;
312 fflush(stdout);
315 void enter_shell_loop(int __tsocki, int __tsocko)
317 char *line, *cmd;
319 tsocki = __tsocki;
320 tsocko = __tsocko;
322 prompt = xzmalloc(prompt_len);
324 setup_prompt(prompt, prompt_len, "idle");
325 setup_readline();
326 print_shell_header();
327 init_stun();
328 register_call_notifier(&call_event);
330 while (!quit) {
331 line = readline(prompt);
332 if (!line) {
333 printf("\n");
334 break;
337 cmd = strip_white(line);
338 if (*cmd) {
339 add_history(cmd);
340 exit_val = process_command(cmd);
343 xfree(line);
346 xfree(prompt);
347 printf("\n");
350 int cmd_help(char *args)
352 struct shell_cmd *cmd;
353 int i, entries = (sizeof(cmd_tree) / sizeof(cmd_tree[0])) - 1;
355 if (!*args) {
356 for (i = 0; i < entries; ++i)
357 printf("%s - %s\n", cmd_tree[i].name, cmd_tree[i].doc);
358 return 0;
361 cmd = walk_commands(args, strlen(args), FETCH_ELEM);
362 if (!cmd || !cmd->doc || !cmd->name)
363 return -EINVAL;
365 printf("%s - %s\n", cmd->name, cmd->doc);
366 return 0;
369 int cmd_quit(char *args)
371 quit = 1;
372 return 0;
375 int cmd_stat(char *args)
377 printf("%d\n", exit_val);
378 return 0;
381 int cmd_call(char *arg)
383 int argc;
384 ssize_t ret;
385 char **argv = strntoargv(arg, strlen(arg), &argc);
386 struct cli_pkt cpkt;
388 if (argc != 2) {
389 whine("Missing arguments: call <ipv4/ipv6/host> <port>\n");
390 xfree(argv);
391 return -EINVAL;
393 if (strlen(argv[0]) > ADDRSIZ || strlen(argv[1]) > PORTSIZ) {
394 whine("Arguments too long!\n");
395 xfree(argv);
396 return -EINVAL;
399 memset(&cpkt, 0, sizeof(cpkt));
400 cpkt.ring = 1;
401 strlcpy(cpkt.address, argv[0], sizeof(cpkt.address));
402 strlcpy(cpkt.port, argv[1], sizeof(cpkt.port));
404 ret = write(tsocko, &cpkt, sizeof(cpkt));
405 ret = write(tsocko, &cpkt, sizeof(cpkt)); //XXX
406 if (ret != sizeof(cpkt)) {
407 whine("Error notifying thread!\n");
408 return -EIO;
411 printf("Calling ... hang up the line with: hangup\n");
413 xfree(argv);
414 return 0;
417 int cmd_hangup(char *arg)
419 ssize_t ret;
420 struct cli_pkt cpkt;
422 memset(&cpkt, 0, sizeof(cpkt));
423 cpkt.fin = 1;
425 ret = write(tsocko, &cpkt, sizeof(cpkt));
426 if (ret != sizeof(cpkt)) {
427 whine("Error notifying thread!\n");
428 return -EIO;
431 return 0;
434 int cmd_take(char *arg)
436 ssize_t ret;
437 struct cli_pkt cpkt;
439 memset(&cpkt, 0, sizeof(cpkt));
440 cpkt.take = 1;
442 ret = write(tsocko, &cpkt, sizeof(cpkt));
443 if (ret != sizeof(cpkt)) {
444 whine("Error notifying thread!\n");
445 return -EIO;
448 return 0;