3 * Copyright (C) 2002, Linux Support Services, Inc.
5 * Distributed under the terms of the GNU General Public License
10 #include <sys/socket.h>
13 #include <netinet/in.h>
14 #include <arpa/inet.h>
15 #include <sys/select.h>
23 #include <asterisk/manager.h>
25 #define MAX_HEADERS 80
28 static struct mansession {
29 struct sockaddr_in sin;
37 char headers[MAX_HEADERS][MAX_LEN];
40 static struct ast_chan {
47 struct ast_chan *next;
50 static struct ast_chan *find_chan(char *name)
52 struct ast_chan *prev = NULL, *chan = chans;
54 if (!strcmp(name, chan->name))
59 chan = malloc(sizeof(struct ast_chan));
61 memset(chan, 0, sizeof(struct ast_chan));
62 strncpy(chan->name, name, sizeof(chan->name) - 1);
71 static void del_chan(char *name)
73 struct ast_chan *prev = NULL, *chan = chans;
75 if (!strcmp(name, chan->name)) {
77 prev->next = chan->next;
87 static void fdprintf(int fd, char *fmt, ...)
92 vsnprintf(stuff, sizeof(stuff), fmt, ap);
94 write(fd, stuff, strlen(stuff));
97 static char *get_header(struct message *m, char *var)
101 snprintf(cmp, sizeof(cmp), "%s: ", var);
102 for (x=0;x<m->hdrcount;x++)
103 if (!strncasecmp(cmp, m->headers[x], strlen(cmp)))
104 return m->headers[x] + strlen(cmp);
108 static int event_newstate(struct mansession *s, struct message *m)
110 struct ast_chan *chan;
111 chan = find_chan(get_header(m, "Channel"));
112 strncpy(chan->state, get_header(m, "State"), sizeof(chan->state) - 1);
116 static int event_newexten(struct mansession *s, struct message *m)
118 struct ast_chan *chan;
119 chan = find_chan(get_header(m, "Channel"));
120 strncpy(chan->exten, get_header(m, "Extension"), sizeof(chan->exten) - 1);
121 strncpy(chan->context, get_header(m, "Context"), sizeof(chan->context) - 1);
122 strncpy(chan->priority, get_header(m, "Priority"), sizeof(chan->priority) - 1);
126 static int event_newchannel(struct mansession *s, struct message *m)
128 struct ast_chan *chan;
129 chan = find_chan(get_header(m, "Channel"));
130 strncpy(chan->state, get_header(m, "State"), sizeof(chan->state) - 1);
131 strncpy(chan->callerid, get_header(m, "Callerid"), sizeof(chan->callerid) - 1);
135 static int event_status(struct mansession *s, struct message *m)
137 struct ast_chan *chan;
138 chan = find_chan(get_header(m, "Channel"));
139 strncpy(chan->state, get_header(m, "State"), sizeof(chan->state) - 1);
140 strncpy(chan->callerid, get_header(m, "Callerid"), sizeof(chan->callerid) - 1);
141 strncpy(chan->exten, get_header(m, "Extension"), sizeof(chan->exten) - 1);
142 strncpy(chan->context, get_header(m, "Context"), sizeof(chan->context) - 1);
143 strncpy(chan->priority, get_header(m, "Priority"), sizeof(chan->priority) - 1);
147 static int event_hangup(struct mansession *s, struct message *m)
149 del_chan(get_header(m, "Channel"));
153 static int event_ignore(struct mansession *s, struct message *m)
158 static int event_rename(struct mansession *s, struct message *m)
160 struct ast_chan *chan;
161 chan = find_chan(get_header(m, "Oldname"));
162 strncpy(chan->name, get_header(m, "Newname"), sizeof(chan->name) - 1);
165 static struct event {
167 int (*func)(struct mansession *s, struct message *m);
169 { "Newstate", event_newstate },
170 { "Newchannel", event_newchannel },
171 { "Newexten", event_newexten },
172 { "Hangup", event_hangup },
173 { "Rename", event_rename },
174 { "Status", event_status },
175 { "Link", event_ignore },
176 { "Unlink", event_ignore },
179 static int process_message(struct mansession *s, struct message *m)
183 strncpy(event, get_header(m, "Event"), sizeof(event));
184 if (!strlen(event)) {
185 fprintf(stderr, "Missing event in request");
188 for (x=0;x<sizeof(events) / sizeof(events[0]);x++) {
189 if (!strcasecmp(event, events[x].event)) {
190 if (events[x].func(s, m))
195 if (x >= sizeof(events) / sizeof(events[0]))
196 fprintf(stderr, "Ignoring unknown event '%s'", event);
198 for (x=0;x<m->hdrcount;x++) {
199 printf("Header: %s\n", m->headers[x]);
205 static void rebuild_channels(newtComponent c)
208 struct ast_chan *chan;
212 prev = newtListboxGetCurrent(c);
216 snprintf(tmpn, sizeof(tmpn), "%s (%s)", chan->name, chan->callerid);
217 if (strlen(chan->exten))
218 snprintf(tmp, sizeof(tmp), "%-30s %8s -> %s@%s:%s",
220 chan->exten, chan->context, chan->priority);
222 snprintf(tmp, sizeof(tmp), "%-30s %8s",
224 newtListboxAppendEntry(c, tmp, chan);
229 newtListboxAppendEntry(c, " << No Active Channels >> ", NULL);
230 newtListboxSetCurrentByKey(c, prev);
233 static int has_input(struct mansession *s)
236 for (x=1;x<s->inlen;x++)
237 if ((s->inbuf[x] == '\n') && (s->inbuf[x-1] == '\r'))
242 static int get_input(struct mansession *s, char *output)
244 /* output must have at least sizeof(s->inbuf) space */
247 struct timeval tv = {0, 0};
249 for (x=1;x<s->inlen;x++) {
250 if ((s->inbuf[x] == '\n') && (s->inbuf[x-1] == '\r')) {
251 /* Copy output data up to and including \r\n */
252 memcpy(output, s->inbuf, x + 1);
253 /* Add trailing \0 */
255 /* Move remaining data back to the front */
256 memmove(s->inbuf, s->inbuf + x + 1, s->inlen - x);
261 if (s->inlen >= sizeof(s->inbuf) - 1) {
262 fprintf(stderr, "Dumping long line with no return from %s: %s\n", inet_ntoa(s->sin.sin_addr), s->inbuf);
267 res = select(s->fd + 1, &fds, NULL, NULL, &tv);
269 fprintf(stderr, "Select returned error: %s\n", strerror(errno));
270 } else if (res > 0) {
271 res = read(s->fd, s->inbuf + s->inlen, sizeof(s->inbuf) - 1 - s->inlen);
275 s->inbuf[s->inlen] = '\0';
282 static int input_check(struct mansession *s, struct message **mout)
284 static struct message m;
291 res = get_input(s, m.headers[m.hdrcount]);
294 fprintf(stderr, "Got header: %s", m.headers[m.hdrcount]);
297 /* Strip trailing \r\n */
298 if (strlen(m.headers[m.hdrcount]) < 2)
300 m.headers[m.hdrcount][strlen(m.headers[m.hdrcount]) - 2] = '\0';
301 if (!strlen(m.headers[m.hdrcount])) {
302 if (mout && strlen(get_header(&m, "Response"))) {
306 if (process_message(s, &m))
308 memset(&m, 0, sizeof(&m));
309 } else if (m.hdrcount < MAX_HEADERS - 1)
311 } else if (res < 0) {
319 static struct message *wait_for_response(int timeout)
326 tv.tv_sec = timeout / 1000;
327 tv.tv_usec = (timeout % 1000) * 1000;
328 FD_SET(session.fd, &fds);
329 res = select(session.fd + 1, &fds, NULL, NULL, &tv);
332 if (input_check(&session, &m) < 0) {
341 static int manager_action(char *action, char *fmt, ...)
343 struct mansession *s;
348 fdprintf(s->fd, "Action: %s\r\n", action);
350 vsnprintf(tmp, sizeof(tmp), fmt, ap);
352 write(s->fd, tmp, strlen(tmp));
353 fdprintf(s->fd, "\r\n");
357 static int show_message(char *title, char *msg)
362 struct newtExitStruct es;
364 newtCenteredWindow(60,7, title);
366 label = newtLabel(4,1,msg);
367 ok = newtButton(27, 3, "OK");
368 form = newtForm(NULL, NULL, 0);
369 newtFormAddComponents(form, label, ok, NULL);
370 newtFormRun(form, &es);
372 newtFormDestroy(form);
376 static newtComponent showform;
377 static int show_doing(char *title, char *tmp)
379 struct newtExitStruct es;
381 showform = newtForm(NULL, NULL, 0);
382 newtCenteredWindow(70,4, title);
383 label = newtLabel(3,1,tmp);
384 newtFormAddComponents(showform,label, NULL);
385 newtFormSetTimer(showform, 200);
386 newtFormRun(showform, &es);
390 static int hide_doing()
393 newtFormDestroy(showform);
397 static void try_status()
400 manager_action("Status", "");
401 m = wait_for_response(10000);
403 show_message("Status Failed", "Timeout waiting for response");
404 } else if (strcasecmp(get_header(m, "Response"), "Success")) {
405 show_message("Status Failed Failed", get_header(m, "Message"));
410 static void try_hangup(newtComponent c)
412 struct ast_chan *chan;
415 chan = newtListboxGetCurrent(c);
417 manager_action("Hangup", "Channel: %s\r\n", chan->name);
418 m = wait_for_response(10000);
420 show_message("Hangup Failed", "Timeout waiting for response");
421 } else if (strcasecmp(get_header(m, "Response"), "Success")) {
422 show_message("Hangup Failed", get_header(m, "Message"));
428 static int get_user_input(char *msg, char *buf, int buflen)
432 newtComponent cancel;
433 newtComponent inpfield;
436 struct newtExitStruct es;
438 newtCenteredWindow(60,7, msg);
440 inpfield = newtEntry(5, 2, "", 50, &input, 0);
441 ok = newtButton(22, 3, "OK");
442 cancel = newtButton(32, 3, "Cancel");
443 form = newtForm(NULL, NULL, 0);
444 newtFormAddComponents(form, inpfield, ok, cancel, NULL);
445 newtFormRun(form, &es);
446 strncpy(buf, input, buflen - 1);
452 newtFormDestroy(form);
456 static void try_redirect(newtComponent c)
458 struct ast_chan *chan;
465 chan = newtListboxGetCurrent(c);
467 strncpy(channame, chan->name, sizeof(channame) - 1);
468 snprintf(tmp, sizeof(tmp), "Enter new extension for %s", channame);
469 if (get_user_input(tmp, dest, sizeof(dest)))
471 if ((context = strchr(dest, '@'))) {
474 manager_action("Redirect", "Channel: %s\r\nContext: %s\r\nExten: %s\r\nPriority: 1\r\n", chan->name,context,dest);
476 manager_action("Redirect", "Channel: %s\r\nExten: %s\r\nPriority: 1\r\n", chan->name, dest);
478 m = wait_for_response(10000);
480 show_message("Hangup Failed", "Timeout waiting for response");
481 } else if (strcasecmp(get_header(m, "Response"), "Success")) {
482 show_message("Hangup Failed", get_header(m, "Message"));
488 static int manage_calls(char *host)
492 newtComponent hangup;
493 newtComponent redirect;
494 newtComponent channels;
495 struct newtExitStruct es;
498 /* If there's one thing you learn from this code, it is this...
499 Never, ever fly Air France. Their customer service is absolutely
500 the worst. I've never heard the words "That's not my problem" as
501 many times as I have from their staff -- It should, without doubt
502 be their corporate motto if it isn't already. Don't bother giving
503 them business because you're just a pain in their side and they
504 will be sure to let you know the first time you speak to them.
506 If you ever want to make me happy just tell me that you, too, will
507 never fly Air France again either (in spite of their excellent
509 snprintf(tmp, sizeof(tmp), "Asterisk Manager at %s", host);
510 newtCenteredWindow(74, 20, tmp);
511 form = newtForm(NULL, NULL, 0);
512 newtFormWatchFd(form, session.fd, NEWT_FD_READ);
513 newtFormSetTimer(form, 100);
514 quit = newtButton(62, 16, "Quit");
515 redirect = newtButton(35, 16, "Redirect");
516 hangup = newtButton(50, 16, "Hangup");
517 channels = newtListbox(1,1,14, NEWT_FLAG_SCROLL);
518 newtFormAddComponents(form, channels, redirect, hangup, quit, NULL);
519 newtListboxSetWidth(channels, 72);
521 show_doing("Getting Status", "Retrieving system status...");
526 newtFormRun(form, &es);
527 if (has_input(&session) || (es.reason == NEWT_EXIT_FDREADY)) {
528 if (input_check(&session, NULL)) {
529 show_message("Disconnected", "Disconnected from remote host");
532 } else if (es.reason == NEWT_EXIT_COMPONENT) {
535 if (es.u.co == hangup) {
536 try_hangup(channels);
537 } else if (es.u.co == redirect) {
538 try_redirect(channels);
541 rebuild_channels(channels);
543 newtFormDestroy(form);
547 static int login(char *hostname)
550 newtComponent cancel;
552 newtComponent username;
553 newtComponent password;
555 newtComponent ulabel;
556 newtComponent plabel;
560 struct newtExitStruct es;
565 session.fd = socket(AF_INET, SOCK_STREAM, 0);
566 if (session.fd < 0) {
567 snprintf(tmp, sizeof(tmp), "socket() failed: %s\n", strerror(errno));
568 show_message("Socket failed", tmp);
572 snprintf(tmp, sizeof(tmp), "Looking up %s\n", hostname);
573 show_doing("Connecting....", tmp);
576 hp = gethostbyname(hostname);
578 snprintf(tmp, sizeof(tmp), "No such address: %s\n", hostname);
579 show_message("Host lookup failed", tmp);
583 snprintf(tmp, sizeof(tmp), "Connecting to %s", hostname);
584 show_doing("Connecting...", tmp);
586 session.sin.sin_family = AF_INET;
587 session.sin.sin_port = htons(DEFAULT_MANAGER_PORT);
588 memcpy(&session.sin.sin_addr, hp->h_addr, sizeof(session.sin.sin_addr));
590 if (connect(session.fd, &session.sin, sizeof(session.sin))) {
591 snprintf(tmp, sizeof(tmp), "%s failed: %s\n", hostname, strerror(errno));
592 show_message("Connect Failed", tmp);
598 login = newtButton(5, 6, "Login");
599 cancel = newtButton(25, 6, "Cancel");
600 newtCenteredWindow(40, 10, "Asterisk Manager Login");
601 snprintf(tmp, sizeof(tmp), "Host: %s", hostname);
602 label = newtLabel(4,1, tmp);
604 ulabel = newtLabel(4,2,"Username:");
605 plabel = newtLabel(4,3,"Password:");
607 username = newtEntry(14, 2, "", 20, &user, 0);
608 password = newtEntry(14, 3, "", 20, &pass, NEWT_FLAG_HIDDEN);
610 form = newtForm(NULL, NULL, 0);
611 newtFormAddComponents(form, username, password, login, cancel, label, ulabel, plabel,NULL);
612 newtFormRun(form, &es);
613 if (es.reason == NEWT_EXIT_COMPONENT) {
614 if (es.u.co == login) {
615 snprintf(tmp, sizeof(tmp), "Logging in '%s'...", user);
616 show_doing("Logging in", tmp);
617 manager_action("Login",
621 m = wait_for_response(10000);
624 if (!strcasecmp(get_header(m, "Response"), "Success")) {
627 show_message("Login Failed", get_header(m, "Message"));
632 newtFormDestroy(form);
636 int main(int argc, char *argv[])
639 fprintf(stderr, "Usage: astman <host>\n");
644 newtDrawRootText(0, 0, "Asterisk Manager (C)2002, Linux Support Services, Inc.");
645 newtPushHelpLine("Welcome to the Asterisk Manager!");
646 if (login(argv[1])) {
650 manage_calls(argv[1]);