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