Binaural synthesis (confbridge): Adds utils/conf_bridge_binaural_hrir_importer
[asterisk/asterisk.git] / utils / astman.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2005, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*
20  *
21  * ASTerisk MANager
22  *
23  */
24
25 /*** MODULEINFO
26         <support_level>extended</support_level>
27  ***/
28
29 #include "asterisk.h"
30
31 #include <newt.h>
32 #include <stdio.h>
33 #include <sys/time.h>
34 #include <netdb.h>
35 #include <netinet/in.h>
36 #include <arpa/inet.h>
37 #include <sys/socket.h>
38 #include <sys/select.h>
39 #include <fcntl.h>
40 #include <string.h>
41 #include <errno.h>
42 #include <unistd.h>
43 #include <stdlib.h>
44
45 #include "asterisk/md5.h"
46 #include "asterisk/linkedlists.h"
47
48 #define ARRAY_LEN(a) (sizeof(a) / sizeof(a[0]))
49
50 #undef gethostbyname
51
52 #define MAX_HEADERS 80
53 #define MAX_LEN 256
54
55 /*
56  * 2005.05.27 - different versions of newt define the type of the buffer
57  * for the 5th argument to newtEntry() as char ** or const char ** . To
58  * let the code compile cleanly with -Werror, we cast it to void * through
59  * _NEWT_CAST.
60  */
61 #define _NEWT_CAST (void *)
62
63 #define DEFAULT_MANAGER_PORT 5038
64
65 struct message {
66         unsigned int hdrcount;
67         char headers[MAX_HEADERS][MAX_LEN];
68 };
69
70 static struct ast_mansession {
71         struct sockaddr_in sin;
72         int fd;
73         char inbuf[MAX_LEN];
74         int inlen;
75 } session;
76
77 struct ast_chan {
78         char name[80];
79         char exten[20];
80         char context[20];
81         char priority[20];
82         char callerid[40];
83         char state[10];
84         AST_LIST_ENTRY(ast_chan) list;
85 };
86
87 static AST_LIST_HEAD_NOLOCK_STATIC(chans, ast_chan);
88
89 /* dummy functions to be compatible with the Asterisk core for md5.c */
90 int ast_add_profile(const char *, uint64_t scale);
91 int ast_add_profile(const char *s, uint64_t scale)
92 {
93         return -1;
94 }
95
96 int64_t ast_profile(int, int64_t);
97 int64_t ast_profile(int key, int64_t val)
98 {
99         return 0;
100 }
101 int64_t ast_mark(int, int start1_stop0);
102 int64_t ast_mark(int key, int start1_stop0)
103 {
104         return 0;
105 }
106
107 /* end of dummy functions */
108
109 static struct ast_chan *find_chan(char *name)
110 {
111         struct ast_chan *chan;
112         AST_LIST_TRAVERSE(&chans, chan, list) {
113                 if (!strcmp(name, chan->name))
114                         return chan;
115         }
116         chan = malloc(sizeof(struct ast_chan));
117         if (chan) {
118                 memset(chan, 0, sizeof(struct ast_chan));
119                 strncpy(chan->name, name, sizeof(chan->name) - 1);
120                 AST_LIST_INSERT_TAIL(&chans, chan, list);
121         }
122         return chan;
123 }
124
125 static void del_chan(char *name)
126 {
127         struct ast_chan *chan;
128
129         AST_LIST_TRAVERSE_SAFE_BEGIN(&chans, chan, list) {
130                 if (!strcmp(name, chan->name)) {
131                         AST_LIST_REMOVE_CURRENT(list);
132                         free(chan);
133                         return;
134                 }
135         }
136         AST_LIST_TRAVERSE_SAFE_END;
137 }
138
139
140 static void __attribute__((format(printf, 2, 3))) fdprintf(int fd, char *fmt, ...)
141 {
142         char stuff[4096];
143         va_list ap;
144
145         va_start(ap, fmt);
146         vsnprintf(stuff, sizeof(stuff), fmt, ap);
147         va_end(ap);
148         if (write(fd, stuff, strlen(stuff)) < 0) {
149                 fprintf(stderr, "write() failed: %s\n", strerror(errno));
150         }
151 }
152
153 static char *get_header(struct message *m, char *var)
154 {
155         char cmp[80];
156         int x;
157         snprintf(cmp, sizeof(cmp), "%s: ", var);
158         for (x=0;x<m->hdrcount;x++)
159                 if (!strncasecmp(cmp, m->headers[x], strlen(cmp)))
160                         return m->headers[x] + strlen(cmp);
161         return "";
162 }
163
164 static int event_newstate(struct ast_mansession *s, struct message *m)
165 {
166         struct ast_chan *chan;
167         chan = find_chan(get_header(m, "Channel"));
168         strncpy(chan->state, get_header(m, "State"), sizeof(chan->state) - 1);
169         return 0;
170 }
171
172 static int event_newexten(struct ast_mansession *s, struct message *m)
173 {
174         struct ast_chan *chan;
175         chan = find_chan(get_header(m, "Channel"));
176         strncpy(chan->exten, get_header(m, "Extension"), sizeof(chan->exten) - 1);
177         strncpy(chan->context, get_header(m, "Context"), sizeof(chan->context) - 1);
178         strncpy(chan->priority, get_header(m, "Priority"), sizeof(chan->priority) - 1);
179         return 0;
180 }
181
182 static int event_newchannel(struct ast_mansession *s, struct message *m)
183 {
184         struct ast_chan *chan;
185         chan = find_chan(get_header(m, "Channel"));
186         strncpy(chan->state, get_header(m, "State"), sizeof(chan->state) - 1);
187         strncpy(chan->callerid, get_header(m, "Callerid"), sizeof(chan->callerid) - 1);
188         return 0;
189 }
190
191 static int event_status(struct ast_mansession *s, struct message *m)
192 {
193         struct ast_chan *chan;
194         chan = find_chan(get_header(m, "Channel"));
195         strncpy(chan->state, get_header(m, "State"), sizeof(chan->state) - 1);
196         strncpy(chan->callerid, get_header(m, "Callerid"), sizeof(chan->callerid) - 1);
197         strncpy(chan->exten, get_header(m, "Extension"), sizeof(chan->exten) - 1);
198         strncpy(chan->context, get_header(m, "Context"), sizeof(chan->context) - 1);
199         strncpy(chan->priority, get_header(m, "Priority"), sizeof(chan->priority) - 1);
200         return 0;
201 }
202
203 static int event_hangup(struct ast_mansession *s, struct message *m)
204 {
205         del_chan(get_header(m, "Channel"));
206         return 0;
207 }
208
209 static int event_ignore(struct ast_mansession *s, struct message *m)
210 {
211         return 0;
212 }
213
214 static int event_rename(struct ast_mansession *s, struct message *m)
215 {
216         struct ast_chan *chan;
217         chan = find_chan(get_header(m, "Oldname"));
218         strncpy(chan->name, get_header(m, "Newname"), sizeof(chan->name) - 1);
219         return 0;
220 }
221 static struct event {
222         char *event;
223         int (*func)(struct ast_mansession *s, struct message *m);
224 } events[] = {
225         { "Newstate", event_newstate },
226         { "Newchannel", event_newchannel },
227         { "Newexten", event_newexten },
228         { "Hangup", event_hangup },
229         { "Rename", event_rename },
230         { "Status", event_status },
231         { "Link", event_ignore },
232         { "Unlink", event_ignore },
233         { "StatusComplete", event_ignore },
234         { "Dial", event_ignore },
235         { "PeerStatus", event_ignore },
236         { "MessageWaiting", event_ignore },
237         { "Newcallerid", event_ignore },
238         { "AGIExec", event_ignore},
239         { "VarSet", event_ignore},
240         { "MeetmeTalking", event_ignore},
241         { "MeetmeJoin", event_ignore},
242         { "MeetmeLeave", event_ignore},
243         { "MeetmeEnd", event_ignore},
244         { "MeetmeMute", event_ignore},
245         { "Masquerade", event_ignore},
246 };
247
248 static int process_message(struct ast_mansession *s, struct message *m)
249 {
250         int x;
251         char event[80] = "";
252         strncpy(event, get_header(m, "Event"), sizeof(event) - 1);
253         if (!strlen(event)) {
254                 fprintf(stderr, "Missing event in request");
255                 return 0;
256         }
257         for (x = 0; x < ARRAY_LEN(events); x++) {
258                 if (!strcasecmp(event, events[x].event)) {
259                         if (events[x].func(s, m))
260                                 return -1;
261                         break;
262                 }
263         }
264         if (x >= ARRAY_LEN(events))
265                 fprintf(stderr, "Ignoring unknown event '%s'", event);
266 #if 0
267         for (x=0;x<m->hdrcount;x++) {
268                 printf("Header: %s\n", m->headers[x]);
269         }
270 #endif
271         return 0;
272 }
273
274 static void rebuild_channels(newtComponent c)
275 {
276         void *prev = NULL;
277         struct ast_chan *chan;
278         char tmpn[42];
279         char tmp[256];
280         int x=0;
281         prev = newtListboxGetCurrent(c);
282         newtListboxClear(c);
283         AST_LIST_TRAVERSE(&chans, chan, list) {
284                 snprintf(tmpn, sizeof(tmpn), "%s (%s)", chan->name, chan->callerid);
285                 if (strlen(chan->exten))
286                         snprintf(tmp, sizeof(tmp), "%-30s %8s -> %s@%s:%s",
287                                 tmpn, chan->state,
288                                 chan->exten, chan->context, chan->priority);
289                 else
290                         snprintf(tmp, sizeof(tmp), "%-30s %8s",
291                                 tmpn, chan->state);
292                 newtListboxAppendEntry(c, tmp, chan);
293                 x++;
294         }
295         if (!x)
296                 newtListboxAppendEntry(c, " << No Active Channels >> ", NULL);
297         newtListboxSetCurrentByKey(c, prev);
298 }
299
300 static int has_input(struct ast_mansession *s)
301 {
302         int x;
303         for (x=1;x<s->inlen;x++)
304                 if ((s->inbuf[x] == '\n') && (s->inbuf[x-1] == '\r'))
305                         return 1;
306         return 0;
307 }
308
309 static int get_input(struct ast_mansession *s, char *output)
310 {
311         /* output must have at least sizeof(s->inbuf) space */
312         int res;
313         int x;
314         struct timeval tv = {0, 0};
315         fd_set fds;
316         for (x=1;x<s->inlen;x++) {
317                 if ((s->inbuf[x] == '\n') && (s->inbuf[x-1] == '\r')) {
318                         /* Copy output data up to and including \r\n */
319                         memcpy(output, s->inbuf, x + 1);
320                         /* Add trailing \0 */
321                         output[x+1] = '\0';
322                         /* Move remaining data back to the front */
323                         memmove(s->inbuf, s->inbuf + x + 1, s->inlen - x);
324                         s->inlen -= (x + 1);
325                         return 1;
326                 }
327         }
328         if (s->inlen >= sizeof(s->inbuf) - 1) {
329                 fprintf(stderr, "Dumping long line with no return from %s: %s\n", inet_ntoa(s->sin.sin_addr), s->inbuf);
330                 s->inlen = 0;
331         }
332         FD_ZERO(&fds);
333         FD_SET(s->fd, &fds);
334         res = select(s->fd + 1, &fds, NULL, NULL, &tv);
335         if (res < 0) {
336                 fprintf(stderr, "Select returned error: %s\n", strerror(errno));
337         } else if (res > 0) {
338                 res = read(s->fd, s->inbuf + s->inlen, sizeof(s->inbuf) - 1 - s->inlen);
339                 if (res < 1)
340                         return -1;
341                 s->inlen += res;
342                 s->inbuf[s->inlen] = '\0';
343         } else {
344                 return 2;
345         }
346         return 0;
347 }
348
349 static int input_check(struct ast_mansession *s, struct message **mout)
350 {
351         static struct message m;
352         int res;
353
354         if (mout)
355                 *mout = NULL;
356
357         for(;;) {
358                 res = get_input(s, m.headers[m.hdrcount]);
359                 if (res == 1) {
360 #if 0
361                         fprintf(stderr, "Got header: %s", m.headers[m.hdrcount]);
362                         fgetc(stdin);
363 #endif
364                         /* Strip trailing \r\n */
365                         if (strlen(m.headers[m.hdrcount]) < 2)
366                                 continue;
367                         m.headers[m.hdrcount][strlen(m.headers[m.hdrcount]) - 2] = '\0';
368                         if (!strlen(m.headers[m.hdrcount])) {
369                                 if (mout && strlen(get_header(&m, "Response"))) {
370                                         *mout = &m;
371                                         return 0;
372                                 }
373                                 if (process_message(s, &m))
374                                         break;
375                                 memset(&m, 0, sizeof(m));
376                         } else if (m.hdrcount < MAX_HEADERS - 1)
377                                 m.hdrcount++;
378                 } else if (res < 0) {
379                         return -1;
380                 } else if (res == 2)
381                         return 0;
382         }
383         return -1;
384 }
385
386 static struct message *wait_for_response(int timeout)
387 {
388         struct message *m;
389         struct timeval tv;
390         int res;
391         fd_set fds;
392         for (;;) {
393                 tv.tv_sec = timeout / 1000;
394                 tv.tv_usec = (timeout % 1000) * 1000;
395                 FD_SET(session.fd, &fds);
396                 res = select(session.fd + 1, &fds, NULL, NULL, &tv);
397                 if (res < 1)
398                         break;
399                 if (input_check(&session, &m) < 0) {
400                         return NULL;
401                 }
402                 if (m)
403                         return m;
404         }
405         return NULL;
406 }
407
408
409 static int __attribute__((format(printf, 2, 3))) manager_action(char *action, char *fmt, ...)
410 {
411         struct ast_mansession *s;
412         char tmp[4096];
413         va_list ap;
414         int res;
415
416         s = &session;
417         fdprintf(s->fd, "Action: %s\r\n", action);
418         va_start(ap, fmt);
419         vsnprintf(tmp, sizeof(tmp), fmt, ap);
420         va_end(ap);
421         if ((res = write(s->fd, tmp, strlen(tmp))) < 0) {
422                 fprintf(stderr, "write() failed: %s\n", strerror(errno));
423         }
424         fdprintf(s->fd, "\r\n");
425         return 0;
426 }
427
428 static int show_message(char *title, char *msg)
429 {
430         newtComponent form;
431         newtComponent label;
432         newtComponent ok;
433         struct newtExitStruct es;
434
435         newtCenteredWindow(60,7, title);
436
437         label = newtLabel(4,1,msg);
438         ok = newtButton(27, 3, "OK");
439         form = newtForm(NULL, NULL, 0);
440         newtFormAddComponents(form, label, ok, NULL);
441         newtFormRun(form, &es);
442         newtPopWindow();
443         newtFormDestroy(form);
444         return 0;
445 }
446
447 static newtComponent showform;
448 static int show_doing(char *title, char *tmp)
449 {
450         struct newtExitStruct es;
451         newtComponent label;
452         showform = newtForm(NULL, NULL, 0);
453         newtCenteredWindow(70,4, title);
454         label = newtLabel(3,1,tmp);
455         newtFormAddComponents(showform,label, NULL);
456         newtFormSetTimer(showform, 200);
457         newtFormRun(showform, &es);
458         return 0;
459 }
460
461 static int hide_doing(void)
462 {
463         newtPopWindow();
464         newtFormDestroy(showform);
465         return 0;
466 }
467
468 static void try_status(void)
469 {
470         struct message *m;
471         manager_action("Status", "%s", "");
472         m = wait_for_response(10000);
473         if (!m) {
474                 show_message("Status Failed", "Timeout waiting for response");
475         } else if (strcasecmp(get_header(m, "Response"), "Success"))  {
476                 show_message("Status Failed Failed", get_header(m, "Message"));
477         }
478 }
479
480
481 static void try_hangup(newtComponent c)
482 {
483         struct ast_chan *chan;
484         struct message *m;
485
486         chan = newtListboxGetCurrent(c);
487         if (chan) {
488                 manager_action("Hangup", "Channel: %s\r\n", chan->name);
489                 m = wait_for_response(10000);
490                 if (!m) {
491                         show_message("Hangup Failed", "Timeout waiting for response");
492                 } else if (strcasecmp(get_header(m, "Response"), "Success"))  {
493                         show_message("Hangup Failed", get_header(m, "Message"));
494                 }
495         }
496
497 }
498
499 static int get_user_input(char *msg, char *buf, int buflen)
500 {
501         newtComponent form;
502         newtComponent ok;
503         newtComponent cancel;
504         newtComponent inpfield;
505         const char *input;
506         int res = -1;
507         struct newtExitStruct es;
508
509         newtCenteredWindow(60,7, msg);
510
511         inpfield = newtEntry(5, 2, "", 50, _NEWT_CAST &input, 0);
512         ok = newtButton(22, 3, "OK");
513         cancel = newtButton(32, 3, "Cancel");
514         form = newtForm(NULL, NULL, 0);
515         newtFormAddComponents(form, inpfield, ok, cancel, NULL);
516         newtFormRun(form, &es);
517         strncpy(buf, input, buflen - 1);
518         if (es.u.co == ok)
519                 res = 0;
520         else
521                 res = -1;
522         newtPopWindow();
523         newtFormDestroy(form);
524         return res;
525 }
526
527 static void try_redirect(newtComponent c)
528 {
529         struct ast_chan *chan;
530         char dest[256];
531         struct message *m;
532         char channame[256];
533         char tmp[80];
534         char *context;
535
536         chan = newtListboxGetCurrent(c);
537         if (chan) {
538                 strncpy(channame, chan->name, sizeof(channame) - 1);
539                 snprintf(tmp, sizeof(tmp), "Enter new extension for %s", channame);
540                 if (get_user_input(tmp, dest, sizeof(dest)))
541                         return;
542                 if ((context = strchr(dest, '@'))) {
543                         *context = '\0';
544                         context++;
545                         manager_action("Redirect", "Channel: %s\r\nContext: %s\r\nExten: %s\r\nPriority: 1\r\n", chan->name,context,dest);
546                 } else {
547                         manager_action("Redirect", "Channel: %s\r\nExten: %s\r\nPriority: 1\r\n", chan->name, dest);
548                 }
549                 m = wait_for_response(10000);
550                 if (!m) {
551                         show_message("Hangup Failed", "Timeout waiting for response");
552                 } else if (strcasecmp(get_header(m, "Response"), "Success"))  {
553                         show_message("Hangup Failed", get_header(m, "Message"));
554                 }
555         }
556
557 }
558
559 static int manage_calls(char *host)
560 {
561         newtComponent form;
562         newtComponent quit;
563         newtComponent hangup;
564         newtComponent redirect;
565         newtComponent channels;
566         struct newtExitStruct es;
567         char tmp[80];
568
569         /* Mark: If there's one thing you learn from this code, it is this...
570            Never, ever fly Air France.  Their customer service is absolutely
571            the worst.  I've never heard the words "That's not my problem" as
572            many times as I have from their staff -- It should, without doubt
573            be their corporate motto if it isn't already.  Don't bother giving
574            them business because you're just a pain in their side and they
575            will be sure to let you know the first time you speak to them.
576
577            If you ever want to make me happy just tell me that you, too, will
578            never fly Air France again either (in spite of their excellent
579            cuisine).
580
581            Update by oej: The merger with KLM has transferred this
582            behaviour to KLM as well.
583            Don't bother giving them business either...
584
585            Only if you want to travel randomly without luggage, you
586            might pick either of them.
587
588         */
589         snprintf(tmp, sizeof(tmp), "Asterisk Manager at %s", host);
590         newtCenteredWindow(74, 20, tmp);
591         form = newtForm(NULL, NULL, 0);
592         newtFormWatchFd(form, session.fd, NEWT_FD_READ);
593         newtFormSetTimer(form, 100);
594         quit = newtButton(62, 16, "Quit");
595         redirect = newtButton(35, 16, "Redirect");
596         hangup = newtButton(50, 16, "Hangup");
597         channels = newtListbox(1,1,14, NEWT_FLAG_SCROLL);
598         newtFormAddComponents(form, channels, redirect, hangup, quit, NULL);
599         newtListboxSetWidth(channels, 72);
600
601         show_doing("Getting Status", "Retrieving system status...");
602         try_status();
603         hide_doing();
604
605         for(;;) {
606                 newtFormRun(form, &es);
607                 if (has_input(&session) || (es.reason == NEWT_EXIT_FDREADY)) {
608                         if (input_check(&session, NULL)) {
609                                 show_message("Disconnected", "Disconnected from remote host");
610                                 break;
611                         }
612                 } else if (es.reason == NEWT_EXIT_COMPONENT) {
613                         if (es.u.co == quit)
614                                 break;
615                         if (es.u.co == hangup) {
616                                 try_hangup(channels);
617                         } else if (es.u.co == redirect) {
618                                 try_redirect(channels);
619                         }
620                 }
621                 rebuild_channels(channels);
622         }
623         newtFormDestroy(form);
624         return 0;
625 }
626
627 static int manager_login(char *hostname)
628 {
629         newtComponent form;
630         newtComponent cancel;
631         newtComponent login;
632         newtComponent username;
633         newtComponent password;
634         newtComponent label;
635         newtComponent ulabel;
636         newtComponent plabel;
637         const char *user;
638         const char *pass;
639         struct message *m;
640         struct newtExitStruct es;
641         char tmp[55];
642         struct hostent *hp;
643         int res = -1;
644
645         session.fd = socket(AF_INET, SOCK_STREAM, 0);
646         if (session.fd < 0) {
647                 snprintf(tmp, sizeof(tmp), "socket() failed: %s\n", strerror(errno));
648                 show_message("Socket failed", tmp);
649                 return -1;
650         }
651
652         snprintf(tmp, sizeof(tmp), "Looking up %s\n", hostname);
653         show_doing("Connecting....", tmp);
654
655
656         hp = gethostbyname(hostname);
657         if (!hp) {
658                 snprintf(tmp, sizeof(tmp), "No such address: %s\n", hostname);
659                 show_message("Host lookup failed", tmp);
660                 return -1;
661         }
662         hide_doing();
663         snprintf(tmp, sizeof(tmp), "Connecting to %s", hostname);
664         show_doing("Connecting...", tmp);
665
666         session.sin.sin_family = AF_INET;
667         session.sin.sin_port = htons(DEFAULT_MANAGER_PORT);
668         memcpy(&session.sin.sin_addr, hp->h_addr, sizeof(session.sin.sin_addr));
669
670         if (connect(session.fd,(struct sockaddr*)&session.sin, sizeof(session.sin))) {
671                 snprintf(tmp, sizeof(tmp), "%s failed: %s\n", hostname, strerror(errno));
672                 show_message("Connect Failed", tmp);
673                 return -1;
674         }
675
676         hide_doing();
677
678         login = newtButton(5, 6, "Login");
679         cancel = newtButton(25, 6, "Cancel");
680         newtCenteredWindow(40, 10, "Asterisk Manager Login");
681         snprintf(tmp, sizeof(tmp), "Host:     %s", hostname);
682         label = newtLabel(4,1, tmp);
683
684         ulabel = newtLabel(4,2,"Username:");
685         plabel = newtLabel(4,3,"Password:");
686
687         username = newtEntry(14, 2, "", 20, _NEWT_CAST &user, 0);
688         password = newtEntry(14, 3, "", 20, _NEWT_CAST &pass, NEWT_FLAG_HIDDEN);
689
690         form = newtForm(NULL, NULL, 0);
691         newtFormAddComponents(form, username, password, login, cancel, label, ulabel, plabel,NULL);
692         newtFormRun(form, &es);
693         if (es.reason == NEWT_EXIT_COMPONENT) {
694                 if (es.u.co == login) {
695                         snprintf(tmp, sizeof(tmp), "Logging in '%s'...", user);
696                         show_doing("Logging in", tmp);
697                         /* Check to see if the remote host supports MD5 Authentication */
698                         manager_action("Challenge", "AuthType: MD5\r\n");
699                         m = wait_for_response(10000);
700                         if (m && !strcasecmp(get_header(m, "Response"), "Success")) {
701                                 char *challenge = get_header(m, "Challenge");
702                                 int x;
703                                 int len = 0;
704                                 char md5key[256] = "";
705                                 struct MD5Context md5;
706                                 unsigned char digest[16];
707                                 MD5Init(&md5);
708                                 MD5Update(&md5, (unsigned char *)challenge, strlen(challenge));
709                                 MD5Update(&md5, (unsigned char *)pass, strlen(pass));
710                                 MD5Final(digest, &md5);
711                                 for (x=0; x<16; x++)
712                                         len += sprintf(md5key + len, "%02hhx", digest[x]);
713                                 manager_action("Login",
714                                                 "AuthType: MD5\r\n"
715                                                 "Username: %s\r\n"
716                                                 "Key: %s\r\n",
717                                                 user, md5key);
718                                 m = wait_for_response(10000);
719                                 hide_doing();
720                                 if (!strcasecmp(get_header(m, "Response"), "Success")) {
721                                         res = 0;
722                                 } else {
723                                         show_message("Login Failed", get_header(m, "Message"));
724                                 }
725                         } else {
726                                 manager_action("Login",
727                                         "Username: %s\r\n"
728                                         "Secret: %s\r\n",
729                                                 user, pass);
730                                 m = wait_for_response(10000);
731                                 hide_doing();
732                                 if (m) {
733                                         if (!strcasecmp(get_header(m, "Response"), "Success")) {
734                                                 res = 0;
735                                         } else {
736                                                 show_message("Login Failed", get_header(m, "Message"));
737                                         }
738                                 }
739                         }
740                 }
741         }
742         newtFormDestroy(form);
743         return res;
744 }
745
746 int main(int argc, char *argv[])
747 {
748         if (argc < 2) {
749                 fprintf(stderr, "Usage: astman <host>\n");
750                 exit(1);
751         }
752         newtInit();
753         newtCls();
754         newtDrawRootText(0, 0, "Asterisk Manager (C)2002, Linux Support Services, Inc.");
755         newtPushHelpLine("Welcome to the Asterisk Manager!");
756         if (manager_login(argv[1])) {
757                 newtFinished();
758                 exit(1);
759         }
760         manage_calls(argv[1]);
761         newtFinished();
762         return 0;
763 }