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