more command completion normalization.
[asterisk/asterisk.git] / manager.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2006, 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 /*! \file
20  *
21  * \brief The Asterisk Management Interface - AMI
22  *
23  * \author Mark Spencer <markster@digium.com>
24  *
25  * Channel Management and more
26  * 
27  * \ref amiconf
28  */
29
30 /*! \addtogroup Group_AMI AMI functions 
31 */
32 /*! @{ 
33  Doxygen group */
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <sys/time.h>
39 #include <sys/types.h>
40 #include <netdb.h>
41 #include <sys/socket.h>
42 #include <netinet/in.h>
43 #include <netinet/tcp.h>
44 #include <arpa/inet.h>
45 #include <signal.h>
46 #include <errno.h>
47 #include <unistd.h>
48
49 #include "asterisk.h"
50
51 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
52
53 #include "asterisk/channel.h"
54 #include "asterisk/file.h"
55 #include "asterisk/manager.h"
56 #include "asterisk/config.h"
57 #include "asterisk/callerid.h"
58 #include "asterisk/lock.h"
59 #include "asterisk/logger.h"
60 #include "asterisk/options.h"
61 #include "asterisk/cli.h"
62 #include "asterisk/app.h"
63 #include "asterisk/pbx.h"
64 #include "asterisk/md5.h"
65 #include "asterisk/acl.h"
66 #include "asterisk/utils.h"
67
68 struct fast_originate_helper {
69         char tech[AST_MAX_MANHEADER_LEN];
70         char data[AST_MAX_MANHEADER_LEN];
71         int timeout;
72         char app[AST_MAX_APP];
73         char appdata[AST_MAX_MANHEADER_LEN];
74         char cid_name[AST_MAX_MANHEADER_LEN];
75         char cid_num[AST_MAX_MANHEADER_LEN];
76         char context[AST_MAX_CONTEXT];
77         char exten[AST_MAX_EXTENSION];
78         char idtext[AST_MAX_MANHEADER_LEN];
79         char account[AST_MAX_ACCOUNT_CODE];
80         int priority;
81         struct ast_variable *vars;
82 };
83
84 static int enabled = 0;
85 static int portno = DEFAULT_MANAGER_PORT;
86 static int asock = -1;
87 static int displayconnects = 1;
88 static int timestampevents = 0;
89
90 static pthread_t t;
91 AST_MUTEX_DEFINE_STATIC(sessionlock);
92 static int block_sockets = 0;
93
94 static struct permalias {
95         int num;
96         char *label;
97 } perms[] = {
98         { EVENT_FLAG_SYSTEM, "system" },
99         { EVENT_FLAG_CALL, "call" },
100         { EVENT_FLAG_LOG, "log" },
101         { EVENT_FLAG_VERBOSE, "verbose" },
102         { EVENT_FLAG_COMMAND, "command" },
103         { EVENT_FLAG_AGENT, "agent" },
104         { EVENT_FLAG_USER, "user" },
105         { -1, "all" },
106         { 0, "none" },
107 };
108
109 static struct mansession {
110         /*! Execution thread */
111         pthread_t t;
112         /*! Thread lock -- don't use in action callbacks, it's already taken care of  */
113         ast_mutex_t __lock;
114         /*! socket address */
115         struct sockaddr_in sin;
116         /*! TCP socket */
117         int fd;
118         /*! Whether or not we're busy doing an action */
119         int busy;
120         /*! Whether or not we're "dead" */
121         int dead;
122         /*! Logged in username */
123         char username[80];
124         /*! Authentication challenge */
125         char challenge[10];
126         /*! Authentication status */
127         int authenticated;
128         /*! Authorization for reading */
129         int readperm;
130         /*! Authorization for writing */
131         int writeperm;
132         /*! Buffer */
133         char inbuf[AST_MAX_MANHEADER_LEN];
134         int inlen;
135         int send_events;
136         /* Queued events that we've not had the ability to send yet */
137         struct eventqent *eventq;
138         /* Timeout for ast_carefulwrite() */
139         int writetimeout;
140         struct mansession *next;
141 } *sessions = NULL;
142
143 static struct manager_action *first_action = NULL;
144 AST_MUTEX_DEFINE_STATIC(actionlock);
145
146 /*! If you are calling ast_carefulwrite, it is assumed that you are calling
147    it on a file descriptor that _DOES_ have NONBLOCK set.  This way,
148    there is only one system call made to do a write, unless we actually
149    have a need to wait.  This way, we get better performance. */
150 int ast_carefulwrite(int fd, char *s, int len, int timeoutms) 
151 {
152         /* Try to write string, but wait no more than ms milliseconds
153            before timing out */
154         int res=0;
155         struct pollfd fds[1];
156         while(len) {
157                 res = write(fd, s, len);
158                 if ((res < 0) && (errno != EAGAIN)) {
159                         return -1;
160                 }
161                 if (res < 0) res = 0;
162                 len -= res;
163                 s += res;
164                 res = 0;
165                 if (len) {
166                         fds[0].fd = fd;
167                         fds[0].events = POLLOUT;
168                         /* Wait until writable again */
169                         res = poll(fds, 1, timeoutms);
170                         if (res < 1)
171                                 return -1;
172                 }
173         }
174         return res;
175 }
176
177 /*! authority_to_str: Convert authority code to string with serveral options */
178 static char *authority_to_str(int authority, char *res, int reslen)
179 {
180         int running_total = 0, i;
181         memset(res, 0, reslen);
182         for (i=0; i<sizeof(perms) / sizeof(perms[0]) - 1; i++) {
183                 if (authority & perms[i].num) {
184                         if (*res) {
185                                 strncat(res, ",", (reslen > running_total) ? reslen - running_total : 0);
186                                 running_total++;
187                         }
188                         strncat(res, perms[i].label, (reslen > running_total) ? reslen - running_total : 0);
189                         running_total += strlen(perms[i].label);
190                 }
191         }
192         if (ast_strlen_zero(res)) {
193                 ast_copy_string(res, "<none>", reslen);
194         }
195         return res;
196 }
197
198 static char *complete_show_mancmd(const char *line, const char *word, int pos, int state)
199 {
200         struct manager_action *cur;
201         int which = 0;
202         char *ret = NULL;
203
204         ast_mutex_lock(&actionlock);
205         for (cur = first_action; cur; cur = cur->next) { /* Walk the list of actions */
206                 if (!strncasecmp(word, cur->action, strlen(word)) && ++which > state) {
207                         ret = ast_strdup(cur->action);
208                         break;  /* make sure we exit even if ast_strdup() returns NULL */
209                 }
210         }
211         ast_mutex_unlock(&actionlock);
212         return ret;
213 }
214
215 void astman_append(struct mansession *s, const char *fmt, ...)
216 {
217         char *stuff;
218         int res;
219         va_list ap;
220
221         va_start(ap, fmt);
222         res = vasprintf(&stuff, fmt, ap);
223         va_end(ap);
224         if (res == -1) {
225                 ast_log(LOG_ERROR, "Memory allocation failure\n");
226         } else {
227                 ast_carefulwrite(s->fd, stuff, strlen(stuff), 100);
228                 free(stuff);
229         }
230 }
231
232 static int handle_showmancmd(int fd, int argc, char *argv[])
233 {
234         struct manager_action *cur = first_action;
235         char authority[80];
236         int num;
237
238         if (argc != 4)
239                 return RESULT_SHOWUSAGE;
240         ast_mutex_lock(&actionlock);
241         while (cur) { /* Walk the list of actions */
242                 for (num = 3; num < argc; num++) {
243                         if (!strcasecmp(cur->action, argv[num])) {
244                                 ast_cli(fd, "Action: %s\nSynopsis: %s\nPrivilege: %s\n%s\n", cur->action, cur->synopsis, authority_to_str(cur->authority, authority, sizeof(authority) -1), cur->description ? cur->description : "");
245                         }
246                 }
247                 cur = cur->next;
248         }
249
250         ast_mutex_unlock(&actionlock);
251         return RESULT_SUCCESS;
252 }
253
254 /*! \brief  handle_showmancmds: CLI command */
255 /* Should change to "manager show commands" */
256 static int handle_showmancmds(int fd, int argc, char *argv[])
257 {
258         struct manager_action *cur = first_action;
259         char authority[80];
260         char *format = "  %-15.15s  %-15.15s  %-55.55s\n";
261
262         ast_mutex_lock(&actionlock);
263         ast_cli(fd, format, "Action", "Privilege", "Synopsis");
264         ast_cli(fd, format, "------", "---------", "--------");
265         while (cur) { /* Walk the list of actions */
266                 ast_cli(fd, format, cur->action, authority_to_str(cur->authority, authority, sizeof(authority) -1), cur->synopsis);
267                 cur = cur->next;
268         }
269
270         ast_mutex_unlock(&actionlock);
271         return RESULT_SUCCESS;
272 }
273
274 /*! \brief  handle_showmanconn: CLI command show manager connected */
275 /* Should change to "manager show connected" */
276 static int handle_showmanconn(int fd, int argc, char *argv[])
277 {
278         struct mansession *s;
279         char iabuf[INET_ADDRSTRLEN];
280         char *format = "  %-15.15s  %-15.15s\n";
281         ast_mutex_lock(&sessionlock);
282         s = sessions;
283         ast_cli(fd, format, "Username", "IP Address");
284         while (s) {
285                 ast_cli(fd, format,s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
286                 s = s->next;
287         }
288
289         ast_mutex_unlock(&sessionlock);
290         return RESULT_SUCCESS;
291 }
292
293 static char showmancmd_help[] = 
294 "Usage: show manager command <actionname>\n"
295 "       Shows the detailed description for a specific Asterisk manager interface command.\n";
296
297 static char showmancmds_help[] = 
298 "Usage: show manager commands\n"
299 "       Prints a listing of all the available Asterisk manager interface commands.\n";
300
301 static char showmanconn_help[] = 
302 "Usage: show manager connected\n"
303 "       Prints a listing of the users that are currently connected to the\n"
304 "Asterisk manager interface.\n";
305
306 static struct ast_cli_entry show_mancmd_cli =
307         { { "show", "manager", "command", NULL },
308         handle_showmancmd, "Show a manager interface command", showmancmd_help, complete_show_mancmd };
309
310 static struct ast_cli_entry show_mancmds_cli =
311         { { "show", "manager", "commands", NULL },
312         handle_showmancmds, "List manager interface commands", showmancmds_help };
313
314 static struct ast_cli_entry show_manconn_cli =
315         { { "show", "manager", "connected", NULL },
316         handle_showmanconn, "Show connected manager interface users", showmanconn_help };
317
318 static void free_session(struct mansession *s)
319 {
320         struct eventqent *eqe;
321         if (s->fd > -1)
322                 close(s->fd);
323         ast_mutex_destroy(&s->__lock);
324         while(s->eventq) {
325                 eqe = s->eventq;
326                 s->eventq = s->eventq->next;
327                 free(eqe);
328         }
329         free(s);
330 }
331
332 static void destroy_session(struct mansession *s)
333 {
334         struct mansession *cur, *prev = NULL;
335         ast_mutex_lock(&sessionlock);
336         cur = sessions;
337         while(cur) {
338                 if (cur == s)
339                         break;
340                 prev = cur;
341                 cur = cur->next;
342         }
343         if (cur) {
344                 if (prev)
345                         prev->next = cur->next;
346                 else
347                         sessions = cur->next;
348                 free_session(s);
349         } else
350                 ast_log(LOG_WARNING, "Trying to delete nonexistent session %p?\n", s);
351         ast_mutex_unlock(&sessionlock);
352         
353 }
354
355 char *astman_get_header(struct message *m, char *var)
356 {
357         char cmp[80];
358         int x;
359         snprintf(cmp, sizeof(cmp), "%s: ", var);
360         for (x=0;x<m->hdrcount;x++)
361                 if (!strncasecmp(cmp, m->headers[x], strlen(cmp)))
362                         return m->headers[x] + strlen(cmp);
363         return "";
364 }
365
366 struct ast_variable *astman_get_variables(struct message *m)
367 {
368         int varlen, x, y;
369         struct ast_variable *head = NULL, *cur;
370         char *var, *val;
371
372         char *parse;    
373         AST_DECLARE_APP_ARGS(args,
374                 AST_APP_ARG(vars)[32];
375         );
376
377         varlen = strlen("Variable: ");  
378
379         for (x = 0; x < m->hdrcount; x++) {
380                 if (strncasecmp("Variable: ", m->headers[x], varlen))
381                         continue;
382
383                 if (!(parse = ast_strdupa(m->headers[x] + varlen)))
384                         return head;
385
386                 AST_STANDARD_APP_ARGS(args, parse);
387                 if (args.argc) {
388                         for (y = 0; y < args.argc; y++) {
389                                 if (!args.vars[y])
390                                         continue;
391                                 var = val = ast_strdupa(args.vars[y]);
392                                 strsep(&val, "=");
393                                 if (!val || ast_strlen_zero(var))
394                                         continue;
395                                 cur = ast_variable_new(var, val);
396                                 if (head) {
397                                         cur->next = head;
398                                         head = cur;
399                                 } else
400                                         head = cur;
401                         }
402                 }
403         }
404
405         return head;
406 }
407
408 /*! NOTE:
409    Callers of astman_send_error(), astman_send_response() or astman_send_ack() must EITHER
410    hold the session lock _or_ be running in an action callback (in which case s->busy will
411    be non-zero). In either of these cases, there is no need to lock-protect the session's
412    fd, since no other output will be sent (events will be queued), and no input will
413    be read until either the current action finishes or get_input() obtains the session
414    lock.
415  */
416 void astman_send_error(struct mansession *s, struct message *m, char *error)
417 {
418         char *id = astman_get_header(m,"ActionID");
419
420         astman_append(s, "Response: Error\r\n");
421         if (!ast_strlen_zero(id))
422                 astman_append(s, "ActionID: %s\r\n",id);
423         astman_append(s, "Message: %s\r\n\r\n", error);
424 }
425
426 void astman_send_response(struct mansession *s, struct message *m, char *resp, char *msg)
427 {
428         char *id = astman_get_header(m,"ActionID");
429
430         astman_append(s, "Response: %s\r\n", resp);
431         if (!ast_strlen_zero(id))
432                 astman_append(s, "ActionID: %s\r\n",id);
433         if (msg)
434                 astman_append(s, "Message: %s\r\n\r\n", msg);
435         else
436                 astman_append(s, "\r\n");
437 }
438
439 void astman_send_ack(struct mansession *s, struct message *m, char *msg)
440 {
441         astman_send_response(s, m, "Success", msg);
442 }
443
444 /*! Tells you if smallstr exists inside bigstr
445    which is delim by delim and uses no buf or stringsep
446    ast_instring("this|that|more","this",',') == 1;
447
448    feel free to move this to app.c -anthm */
449 static int ast_instring(char *bigstr, char *smallstr, char delim) 
450 {
451         char *val = bigstr, *next;
452
453         do {
454                 if ((next = strchr(val, delim))) {
455                         if (!strncmp(val, smallstr, (next - val)))
456                                 return 1;
457                         else
458                                 continue;
459                 } else
460                         return !strcmp(smallstr, val);
461
462         } while (*(val = (next + 1)));
463
464         return 0;
465 }
466
467 static int get_perm(char *instr)
468 {
469         int x = 0, ret = 0;
470
471         if (!instr)
472                 return 0;
473
474         for (x=0; x<sizeof(perms) / sizeof(perms[0]); x++)
475                 if (ast_instring(instr, perms[x].label, ','))
476                         ret |= perms[x].num;
477         
478         return ret;
479 }
480
481 static int ast_is_number(char *string) 
482 {
483         int ret = 1, x = 0;
484
485         if (!string)
486                 return 0;
487
488         for (x=0; x < strlen(string); x++) {
489                 if (!(string[x] >= 48 && string[x] <= 57)) {
490                         ret = 0;
491                         break;
492                 }
493         }
494         
495         return ret ? atoi(string) : 0;
496 }
497
498 static int ast_strings_to_mask(char *string) 
499 {
500         int x, ret = -1;
501         
502         x = ast_is_number(string);
503
504         if (x) {
505                 ret = x;
506         } else if (ast_strlen_zero(string)) {
507                 ret = -1;
508         } else if (ast_false(string)) {
509                 ret = 0;
510         } else if (ast_true(string)) {
511                 ret = 0;
512                 for (x=0; x<sizeof(perms) / sizeof(perms[0]); x++)
513                         ret |= perms[x].num;            
514         } else {
515                 ret = 0;
516                 for (x=0; x<sizeof(perms) / sizeof(perms[0]); x++) {
517                         if (ast_instring(string, perms[x].label, ',')) 
518                                 ret |= perms[x].num;            
519                 }
520         }
521
522         return ret;
523 }
524
525 /*! 
526    Rather than braindead on,off this now can also accept a specific int mask value 
527    or a ',' delim list of mask strings (the same as manager.conf) -anthm
528 */
529
530 static int set_eventmask(struct mansession *s, char *eventmask)
531 {
532         int maskint = ast_strings_to_mask(eventmask);
533
534         ast_mutex_lock(&s->__lock);
535         if (maskint >= 0)       
536                 s->send_events = maskint;
537         ast_mutex_unlock(&s->__lock);
538         
539         return maskint;
540 }
541
542 static int authenticate(struct mansession *s, struct message *m)
543 {
544         struct ast_config *cfg;
545         char iabuf[INET_ADDRSTRLEN];
546         char *cat;
547         char *user = astman_get_header(m, "Username");
548         char *pass = astman_get_header(m, "Secret");
549         char *authtype = astman_get_header(m, "AuthType");
550         char *key = astman_get_header(m, "Key");
551         char *events = astman_get_header(m, "Events");
552         
553         cfg = ast_config_load("manager.conf");
554         if (!cfg)
555                 return -1;
556         cat = ast_category_browse(cfg, NULL);
557         while(cat) {
558                 if (strcasecmp(cat, "general")) {
559                         /* This is a user */
560                         if (!strcasecmp(cat, user)) {
561                                 struct ast_variable *v;
562                                 struct ast_ha *ha = NULL;
563                                 char *password = NULL;
564                                 v = ast_variable_browse(cfg, cat);
565                                 while (v) {
566                                         if (!strcasecmp(v->name, "secret")) {
567                                                 password = v->value;
568                                         } else if (!strcasecmp(v->name, "permit") ||
569                                                    !strcasecmp(v->name, "deny")) {
570                                                 ha = ast_append_ha(v->name, v->value, ha);
571                                         } else if (!strcasecmp(v->name, "writetimeout")) {
572                                                 int val = atoi(v->value);
573
574                                                 if (val < 100)
575                                                         ast_log(LOG_WARNING, "Invalid writetimeout value '%s' at line %d\n", v->value, v->lineno);
576                                                 else
577                                                         s->writetimeout = val;
578                                         }
579                                                 
580                                         v = v->next;
581                                 }
582                                 if (ha && !ast_apply_ha(ha, &(s->sin))) {
583                                         ast_log(LOG_NOTICE, "%s failed to pass IP ACL as '%s'\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), user);
584                                         ast_free_ha(ha);
585                                         ast_config_destroy(cfg);
586                                         return -1;
587                                 } else if (ha)
588                                         ast_free_ha(ha);
589                                 if (!strcasecmp(authtype, "MD5")) {
590                                         if (!ast_strlen_zero(key) && s->challenge) {
591                                                 int x;
592                                                 int len=0;
593                                                 char md5key[256] = "";
594                                                 struct MD5Context md5;
595                                                 unsigned char digest[16];
596                                                 MD5Init(&md5);
597                                                 MD5Update(&md5, (unsigned char *) s->challenge, strlen(s->challenge));
598                                                 MD5Update(&md5, (unsigned char *) password, strlen(password));
599                                                 MD5Final(digest, &md5);
600                                                 for (x=0;x<16;x++)
601                                                         len += sprintf(md5key + len, "%2.2x", digest[x]);
602                                                 if (!strcmp(md5key, key))
603                                                         break;
604                                                 else {
605                                                         ast_config_destroy(cfg);
606                                                         return -1;
607                                                 }
608                                         }
609                                 } else if (password && !strcasecmp(password, pass)) {
610                                         break;
611                                 } else {
612                                         ast_log(LOG_NOTICE, "%s failed to authenticate as '%s'\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), user);
613                                         ast_config_destroy(cfg);
614                                         return -1;
615                                 }       
616                         }
617                 }
618                 cat = ast_category_browse(cfg, cat);
619         }
620         if (cat) {
621                 ast_copy_string(s->username, cat, sizeof(s->username));
622                 s->readperm = get_perm(ast_variable_retrieve(cfg, cat, "read"));
623                 s->writeperm = get_perm(ast_variable_retrieve(cfg, cat, "write"));
624                 ast_config_destroy(cfg);
625                 if (events)
626                         set_eventmask(s, events);
627                 return 0;
628         }
629         ast_log(LOG_NOTICE, "%s tried to authenticate with nonexistent user '%s'\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), user);
630         ast_config_destroy(cfg);
631         return -1;
632 }
633
634 /*! \brief PING: Manager PING */
635 static char mandescr_ping[] = 
636 "Description: A 'Ping' action will ellicit a 'Pong' response.  Used to keep the "
637 "  manager connection open.\n"
638 "Variables: NONE\n";
639
640 static int action_ping(struct mansession *s, struct message *m)
641 {
642         astman_send_response(s, m, "Pong", NULL);
643         return 0;
644 }
645
646 static char mandescr_listcommands[] = 
647 "Description: Returns the action name and synopsis for every\n"
648 "  action that is available to the user\n"
649 "Variables: NONE\n";
650
651 static int action_listcommands(struct mansession *s, struct message *m)
652 {
653         struct manager_action *cur = first_action;
654         char idText[256] = "";
655         char temp[BUFSIZ];
656         char *id = astman_get_header(m,"ActionID");
657
658         if (!ast_strlen_zero(id))
659                 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
660         astman_append(s, "Response: Success\r\n%s", idText);
661         ast_mutex_lock(&actionlock);
662         while (cur) { /* Walk the list of actions */
663                 if ((s->writeperm & cur->authority) == cur->authority)
664                         astman_append(s, "%s: %s (Priv: %s)\r\n", cur->action, cur->synopsis, authority_to_str(cur->authority, temp, sizeof(temp)) );
665                 cur = cur->next;
666         }
667         ast_mutex_unlock(&actionlock);
668         astman_append(s, "\r\n");
669
670         return 0;
671 }
672
673 static char mandescr_events[] = 
674 "Description: Enable/Disable sending of events to this manager\n"
675 "  client.\n"
676 "Variables:\n"
677 "       EventMask: 'on' if all events should be sent,\n"
678 "               'off' if no events should be sent,\n"
679 "               'system,call,log' to select which flags events should have to be sent.\n";
680
681 static int action_events(struct mansession *s, struct message *m)
682 {
683         char *mask = astman_get_header(m, "EventMask");
684         int res;
685
686         res = set_eventmask(s, mask);
687         if (res > 0)
688                 astman_send_response(s, m, "Events On", NULL);
689         else if (res == 0)
690                 astman_send_response(s, m, "Events Off", NULL);
691
692         return 0;
693 }
694
695 static char mandescr_logoff[] = 
696 "Description: Logoff this manager session\n"
697 "Variables: NONE\n";
698
699 static int action_logoff(struct mansession *s, struct message *m)
700 {
701         astman_send_response(s, m, "Goodbye", "Thanks for all the fish.");
702         return -1;
703 }
704
705 static char mandescr_hangup[] = 
706 "Description: Hangup a channel\n"
707 "Variables: \n"
708 "       Channel: The channel name to be hungup\n";
709
710 static int action_hangup(struct mansession *s, struct message *m)
711 {
712         struct ast_channel *c = NULL;
713         char *name = astman_get_header(m, "Channel");
714         if (ast_strlen_zero(name)) {
715                 astman_send_error(s, m, "No channel specified");
716                 return 0;
717         }
718         c = ast_get_channel_by_name_locked(name);
719         if (!c) {
720                 astman_send_error(s, m, "No such channel");
721                 return 0;
722         }
723         ast_softhangup(c, AST_SOFTHANGUP_EXPLICIT);
724         ast_mutex_unlock(&c->lock);
725         astman_send_ack(s, m, "Channel Hungup");
726         return 0;
727 }
728
729 static char mandescr_setvar[] = 
730 "Description: Set a global or local channel variable.\n"
731 "Variables: (Names marked with * are required)\n"
732 "       Channel: Channel to set variable for\n"
733 "       *Variable: Variable name\n"
734 "       *Value: Value\n";
735
736 static int action_setvar(struct mansession *s, struct message *m)
737 {
738         struct ast_channel *c = NULL;
739         char *name = astman_get_header(m, "Channel");
740         char *varname = astman_get_header(m, "Variable");
741         char *varval = astman_get_header(m, "Value");
742         
743         if (ast_strlen_zero(varname)) {
744                 astman_send_error(s, m, "No variable specified");
745                 return 0;
746         }
747         
748         if (ast_strlen_zero(varval)) {
749                 astman_send_error(s, m, "No value specified");
750                 return 0;
751         }
752
753         if (!ast_strlen_zero(name)) {
754                 c = ast_get_channel_by_name_locked(name);
755                 if (!c) {
756                         astman_send_error(s, m, "No such channel");
757                         return 0;
758                 }
759         }
760         
761         pbx_builtin_setvar_helper(c, varname, varval);
762           
763         if (c)
764                 ast_mutex_unlock(&c->lock);
765
766         astman_send_ack(s, m, "Variable Set");  
767
768         return 0;
769 }
770
771 static char mandescr_getvar[] = 
772 "Description: Get the value of a global or local channel variable.\n"
773 "Variables: (Names marked with * are required)\n"
774 "       Channel: Channel to read variable from\n"
775 "       *Variable: Variable name\n"
776 "       ActionID: Optional Action id for message matching.\n";
777
778 static int action_getvar(struct mansession *s, struct message *m)
779 {
780         struct ast_channel *c = NULL;
781         char *name = astman_get_header(m, "Channel");
782         char *varname = astman_get_header(m, "Variable");
783         char *id = astman_get_header(m,"ActionID");
784         char *varval;
785         char workspace[1024];
786
787         if (ast_strlen_zero(varname)) {
788                 astman_send_error(s, m, "No variable specified");
789                 return 0;
790         }
791
792         if (!ast_strlen_zero(name)) {
793                 c = ast_get_channel_by_name_locked(name);
794                 if (!c) {
795                         astman_send_error(s, m, "No such channel");
796                         return 0;
797                 }
798         }
799
800         if (varname[strlen(varname) - 1] == ')') {
801                 ast_func_read(c, varname, workspace, sizeof(workspace));
802         } else {
803                 pbx_retrieve_variable(c, varname, &varval, workspace, sizeof(workspace), NULL);
804         }
805
806         if (c)
807                 ast_mutex_unlock(&c->lock);
808         astman_append(s, "Response: Success\r\n"
809                 "Variable: %s\r\nValue: %s\r\n", varname, varval);
810         if (!ast_strlen_zero(id))
811                 astman_append(s, "ActionID: %s\r\n",id);
812         astman_append(s, "\r\n");
813
814         return 0;
815 }
816
817
818 /*! \brief  action_status: Manager "status" command to show channels */
819 /* Needs documentation... */
820 static int action_status(struct mansession *s, struct message *m)
821 {
822         char *id = astman_get_header(m,"ActionID");
823         char *name = astman_get_header(m,"Channel");
824         char idText[256] = "";
825         struct ast_channel *c;
826         char bridge[256];
827         struct timeval now = ast_tvnow();
828         long elapsed_seconds=0;
829         int all = ast_strlen_zero(name); /* set if we want all channels */
830
831         astman_send_ack(s, m, "Channel status will follow");
832         if (!ast_strlen_zero(id))
833                 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
834         if (all)
835                 c = ast_channel_walk_locked(NULL);
836         else {
837                 c = ast_get_channel_by_name_locked(name);
838                 if (!c) {
839                         astman_send_error(s, m, "No such channel");
840                         return 0;
841                 }
842         }
843         /* if we look by name, we break after the first iteration */
844         while(c) {
845                 if (c->_bridge)
846                         snprintf(bridge, sizeof(bridge), "Link: %s\r\n", c->_bridge->name);
847                 else
848                         bridge[0] = '\0';
849                 if (c->pbx) {
850                         if (c->cdr) {
851                                 elapsed_seconds = now.tv_sec - c->cdr->start.tv_sec;
852                         }
853                         astman_append(s,
854                         "Event: Status\r\n"
855                         "Privilege: Call\r\n"
856                         "Channel: %s\r\n"
857                         "CallerID: %s\r\n"
858                         "CallerIDName: %s\r\n"
859                         "Account: %s\r\n"
860                         "State: %s\r\n"
861                         "Context: %s\r\n"
862                         "Extension: %s\r\n"
863                         "Priority: %d\r\n"
864                         "Seconds: %ld\r\n"
865                         "%s"
866                         "Uniqueid: %s\r\n"
867                         "%s"
868                         "\r\n",
869                         c->name, 
870                         c->cid.cid_num ? c->cid.cid_num : "<unknown>", 
871                         c->cid.cid_name ? c->cid.cid_name : "<unknown>", 
872                         c->accountcode,
873                         ast_state2str(c->_state), c->context,
874                         c->exten, c->priority, (long)elapsed_seconds, bridge, c->uniqueid, idText);
875                 } else {
876                         astman_append(s,
877                         "Event: Status\r\n"
878                         "Privilege: Call\r\n"
879                         "Channel: %s\r\n"
880                         "CallerID: %s\r\n"
881                         "CallerIDName: %s\r\n"
882                         "Account: %s\r\n"
883                         "State: %s\r\n"
884                         "%s"
885                         "Uniqueid: %s\r\n"
886                         "%s"
887                         "\r\n",
888                         c->name, 
889                         c->cid.cid_num ? c->cid.cid_num : "<unknown>", 
890                         c->cid.cid_name ? c->cid.cid_name : "<unknown>", 
891                         c->accountcode,
892                         ast_state2str(c->_state), bridge, c->uniqueid, idText);
893                 }
894                 ast_mutex_unlock(&c->lock);
895                 if (!all)
896                         break;
897                 c = ast_channel_walk_locked(c);
898         }
899         astman_append(s,
900         "Event: StatusComplete\r\n"
901         "%s"
902         "\r\n",idText);
903         return 0;
904 }
905
906 static char mandescr_redirect[] = 
907 "Description: Redirect (transfer) a call.\n"
908 "Variables: (Names marked with * are required)\n"
909 "       *Channel: Channel to redirect\n"
910 "       ExtraChannel: Second call leg to transfer (optional)\n"
911 "       *Exten: Extension to transfer to\n"
912 "       *Context: Context to transfer to\n"
913 "       *Priority: Priority to transfer to\n"
914 "       ActionID: Optional Action id for message matching.\n";
915
916 /*! \brief  action_redirect: The redirect manager command */
917 static int action_redirect(struct mansession *s, struct message *m)
918 {
919         char *name = astman_get_header(m, "Channel");
920         char *name2 = astman_get_header(m, "ExtraChannel");
921         char *exten = astman_get_header(m, "Exten");
922         char *context = astman_get_header(m, "Context");
923         char *priority = astman_get_header(m, "Priority");
924         struct ast_channel *chan, *chan2 = NULL;
925         int pi = 0;
926         int res;
927
928         if (ast_strlen_zero(name)) {
929                 astman_send_error(s, m, "Channel not specified");
930                 return 0;
931         }
932         if (!ast_strlen_zero(priority) && (sscanf(priority, "%d", &pi) != 1)) {
933                 if ((pi = ast_findlabel_extension(NULL, context, exten, priority, NULL)) < 1) {
934                         astman_send_error(s, m, "Invalid priority\n");
935                         return 0;
936                 }
937         }
938         /* XXX watch out, possible deadlock!!! */
939         chan = ast_get_channel_by_name_locked(name);
940         if (!chan) {
941                 char buf[BUFSIZ];
942                 snprintf(buf, sizeof(buf), "Channel does not exist: %s", name);
943                 astman_send_error(s, m, buf);
944                 return 0;
945         }
946         if (!ast_strlen_zero(name2))
947                 chan2 = ast_get_channel_by_name_locked(name2);
948         res = ast_async_goto(chan, context, exten, pi);
949         if (!res) {
950                 if (!ast_strlen_zero(name2)) {
951                         if (chan2)
952                                 res = ast_async_goto(chan2, context, exten, pi);
953                         else
954                                 res = -1;
955                         if (!res)
956                                 astman_send_ack(s, m, "Dual Redirect successful");
957                         else
958                                 astman_send_error(s, m, "Secondary redirect failed");
959                 } else
960                         astman_send_ack(s, m, "Redirect successful");
961         } else
962                 astman_send_error(s, m, "Redirect failed");
963         if (chan)
964                 ast_mutex_unlock(&chan->lock);
965         if (chan2)
966                 ast_mutex_unlock(&chan2->lock);
967         return 0;
968 }
969
970 static char mandescr_command[] = 
971 "Description: Run a CLI command.\n"
972 "Variables: (Names marked with * are required)\n"
973 "       *Command: Asterisk CLI command to run\n"
974 "       ActionID: Optional Action id for message matching.\n";
975
976 /*! \brief  action_command: Manager command "command" - execute CLI command */
977 static int action_command(struct mansession *s, struct message *m)
978 {
979         char *cmd = astman_get_header(m, "Command");
980         char *id = astman_get_header(m, "ActionID");
981         astman_append(s, "Response: Follows\r\nPrivilege: Command\r\n");
982         if (!ast_strlen_zero(id))
983                 astman_append(s, "ActionID: %s\r\n", id);
984         /* FIXME: Wedge a ActionID response in here, waiting for later changes */
985         ast_cli_command(s->fd, cmd);
986         astman_append(s, "--END COMMAND--\r\n\r\n");
987         return 0;
988 }
989
990 static void *fast_originate(void *data)
991 {
992         struct fast_originate_helper *in = data;
993         int res;
994         int reason = 0;
995         struct ast_channel *chan = NULL;
996
997         if (!ast_strlen_zero(in->app)) {
998                 res = ast_pbx_outgoing_app(in->tech, AST_FORMAT_SLINEAR, in->data, in->timeout, in->app, in->appdata, &reason, 1, 
999                         S_OR(in->cid_num, NULL), 
1000                         S_OR(in->cid_name, NULL),
1001                         in->vars, in->account, &chan);
1002         } else {
1003                 res = ast_pbx_outgoing_exten(in->tech, AST_FORMAT_SLINEAR, in->data, in->timeout, in->context, in->exten, in->priority, &reason, 1, 
1004                         S_OR(in->cid_num, NULL), 
1005                         S_OR(in->cid_name, NULL),
1006                         in->vars, in->account, &chan);
1007         }   
1008         
1009         /* Tell the manager what happened with the channel */
1010         manager_event(EVENT_FLAG_CALL,
1011                 res ? "OriginateSuccess" : "OriginateFailure",
1012                 "%s"
1013                 "Channel: %s/%s\r\n"
1014                 "Context: %s\r\n"
1015                 "Exten: %s\r\n"
1016                 "Reason: %d\r\n"
1017                 "Uniqueid: %s\r\n"
1018                 "CallerID: %s\r\n"
1019                 "CallerIDName: %s\r\n",
1020                 in->idtext, in->tech, in->data, in->context, in->exten, reason, 
1021                 chan ? chan->uniqueid : "<null>",
1022                 in->cid_num ? in->cid_num : "<unknown>",
1023                 in->cid_name ? in->cid_name : "<unknown>"
1024                 );
1025
1026         /* Locked by ast_pbx_outgoing_exten or ast_pbx_outgoing_app */
1027         if (chan)
1028                 ast_mutex_unlock(&chan->lock);
1029         free(in);
1030         return NULL;
1031 }
1032
1033 static char mandescr_originate[] = 
1034 "Description: Generates an outgoing call to a Extension/Context/Priority or\n"
1035 "  Application/Data\n"
1036 "Variables: (Names marked with * are required)\n"
1037 "       *Channel: Channel name to call\n"
1038 "       Exten: Extension to use (requires 'Context' and 'Priority')\n"
1039 "       Context: Context to use (requires 'Exten' and 'Priority')\n"
1040 "       Priority: Priority to use (requires 'Exten' and 'Context')\n"
1041 "       Application: Application to use\n"
1042 "       Data: Data to use (requires 'Application')\n"
1043 "       Timeout: How long to wait for call to be answered (in ms)\n"
1044 "       CallerID: Caller ID to be set on the outgoing channel\n"
1045 "       Variable: Channel variable to set, multiple Variable: headers are allowed\n"
1046 "       Account: Account code\n"
1047 "       Async: Set to 'true' for fast origination\n";
1048
1049 static int action_originate(struct mansession *s, struct message *m)
1050 {
1051         char *name = astman_get_header(m, "Channel");
1052         char *exten = astman_get_header(m, "Exten");
1053         char *context = astman_get_header(m, "Context");
1054         char *priority = astman_get_header(m, "Priority");
1055         char *timeout = astman_get_header(m, "Timeout");
1056         char *callerid = astman_get_header(m, "CallerID");
1057         char *account = astman_get_header(m, "Account");
1058         char *app = astman_get_header(m, "Application");
1059         char *appdata = astman_get_header(m, "Data");
1060         char *async = astman_get_header(m, "Async");
1061         char *id = astman_get_header(m, "ActionID");
1062         struct ast_variable *vars = astman_get_variables(m);
1063         char *tech, *data;
1064         char *l=NULL, *n=NULL;
1065         int pi = 0;
1066         int res;
1067         int to = 30000;
1068         int reason = 0;
1069         char tmp[256];
1070         char tmp2[256];
1071         
1072         pthread_t th;
1073         pthread_attr_t attr;
1074         if (!name) {
1075                 astman_send_error(s, m, "Channel not specified");
1076                 return 0;
1077         }
1078         if (!ast_strlen_zero(priority) && (sscanf(priority, "%d", &pi) != 1)) {
1079                 if ((pi = ast_findlabel_extension(NULL, context, exten, priority, NULL)) < 1) {
1080                         astman_send_error(s, m, "Invalid priority\n");
1081                         return 0;
1082                 }
1083         }
1084         if (!ast_strlen_zero(timeout) && (sscanf(timeout, "%d", &to) != 1)) {
1085                 astman_send_error(s, m, "Invalid timeout\n");
1086                 return 0;
1087         }
1088         ast_copy_string(tmp, name, sizeof(tmp));
1089         tech = tmp;
1090         data = strchr(tmp, '/');
1091         if (!data) {
1092                 astman_send_error(s, m, "Invalid channel\n");
1093                 return 0;
1094         }
1095         *data++ = '\0';
1096         ast_copy_string(tmp2, callerid, sizeof(tmp2));
1097         ast_callerid_parse(tmp2, &n, &l);
1098         if (n) {
1099                 if (ast_strlen_zero(n))
1100                         n = NULL;
1101         }
1102         if (l) {
1103                 ast_shrink_phone_number(l);
1104                 if (ast_strlen_zero(l))
1105                         l = NULL;
1106         }
1107         if (ast_true(async)) {
1108                 struct fast_originate_helper *fast = malloc(sizeof(struct fast_originate_helper));
1109                 if (!fast) {
1110                         res = -1;
1111                 } else {
1112                         memset(fast, 0, sizeof(struct fast_originate_helper));
1113                         if (!ast_strlen_zero(id))
1114                                 snprintf(fast->idtext, sizeof(fast->idtext), "ActionID: %s\r\n", id);
1115                         ast_copy_string(fast->tech, tech, sizeof(fast->tech));
1116                         ast_copy_string(fast->data, data, sizeof(fast->data));
1117                         ast_copy_string(fast->app, app, sizeof(fast->app));
1118                         ast_copy_string(fast->appdata, appdata, sizeof(fast->appdata));
1119                         if (l)
1120                                 ast_copy_string(fast->cid_num, l, sizeof(fast->cid_num));
1121                         if (n)
1122                                 ast_copy_string(fast->cid_name, n, sizeof(fast->cid_name));
1123                         fast->vars = vars;      
1124                         ast_copy_string(fast->context, context, sizeof(fast->context));
1125                         ast_copy_string(fast->exten, exten, sizeof(fast->exten));
1126                         ast_copy_string(fast->account, account, sizeof(fast->account));
1127                         fast->timeout = to;
1128                         fast->priority = pi;
1129                         pthread_attr_init(&attr);
1130                         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1131                         if (ast_pthread_create(&th, &attr, fast_originate, fast)) {
1132                                 res = -1;
1133                         } else {
1134                                 res = 0;
1135                         }
1136                 }
1137         } else if (!ast_strlen_zero(app)) {
1138                 res = ast_pbx_outgoing_app(tech, AST_FORMAT_SLINEAR, data, to, app, appdata, &reason, 1, l, n, vars, account, NULL);
1139         } else {
1140                 if (exten && context && pi)
1141                         res = ast_pbx_outgoing_exten(tech, AST_FORMAT_SLINEAR, data, to, context, exten, pi, &reason, 1, l, n, vars, account, NULL);
1142                 else {
1143                         astman_send_error(s, m, "Originate with 'Exten' requires 'Context' and 'Priority'");
1144                         return 0;
1145                 }
1146         }   
1147         if (!res)
1148                 astman_send_ack(s, m, "Originate successfully queued");
1149         else
1150                 astman_send_error(s, m, "Originate failed");
1151         return 0;
1152 }
1153
1154 /*!     \brief Help text for manager command mailboxstatus
1155  */
1156 static char mandescr_mailboxstatus[] = 
1157 "Description: Checks a voicemail account for status.\n"
1158 "Variables: (Names marked with * are required)\n"
1159 "       *Mailbox: Full mailbox ID <mailbox>@<vm-context>\n"
1160 "       ActionID: Optional ActionID for message matching.\n"
1161 "Returns number of messages.\n"
1162 "       Message: Mailbox Status\n"
1163 "       Mailbox: <mailboxid>\n"
1164 "       Waiting: <count>\n"
1165 "\n";
1166
1167 static int action_mailboxstatus(struct mansession *s, struct message *m)
1168 {
1169         char *mailbox = astman_get_header(m, "Mailbox");
1170         char *id = astman_get_header(m,"ActionID");
1171         char idText[256] = "";
1172         int ret;
1173         if (ast_strlen_zero(mailbox)) {
1174                 astman_send_error(s, m, "Mailbox not specified");
1175                 return 0;
1176         }
1177         if (!ast_strlen_zero(id))
1178                 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
1179         ret = ast_app_has_voicemail(mailbox, NULL);
1180         astman_append(s, "Response: Success\r\n"
1181                                    "%s"
1182                                    "Message: Mailbox Status\r\n"
1183                                    "Mailbox: %s\r\n"
1184                                    "Waiting: %d\r\n\r\n", idText, mailbox, ret);
1185         return 0;
1186 }
1187
1188 static char mandescr_mailboxcount[] = 
1189 "Description: Checks a voicemail account for new messages.\n"
1190 "Variables: (Names marked with * are required)\n"
1191 "       *Mailbox: Full mailbox ID <mailbox>@<vm-context>\n"
1192 "       ActionID: Optional ActionID for message matching.\n"
1193 "Returns number of new and old messages.\n"
1194 "       Message: Mailbox Message Count\n"
1195 "       Mailbox: <mailboxid>\n"
1196 "       NewMessages: <count>\n"
1197 "       OldMessages: <count>\n"
1198 "\n";
1199 static int action_mailboxcount(struct mansession *s, struct message *m)
1200 {
1201         char *mailbox = astman_get_header(m, "Mailbox");
1202         char *id = astman_get_header(m,"ActionID");
1203         char idText[256] = "";
1204         int newmsgs = 0, oldmsgs = 0;
1205         if (ast_strlen_zero(mailbox)) {
1206                 astman_send_error(s, m, "Mailbox not specified");
1207                 return 0;
1208         }
1209         ast_app_messagecount(mailbox, &newmsgs, &oldmsgs);
1210         if (!ast_strlen_zero(id)) {
1211                 snprintf(idText, sizeof(idText), "ActionID: %s\r\n",id);
1212         }
1213         astman_append(s, "Response: Success\r\n"
1214                                    "%s"
1215                                    "Message: Mailbox Message Count\r\n"
1216                                    "Mailbox: %s\r\n"
1217                                    "NewMessages: %d\r\n"
1218                                    "OldMessages: %d\r\n" 
1219                                    "\r\n",
1220                                     idText,mailbox, newmsgs, oldmsgs);
1221         return 0;
1222 }
1223
1224 static char mandescr_extensionstate[] = 
1225 "Description: Report the extension state for given extension.\n"
1226 "  If the extension has a hint, will use devicestate to check\n"
1227 "  the status of the device connected to the extension.\n"
1228 "Variables: (Names marked with * are required)\n"
1229 "       *Exten: Extension to check state on\n"
1230 "       *Context: Context for extension\n"
1231 "       ActionId: Optional ID for this transaction\n"
1232 "Will return an \"Extension Status\" message.\n"
1233 "The response will include the hint for the extension and the status.\n";
1234
1235 static int action_extensionstate(struct mansession *s, struct message *m)
1236 {
1237         char *exten = astman_get_header(m, "Exten");
1238         char *context = astman_get_header(m, "Context");
1239         char *id = astman_get_header(m,"ActionID");
1240         char idText[256] = "";
1241         char hint[256] = "";
1242         int status;
1243         if (ast_strlen_zero(exten)) {
1244                 astman_send_error(s, m, "Extension not specified");
1245                 return 0;
1246         }
1247         if (ast_strlen_zero(context))
1248                 context = "default";
1249         status = ast_extension_state(NULL, context, exten);
1250         ast_get_hint(hint, sizeof(hint) - 1, NULL, 0, NULL, context, exten);
1251         if (!ast_strlen_zero(id)) {
1252                 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
1253         }
1254         astman_append(s, "Response: Success\r\n"
1255                                    "%s"
1256                                    "Message: Extension Status\r\n"
1257                                    "Exten: %s\r\n"
1258                                    "Context: %s\r\n"
1259                                    "Hint: %s\r\n"
1260                                    "Status: %d\r\n\r\n",
1261                                    idText,exten, context, hint, status);
1262         return 0;
1263 }
1264
1265 static char mandescr_timeout[] = 
1266 "Description: Hangup a channel after a certain time.\n"
1267 "Variables: (Names marked with * are required)\n"
1268 "       *Channel: Channel name to hangup\n"
1269 "       *Timeout: Maximum duration of the call (sec)\n"
1270 "Acknowledges set time with 'Timeout Set' message\n";
1271
1272 static int action_timeout(struct mansession *s, struct message *m)
1273 {
1274         struct ast_channel *c = NULL;
1275         char *name = astman_get_header(m, "Channel");
1276         int timeout = atoi(astman_get_header(m, "Timeout"));
1277         if (ast_strlen_zero(name)) {
1278                 astman_send_error(s, m, "No channel specified");
1279                 return 0;
1280         }
1281         if (!timeout) {
1282                 astman_send_error(s, m, "No timeout specified");
1283                 return 0;
1284         }
1285         c = ast_get_channel_by_name_locked(name);
1286         if (!c) {
1287                 astman_send_error(s, m, "No such channel");
1288                 return 0;
1289         }
1290         ast_channel_setwhentohangup(c, timeout);
1291         ast_mutex_unlock(&c->lock);
1292         astman_send_ack(s, m, "Timeout Set");
1293         return 0;
1294 }
1295
1296 static int process_message(struct mansession *s, struct message *m)
1297 {
1298         char action[80] = "";
1299         struct manager_action *tmp = first_action;
1300         char *id = astman_get_header(m,"ActionID");
1301         char idText[256] = "";
1302         char iabuf[INET_ADDRSTRLEN];
1303
1304         ast_copy_string(action, astman_get_header(m, "Action"), sizeof(action));
1305         ast_log( LOG_DEBUG, "Manager received command '%s'\n", action );
1306
1307         if (ast_strlen_zero(action)) {
1308                 astman_send_error(s, m, "Missing action in request");
1309                 return 0;
1310         }
1311         if (!ast_strlen_zero(id)) {
1312                 snprintf(idText, sizeof(idText), "ActionID: %s\r\n",id);
1313         }
1314         if (!s->authenticated) {
1315                 if (!strcasecmp(action, "Challenge")) {
1316                         char *authtype;
1317                         authtype = astman_get_header(m, "AuthType");
1318                         if (!strcasecmp(authtype, "MD5")) {
1319                                 if (ast_strlen_zero(s->challenge))
1320                                         snprintf(s->challenge, sizeof(s->challenge), "%d", rand());
1321                                 ast_mutex_lock(&s->__lock);
1322                                 astman_append(s, "Response: Success\r\n"
1323                                                 "%s"
1324                                                 "Challenge: %s\r\n\r\n",
1325                                                 idText,s->challenge);
1326                                 ast_mutex_unlock(&s->__lock);
1327                                 return 0;
1328                         } else {
1329                                 astman_send_error(s, m, "Must specify AuthType");
1330                                 return 0;
1331                         }
1332                 } else if (!strcasecmp(action, "Login")) {
1333                         if (authenticate(s, m)) {
1334                                 sleep(1);
1335                                 astman_send_error(s, m, "Authentication failed");
1336                                 return -1;
1337                         } else {
1338                                 s->authenticated = 1;
1339                                 if (option_verbose > 1) {
1340                                         if ( displayconnects ) {
1341                                                 ast_verbose(VERBOSE_PREFIX_2 "Manager '%s' logged on from %s\n", s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
1342                                         }
1343                                 }
1344                                 ast_log(LOG_EVENT, "Manager '%s' logged on from %s\n", s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
1345                                 astman_send_ack(s, m, "Authentication accepted");
1346                         }
1347                 } else if (!strcasecmp(action, "Logoff")) {
1348                         astman_send_ack(s, m, "See ya");
1349                         return -1;
1350                 } else
1351                         astman_send_error(s, m, "Authentication Required");
1352         } else {
1353                 int ret=0;
1354                 struct eventqent *eqe;
1355                 ast_mutex_lock(&s->__lock);
1356                 s->busy = 1;
1357                 ast_mutex_unlock(&s->__lock);
1358                 while( tmp ) {          
1359                         if (!strcasecmp(action, tmp->action)) {
1360                                 if ((s->writeperm & tmp->authority) == tmp->authority) {
1361                                         if (tmp->func(s, m))
1362                                                 ret = -1;
1363                                 } else {
1364                                         astman_send_error(s, m, "Permission denied");
1365                                 }
1366                                 break;
1367                         }
1368                         tmp = tmp->next;
1369                 }
1370                 if (!tmp)
1371                         astman_send_error(s, m, "Invalid/unknown command");
1372                 ast_mutex_lock(&s->__lock);
1373                 s->busy = 0;
1374                 while(s->eventq) {
1375                         if (ast_carefulwrite(s->fd, s->eventq->eventdata, strlen(s->eventq->eventdata), s->writetimeout) < 0) {
1376                                 ret = -1;
1377                                 break;
1378                         }
1379                         eqe = s->eventq;
1380                         s->eventq = s->eventq->next;
1381                         free(eqe);
1382                 }
1383                 ast_mutex_unlock(&s->__lock);
1384                 return ret;
1385         }
1386         return 0;
1387 }
1388
1389 static int get_input(struct mansession *s, char *output)
1390 {
1391         /* output must have at least sizeof(s->inbuf) space */
1392         int res;
1393         int x;
1394         struct pollfd fds[1];
1395         char iabuf[INET_ADDRSTRLEN];
1396         for (x=1;x<s->inlen;x++) {
1397                 if ((s->inbuf[x] == '\n') && (s->inbuf[x-1] == '\r')) {
1398                         /* Copy output data up to and including \r\n */
1399                         memcpy(output, s->inbuf, x + 1);
1400                         /* Add trailing \0 */
1401                         output[x+1] = '\0';
1402                         /* Move remaining data back to the front */
1403                         memmove(s->inbuf, s->inbuf + x + 1, s->inlen - x);
1404                         s->inlen -= (x + 1);
1405                         return 1;
1406                 }
1407         } 
1408         if (s->inlen >= sizeof(s->inbuf) - 1) {
1409                 ast_log(LOG_WARNING, "Dumping long line with no return from %s: %s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), s->inbuf);
1410                 s->inlen = 0;
1411         }
1412         fds[0].fd = s->fd;
1413         fds[0].events = POLLIN;
1414         do {
1415                 res = poll(fds, 1, -1);
1416                 if (res < 0) {
1417                         if (errno == EINTR) {
1418                                 if (s->dead)
1419                                         return -1;
1420                                 continue;
1421                         }
1422                         ast_log(LOG_WARNING, "Select returned error: %s\n", strerror(errno));
1423                         return -1;
1424                 } else if (res > 0) {
1425                         ast_mutex_lock(&s->__lock);
1426                         res = read(s->fd, s->inbuf + s->inlen, sizeof(s->inbuf) - 1 - s->inlen);
1427                         ast_mutex_unlock(&s->__lock);
1428                         if (res < 1)
1429                                 return -1;
1430                         break;
1431                 }
1432         } while(1);
1433         s->inlen += res;
1434         s->inbuf[s->inlen] = '\0';
1435         return 0;
1436 }
1437
1438 static void *session_do(void *data)
1439 {
1440         struct mansession *s = data;
1441         struct message m;
1442         char iabuf[INET_ADDRSTRLEN];
1443         int res;
1444         
1445         ast_mutex_lock(&s->__lock);
1446         astman_append(s, "Asterisk Call Manager/1.0\r\n");
1447         ast_mutex_unlock(&s->__lock);
1448         memset(&m, 0, sizeof(m));
1449         for (;;) {
1450                 res = get_input(s, m.headers[m.hdrcount]);
1451                 if (res > 0) {
1452                         /* Strip trailing \r\n */
1453                         if (strlen(m.headers[m.hdrcount]) < 2)
1454                                 continue;
1455                         m.headers[m.hdrcount][strlen(m.headers[m.hdrcount]) - 2] = '\0';
1456                         if (ast_strlen_zero(m.headers[m.hdrcount])) {
1457                                 if (process_message(s, &m))
1458                                         break;
1459                                 memset(&m, 0, sizeof(m));
1460                         } else if (m.hdrcount < AST_MAX_MANHEADERS - 1)
1461                                 m.hdrcount++;
1462                 } else if (res < 0)
1463                         break;
1464         }
1465         if (s->authenticated) {
1466                 if (option_verbose > 1) {
1467                         if (displayconnects) 
1468                                 ast_verbose(VERBOSE_PREFIX_2 "Manager '%s' logged off from %s\n", s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));    
1469                 }
1470                 ast_log(LOG_EVENT, "Manager '%s' logged off from %s\n", s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
1471         } else {
1472                 if (option_verbose > 1) {
1473                         if ( displayconnects )
1474                                 ast_verbose(VERBOSE_PREFIX_2 "Connect attempt from '%s' unable to authenticate\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
1475                 }
1476                 ast_log(LOG_EVENT, "Failed attempt from %s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
1477         }
1478         destroy_session(s);
1479         return NULL;
1480 }
1481
1482 static void *accept_thread(void *ignore)
1483 {
1484         int as;
1485         struct sockaddr_in sin;
1486         socklen_t sinlen;
1487         struct mansession *s;
1488         struct protoent *p;
1489         int arg = 1;
1490         int flags;
1491         pthread_attr_t attr;
1492
1493         pthread_attr_init(&attr);
1494         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1495
1496         for (;;) {
1497                 sinlen = sizeof(sin);
1498                 as = accept(asock, (struct sockaddr *)&sin, &sinlen);
1499                 if (as < 0) {
1500                         ast_log(LOG_NOTICE, "Accept returned -1: %s\n", strerror(errno));
1501                         continue;
1502                 }
1503                 p = getprotobyname("tcp");
1504                 if (p) {
1505                         if( setsockopt(as, p->p_proto, TCP_NODELAY, (char *)&arg, sizeof(arg) ) < 0 ) {
1506                                 ast_log(LOG_WARNING, "Failed to set manager tcp connection to TCP_NODELAY mode: %s\n", strerror(errno));
1507                         }
1508                 }
1509                 s = malloc(sizeof(struct mansession));
1510                 if (!s) {
1511                         ast_log(LOG_WARNING, "Failed to allocate management session: %s\n", strerror(errno));
1512                         continue;
1513                 } 
1514                 memset(s, 0, sizeof(struct mansession));
1515                 memcpy(&s->sin, &sin, sizeof(sin));
1516                 s->writetimeout = 100;
1517
1518                 if(! block_sockets) {
1519                         /* For safety, make sure socket is non-blocking */
1520                         flags = fcntl(as, F_GETFL);
1521                         fcntl(as, F_SETFL, flags | O_NONBLOCK);
1522                 }
1523                 ast_mutex_init(&s->__lock);
1524                 s->fd = as;
1525                 s->send_events = -1;
1526                 ast_mutex_lock(&sessionlock);
1527                 s->next = sessions;
1528                 sessions = s;
1529                 ast_mutex_unlock(&sessionlock);
1530                 if (ast_pthread_create(&s->t, &attr, session_do, s))
1531                         destroy_session(s);
1532         }
1533         pthread_attr_destroy(&attr);
1534         return NULL;
1535 }
1536
1537 static int append_event(struct mansession *s, const char *str)
1538 {
1539         struct eventqent *tmp, *prev=NULL;
1540         tmp = malloc(sizeof(struct eventqent) + strlen(str));
1541         if (tmp) {
1542                 tmp->next = NULL;
1543                 strcpy(tmp->eventdata, str);
1544                 if (s->eventq) {
1545                         prev = s->eventq;
1546                         while(prev->next) 
1547                                 prev = prev->next;
1548                         prev->next = tmp;
1549                 } else {
1550                         s->eventq = tmp;
1551                 }
1552                 return 0;
1553         }
1554         return -1;
1555 }
1556
1557 /*! \brief  manager_event: Send AMI event to client */
1558 int manager_event(int category, const char *event, const char *fmt, ...)
1559 {
1560         struct mansession *s;
1561         char auth[80];
1562         char tmp[4096] = "";
1563         char *tmp_next = tmp;
1564         size_t tmp_left = sizeof(tmp) - 2;
1565         va_list ap;
1566
1567         ast_mutex_lock(&sessionlock);
1568         for (s = sessions; s; s = s->next) {
1569                 if ((s->readperm & category) != category)
1570                         continue;
1571
1572                 if ((s->send_events & category) != category)
1573                         continue;
1574
1575                 if (ast_strlen_zero(tmp)) {
1576                         struct timeval now;
1577
1578                         ast_build_string(&tmp_next, &tmp_left, "Event: %s\r\nPrivilege: %s\r\n",
1579                                          event, authority_to_str(category, auth, sizeof(auth)));
1580                         if (timestampevents) {
1581                                 now = ast_tvnow();
1582                                 ast_build_string(&tmp_next, &tmp_left, "Timestamp: %ld.%06lu\r\n",
1583                                                  now.tv_sec, (unsigned long) now.tv_usec);
1584                         }
1585                         va_start(ap, fmt);
1586                         ast_build_string_va(&tmp_next, &tmp_left, fmt, ap);
1587                         va_end(ap);
1588                         *tmp_next++ = '\r';
1589                         *tmp_next++ = '\n';
1590                         *tmp_next = '\0';
1591                 }
1592
1593                 ast_mutex_lock(&s->__lock);
1594                 if (s->busy) {
1595                         append_event(s, tmp);
1596                 } else if (!s->dead) {
1597                         if (ast_carefulwrite(s->fd, tmp, tmp_next - tmp, s->writetimeout) < 0) {
1598                                 ast_log(LOG_WARNING, "Disconnecting slow (or gone) manager session!\n");
1599                                 s->dead = 1;
1600                                 pthread_kill(s->t, SIGURG);
1601                         }
1602                 }
1603                 ast_mutex_unlock(&s->__lock);
1604         }
1605         ast_mutex_unlock(&sessionlock);
1606
1607         return 0;
1608 }
1609
1610 int ast_manager_unregister( char *action ) 
1611 {
1612         struct manager_action *cur = first_action, *prev = first_action;
1613
1614         ast_mutex_lock(&actionlock);
1615         while( cur ) {          
1616                 if (!strcasecmp(action, cur->action)) {
1617                         prev->next = cur->next;
1618                         free(cur);
1619                         if (option_verbose > 1) 
1620                                 ast_verbose(VERBOSE_PREFIX_2 "Manager unregistered action %s\n", action);
1621                         ast_mutex_unlock(&actionlock);
1622                         return 0;
1623                 }
1624                 prev = cur;
1625                 cur = cur->next;
1626         }
1627         ast_mutex_unlock(&actionlock);
1628         return 0;
1629 }
1630
1631 static int manager_state_cb(char *context, char *exten, int state, void *data)
1632 {
1633         /* Notify managers of change */
1634         manager_event(EVENT_FLAG_CALL, "ExtensionStatus", "Exten: %s\r\nContext: %s\r\nStatus: %d\r\n", exten, context, state);
1635         return 0;
1636 }
1637
1638 static int ast_manager_register_struct(struct manager_action *act)
1639 {
1640         struct manager_action *cur = first_action, *prev = NULL;
1641         int ret;
1642
1643         ast_mutex_lock(&actionlock);
1644         while(cur) { /* Walk the list of actions */
1645                 ret = strcasecmp(cur->action, act->action);
1646                 if (ret == 0) {
1647                         ast_log(LOG_WARNING, "Manager: Action '%s' already registered\n", act->action);
1648                         ast_mutex_unlock(&actionlock);
1649                         return -1;
1650                 } else if (ret > 0) {
1651                         /* Insert these alphabetically */
1652                         if (prev) {
1653                                 act->next = prev->next;
1654                                 prev->next = act;
1655                         } else {
1656                                 act->next = first_action;
1657                                 first_action = act;
1658                         }
1659                         break;
1660                 }
1661                 prev = cur; 
1662                 cur = cur->next;
1663         }
1664         
1665         if (!cur) {
1666                 if (prev)
1667                         prev->next = act;
1668                 else
1669                         first_action = act;
1670                 act->next = NULL;
1671         }
1672
1673         if (option_verbose > 1) 
1674                 ast_verbose(VERBOSE_PREFIX_2 "Manager registered action %s\n", act->action);
1675         ast_mutex_unlock(&actionlock);
1676         return 0;
1677 }
1678
1679 /*! \brief register a new command with manager, including online help. This is 
1680         the preferred way to register a manager command */
1681 int ast_manager_register2(const char *action, int auth, int (*func)(struct mansession *s, struct message *m), const char *synopsis, const char *description)
1682 {
1683         struct manager_action *cur;
1684
1685         cur = malloc(sizeof(struct manager_action));
1686         if (!cur) {
1687                 ast_log(LOG_WARNING, "Manager: out of memory trying to register action\n");
1688                 return -1;
1689         }
1690         cur->action = action;
1691         cur->authority = auth;
1692         cur->func = func;
1693         cur->synopsis = synopsis;
1694         cur->description = description;
1695         cur->next = NULL;
1696
1697         ast_manager_register_struct(cur);
1698
1699         return 0;
1700 }
1701 /*! @}
1702  END Doxygen group */
1703
1704 static int registered = 0;
1705
1706 int init_manager(void)
1707 {
1708         struct ast_config *cfg;
1709         char *val;
1710         int oldportno = portno;
1711         static struct sockaddr_in ba;
1712         int x = 1;
1713         if (!registered) {
1714                 /* Register default actions */
1715                 ast_manager_register2("Ping", 0, action_ping, "Keepalive command", mandescr_ping);
1716                 ast_manager_register2("Events", 0, action_events, "Control Event Flow", mandescr_events);
1717                 ast_manager_register2("Logoff", 0, action_logoff, "Logoff Manager", mandescr_logoff);
1718                 ast_manager_register2("Hangup", EVENT_FLAG_CALL, action_hangup, "Hangup Channel", mandescr_hangup);
1719                 ast_manager_register("Status", EVENT_FLAG_CALL, action_status, "Lists channel status" );
1720                 ast_manager_register2("Setvar", EVENT_FLAG_CALL, action_setvar, "Set Channel Variable", mandescr_setvar );
1721                 ast_manager_register2("Getvar", EVENT_FLAG_CALL, action_getvar, "Gets a Channel Variable", mandescr_getvar );
1722                 ast_manager_register2("Redirect", EVENT_FLAG_CALL, action_redirect, "Redirect (transfer) a call", mandescr_redirect );
1723                 ast_manager_register2("Originate", EVENT_FLAG_CALL, action_originate, "Originate Call", mandescr_originate);
1724                 ast_manager_register2("Command", EVENT_FLAG_COMMAND, action_command, "Execute Asterisk CLI Command", mandescr_command );
1725                 ast_manager_register2("ExtensionState", EVENT_FLAG_CALL, action_extensionstate, "Check Extension Status", mandescr_extensionstate );
1726                 ast_manager_register2("AbsoluteTimeout", EVENT_FLAG_CALL, action_timeout, "Set Absolute Timeout", mandescr_timeout );
1727                 ast_manager_register2("MailboxStatus", EVENT_FLAG_CALL, action_mailboxstatus, "Check Mailbox", mandescr_mailboxstatus );
1728                 ast_manager_register2("MailboxCount", EVENT_FLAG_CALL, action_mailboxcount, "Check Mailbox Message Count", mandescr_mailboxcount );
1729                 ast_manager_register2("ListCommands", 0, action_listcommands, "List available manager commands", mandescr_listcommands);
1730
1731                 ast_cli_register(&show_mancmd_cli);
1732                 ast_cli_register(&show_mancmds_cli);
1733                 ast_cli_register(&show_manconn_cli);
1734                 ast_extension_state_add(NULL, NULL, manager_state_cb, NULL);
1735                 registered = 1;
1736         }
1737         portno = DEFAULT_MANAGER_PORT;
1738         displayconnects = 1;
1739         cfg = ast_config_load("manager.conf");
1740         if (!cfg) {
1741                 ast_log(LOG_NOTICE, "Unable to open management configuration manager.conf.  Call management disabled.\n");
1742                 return 0;
1743         }
1744         memset(&ba, 0, sizeof(ba));
1745         val = ast_variable_retrieve(cfg, "general", "enabled");
1746         if (val)
1747                 enabled = ast_true(val);
1748
1749         val = ast_variable_retrieve(cfg, "general", "block-sockets");
1750         if(val)
1751                 block_sockets = ast_true(val);
1752
1753         if ((val = ast_variable_retrieve(cfg, "general", "port"))) {
1754                 if (sscanf(val, "%d", &portno) != 1) {
1755                         ast_log(LOG_WARNING, "Invalid port number '%s'\n", val);
1756                         portno = DEFAULT_MANAGER_PORT;
1757                 }
1758         }
1759
1760         if ((val = ast_variable_retrieve(cfg, "general", "displayconnects")))
1761                 displayconnects = ast_true(val);
1762
1763         if ((val = ast_variable_retrieve(cfg, "general", "timestampevents")))
1764                 timestampevents = ast_true(val);
1765         
1766         ba.sin_family = AF_INET;
1767         ba.sin_port = htons(portno);
1768         memset(&ba.sin_addr, 0, sizeof(ba.sin_addr));
1769         
1770         if ((val = ast_variable_retrieve(cfg, "general", "bindaddr"))) {
1771                 if (!inet_aton(val, &ba.sin_addr)) { 
1772                         ast_log(LOG_WARNING, "Invalid address '%s' specified, using 0.0.0.0\n", val);
1773                         memset(&ba.sin_addr, 0, sizeof(ba.sin_addr));
1774                 }
1775         }
1776         
1777         if ((asock > -1) && ((portno != oldportno) || !enabled)) {
1778 #if 0
1779                 /* Can't be done yet */
1780                 close(asock);
1781                 asock = -1;
1782 #else
1783                 ast_log(LOG_WARNING, "Unable to change management port / enabled\n");
1784 #endif
1785         }
1786         ast_config_destroy(cfg);
1787         
1788         /* If not enabled, do nothing */
1789         if (!enabled) {
1790                 return 0;
1791         }
1792         if (asock < 0) {
1793                 asock = socket(AF_INET, SOCK_STREAM, 0);
1794                 if (asock < 0) {
1795                         ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
1796                         return -1;
1797                 }
1798                 setsockopt(asock, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x));
1799                 if (bind(asock, (struct sockaddr *)&ba, sizeof(ba))) {
1800                         ast_log(LOG_WARNING, "Unable to bind socket: %s\n", strerror(errno));
1801                         close(asock);
1802                         asock = -1;
1803                         return -1;
1804                 }
1805                 if (listen(asock, 2)) {
1806                         ast_log(LOG_WARNING, "Unable to listen on socket: %s\n", strerror(errno));
1807                         close(asock);
1808                         asock = -1;
1809                         return -1;
1810                 }
1811                 if (option_verbose)
1812                         ast_verbose("Asterisk Management interface listening on port %d\n", portno);
1813                 ast_pthread_create(&t, NULL, accept_thread, NULL);
1814         }
1815         return 0;
1816 }
1817
1818 int reload_manager(void)
1819 {
1820         manager_event(EVENT_FLAG_SYSTEM, "Reload", "Message: Reload Requested\r\n");
1821         return init_manager();
1822 }