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