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.
14 #include <readline/readline.h>
15 #include <readline/history.h>
22 #include "call-notifier.h"
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
);
40 strlcpy(user
, "anon", len
);
44 static void fetch_host(char *host
, size_t len
)
46 int ret
= gethostname(host
, len
);
48 strlcpy(host
, "local", len
);
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
)
68 for (i
= 0; (cmd
= (*list
)[i
].name
); ++i
) {
69 if (strncmp(cmd
, token
, min(strlen(token
), strlen(cmd
))))
71 if (strlen(cmd
) != strlen(token
))
73 if ((*list
)[i
].sub_cmd
!= NULL
)
74 (*list
) = (*list
)[i
].sub_cmd
;
79 static struct shell_cmd
*find_elem(struct shell_cmd
*list
, const char *token
)
83 struct shell_cmd
*elem
;
88 for (i
= 0, elem
= NULL
; (cmd
= list
[i
].name
); ++i
) {
89 if (strncmp(cmd
, token
, min(strlen(token
), strlen(cmd
))))
97 static char *get_next_token(char *line
, int *off
)
102 while (line
[i
] && isspace(line
[i
]))
105 while (line
[i
] && !isspace(line
[i
]))
114 static struct shell_cmd
*walk_commands(char *line_buffer
, int len
, int ret
)
118 struct shell_cmd
*list
, *elem
= NULL
;
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)
129 find_list(&list
, token
);
130 elem
= find_elem(list
, token
);
132 if (strlen(elem
->name
) == strlen(token
))
139 return (ret
== FETCH_ELEM
? elem
: list
);
142 static char **__cmd_complete_line(const char *text
, char *line_buffer
, int point
)
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
);
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
);
163 static char *cmd_line_completion(const char *text
, int matches
,
164 char *line_buffer
, int point
)
166 static char **list
= NULL
;
177 list
= __cmd_complete_line(text
, line_buffer
, point
);
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
)
198 struct shell_cmd
*curr
;
200 curr
= walk_commands(line
, strlen(line
), FETCH_ELEM
);
201 if (!curr
|| curr
->callback
== NULL
)
204 ptr
= strstr(line
, curr
->name
);
207 ptr
+= strlen(curr
->name
);
209 while (ptr
[i
] && isspace(ptr
[i
]))
213 return curr
->callback(token
);
215 printf("Ooops, bad command! Try `help` for more information.\n");
219 void clear_term(int signal
)
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;
236 register_signal(SIGINT
, clear_term
);
239 static char *strip_white(char *line
)
243 for (l
= line
; isspace(*l
); l
++)
248 t
= l
+ strlen(l
) - 1;
249 while (t
> l
&& isspace(*t
))
256 static int call_event_hook_handle_changed(int num
)
259 case CALL_STATE_MACHINE_IDLE
:
260 setup_prompt(prompt
, prompt_len
, "idle");
262 case CALL_STATE_MACHINE_CALLIN
:
263 setup_prompt(prompt
, prompt_len
, "call-in");
265 case CALL_STATE_MACHINE_CALLOUT
:
266 setup_prompt(prompt
, prompt_len
, "call-out");
268 case CALL_STATE_MACHINE_SPEAKING
:
269 setup_prompt(prompt
, prompt_len
, "speaking");
278 static int call_event_hook(const struct event_block
*self
,
279 unsigned long event
, const void *arg
)
284 case CALL_STATE_MACHINE_CHANGED
: {
285 int num
= *(int *) arg
;
286 ret
= call_event_hook_handle_changed(num
);
295 struct event_block call_event
= {
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);
310 printf("STUN failed!\n");
315 void enter_shell_loop(int __tsocki
, int __tsocko
)
322 prompt
= xzmalloc(prompt_len
);
324 setup_prompt(prompt
, prompt_len
, "idle");
326 print_shell_header();
328 register_call_notifier(&call_event
);
331 line
= readline(prompt
);
337 cmd
= strip_white(line
);
340 exit_val
= process_command(cmd
);
350 int cmd_help(char *args
)
352 struct shell_cmd
*cmd
;
353 int i
, entries
= (sizeof(cmd_tree
) / sizeof(cmd_tree
[0])) - 1;
356 for (i
= 0; i
< entries
; ++i
)
357 printf("%s - %s\n", cmd_tree
[i
].name
, cmd_tree
[i
].doc
);
361 cmd
= walk_commands(args
, strlen(args
), FETCH_ELEM
);
362 if (!cmd
|| !cmd
->doc
|| !cmd
->name
)
365 printf("%s - %s\n", cmd
->name
, cmd
->doc
);
369 int cmd_quit(char *args
)
375 int cmd_stat(char *args
)
377 printf("%d\n", exit_val
);
381 int cmd_call(char *arg
)
385 char **argv
= strntoargv(arg
, strlen(arg
), &argc
);
389 whine("Missing arguments: call <ipv4/ipv6/host> <port>\n");
393 if (strlen(argv
[0]) > ADDRSIZ
|| strlen(argv
[1]) > PORTSIZ
) {
394 whine("Arguments too long!\n");
399 memset(&cpkt
, 0, sizeof(cpkt
));
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");
411 printf("Calling ... hang up the line with: hangup\n");
417 int cmd_hangup(char *arg
)
422 memset(&cpkt
, 0, sizeof(cpkt
));
425 ret
= write(tsocko
, &cpkt
, sizeof(cpkt
));
426 if (ret
!= sizeof(cpkt
)) {
427 whine("Error notifying thread!\n");
434 int cmd_take(char *arg
)
439 memset(&cpkt
, 0, sizeof(cpkt
));
442 ret
= write(tsocko
, &cpkt
, sizeof(cpkt
));
443 if (ret
!= sizeof(cpkt
)) {
444 whine("Error notifying thread!\n");