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