6 #include <readline/readline.h>
7 #include <readline/history.h>
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
);
31 strlcpy(user
, "anon", len
);
35 static void fetch_host(char *host
, size_t len
)
37 int ret
= gethostname(host
, len
);
39 strlcpy(host
, "local", len
);
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
)
59 for (i
= 0; (cmd
= (*list
)[i
].name
); ++i
) {
60 if (strncmp(cmd
, token
, min(strlen(token
), strlen(cmd
))))
62 if (strlen(cmd
) != strlen(token
))
64 if ((*list
)[i
].sub_cmd
!= NULL
)
65 (*list
) = (*list
)[i
].sub_cmd
;
70 static struct shell_cmd
*find_elem(struct shell_cmd
*list
, const char *token
)
74 struct shell_cmd
*elem
;
79 for (i
= 0, elem
= NULL
; (cmd
= list
[i
].name
); ++i
) {
80 if (strncmp(cmd
, token
, min(strlen(token
), strlen(cmd
))))
88 static char *get_next_token(char *line
, int *off
)
93 while (line
[i
] && isspace(line
[i
]))
96 while (line
[i
] && !isspace(line
[i
]))
105 static struct shell_cmd
*walk_commands(char *line_buffer
, int len
, int ret
)
109 struct shell_cmd
*list
, *elem
= NULL
;
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)
120 find_list(&list
, token
);
121 elem
= find_elem(list
, token
);
123 if (strlen(elem
->name
) == strlen(token
))
130 return (ret
== FETCH_ELEM
? elem
: list
);
133 static char **__cmd_complete_line(const char *text
, char *line_buffer
, int point
)
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
);
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
);
154 static char *cmd_line_completion(const char *text
, int matches
,
155 char *line_buffer
, int point
)
157 static char **list
= NULL
;
168 list
= __cmd_complete_line(text
, line_buffer
, point
);
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
)
189 struct shell_cmd
*curr
;
191 curr
= walk_commands(line
, strlen(line
), FETCH_ELEM
);
192 if (!curr
|| curr
->callback
== NULL
)
195 ptr
= strstr(line
, curr
->name
);
198 ptr
+= strlen(curr
->name
);
200 while (ptr
[i
] && isspace(ptr
[i
]))
204 return curr
->callback(token
);
206 printf("Ooops, bad command! Try `help` for more information.\n");
210 void clear_term(int signal
)
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;
227 register_signal(SIGINT
, clear_term
);
230 static char *strip_white(char *line
)
234 for (l
= line
; isspace(*l
); l
++)
239 t
= l
+ strlen(l
) - 1;
240 while (t
> l
&& isspace(*t
))
247 static int tsocki
, tsocko
;
249 void enter_shell_loop(int __tsocki
, int __tsocko
)
253 size_t prompt_len
= 256;
258 prompt
= xzmalloc(prompt_len
);
259 setup_prompt(prompt
, prompt_len
);
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);
269 line
= readline(prompt
);
275 cmd
= strip_white(line
);
278 exit_val
= process_command(cmd
);
288 int cmd_help(char *args
)
290 struct shell_cmd
*cmd
;
291 int i
, entries
= (sizeof(cmd_tree
) / sizeof(cmd_tree
[0])) - 1;
294 for (i
= 0; i
< entries
; ++i
)
295 printf("%s - %s\n", cmd_tree
[i
].name
, cmd_tree
[i
].doc
);
299 cmd
= walk_commands(args
, strlen(args
), FETCH_ELEM
);
300 if (!cmd
|| !cmd
->doc
|| !cmd
->name
)
303 printf("%s - %s\n", cmd
->name
, cmd
->doc
);
307 int cmd_quit(char *args
)
313 int cmd_stat(char *args
)
315 printf("%d\n", exit_val
);
319 int cmd_call(char *arg
)
323 char **argv
= strntoargv(arg
, strlen(arg
), &argc
);
327 whine("Missing arguments: call <ipv4/ipv6/host> <port>\n");
331 if (strlen(argv
[0]) > ADDRSIZ
|| strlen(argv
[1]) > PORTSIZ
) {
332 whine("Arguments too long!\n");
337 memset(&cpkt
, 0, sizeof(cpkt
));
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");
349 printf("Calling ... hang up the line with: hangup\n");
355 int cmd_hangup(char *arg
)
360 memset(&cpkt
, 0, sizeof(cpkt
));
363 ret
= write(tsocko
, &cpkt
, sizeof(cpkt
));
364 if (ret
!= sizeof(cpkt
)) {
365 whine("Error notifying thread!\n");
372 int cmd_take(char *arg
)
377 memset(&cpkt
, 0, sizeof(cpkt
));
380 ret
= write(tsocko
, &cpkt
, sizeof(cpkt
));
381 if (ret
!= sizeof(cpkt
)) {
382 whine("Error notifying thread!\n");