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