silly people that don't want to install/run autoconf :-)
[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 <ctype.h>
39 #include <sys/time.h>
40 #include <sys/types.h>
41 #include <netdb.h>
42 #include <sys/socket.h>
43 #include <netinet/in.h>
44 #include <netinet/tcp.h>
45 #include <arpa/inet.h>
46 #include <signal.h>
47 #include <errno.h>
48 #include <unistd.h>
49
50 #include "asterisk.h"
51
52 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
53
54 #include "asterisk/channel.h"
55 #include "asterisk/file.h"
56 #include "asterisk/manager.h"
57 #include "asterisk/config.h"
58 #include "asterisk/callerid.h"
59 #include "asterisk/lock.h"
60 #include "asterisk/logger.h"
61 #include "asterisk/options.h"
62 #include "asterisk/cli.h"
63 #include "asterisk/app.h"
64 #include "asterisk/pbx.h"
65 #include "asterisk/md5.h"
66 #include "asterisk/acl.h"
67 #include "asterisk/utils.h"
68 #include "asterisk/http.h"
69
70 struct fast_originate_helper {
71         char tech[AST_MAX_MANHEADER_LEN];
72         char data[AST_MAX_MANHEADER_LEN];
73         int timeout;
74         char app[AST_MAX_APP];
75         char appdata[AST_MAX_MANHEADER_LEN];
76         char cid_name[AST_MAX_MANHEADER_LEN];
77         char cid_num[AST_MAX_MANHEADER_LEN];
78         char context[AST_MAX_CONTEXT];
79         char exten[AST_MAX_EXTENSION];
80         char idtext[AST_MAX_MANHEADER_LEN];
81         char account[AST_MAX_ACCOUNT_CODE];
82         int priority;
83         struct ast_variable *vars;
84 };
85
86 struct eventqent {
87         int usecount;
88         int category;
89         ast_mutex_t lock;
90         struct eventqent *next;
91         char eventdata[1];
92 };
93
94 static int enabled = 0;
95 static int portno = DEFAULT_MANAGER_PORT;
96 static int asock = -1;
97 static int displayconnects = 1;
98 static int timestampevents = 0;
99 static int httptimeout = 60;
100
101 static pthread_t t;
102 AST_MUTEX_DEFINE_STATIC(sessionlock);
103 static int block_sockets = 0;
104 static int num_sessions = 0;
105 struct eventqent *master_eventq = NULL;
106
107 static struct permalias {
108         int num;
109         char *label;
110 } perms[] = {
111         { EVENT_FLAG_SYSTEM, "system" },
112         { EVENT_FLAG_CALL, "call" },
113         { EVENT_FLAG_LOG, "log" },
114         { EVENT_FLAG_VERBOSE, "verbose" },
115         { EVENT_FLAG_COMMAND, "command" },
116         { EVENT_FLAG_AGENT, "agent" },
117         { EVENT_FLAG_USER, "user" },
118         { -1, "all" },
119         { 0, "none" },
120 };
121
122 static struct mansession {
123         /*! Execution thread */
124         pthread_t t;
125         /*! Thread lock -- don't use in action callbacks, it's already taken care of  */
126         ast_mutex_t __lock;
127         /*! socket address */
128         struct sockaddr_in sin;
129         /*! TCP socket */
130         int fd;
131         /*! Whether or not we're busy doing an action */
132         int busy;
133         /*! Whether or not we're "dead" */
134         int dead;
135         /*! Whether an HTTP manager is in use */
136         int inuse;
137         /*! Whether an HTTP session should be destroyed */
138         int needdestroy;
139         /*! Whether an HTTP session has someone waiting on events */
140         pthread_t waiting_thread;
141         /*! Unique manager identifer */
142         unsigned long managerid;
143         /*! Session timeout if HTTP */
144         time_t sessiontimeout;
145         /*! Output from manager interface */
146         char *outputstr;
147         /*! Logged in username */
148         char username[80];
149         /*! Authentication challenge */
150         char challenge[10];
151         /*! Authentication status */
152         int authenticated;
153         /*! Authorization for reading */
154         int readperm;
155         /*! Authorization for writing */
156         int writeperm;
157         /*! Buffer */
158         char inbuf[AST_MAX_MANHEADER_LEN];
159         int inlen;
160         int send_events;
161         /* Queued events that we've not had the ability to send yet */
162         struct eventqent *eventq;
163         /* Timeout for ast_carefulwrite() */
164         int writetimeout;
165         struct mansession *next;
166 } *sessions = NULL;
167
168 static struct manager_action *first_action = NULL;
169 AST_MUTEX_DEFINE_STATIC(actionlock);
170
171 /*! authority_to_str: Convert authority code to string with serveral options */
172 static char *authority_to_str(int authority, char *res, int reslen)
173 {
174         int running_total = 0, i;
175         memset(res, 0, reslen);
176         for (i=0; i<sizeof(perms) / sizeof(perms[0]) - 1; i++) {
177                 if (authority & perms[i].num) {
178                         if (*res) {
179                                 strncat(res, ",", (reslen > running_total) ? reslen - running_total : 0);
180                                 running_total++;
181                         }
182                         strncat(res, perms[i].label, (reslen > running_total) ? reslen - running_total : 0);
183                         running_total += strlen(perms[i].label);
184                 }
185         }
186         if (ast_strlen_zero(res)) {
187                 ast_copy_string(res, "<none>", reslen);
188         }
189         return res;
190 }
191
192 static char *complete_show_mancmd(const char *line, const char *word, int pos, int state)
193 {
194         struct manager_action *cur;
195         int which = 0;
196         char *ret = NULL;
197
198         ast_mutex_lock(&actionlock);
199         for (cur = first_action; cur; cur = cur->next) { /* Walk the list of actions */
200                 if (!strncasecmp(word, cur->action, strlen(word)) && ++which > state) {
201                         ret = ast_strdup(cur->action);
202                         break;  /* make sure we exit even if ast_strdup() returns NULL */
203                 }
204         }
205         ast_mutex_unlock(&actionlock);
206         return ret;
207 }
208
209 static void xml_copy_escape(char **dst, size_t *maxlen, const char *src, int lower)
210 {
211         while (*src && (*maxlen > 6)) {
212                 switch (*src) {
213                 case '<':
214                         strcpy(*dst, "&lt;");
215                         (*dst) += 4;
216                         *maxlen -= 4;
217                         break;
218                 case '>':
219                         strcpy(*dst, "&gt;");
220                         (*dst) += 4;
221                         *maxlen -= 4;
222                         break;
223                 case '\"':
224                         strcpy(*dst, "&quot;");
225                         (*dst) += 6;
226                         *maxlen -= 6;
227                         break;
228                 case '\'':
229                         strcpy(*dst, "&apos;");
230                         (*dst) += 6;
231                         *maxlen -= 6;
232                         break;
233                 case '&':
234                         strcpy(*dst, "&amp;");
235                         (*dst) += 4;
236                         *maxlen -= 4;
237                         break;          
238                 default:
239                         *(*dst)++ = lower ? tolower(*src) : *src;
240                         (*maxlen)--;
241                 }
242                 src++;
243         }
244 }
245
246 static char *xml_translate(char *in, struct ast_variable *vars)
247 {
248         struct ast_variable *v;
249         char *dest = NULL;
250         char *out, *tmp, *var, *val;
251         char *objtype = NULL;
252         int colons = 0;
253         int breaks = 0;
254         size_t len;
255         int count = 1;
256         int escaped = 0;
257         int inobj = 0;
258         int x;
259         v = vars;
260
261         while (v) {
262                 if (!dest && !strcasecmp(v->name, "ajaxdest"))
263                         dest = v->value;
264                 else if (!objtype && !strcasecmp(v->name, "ajaxobjtype")) 
265                         objtype = v->value;
266                 v = v->next;
267         }
268         if (!dest)
269                 dest = "unknown";
270         if (!objtype)
271                 objtype = "generic";
272         for (x=0; in[x]; x++) {
273                 if (in[x] == ':')
274                         colons++;
275                 else if (in[x] == '\n')
276                         breaks++;
277                 else if (strchr("&\"<>", in[x]))
278                         escaped++;
279         }
280         len = (size_t) (strlen(in) + colons * 5 + breaks * (40 + strlen(dest) + strlen(objtype)) + escaped * 10); /* foo="bar", "<response type=\"object\" id=\"dest\"", "&amp;" */
281         out = malloc(len);
282         if (!out)
283                 return 0;
284         tmp = out;
285         while (*in) {
286                 var = in;
287                 while (*in && (*in >= 32))
288                         in++;
289                 if (*in) {
290                         if ((count > 3) && inobj) {
291                                 ast_build_string(&tmp, &len, " /></response>\n");
292                                 inobj = 0;
293                         }
294                         count = 0;
295                         while (*in && (*in < 32)) {
296                                 *in = '\0';
297                                 in++;
298                                 count++;
299                         }
300                         val = strchr(var, ':');
301                         if (val) {
302                                 *val = '\0';
303                                 val++;
304                                 if (*val == ' ')
305                                         val++;
306                                 if (!inobj) {
307                                         ast_build_string(&tmp, &len, "<response type='object' id='%s'><%s", dest, objtype);
308                                         inobj = 1;
309                                 }
310                                 ast_build_string(&tmp, &len, " ");                              
311                                 xml_copy_escape(&tmp, &len, var, 1);
312                                 ast_build_string(&tmp, &len, "='");
313                                 xml_copy_escape(&tmp, &len, val, 0);
314                                 ast_build_string(&tmp, &len, "'");
315                         }
316                 }
317         }
318         if (inobj)
319                 ast_build_string(&tmp, &len, " /></response>\n");
320         return out;
321 }
322
323 static char *html_translate(char *in)
324 {
325         int x;
326         int colons = 0;
327         int breaks = 0;
328         size_t len;
329         int count = 1;
330         char *tmp, *var, *val, *out;
331
332         for (x=0; in[x]; x++) {
333                 if (in[x] == ':')
334                         colons++;
335                 if (in[x] == '\n')
336                         breaks++;
337         }
338         len = strlen(in) + colons * 40 + breaks * 40; /* <tr><td></td><td></td></tr>, "<tr><td colspan=\"2\"><hr></td></tr> */
339         out = malloc(len);
340         if (!out)
341                 return 0;
342         tmp = out;
343         while (*in) {
344                 var = in;
345                 while (*in && (*in >= 32))
346                         in++;
347                 if (*in) {
348                         if ((count % 4) == 0){
349                                 ast_build_string(&tmp, &len, "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
350                         }
351                         count = 0;
352                         while (*in && (*in < 32)) {
353                                 *in = '\0';
354                                 in++;
355                                 count++;
356                         }
357                         val = strchr(var, ':');
358                         if (val) {
359                                 *val = '\0';
360                                 val++;
361                                 if (*val == ' ')
362                                         val++;
363                                 ast_build_string(&tmp, &len, "<tr><td>%s</td><td>%s</td></tr>\r\n", var, val);
364                         }
365                 }
366         }
367         return out;
368 }
369
370 void astman_append(struct mansession *s, const char *fmt, ...)
371 {
372         char *stuff;
373         int res;
374         va_list ap;
375         char *tmp;
376
377         va_start(ap, fmt);
378         res = vasprintf(&stuff, fmt, ap);
379         va_end(ap);
380         if (res == -1) {
381                 ast_log(LOG_ERROR, "Memory allocation failure\n");
382                 return;
383         } 
384         if (s->fd > -1)
385                 ast_carefulwrite(s->fd, stuff, strlen(stuff), s->writetimeout);
386         else {
387                 tmp = realloc(s->outputstr, (s->outputstr ? strlen(s->outputstr) : 0) + strlen(stuff) + 1);
388                 if (tmp) {
389                         if (!s->outputstr)
390                                 tmp[0] = '\0';
391                         s->outputstr = tmp;
392                         strcat(s->outputstr, stuff);
393                 }
394         }
395         free(stuff);
396 }
397
398 static int handle_showmancmd(int fd, int argc, char *argv[])
399 {
400         struct manager_action *cur = first_action;
401         char authority[80];
402         int num;
403
404         if (argc != 4)
405                 return RESULT_SHOWUSAGE;
406         ast_mutex_lock(&actionlock);
407         while (cur) { /* Walk the list of actions */
408                 for (num = 3; num < argc; num++) {
409                         if (!strcasecmp(cur->action, argv[num])) {
410                                 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 : "");
411                         }
412                 }
413                 cur = cur->next;
414         }
415
416         ast_mutex_unlock(&actionlock);
417         return RESULT_SUCCESS;
418 }
419
420 /*! \brief  handle_showmancmds: CLI command */
421 /* Should change to "manager show commands" */
422 static int handle_showmancmds(int fd, int argc, char *argv[])
423 {
424         struct manager_action *cur = first_action;
425         char authority[80];
426         char *format = "  %-15.15s  %-15.15s  %-55.55s\n";
427
428         ast_mutex_lock(&actionlock);
429         ast_cli(fd, format, "Action", "Privilege", "Synopsis");
430         ast_cli(fd, format, "------", "---------", "--------");
431         while (cur) { /* Walk the list of actions */
432                 ast_cli(fd, format, cur->action, authority_to_str(cur->authority, authority, sizeof(authority) -1), cur->synopsis);
433                 cur = cur->next;
434         }
435
436         ast_mutex_unlock(&actionlock);
437         return RESULT_SUCCESS;
438 }
439
440 /*! \brief  handle_showmanconn: CLI command show manager connected */
441 /* Should change to "manager show connected" */
442 static int handle_showmanconn(int fd, int argc, char *argv[])
443 {
444         struct mansession *s;
445         char iabuf[INET_ADDRSTRLEN];
446         char *format = "  %-15.15s  %-15.15s\n";
447         ast_mutex_lock(&sessionlock);
448         s = sessions;
449         ast_cli(fd, format, "Username", "IP Address");
450         while (s) {
451                 ast_cli(fd, format,s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
452                 s = s->next;
453         }
454
455         ast_mutex_unlock(&sessionlock);
456         return RESULT_SUCCESS;
457 }
458
459 /*! \brief  handle_showmanconn: CLI command show manager connected */
460 /* Should change to "manager show connected" */
461 static int handle_showmaneventq(int fd, int argc, char *argv[])
462 {
463         struct eventqent *s;
464         ast_mutex_lock(&sessionlock);
465         s = master_eventq;
466         while (s) {
467                 ast_cli(fd, "Usecount: %d\n",s->usecount);
468                 ast_cli(fd, "Category: %d\n", s->category);
469                 ast_cli(fd, "Event:\n%s", s->eventdata);
470                 s = s->next;
471         }
472         ast_mutex_unlock(&sessionlock);
473         return RESULT_SUCCESS;
474 }
475
476 static char showmancmd_help[] = 
477 "Usage: show manager command <actionname>\n"
478 "       Shows the detailed description for a specific Asterisk manager interface command.\n";
479
480 static char showmancmds_help[] = 
481 "Usage: show manager commands\n"
482 "       Prints a listing of all the available Asterisk manager interface commands.\n";
483
484 static char showmanconn_help[] = 
485 "Usage: show manager connected\n"
486 "       Prints a listing of the users that are currently connected to the\n"
487 "Asterisk manager interface.\n";
488
489 static char showmaneventq_help[] = 
490 "Usage: show manager eventq\n"
491 "       Prints a listing of all events pending in the Asterisk manger\n"
492 "event queue.\n";
493
494 static struct ast_cli_entry show_mancmd_cli =
495         { { "show", "manager", "command", NULL },
496         handle_showmancmd, "Show a manager interface command", showmancmd_help, complete_show_mancmd };
497
498 static struct ast_cli_entry show_mancmds_cli =
499         { { "show", "manager", "commands", NULL },
500         handle_showmancmds, "List manager interface commands", showmancmds_help };
501
502 static struct ast_cli_entry show_manconn_cli =
503         { { "show", "manager", "connected", NULL },
504         handle_showmanconn, "Show connected manager interface users", showmanconn_help };
505
506 static struct ast_cli_entry show_maneventq_cli =
507         { { "show", "manager", "eventq", NULL },
508         handle_showmaneventq, "Show manager interface queued events", showmaneventq_help };
509
510 static void unuse_eventqent(struct eventqent *e)
511 {
512         /* XXX Need to atomically decrement the users.  Change this to atomic_dec
513                one day when we have such a beast XXX */
514         int val;
515         ast_mutex_lock(&e->lock);
516         e->usecount--;
517         val = !e->usecount && e->next;
518         ast_mutex_unlock(&e->lock);
519         /* Wake up sleeping beauty */
520         if (val)
521                 pthread_kill(t, SIGURG);
522 }
523
524 static void free_session(struct mansession *s)
525 {
526         struct eventqent *eqe;
527         if (s->fd > -1)
528                 close(s->fd);
529         if (s->outputstr)
530                 free(s->outputstr);
531         ast_mutex_destroy(&s->__lock);
532         while (s->eventq) {
533                 eqe = s->eventq;
534                 s->eventq = s->eventq->next;
535                 unuse_eventqent(eqe);
536         }
537         free(s);
538 }
539
540 static void destroy_session(struct mansession *s)
541 {
542         struct mansession *cur, *prev = NULL;
543         ast_mutex_lock(&sessionlock);
544         cur = sessions;
545         while (cur) {
546                 if (cur == s)
547                         break;
548                 prev = cur;
549                 cur = cur->next;
550         }
551         if (cur) {
552                 if (prev)
553                         prev->next = cur->next;
554                 else
555                         sessions = cur->next;
556                 free_session(s);
557                 num_sessions--;
558         } else
559                 ast_log(LOG_WARNING, "Trying to delete nonexistent session %p?\n", s);
560         ast_mutex_unlock(&sessionlock);
561 }
562
563 char *astman_get_header(struct message *m, char *var)
564 {
565         char cmp[80];
566         int x;
567         snprintf(cmp, sizeof(cmp), "%s: ", var);
568         for (x=0; x<m->hdrcount; x++)
569                 if (!strncasecmp(cmp, m->headers[x], strlen(cmp)))
570                         return m->headers[x] + strlen(cmp);
571         return "";
572 }
573
574 struct ast_variable *astman_get_variables(struct message *m)
575 {
576         int varlen, x, y;
577         struct ast_variable *head = NULL, *cur;
578         char *var, *val;
579
580         char *parse;    
581         AST_DECLARE_APP_ARGS(args,
582                 AST_APP_ARG(vars)[32];
583         );
584
585         varlen = strlen("Variable: ");  
586
587         for (x = 0; x < m->hdrcount; x++) {
588                 if (strncasecmp("Variable: ", m->headers[x], varlen))
589                         continue;
590
591                 if (!(parse = ast_strdupa(m->headers[x] + varlen)))
592                         return head;
593
594                 AST_STANDARD_APP_ARGS(args, parse);
595                 if (args.argc) {
596                         for (y = 0; y < args.argc; y++) {
597                                 if (!args.vars[y])
598                                         continue;
599                                 var = val = ast_strdupa(args.vars[y]);
600                                 strsep(&val, "=");
601                                 if (!val || ast_strlen_zero(var))
602                                         continue;
603                                 cur = ast_variable_new(var, val);
604                                 if (head) {
605                                         cur->next = head;
606                                         head = cur;
607                                 } else
608                                         head = cur;
609                         }
610                 }
611         }
612
613         return head;
614 }
615
616 /*! NOTE:
617    Callers of astman_send_error(), astman_send_response() or astman_send_ack() must EITHER
618    hold the session lock _or_ be running in an action callback (in which case s->busy will
619    be non-zero). In either of these cases, there is no need to lock-protect the session's
620    fd, since no other output will be sent (events will be queued), and no input will
621    be read until either the current action finishes or get_input() obtains the session
622    lock.
623  */
624 void astman_send_error(struct mansession *s, struct message *m, char *error)
625 {
626         char *id = astman_get_header(m,"ActionID");
627
628         astman_append(s, "Response: Error\r\n");
629         if (!ast_strlen_zero(id))
630                 astman_append(s, "ActionID: %s\r\n", id);
631         astman_append(s, "Message: %s\r\n\r\n", error);
632 }
633
634 void astman_send_response(struct mansession *s, struct message *m, char *resp, char *msg)
635 {
636         char *id = astman_get_header(m,"ActionID");
637
638         astman_append(s, "Response: %s\r\n", resp);
639         if (!ast_strlen_zero(id))
640                 astman_append(s, "ActionID: %s\r\n", id);
641         if (msg)
642                 astman_append(s, "Message: %s\r\n\r\n", msg);
643         else
644                 astman_append(s, "\r\n");
645 }
646
647 void astman_send_ack(struct mansession *s, struct message *m, char *msg)
648 {
649         astman_send_response(s, m, "Success", msg);
650 }
651
652 /*! Tells you if smallstr exists inside bigstr
653    which is delim by delim and uses no buf or stringsep
654    ast_instring("this|that|more","this",',') == 1;
655
656    feel free to move this to app.c -anthm */
657 static int ast_instring(char *bigstr, char *smallstr, char delim) 
658 {
659         char *val = bigstr, *next;
660
661         do {
662                 if ((next = strchr(val, delim))) {
663                         if (!strncmp(val, smallstr, (next - val)))
664                                 return 1;
665                         else
666                                 continue;
667                 } else
668                         return !strcmp(smallstr, val);
669
670         } while (*(val = (next + 1)));
671
672         return 0;
673 }
674
675 static int get_perm(char *instr)
676 {
677         int x = 0, ret = 0;
678
679         if (!instr)
680                 return 0;
681
682         for (x=0; x<sizeof(perms) / sizeof(perms[0]); x++)
683                 if (ast_instring(instr, perms[x].label, ','))
684                         ret |= perms[x].num;
685         
686         return ret;
687 }
688
689 static int ast_is_number(char *string) 
690 {
691         int ret = 1, x = 0;
692
693         if (!string)
694                 return 0;
695
696         for (x=0; x < strlen(string); x++) {
697                 if (!(string[x] >= 48 && string[x] <= 57)) {
698                         ret = 0;
699                         break;
700                 }
701         }
702         
703         return ret ? atoi(string) : 0;
704 }
705
706 static int ast_strings_to_mask(char *string) 
707 {
708         int x, ret = -1;
709         
710         x = ast_is_number(string);
711
712         if (x) {
713                 ret = x;
714         } else if (ast_strlen_zero(string)) {
715                 ret = -1;
716         } else if (ast_false(string)) {
717                 ret = 0;
718         } else if (ast_true(string)) {
719                 ret = 0;
720                 for (x=0; x<sizeof(perms) / sizeof(perms[0]); x++)
721                         ret |= perms[x].num;            
722         } else {
723                 ret = 0;
724                 for (x=0; x<sizeof(perms) / sizeof(perms[0]); x++) {
725                         if (ast_instring(string, perms[x].label, ',')) 
726                                 ret |= perms[x].num;            
727                 }
728         }
729
730         return ret;
731 }
732
733 /*! 
734    Rather than braindead on,off this now can also accept a specific int mask value 
735    or a ',' delim list of mask strings (the same as manager.conf) -anthm
736 */
737
738 static int set_eventmask(struct mansession *s, char *eventmask)
739 {
740         int maskint = ast_strings_to_mask(eventmask);
741
742         ast_mutex_lock(&s->__lock);
743         if (maskint >= 0)       
744                 s->send_events = maskint;
745         ast_mutex_unlock(&s->__lock);
746         
747         return maskint;
748 }
749
750 static int authenticate(struct mansession *s, struct message *m)
751 {
752         struct ast_config *cfg;
753         char iabuf[INET_ADDRSTRLEN];
754         char *cat;
755         char *user = astman_get_header(m, "Username");
756         char *pass = astman_get_header(m, "Secret");
757         char *authtype = astman_get_header(m, "AuthType");
758         char *key = astman_get_header(m, "Key");
759         char *events = astman_get_header(m, "Events");
760         
761         cfg = ast_config_load("manager.conf");
762         if (!cfg)
763                 return -1;
764         cat = ast_category_browse(cfg, NULL);
765         while (cat) {
766                 if (strcasecmp(cat, "general")) {
767                         /* This is a user */
768                         if (!strcasecmp(cat, user)) {
769                                 struct ast_variable *v;
770                                 struct ast_ha *ha = NULL;
771                                 char *password = NULL;
772                                 v = ast_variable_browse(cfg, cat);
773                                 while (v) {
774                                         if (!strcasecmp(v->name, "secret")) {
775                                                 password = v->value;
776                                         } else if (!strcasecmp(v->name, "permit") ||
777                                                    !strcasecmp(v->name, "deny")) {
778                                                 ha = ast_append_ha(v->name, v->value, ha);
779                                         } else if (!strcasecmp(v->name, "writetimeout")) {
780                                                 int val = atoi(v->value);
781
782                                                 if (val < 100)
783                                                         ast_log(LOG_WARNING, "Invalid writetimeout value '%s' at line %d\n", v->value, v->lineno);
784                                                 else
785                                                         s->writetimeout = val;
786                                         }
787                                                 
788                                         v = v->next;
789                                 }
790                                 if (ha && !ast_apply_ha(ha, &(s->sin))) {
791                                         ast_log(LOG_NOTICE, "%s failed to pass IP ACL as '%s'\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), user);
792                                         ast_free_ha(ha);
793                                         ast_config_destroy(cfg);
794                                         return -1;
795                                 } else if (ha)
796                                         ast_free_ha(ha);
797                                 if (!strcasecmp(authtype, "MD5")) {
798                                         if (!ast_strlen_zero(key) && s->challenge) {
799                                                 int x;
800                                                 int len = 0;
801                                                 char md5key[256] = "";
802                                                 struct MD5Context md5;
803                                                 unsigned char digest[16];
804                                                 MD5Init(&md5);
805                                                 MD5Update(&md5, (unsigned char *) s->challenge, strlen(s->challenge));
806                                                 MD5Update(&md5, (unsigned char *) password, strlen(password));
807                                                 MD5Final(digest, &md5);
808                                                 for (x=0; x<16; x++)
809                                                         len += sprintf(md5key + len, "%2.2x", digest[x]);
810                                                 if (!strcmp(md5key, key))
811                                                         break;
812                                                 else {
813                                                         ast_config_destroy(cfg);
814                                                         return -1;
815                                                 }
816                                         }
817                                 } else if (password && !strcmp(password, pass)) {
818                                         break;
819                                 } else {
820                                         ast_log(LOG_NOTICE, "%s failed to authenticate as '%s'\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), user);
821                                         ast_config_destroy(cfg);
822                                         return -1;
823                                 }       
824                         }
825                 }
826                 cat = ast_category_browse(cfg, cat);
827         }
828         if (cat) {
829                 ast_copy_string(s->username, cat, sizeof(s->username));
830                 s->readperm = get_perm(ast_variable_retrieve(cfg, cat, "read"));
831                 s->writeperm = get_perm(ast_variable_retrieve(cfg, cat, "write"));
832                 ast_config_destroy(cfg);
833                 if (events)
834                         set_eventmask(s, events);
835                 return 0;
836         }
837         ast_log(LOG_NOTICE, "%s tried to authenticate with nonexistent user '%s'\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), user);
838         ast_config_destroy(cfg);
839         return -1;
840 }
841
842 /*! \brief PING: Manager PING */
843 static char mandescr_ping[] = 
844 "Description: A 'Ping' action will ellicit a 'Pong' response.  Used to keep the\n"
845 "  manager connection open.\n"
846 "Variables: NONE\n";
847
848 static int action_ping(struct mansession *s, struct message *m)
849 {
850         astman_send_response(s, m, "Pong", NULL);
851         return 0;
852 }
853
854 /*! \brief WAITEVENT: Manager WAITEVENT */
855 static char mandescr_waitevent[] = 
856 "Description: A 'WaitEvent' action will ellicit a 'Success' response.  Whenever\n"
857 "a manager event is queued.  Once WaitEvent has been called on an HTTP manager\n"
858 "session, events will be generated and queued.\n"
859 "Variables: \n"
860 "   Timeout: Maximum time to wait for events\n";
861
862 static int action_waitevent(struct mansession *s, struct message *m)
863 {
864         char *timeouts = astman_get_header(m, "Timeout");
865         int timeout = -1, max;
866         int x;
867         int needexit = 0;
868         time_t now;
869         struct eventqent *eqe;
870         char *id = astman_get_header(m,"ActionID");
871         char idText[256] = "";
872
873         if (!ast_strlen_zero(id))
874                 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
875
876         if (!ast_strlen_zero(timeouts)) {
877                 sscanf(timeouts, "%i", &timeout);
878         }
879         
880         ast_mutex_lock(&s->__lock);
881         if (s->waiting_thread != AST_PTHREADT_NULL) {
882                 pthread_kill(s->waiting_thread, SIGURG);
883         }
884         if (s->sessiontimeout) {
885                 time(&now);
886                 max = s->sessiontimeout - now - 10;
887                 if (max < 0)
888                         max = 0;
889                 if ((timeout < 0) || (timeout > max))
890                         timeout = max;
891                 if (!s->send_events)
892                         s->send_events = -1;
893                 /* Once waitevent is called, always queue events from now on */
894                 if (s->busy == 1)
895                         s->busy = 2;
896         }
897         ast_mutex_unlock(&s->__lock);
898         s->waiting_thread = pthread_self();
899         if (option_debug)
900                 ast_log(LOG_DEBUG, "Starting waiting for an event!\n");
901         for (x=0; ((x < timeout) || (timeout < 0)); x++) {
902                 ast_mutex_lock(&s->__lock);
903                 if (s->eventq && s->eventq->next)
904                         needexit = 1;
905                 if (s->waiting_thread != pthread_self())
906                         needexit = 1;
907                 if (s->needdestroy)
908                         needexit = 1;
909                 ast_mutex_unlock(&s->__lock);
910                 if (needexit)
911                         break;
912                 if (s->fd > 0) {
913                         if (ast_wait_for_input(s->fd, 1000))
914                                 break;
915                 } else {
916                         sleep(1);
917                 }
918         }
919         if (option_debug)
920                 ast_log(LOG_DEBUG, "Finished waiting for an event!\n");
921         ast_mutex_lock(&s->__lock);
922         if (s->waiting_thread == pthread_self()) {
923                 astman_send_response(s, m, "Success", "Waiting for Event...");
924                 /* Only show events if we're the most recent waiter */
925                 while(s->eventq->next) {
926                         eqe = s->eventq->next;
927                         if (((s->readperm & eqe->category) == eqe->category) &&
928                             ((s->send_events & eqe->category) == eqe->category)) {
929                                 astman_append(s, "%s", eqe->eventdata);
930                         }
931                         unuse_eventqent(s->eventq);
932                         s->eventq = eqe;
933                 }
934                 astman_append(s,
935                         "Event: WaitEventComplete\r\n"
936                         "%s"
937                         "\r\n", idText);
938                 s->waiting_thread = AST_PTHREADT_NULL;
939         } else {
940                 ast_log(LOG_DEBUG, "Abandoning event request!\n");
941         }
942         ast_mutex_unlock(&s->__lock);
943         return 0;
944 }
945
946 static char mandescr_listcommands[] = 
947 "Description: Returns the action name and synopsis for every\n"
948 "  action that is available to the user\n"
949 "Variables: NONE\n";
950
951 static int action_listcommands(struct mansession *s, struct message *m)
952 {
953         struct manager_action *cur = first_action;
954         char idText[256] = "";
955         char temp[BUFSIZ];
956         char *id = astman_get_header(m,"ActionID");
957
958         if (!ast_strlen_zero(id))
959                 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
960         astman_append(s, "Response: Success\r\n%s", idText);
961         ast_mutex_lock(&actionlock);
962         while (cur) { /* Walk the list of actions */
963                 if ((s->writeperm & cur->authority) == cur->authority)
964                         astman_append(s, "%s: %s (Priv: %s)\r\n", cur->action, cur->synopsis, authority_to_str(cur->authority, temp, sizeof(temp)));
965                 cur = cur->next;
966         }
967         ast_mutex_unlock(&actionlock);
968         astman_append(s, "\r\n");
969
970         return 0;
971 }
972
973 static char mandescr_events[] = 
974 "Description: Enable/Disable sending of events to this manager\n"
975 "  client.\n"
976 "Variables:\n"
977 "       EventMask: 'on' if all events should be sent,\n"
978 "               'off' if no events should be sent,\n"
979 "               'system,call,log' to select which flags events should have to be sent.\n";
980
981 static int action_events(struct mansession *s, struct message *m)
982 {
983         char *mask = astman_get_header(m, "EventMask");
984         int res;
985
986         res = set_eventmask(s, mask);
987         if (res > 0)
988                 astman_send_response(s, m, "Events On", NULL);
989         else if (res == 0)
990                 astman_send_response(s, m, "Events Off", NULL);
991
992         return 0;
993 }
994
995 static char mandescr_logoff[] = 
996 "Description: Logoff this manager session\n"
997 "Variables: NONE\n";
998
999 static int action_logoff(struct mansession *s, struct message *m)
1000 {
1001         astman_send_response(s, m, "Goodbye", "Thanks for all the fish.");
1002         return -1;
1003 }
1004
1005 static char mandescr_hangup[] = 
1006 "Description: Hangup a channel\n"
1007 "Variables: \n"
1008 "       Channel: The channel name to be hungup\n";
1009
1010 static int action_hangup(struct mansession *s, struct message *m)
1011 {
1012         struct ast_channel *c = NULL;
1013         char *name = astman_get_header(m, "Channel");
1014         if (ast_strlen_zero(name)) {
1015                 astman_send_error(s, m, "No channel specified");
1016                 return 0;
1017         }
1018         c = ast_get_channel_by_name_locked(name);
1019         if (!c) {
1020                 astman_send_error(s, m, "No such channel");
1021                 return 0;
1022         }
1023         ast_softhangup(c, AST_SOFTHANGUP_EXPLICIT);
1024         ast_channel_unlock(c);
1025         astman_send_ack(s, m, "Channel Hungup");
1026         return 0;
1027 }
1028
1029 static char mandescr_setvar[] = 
1030 "Description: Set a global or local channel variable.\n"
1031 "Variables: (Names marked with * are required)\n"
1032 "       Channel: Channel to set variable for\n"
1033 "       *Variable: Variable name\n"
1034 "       *Value: Value\n";
1035
1036 static int action_setvar(struct mansession *s, struct message *m)
1037 {
1038         struct ast_channel *c = NULL;
1039         char *name = astman_get_header(m, "Channel");
1040         char *varname = astman_get_header(m, "Variable");
1041         char *varval = astman_get_header(m, "Value");
1042         
1043         if (ast_strlen_zero(varname)) {
1044                 astman_send_error(s, m, "No variable specified");
1045                 return 0;
1046         }
1047         
1048         if (ast_strlen_zero(varval)) {
1049                 astman_send_error(s, m, "No value specified");
1050                 return 0;
1051         }
1052
1053         if (!ast_strlen_zero(name)) {
1054                 c = ast_get_channel_by_name_locked(name);
1055                 if (!c) {
1056                         astman_send_error(s, m, "No such channel");
1057                         return 0;
1058                 }
1059         }
1060         
1061         pbx_builtin_setvar_helper(c, varname, varval);
1062           
1063         if (c)
1064                 ast_channel_unlock(c);
1065
1066         astman_send_ack(s, m, "Variable Set");  
1067
1068         return 0;
1069 }
1070
1071 static char mandescr_getvar[] = 
1072 "Description: Get the value of a global or local channel variable.\n"
1073 "Variables: (Names marked with * are required)\n"
1074 "       Channel: Channel to read variable from\n"
1075 "       *Variable: Variable name\n"
1076 "       ActionID: Optional Action id for message matching.\n";
1077
1078 static int action_getvar(struct mansession *s, struct message *m)
1079 {
1080         struct ast_channel *c = NULL;
1081         char *name = astman_get_header(m, "Channel");
1082         char *varname = astman_get_header(m, "Variable");
1083         char *id = astman_get_header(m,"ActionID");
1084         char *varval;
1085         char workspace[1024];
1086
1087         if (ast_strlen_zero(varname)) {
1088                 astman_send_error(s, m, "No variable specified");
1089                 return 0;
1090         }
1091
1092         if (!ast_strlen_zero(name)) {
1093                 c = ast_get_channel_by_name_locked(name);
1094                 if (!c) {
1095                         astman_send_error(s, m, "No such channel");
1096                         return 0;
1097                 }
1098         }
1099
1100         if (varname[strlen(varname) - 1] == ')') {
1101                 ast_func_read(c, varname, workspace, sizeof(workspace));
1102         } else {
1103                 pbx_retrieve_variable(c, varname, &varval, workspace, sizeof(workspace), NULL);
1104         }
1105
1106         if (c)
1107                 ast_channel_unlock(c);
1108         astman_append(s, "Response: Success\r\n"
1109                 "Variable: %s\r\nValue: %s\r\n", varname, varval);
1110         if (!ast_strlen_zero(id))
1111                 astman_append(s, "ActionID: %s\r\n",id);
1112         astman_append(s, "\r\n");
1113
1114         return 0;
1115 }
1116
1117
1118 /*! \brief  action_status: Manager "status" command to show channels */
1119 /* Needs documentation... */
1120 static int action_status(struct mansession *s, struct message *m)
1121 {
1122         char *id = astman_get_header(m,"ActionID");
1123         char *name = astman_get_header(m,"Channel");
1124         char idText[256] = "";
1125         struct ast_channel *c;
1126         char bridge[256];
1127         struct timeval now = ast_tvnow();
1128         long elapsed_seconds = 0;
1129         int all = ast_strlen_zero(name); /* set if we want all channels */
1130
1131         astman_send_ack(s, m, "Channel status will follow");
1132         if (!ast_strlen_zero(id))
1133                 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
1134         if (all)
1135                 c = ast_channel_walk_locked(NULL);
1136         else {
1137                 c = ast_get_channel_by_name_locked(name);
1138                 if (!c) {
1139                         astman_send_error(s, m, "No such channel");
1140                         return 0;
1141                 }
1142         }
1143         /* if we look by name, we break after the first iteration */
1144         while (c) {
1145                 if (c->_bridge)
1146                         snprintf(bridge, sizeof(bridge), "Link: %s\r\n", c->_bridge->name);
1147                 else
1148                         bridge[0] = '\0';
1149                 if (c->pbx) {
1150                         if (c->cdr) {
1151                                 elapsed_seconds = now.tv_sec - c->cdr->start.tv_sec;
1152                         }
1153                         astman_append(s,
1154                         "Event: Status\r\n"
1155                         "Privilege: Call\r\n"
1156                         "Channel: %s\r\n"
1157                         "CallerID: %s\r\n"              /* This parameter is deprecated and will be removed post-1.4 */
1158                         "CallerIDNum: %s\r\n"
1159                         "CallerIDName: %s\r\n"
1160                         "Account: %s\r\n"
1161                         "State: %s\r\n"
1162                         "Context: %s\r\n"
1163                         "Extension: %s\r\n"
1164                         "Priority: %d\r\n"
1165                         "Seconds: %ld\r\n"
1166                         "%s"
1167                         "Uniqueid: %s\r\n"
1168                         "%s"
1169                         "\r\n",
1170                         c->name, 
1171                         S_OR(c->cid.cid_num, "<unknown>"), 
1172                         S_OR(c->cid.cid_num, "<unknown>"), 
1173                         S_OR(c->cid.cid_name, "<unknown>"), 
1174                         c->accountcode,
1175                         ast_state2str(c->_state), c->context,
1176                         c->exten, c->priority, (long)elapsed_seconds, bridge, c->uniqueid, idText);
1177                 } else {
1178                         astman_append(s,
1179                         "Event: Status\r\n"
1180                         "Privilege: Call\r\n"
1181                         "Channel: %s\r\n"
1182                         "CallerID: %s\r\n"              /* This parameter is deprecated and will be removed post-1.4 */
1183                         "CallerIDNum: %s\r\n"
1184                         "CallerIDName: %s\r\n"
1185                         "Account: %s\r\n"
1186                         "State: %s\r\n"
1187                         "%s"
1188                         "Uniqueid: %s\r\n"
1189                         "%s"
1190                         "\r\n",
1191                         c->name, 
1192                         S_OR(c->cid.cid_num, "<unknown>"), 
1193                         S_OR(c->cid.cid_num, "<unknown>"), 
1194                         S_OR(c->cid.cid_name, "<unknown>"), 
1195                         c->accountcode,
1196                         ast_state2str(c->_state), bridge, c->uniqueid, idText);
1197                 }
1198                 ast_channel_unlock(c);
1199                 if (!all)
1200                         break;
1201                 c = ast_channel_walk_locked(c);
1202         }
1203         astman_append(s,
1204         "Event: StatusComplete\r\n"
1205         "%s"
1206         "\r\n",idText);
1207         return 0;
1208 }
1209
1210 static char mandescr_redirect[] = 
1211 "Description: Redirect (transfer) a call.\n"
1212 "Variables: (Names marked with * are required)\n"
1213 "       *Channel: Channel to redirect\n"
1214 "       ExtraChannel: Second call leg to transfer (optional)\n"
1215 "       *Exten: Extension to transfer to\n"
1216 "       *Context: Context to transfer to\n"
1217 "       *Priority: Priority to transfer to\n"
1218 "       ActionID: Optional Action id for message matching.\n";
1219
1220 /*! \brief  action_redirect: The redirect manager command */
1221 static int action_redirect(struct mansession *s, struct message *m)
1222 {
1223         char *name = astman_get_header(m, "Channel");
1224         char *name2 = astman_get_header(m, "ExtraChannel");
1225         char *exten = astman_get_header(m, "Exten");
1226         char *context = astman_get_header(m, "Context");
1227         char *priority = astman_get_header(m, "Priority");
1228         struct ast_channel *chan, *chan2 = NULL;
1229         int pi = 0;
1230         int res;
1231
1232         if (ast_strlen_zero(name)) {
1233                 astman_send_error(s, m, "Channel not specified");
1234                 return 0;
1235         }
1236         if (!ast_strlen_zero(priority) && (sscanf(priority, "%d", &pi) != 1)) {
1237                 if ((pi = ast_findlabel_extension(NULL, context, exten, priority, NULL)) < 1) {
1238                         astman_send_error(s, m, "Invalid priority\n");
1239                         return 0;
1240                 }
1241         }
1242         /* XXX watch out, possible deadlock!!! */
1243         chan = ast_get_channel_by_name_locked(name);
1244         if (!chan) {
1245                 char buf[BUFSIZ];
1246                 snprintf(buf, sizeof(buf), "Channel does not exist: %s", name);
1247                 astman_send_error(s, m, buf);
1248                 return 0;
1249         }
1250         if (!ast_strlen_zero(name2))
1251                 chan2 = ast_get_channel_by_name_locked(name2);
1252         res = ast_async_goto(chan, context, exten, pi);
1253         if (!res) {
1254                 if (!ast_strlen_zero(name2)) {
1255                         if (chan2)
1256                                 res = ast_async_goto(chan2, context, exten, pi);
1257                         else
1258                                 res = -1;
1259                         if (!res)
1260                                 astman_send_ack(s, m, "Dual Redirect successful");
1261                         else
1262                                 astman_send_error(s, m, "Secondary redirect failed");
1263                 } else
1264                         astman_send_ack(s, m, "Redirect successful");
1265         } else
1266                 astman_send_error(s, m, "Redirect failed");
1267         if (chan)
1268                 ast_channel_unlock(chan);
1269         if (chan2)
1270                 ast_channel_unlock(chan2);
1271         return 0;
1272 }
1273
1274 static char mandescr_command[] = 
1275 "Description: Run a CLI command.\n"
1276 "Variables: (Names marked with * are required)\n"
1277 "       *Command: Asterisk CLI command to run\n"
1278 "       ActionID: Optional Action id for message matching.\n";
1279
1280 /*! \brief  action_command: Manager command "command" - execute CLI command */
1281 static int action_command(struct mansession *s, struct message *m)
1282 {
1283         char *cmd = astman_get_header(m, "Command");
1284         char *id = astman_get_header(m, "ActionID");
1285         astman_append(s, "Response: Follows\r\nPrivilege: Command\r\n");
1286         if (!ast_strlen_zero(id))
1287                 astman_append(s, "ActionID: %s\r\n", id);
1288         /* FIXME: Wedge a ActionID response in here, waiting for later changes */
1289         ast_cli_command(s->fd, cmd);
1290         astman_append(s, "--END COMMAND--\r\n\r\n");
1291         return 0;
1292 }
1293
1294 static void *fast_originate(void *data)
1295 {
1296         struct fast_originate_helper *in = data;
1297         int res;
1298         int reason = 0;
1299         struct ast_channel *chan = NULL;
1300
1301         if (!ast_strlen_zero(in->app)) {
1302                 res = ast_pbx_outgoing_app(in->tech, AST_FORMAT_SLINEAR, in->data, in->timeout, in->app, in->appdata, &reason, 1, 
1303                         S_OR(in->cid_num, NULL), 
1304                         S_OR(in->cid_name, NULL),
1305                         in->vars, in->account, &chan);
1306         } else {
1307                 res = ast_pbx_outgoing_exten(in->tech, AST_FORMAT_SLINEAR, in->data, in->timeout, in->context, in->exten, in->priority, &reason, 1, 
1308                         S_OR(in->cid_num, NULL), 
1309                         S_OR(in->cid_name, NULL),
1310                         in->vars, in->account, &chan);
1311         }   
1312         
1313         /* Tell the manager what happened with the channel */
1314         manager_event(EVENT_FLAG_CALL,
1315                 res ? "OriginateSuccess" : "OriginateFailure",
1316                 "%s"
1317                 "Channel: %s/%s\r\n"
1318                 "Context: %s\r\n"
1319                 "Exten: %s\r\n"
1320                 "Reason: %d\r\n"
1321                 "Uniqueid: %s\r\n"
1322                 "CallerID: %s\r\n"              /* This parameter is deprecated and will be removed post-1.4 */
1323                 "CallerIDNum: %s\r\n"
1324                 "CallerIDName: %s\r\n",
1325                 in->idtext, in->tech, in->data, in->context, in->exten, reason, 
1326                 chan ? chan->uniqueid : "<null>",
1327                 S_OR(in->cid_num, "<unknown>"),
1328                 S_OR(in->cid_num, "<unknown>"),
1329                 S_OR(in->cid_name, "<unknown>")
1330                 );
1331
1332         /* Locked by ast_pbx_outgoing_exten or ast_pbx_outgoing_app */
1333         if (chan)
1334                 ast_channel_unlock(chan);
1335         free(in);
1336         return NULL;
1337 }
1338
1339 static char mandescr_originate[] = 
1340 "Description: Generates an outgoing call to a Extension/Context/Priority or\n"
1341 "  Application/Data\n"
1342 "Variables: (Names marked with * are required)\n"
1343 "       *Channel: Channel name to call\n"
1344 "       Exten: Extension to use (requires 'Context' and 'Priority')\n"
1345 "       Context: Context to use (requires 'Exten' and 'Priority')\n"
1346 "       Priority: Priority to use (requires 'Exten' and 'Context')\n"
1347 "       Application: Application to use\n"
1348 "       Data: Data to use (requires 'Application')\n"
1349 "       Timeout: How long to wait for call to be answered (in ms)\n"
1350 "       CallerID: Caller ID to be set on the outgoing channel\n"
1351 "       Variable: Channel variable to set, multiple Variable: headers are allowed\n"
1352 "       Account: Account code\n"
1353 "       Async: Set to 'true' for fast origination\n";
1354
1355 static int action_originate(struct mansession *s, struct message *m)
1356 {
1357         char *name = astman_get_header(m, "Channel");
1358         char *exten = astman_get_header(m, "Exten");
1359         char *context = astman_get_header(m, "Context");
1360         char *priority = astman_get_header(m, "Priority");
1361         char *timeout = astman_get_header(m, "Timeout");
1362         char *callerid = astman_get_header(m, "CallerID");
1363         char *account = astman_get_header(m, "Account");
1364         char *app = astman_get_header(m, "Application");
1365         char *appdata = astman_get_header(m, "Data");
1366         char *async = astman_get_header(m, "Async");
1367         char *id = astman_get_header(m, "ActionID");
1368         struct ast_variable *vars = astman_get_variables(m);
1369         char *tech, *data;
1370         char *l = NULL, *n = NULL;
1371         int pi = 0;
1372         int res;
1373         int to = 30000;
1374         int reason = 0;
1375         char tmp[256];
1376         char tmp2[256];
1377         
1378         pthread_t th;
1379         pthread_attr_t attr;
1380         if (!name) {
1381                 astman_send_error(s, m, "Channel not specified");
1382                 return 0;
1383         }
1384         if (!ast_strlen_zero(priority) && (sscanf(priority, "%d", &pi) != 1)) {
1385                 if ((pi = ast_findlabel_extension(NULL, context, exten, priority, NULL)) < 1) {
1386                         astman_send_error(s, m, "Invalid priority\n");
1387                         return 0;
1388                 }
1389         }
1390         if (!ast_strlen_zero(timeout) && (sscanf(timeout, "%d", &to) != 1)) {
1391                 astman_send_error(s, m, "Invalid timeout\n");
1392                 return 0;
1393         }
1394         ast_copy_string(tmp, name, sizeof(tmp));
1395         tech = tmp;
1396         data = strchr(tmp, '/');
1397         if (!data) {
1398                 astman_send_error(s, m, "Invalid channel\n");
1399                 return 0;
1400         }
1401         *data++ = '\0';
1402         ast_copy_string(tmp2, callerid, sizeof(tmp2));
1403         ast_callerid_parse(tmp2, &n, &l);
1404         if (n) {
1405                 if (ast_strlen_zero(n))
1406                         n = NULL;
1407         }
1408         if (l) {
1409                 ast_shrink_phone_number(l);
1410                 if (ast_strlen_zero(l))
1411                         l = NULL;
1412         }
1413         if (ast_true(async)) {
1414                 struct fast_originate_helper *fast = malloc(sizeof(struct fast_originate_helper));
1415                 if (!fast) {
1416                         res = -1;
1417                 } else {
1418                         memset(fast, 0, sizeof(struct fast_originate_helper));
1419                         if (!ast_strlen_zero(id))
1420                                 snprintf(fast->idtext, sizeof(fast->idtext), "ActionID: %s\r\n", id);
1421                         ast_copy_string(fast->tech, tech, sizeof(fast->tech));
1422                         ast_copy_string(fast->data, data, sizeof(fast->data));
1423                         ast_copy_string(fast->app, app, sizeof(fast->app));
1424                         ast_copy_string(fast->appdata, appdata, sizeof(fast->appdata));
1425                         if (l)
1426                                 ast_copy_string(fast->cid_num, l, sizeof(fast->cid_num));
1427                         if (n)
1428                                 ast_copy_string(fast->cid_name, n, sizeof(fast->cid_name));
1429                         fast->vars = vars;      
1430                         ast_copy_string(fast->context, context, sizeof(fast->context));
1431                         ast_copy_string(fast->exten, exten, sizeof(fast->exten));
1432                         ast_copy_string(fast->account, account, sizeof(fast->account));
1433                         fast->timeout = to;
1434                         fast->priority = pi;
1435                         pthread_attr_init(&attr);
1436                         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1437                         if (ast_pthread_create(&th, &attr, fast_originate, fast)) {
1438                                 res = -1;
1439                         } else {
1440                                 res = 0;
1441                         }
1442                 }
1443         } else if (!ast_strlen_zero(app)) {
1444                 res = ast_pbx_outgoing_app(tech, AST_FORMAT_SLINEAR, data, to, app, appdata, &reason, 1, l, n, vars, account, NULL);
1445         } else {
1446                 if (exten && context && pi)
1447                         res = ast_pbx_outgoing_exten(tech, AST_FORMAT_SLINEAR, data, to, context, exten, pi, &reason, 1, l, n, vars, account, NULL);
1448                 else {
1449                         astman_send_error(s, m, "Originate with 'Exten' requires 'Context' and 'Priority'");
1450                         return 0;
1451                 }
1452         }   
1453         if (!res)
1454                 astman_send_ack(s, m, "Originate successfully queued");
1455         else
1456                 astman_send_error(s, m, "Originate failed");
1457         return 0;
1458 }
1459
1460 /*!     \brief Help text for manager command mailboxstatus
1461  */
1462 static char mandescr_mailboxstatus[] = 
1463 "Description: Checks a voicemail account for status.\n"
1464 "Variables: (Names marked with * are required)\n"
1465 "       *Mailbox: Full mailbox ID <mailbox>@<vm-context>\n"
1466 "       ActionID: Optional ActionID for message matching.\n"
1467 "Returns number of messages.\n"
1468 "       Message: Mailbox Status\n"
1469 "       Mailbox: <mailboxid>\n"
1470 "       Waiting: <count>\n"
1471 "\n";
1472
1473 static int action_mailboxstatus(struct mansession *s, struct message *m)
1474 {
1475         char *mailbox = astman_get_header(m, "Mailbox");
1476         char *id = astman_get_header(m,"ActionID");
1477         char idText[256] = "";
1478         int ret;
1479         if (ast_strlen_zero(mailbox)) {
1480                 astman_send_error(s, m, "Mailbox not specified");
1481                 return 0;
1482         }
1483         if (!ast_strlen_zero(id))
1484                 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
1485         ret = ast_app_has_voicemail(mailbox, NULL);
1486         astman_append(s, "Response: Success\r\n"
1487                                    "%s"
1488                                    "Message: Mailbox Status\r\n"
1489                                    "Mailbox: %s\r\n"
1490                                    "Waiting: %d\r\n\r\n", idText, mailbox, ret);
1491         return 0;
1492 }
1493
1494 static char mandescr_mailboxcount[] = 
1495 "Description: Checks a voicemail account for new messages.\n"
1496 "Variables: (Names marked with * are required)\n"
1497 "       *Mailbox: Full mailbox ID <mailbox>@<vm-context>\n"
1498 "       ActionID: Optional ActionID for message matching.\n"
1499 "Returns number of new and old messages.\n"
1500 "       Message: Mailbox Message Count\n"
1501 "       Mailbox: <mailboxid>\n"
1502 "       NewMessages: <count>\n"
1503 "       OldMessages: <count>\n"
1504 "\n";
1505 static int action_mailboxcount(struct mansession *s, struct message *m)
1506 {
1507         char *mailbox = astman_get_header(m, "Mailbox");
1508         char *id = astman_get_header(m,"ActionID");
1509         char idText[256] = "";
1510         int newmsgs = 0, oldmsgs = 0;
1511         if (ast_strlen_zero(mailbox)) {
1512                 astman_send_error(s, m, "Mailbox not specified");
1513                 return 0;
1514         }
1515         ast_app_messagecount(mailbox, &newmsgs, &oldmsgs);
1516         if (!ast_strlen_zero(id)) {
1517                 snprintf(idText, sizeof(idText), "ActionID: %s\r\n",id);
1518         }
1519         astman_append(s, "Response: Success\r\n"
1520                                    "%s"
1521                                    "Message: Mailbox Message Count\r\n"
1522                                    "Mailbox: %s\r\n"
1523                                    "NewMessages: %d\r\n"
1524                                    "OldMessages: %d\r\n" 
1525                                    "\r\n",
1526                                     idText,mailbox, newmsgs, oldmsgs);
1527         return 0;
1528 }
1529
1530 static char mandescr_extensionstate[] = 
1531 "Description: Report the extension state for given extension.\n"
1532 "  If the extension has a hint, will use devicestate to check\n"
1533 "  the status of the device connected to the extension.\n"
1534 "Variables: (Names marked with * are required)\n"
1535 "       *Exten: Extension to check state on\n"
1536 "       *Context: Context for extension\n"
1537 "       ActionId: Optional ID for this transaction\n"
1538 "Will return an \"Extension Status\" message.\n"
1539 "The response will include the hint for the extension and the status.\n";
1540
1541 static int action_extensionstate(struct mansession *s, struct message *m)
1542 {
1543         char *exten = astman_get_header(m, "Exten");
1544         char *context = astman_get_header(m, "Context");
1545         char *id = astman_get_header(m,"ActionID");
1546         char idText[256] = "";
1547         char hint[256] = "";
1548         int status;
1549         if (ast_strlen_zero(exten)) {
1550                 astman_send_error(s, m, "Extension not specified");
1551                 return 0;
1552         }
1553         if (ast_strlen_zero(context))
1554                 context = "default";
1555         status = ast_extension_state(NULL, context, exten);
1556         ast_get_hint(hint, sizeof(hint) - 1, NULL, 0, NULL, context, exten);
1557         if (!ast_strlen_zero(id)) {
1558                 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
1559         }
1560         astman_append(s, "Response: Success\r\n"
1561                                    "%s"
1562                                    "Message: Extension Status\r\n"
1563                                    "Exten: %s\r\n"
1564                                    "Context: %s\r\n"
1565                                    "Hint: %s\r\n"
1566                                    "Status: %d\r\n\r\n",
1567                                    idText,exten, context, hint, status);
1568         return 0;
1569 }
1570
1571 static char mandescr_timeout[] = 
1572 "Description: Hangup a channel after a certain time.\n"
1573 "Variables: (Names marked with * are required)\n"
1574 "       *Channel: Channel name to hangup\n"
1575 "       *Timeout: Maximum duration of the call (sec)\n"
1576 "Acknowledges set time with 'Timeout Set' message\n";
1577
1578 static int action_timeout(struct mansession *s, struct message *m)
1579 {
1580         struct ast_channel *c = NULL;
1581         char *name = astman_get_header(m, "Channel");
1582         int timeout = atoi(astman_get_header(m, "Timeout"));
1583         if (ast_strlen_zero(name)) {
1584                 astman_send_error(s, m, "No channel specified");
1585                 return 0;
1586         }
1587         if (!timeout) {
1588                 astman_send_error(s, m, "No timeout specified");
1589                 return 0;
1590         }
1591         c = ast_get_channel_by_name_locked(name);
1592         if (!c) {
1593                 astman_send_error(s, m, "No such channel");
1594                 return 0;
1595         }
1596         ast_channel_setwhentohangup(c, timeout);
1597         ast_channel_unlock(c);
1598         astman_send_ack(s, m, "Timeout Set");
1599         return 0;
1600 }
1601
1602 static int process_events(struct mansession *s)
1603 {
1604         struct eventqent *eqe;
1605         int ret = 0;
1606         ast_mutex_lock(&s->__lock);
1607         if (s->fd > -1) {
1608                 s->busy--;
1609                 if (!s->eventq)
1610                         s->eventq = master_eventq;
1611                 while(s->eventq->next) {
1612                         eqe = s->eventq->next;
1613                         if ((s->authenticated && (s->readperm & eqe->category) == eqe->category) &&
1614                             ((s->send_events & eqe->category) == eqe->category)) {
1615                                 if (!ret && ast_carefulwrite(s->fd, eqe->eventdata, strlen(eqe->eventdata), s->writetimeout) < 0)
1616                                         ret = -1;
1617                         }
1618                         unuse_eventqent(s->eventq);
1619                         s->eventq = eqe;
1620                 }
1621         }
1622         ast_mutex_unlock(&s->__lock);
1623         return ret;
1624 }
1625
1626 static int process_message(struct mansession *s, struct message *m)
1627 {
1628         char action[80] = "";
1629         struct manager_action *tmp = first_action;
1630         char *id = astman_get_header(m,"ActionID");
1631         char idText[256] = "";
1632         char iabuf[INET_ADDRSTRLEN];
1633         int ret = 0;
1634
1635         ast_copy_string(action, astman_get_header(m, "Action"), sizeof(action));
1636         ast_log( LOG_DEBUG, "Manager received command '%s'\n", action );
1637
1638         if (ast_strlen_zero(action)) {
1639                 astman_send_error(s, m, "Missing action in request");
1640                 return 0;
1641         }
1642         if (!ast_strlen_zero(id)) {
1643                 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
1644         }
1645         if (!s->authenticated) {
1646                 if (!strcasecmp(action, "Challenge")) {
1647                         char *authtype;
1648                         authtype = astman_get_header(m, "AuthType");
1649                         if (!strcasecmp(authtype, "MD5")) {
1650                                 if (ast_strlen_zero(s->challenge))
1651                                         snprintf(s->challenge, sizeof(s->challenge), "%ld", ast_random());
1652                                 ast_mutex_lock(&s->__lock);
1653                                 astman_append(s, "Response: Success\r\n"
1654                                                 "%s"
1655                                                 "Challenge: %s\r\n\r\n",
1656                                                 idText, s->challenge);
1657                                 ast_mutex_unlock(&s->__lock);
1658                                 return 0;
1659                         } else {
1660                                 astman_send_error(s, m, "Must specify AuthType");
1661                                 return 0;
1662                         }
1663                 } else if (!strcasecmp(action, "Login")) {
1664                         if (authenticate(s, m)) {
1665                                 sleep(1);
1666                                 astman_send_error(s, m, "Authentication failed");
1667                                 return -1;
1668                         } else {
1669                                 s->authenticated = 1;
1670                                 if (option_verbose > 1) {
1671                                         if (displayconnects) {
1672                                                 ast_verbose(VERBOSE_PREFIX_2 "%sManager '%s' logged on from %s\n", (s->sessiontimeout ? "HTTP " : ""), s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
1673                                         }
1674                                 }
1675                                 ast_log(LOG_EVENT, "%sManager '%s' logged on from %s\n", (s->sessiontimeout ? "HTTP " : ""), s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
1676                                 astman_send_ack(s, m, "Authentication accepted");
1677                         }
1678                 } else if (!strcasecmp(action, "Logoff")) {
1679                         astman_send_ack(s, m, "See ya");
1680                         return -1;
1681                 } else
1682                         astman_send_error(s, m, "Authentication Required");
1683         } else {
1684                 ast_mutex_lock(&s->__lock);
1685                 s->busy++;
1686                 ast_mutex_unlock(&s->__lock);
1687                 while (tmp) {           
1688                         if (!strcasecmp(action, tmp->action)) {
1689                                 if ((s->writeperm & tmp->authority) == tmp->authority) {
1690                                         if (tmp->func(s, m))
1691                                                 ret = -1;
1692                                 } else {
1693                                         astman_send_error(s, m, "Permission denied");
1694                                 }
1695                                 break;
1696                         }
1697                         tmp = tmp->next;
1698                 }
1699                 if (!tmp)
1700                         astman_send_error(s, m, "Invalid/unknown command");
1701         }
1702         if (ret)
1703                 return ret;
1704         return process_events(s);
1705 }
1706
1707 static int get_input(struct mansession *s, char *output)
1708 {
1709         /* output must have at least sizeof(s->inbuf) space */
1710         int res;
1711         int x;
1712         struct pollfd fds[1];
1713         char iabuf[INET_ADDRSTRLEN];
1714         for (x = 1; x < s->inlen; x++) {
1715                 if ((s->inbuf[x] == '\n') && (s->inbuf[x-1] == '\r')) {
1716                         /* Copy output data up to and including \r\n */
1717                         memcpy(output, s->inbuf, x + 1);
1718                         /* Add trailing \0 */
1719                         output[x+1] = '\0';
1720                         /* Move remaining data back to the front */
1721                         memmove(s->inbuf, s->inbuf + x + 1, s->inlen - x);
1722                         s->inlen -= (x + 1);
1723                         return 1;
1724                 }
1725         } 
1726         if (s->inlen >= sizeof(s->inbuf) - 1) {
1727                 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);
1728                 s->inlen = 0;
1729         }
1730         fds[0].fd = s->fd;
1731         fds[0].events = POLLIN;
1732         do {
1733                 ast_mutex_lock(&s->__lock);
1734                 s->waiting_thread = pthread_self();
1735                 ast_mutex_unlock(&s->__lock);
1736
1737                 res = poll(fds, 1, -1);
1738
1739                 ast_mutex_lock(&s->__lock);
1740                 s->waiting_thread = AST_PTHREADT_NULL;
1741                 ast_mutex_unlock(&s->__lock);
1742                 if (res < 0) {
1743                         if (errno == EINTR) {
1744                                 if (s->dead)
1745                                         return -1;
1746                                 return 0;
1747                         }
1748                         ast_log(LOG_WARNING, "Select returned error: %s\n", strerror(errno));
1749                         return -1;
1750                 } else if (res > 0) {
1751                         ast_mutex_lock(&s->__lock);
1752                         res = read(s->fd, s->inbuf + s->inlen, sizeof(s->inbuf) - 1 - s->inlen);
1753                         ast_mutex_unlock(&s->__lock);
1754                         if (res < 1)
1755                                 return -1;
1756                         break;
1757                 }
1758         } while(1);
1759         s->inlen += res;
1760         s->inbuf[s->inlen] = '\0';
1761         return 0;
1762 }
1763
1764 static void *session_do(void *data)
1765 {
1766         struct mansession *s = data;
1767         struct message m;
1768         char iabuf[INET_ADDRSTRLEN];
1769         int res;
1770         
1771         ast_mutex_lock(&s->__lock);
1772         astman_append(s, "Asterisk Call Manager/1.0\r\n");
1773         ast_mutex_unlock(&s->__lock);
1774         memset(&m, 0, sizeof(m));
1775         for (;;) {
1776                 res = get_input(s, m.headers[m.hdrcount]);
1777                 if (res > 0) {
1778                         /* Strip trailing \r\n */
1779                         if (strlen(m.headers[m.hdrcount]) < 2)
1780                                 continue;
1781                         m.headers[m.hdrcount][strlen(m.headers[m.hdrcount]) - 2] = '\0';
1782                         if (ast_strlen_zero(m.headers[m.hdrcount])) {
1783                                 if (process_message(s, &m))
1784                                         break;
1785                                 memset(&m, 0, sizeof(m));
1786                         } else if (m.hdrcount < AST_MAX_MANHEADERS - 1)
1787                                 m.hdrcount++;
1788                 } else if (res < 0) {
1789                         break;
1790                 } else if (s->eventq->next) {
1791                         if (process_events(s))
1792                                 break;
1793                 }
1794         }
1795         if (s->authenticated) {
1796                 if (option_verbose > 1) {
1797                         if (displayconnects) 
1798                                 ast_verbose(VERBOSE_PREFIX_2 "Manager '%s' logged off from %s\n", s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
1799                 }
1800                 ast_log(LOG_EVENT, "Manager '%s' logged off from %s\n", s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
1801         } else {
1802                 if (option_verbose > 1) {
1803                         if (displayconnects)
1804                                 ast_verbose(VERBOSE_PREFIX_2 "Connect attempt from '%s' unable to authenticate\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
1805                 }
1806                 ast_log(LOG_EVENT, "Failed attempt from %s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
1807         }
1808         destroy_session(s);
1809         return NULL;
1810 }
1811
1812 static void *accept_thread(void *ignore)
1813 {
1814         int as;
1815         struct sockaddr_in sin;
1816         socklen_t sinlen;
1817         struct eventqent *eqe;
1818         struct mansession *s, *prev = NULL, *next;
1819         struct protoent *p;
1820         int arg = 1;
1821         int flags;
1822         pthread_attr_t attr;
1823         time_t now;
1824         struct pollfd pfds[1];
1825         char iabuf[INET_ADDRSTRLEN];
1826
1827         pthread_attr_init(&attr);
1828         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1829
1830         for (;;) {
1831                 time(&now);
1832                 ast_mutex_lock(&sessionlock);
1833                 prev = NULL;
1834                 s = sessions;
1835                 while (s) {
1836                         next = s->next;
1837                         if (s->sessiontimeout && (now > s->sessiontimeout) && !s->inuse) {
1838                                 num_sessions--;
1839                                 if (prev)
1840                                         prev->next = next;
1841                                 else
1842                                         sessions = next;
1843                                 if (s->authenticated && (option_verbose > 1) && displayconnects) {
1844                                         ast_verbose(VERBOSE_PREFIX_2 "HTTP Manager '%s' timed out from %s\n",
1845                                                 s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
1846                                 }
1847                                 free_session(s);
1848                         } else
1849                                 prev = s;
1850                         s = next;
1851                 }
1852                 /* Purge master event queue of old, unused events, but make sure we
1853                    always keep at least one in the queue */
1854                 eqe = master_eventq;
1855                 while (master_eventq->next && !master_eventq->usecount) {
1856                         eqe = master_eventq;
1857                         master_eventq = master_eventq->next;
1858                         free(eqe);
1859                 }
1860                 ast_mutex_unlock(&sessionlock);
1861
1862                 sinlen = sizeof(sin);
1863                 pfds[0].fd = asock;
1864                 pfds[0].events = POLLIN;
1865                 /* Wait for something to happen, but timeout every few seconds so
1866                    we can ditch any old manager sessions */
1867                 if (poll(pfds, 1, 5000) < 1)
1868                         continue;
1869                 as = accept(asock, (struct sockaddr *)&sin, &sinlen);
1870                 if (as < 0) {
1871                         ast_log(LOG_NOTICE, "Accept returned -1: %s\n", strerror(errno));
1872                         continue;
1873                 }
1874                 p = getprotobyname("tcp");
1875                 if (p) {
1876                         if( setsockopt(as, p->p_proto, TCP_NODELAY, (char *)&arg, sizeof(arg) ) < 0 ) {
1877                                 ast_log(LOG_WARNING, "Failed to set manager tcp connection to TCP_NODELAY mode: %s\n", strerror(errno));
1878                         }
1879                 }
1880                 s = malloc(sizeof(struct mansession));
1881                 if (!s) {
1882                         ast_log(LOG_WARNING, "Failed to allocate management session: %s\n", strerror(errno));
1883                         continue;
1884                 } 
1885                 memset(s, 0, sizeof(struct mansession));
1886                 memcpy(&s->sin, &sin, sizeof(sin));
1887                 s->writetimeout = 100;
1888                 s->waiting_thread = AST_PTHREADT_NULL;
1889
1890                 if (!block_sockets) {
1891                         /* For safety, make sure socket is non-blocking */
1892                         flags = fcntl(as, F_GETFL);
1893                         fcntl(as, F_SETFL, flags | O_NONBLOCK);
1894                 }
1895                 ast_mutex_init(&s->__lock);
1896                 s->fd = as;
1897                 s->send_events = -1;
1898                 ast_mutex_lock(&sessionlock);
1899                 num_sessions++;
1900                 s->next = sessions;
1901                 sessions = s;
1902                 /* Find the last place in the master event queue and hook ourselves
1903                    in there */
1904                 s->eventq = master_eventq;
1905                 while(s->eventq->next)
1906                         s->eventq = s->eventq->next;
1907                 ast_mutex_lock(&s->eventq->lock);
1908                 s->eventq->usecount++;
1909                 ast_mutex_unlock(&s->eventq->lock);
1910                 ast_mutex_unlock(&sessionlock);
1911                 if (ast_pthread_create(&s->t, &attr, session_do, s))
1912                         destroy_session(s);
1913         }
1914         pthread_attr_destroy(&attr);
1915         return NULL;
1916 }
1917
1918 static int append_event(const char *str, int category)
1919 {
1920         struct eventqent *tmp, *prev = NULL;
1921         tmp = malloc(sizeof(struct eventqent) + strlen(str));
1922         if (tmp) {
1923                 ast_mutex_init(&tmp->lock);
1924                 tmp->next = NULL;
1925                 tmp->category = category;
1926                 strcpy(tmp->eventdata, str);
1927                 if (master_eventq) {
1928                         prev = master_eventq;
1929                         while (prev->next) 
1930                                 prev = prev->next;
1931                         prev->next = tmp;
1932                 } else {
1933                         master_eventq = tmp;
1934                 }
1935                 tmp->usecount = num_sessions;
1936                 return 0;
1937         }
1938         return -1;
1939 }
1940
1941 /*! \brief  manager_event: Send AMI event to client */
1942 int manager_event(int category, const char *event, const char *fmt, ...)
1943 {
1944         struct mansession *s;
1945         char auth[80];
1946         char tmp[4096] = "";
1947         char *tmp_next = tmp;
1948         size_t tmp_left = sizeof(tmp) - 2;
1949         va_list ap;
1950         struct timeval now;
1951
1952         /* Abort if there aren't any manager sessions */
1953         if (!num_sessions)
1954                 return 0;
1955
1956         ast_build_string(&tmp_next, &tmp_left, "Event: %s\r\nPrivilege: %s\r\n",
1957                          event, authority_to_str(category, auth, sizeof(auth)));
1958         if (timestampevents) {
1959                 now = ast_tvnow();
1960                 ast_build_string(&tmp_next, &tmp_left, "Timestamp: %ld.%06lu\r\n",
1961                                  now.tv_sec, (unsigned long) now.tv_usec);
1962         }
1963         va_start(ap, fmt);
1964         ast_build_string_va(&tmp_next, &tmp_left, fmt, ap);
1965         va_end(ap);
1966         *tmp_next++ = '\r';
1967         *tmp_next++ = '\n';
1968         *tmp_next = '\0';
1969         
1970         ast_mutex_lock(&sessionlock);
1971         /* Append even to master list and wake up any sleeping sessions */
1972         append_event(tmp, category);
1973         for (s = sessions; s; s = s->next) {
1974                 ast_mutex_lock(&s->__lock);
1975                 if (s->waiting_thread != AST_PTHREADT_NULL)
1976                         pthread_kill(s->waiting_thread, SIGURG);
1977                 ast_mutex_unlock(&s->__lock);
1978         }
1979         ast_mutex_unlock(&sessionlock);
1980
1981         return 0;
1982 }
1983
1984 int ast_manager_unregister( char *action ) 
1985 {
1986         struct manager_action *cur = first_action, *prev = first_action;
1987
1988         ast_mutex_lock(&actionlock);
1989         while (cur) {
1990                 if (!strcasecmp(action, cur->action)) {
1991                         prev->next = cur->next;
1992                         free(cur);
1993                         if (option_verbose > 1) 
1994                                 ast_verbose(VERBOSE_PREFIX_2 "Manager unregistered action %s\n", action);
1995                         ast_mutex_unlock(&actionlock);
1996                         return 0;
1997                 }
1998                 prev = cur;
1999                 cur = cur->next;
2000         }
2001         ast_mutex_unlock(&actionlock);
2002         return 0;
2003 }
2004
2005 static int manager_state_cb(char *context, char *exten, int state, void *data)
2006 {
2007         /* Notify managers of change */
2008         manager_event(EVENT_FLAG_CALL, "ExtensionStatus", "Exten: %s\r\nContext: %s\r\nStatus: %d\r\n", exten, context, state);
2009         return 0;
2010 }
2011
2012 static int ast_manager_register_struct(struct manager_action *act)
2013 {
2014         struct manager_action *cur = first_action, *prev = NULL;
2015         int ret;
2016
2017         ast_mutex_lock(&actionlock);
2018         while (cur) { /* Walk the list of actions */
2019                 ret = strcasecmp(cur->action, act->action);
2020                 if (ret == 0) {
2021                         ast_log(LOG_WARNING, "Manager: Action '%s' already registered\n", act->action);
2022                         ast_mutex_unlock(&actionlock);
2023                         return -1;
2024                 } else if (ret > 0) {
2025                         /* Insert these alphabetically */
2026                         if (prev) {
2027                                 act->next = prev->next;
2028                                 prev->next = act;
2029                         } else {
2030                                 act->next = first_action;
2031                                 first_action = act;
2032                         }
2033                         break;
2034                 }
2035                 prev = cur; 
2036                 cur = cur->next;
2037         }
2038         
2039         if (!cur) {
2040                 if (prev)
2041                         prev->next = act;
2042                 else
2043                         first_action = act;
2044                 act->next = NULL;
2045         }
2046
2047         if (option_verbose > 1) 
2048                 ast_verbose(VERBOSE_PREFIX_2 "Manager registered action %s\n", act->action);
2049         ast_mutex_unlock(&actionlock);
2050         return 0;
2051 }
2052
2053 /*! \brief register a new command with manager, including online help. This is 
2054         the preferred way to register a manager command */
2055 int ast_manager_register2(const char *action, int auth, int (*func)(struct mansession *s, struct message *m), const char *synopsis, const char *description)
2056 {
2057         struct manager_action *cur;
2058
2059         cur = malloc(sizeof(struct manager_action));
2060         if (!cur) {
2061                 ast_log(LOG_WARNING, "Manager: out of memory trying to register action\n");
2062                 return -1;
2063         }
2064         cur->action = action;
2065         cur->authority = auth;
2066         cur->func = func;
2067         cur->synopsis = synopsis;
2068         cur->description = description;
2069         cur->next = NULL;
2070
2071         ast_manager_register_struct(cur);
2072
2073         return 0;
2074 }
2075 /*! @}
2076  END Doxygen group */
2077
2078 static struct mansession *find_session(unsigned long ident)
2079 {
2080         struct mansession *s;
2081         ast_mutex_lock(&sessionlock);
2082         s = sessions;
2083         while (s) {
2084                 ast_mutex_lock(&s->__lock);
2085                 if (s->sessiontimeout && (s->managerid == ident) && !s->needdestroy) {
2086                         s->inuse++;
2087                         break;
2088                 }
2089                 ast_mutex_unlock(&s->__lock);
2090                 s = s->next;
2091         }
2092         ast_mutex_unlock(&sessionlock);
2093         return s;
2094 }
2095
2096
2097 static void vars2msg(struct message *m, struct ast_variable *vars)
2098 {
2099         int x;
2100         for (x = 0; vars && (x < AST_MAX_MANHEADERS); x++, vars = vars->next) {
2101                 if (!vars)
2102                         break;
2103                 m->hdrcount = x + 1;
2104                 snprintf(m->headers[x], sizeof(m->headers[x]), "%s: %s", vars->name, vars->value);
2105         }
2106 }
2107
2108 #define FORMAT_RAW      0
2109 #define FORMAT_HTML     1
2110 #define FORMAT_XML      2
2111
2112 static char *contenttype[] = { "plain", "html", "xml" };
2113
2114 static char *generic_http_callback(int format, struct sockaddr_in *requestor, const char *uri, struct ast_variable *params, int *status, char **title, int *contentlength)
2115 {
2116         struct mansession *s = NULL;
2117         unsigned long ident = 0;
2118         char workspace[256];
2119         char cookie[128];
2120         char iabuf[INET_ADDRSTRLEN];
2121         size_t len = sizeof(workspace);
2122         int blastaway = 0;
2123         char *c = workspace;
2124         char *retval = NULL;
2125         struct message m;
2126         struct ast_variable *v;
2127
2128         v = params;
2129         while (v) {
2130                 if (!strcasecmp(v->name, "mansession_id")) {
2131                         sscanf(v->value, "%lx", &ident);
2132                         break;
2133                 }
2134                 v = v->next;
2135         }
2136         s = find_session(ident);
2137
2138         if (!s) {
2139                 /* Create new session */
2140                 s = calloc(1, sizeof(struct mansession));
2141                 memcpy(&s->sin, requestor, sizeof(s->sin));
2142                 s->fd = -1;
2143                 s->waiting_thread = AST_PTHREADT_NULL;
2144                 s->send_events = 0;
2145                 ast_mutex_init(&s->__lock);
2146                 ast_mutex_lock(&s->__lock);
2147                 ast_mutex_lock(&sessionlock);
2148                 s->inuse = 1;
2149                 s->managerid = rand() | (unsigned long)s;
2150                 s->next = sessions;
2151                 sessions = s;
2152                 num_sessions++;
2153                 /* Hook into the last spot in the event queue */
2154                 s->eventq = master_eventq;
2155                 while (s->eventq->next)
2156                         s->eventq = s->eventq->next;
2157                 ast_mutex_lock(&s->eventq->lock);
2158                 s->eventq->usecount++;
2159                 ast_mutex_unlock(&s->eventq->lock);
2160                 ast_mutex_unlock(&sessionlock);
2161         }
2162
2163         /* Reset HTTP timeout.  If we're not yet authenticated, keep it extremely short */
2164         time(&s->sessiontimeout);
2165         if (!s->authenticated && (httptimeout > 5))
2166                 s->sessiontimeout += 5;
2167         else
2168                 s->sessiontimeout += httptimeout;
2169         ast_mutex_unlock(&s->__lock);
2170         
2171         memset(&m, 0, sizeof(m));
2172         if (s) {
2173                 char tmp[80];
2174                 ast_build_string(&c, &len, "Content-type: text/%s\n", contenttype[format]);
2175                 sprintf(tmp, "%08lx", s->managerid);
2176                 ast_build_string(&c, &len, "%s\r\n", ast_http_setcookie("mansession_id", tmp, httptimeout, cookie, sizeof(cookie)));
2177                 if (format == FORMAT_HTML)
2178                         ast_build_string(&c, &len, "<title>Asterisk&trade; Manager Test Interface</title>");
2179                 vars2msg(&m, params);
2180                 if (format == FORMAT_XML) {
2181                         ast_build_string(&c, &len, "<ajax-response>\n");
2182                 } else if (format == FORMAT_HTML) {
2183                         ast_build_string(&c, &len, "<body bgcolor=\"#ffffff\"><table align=center bgcolor=\"#f1f1f1\" width=\"500\">\r\n");
2184                         ast_build_string(&c, &len, "<tr><td colspan=\"2\" bgcolor=\"#f1f1ff\"><h1>&nbsp;&nbsp;Manager Tester</h1></td></tr>\r\n");
2185                 }
2186                 if (process_message(s, &m)) {
2187                         if (s->authenticated) {
2188                                 if (option_verbose > 1) {
2189                                         if (displayconnects) 
2190                                                 ast_verbose(VERBOSE_PREFIX_2 "HTTP Manager '%s' logged off from %s\n", s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));    
2191                                 }
2192                                 ast_log(LOG_EVENT, "HTTP Manager '%s' logged off from %s\n", s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
2193                         } else {
2194                                 if (option_verbose > 1) {
2195                                         if (displayconnects)
2196                                                 ast_verbose(VERBOSE_PREFIX_2 "HTTP Connect attempt from '%s' unable to authenticate\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
2197                                 }
2198                                 ast_log(LOG_EVENT, "HTTP Failed attempt from %s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
2199                         }
2200                         s->needdestroy = 1;
2201                 }
2202                 if (s->outputstr) {
2203                         char *tmp;
2204                         if (format == FORMAT_XML)
2205                                 tmp = xml_translate(s->outputstr, params);
2206                         else if (format == FORMAT_HTML)
2207                                 tmp = html_translate(s->outputstr);
2208                         else
2209                                 tmp = s->outputstr;
2210                         if (tmp) {
2211                                 retval = malloc(strlen(workspace) + strlen(tmp) + 128);
2212                                 if (retval) {
2213                                         strcpy(retval, workspace);
2214                                         strcpy(retval + strlen(retval), tmp);
2215                                         c = retval + strlen(retval);
2216                                         len = 120;
2217                                 }
2218                                 free(tmp);
2219                         }
2220                         if (tmp != s->outputstr)
2221                                 free(s->outputstr);
2222                         s->outputstr = NULL;
2223                 }
2224                 /* Still okay because c would safely be pointing to workspace even
2225                    if retval failed to allocate above */
2226                 if (format == FORMAT_XML) {
2227                         ast_build_string(&c, &len, "</ajax-response>\n");
2228                 } else if (format == FORMAT_HTML)
2229                         ast_build_string(&c, &len, "</table></body>\r\n");
2230         } else {
2231                 *status = 500;
2232                 *title = strdup("Server Error");
2233         }
2234         ast_mutex_lock(&s->__lock);
2235         if (s->needdestroy) {
2236                 if (s->inuse == 1) {
2237                         ast_log(LOG_DEBUG, "Need destroy, doing it now!\n");
2238                         blastaway = 1;
2239                 } else {
2240                         ast_log(LOG_DEBUG, "Need destroy, but can't do it yet!\n");
2241                         if (s->waiting_thread != AST_PTHREADT_NULL)
2242                                 pthread_kill(s->waiting_thread, SIGURG);
2243                         s->inuse--;
2244                 }
2245         } else
2246                 s->inuse--;
2247         ast_mutex_unlock(&s->__lock);
2248         
2249         if (blastaway)
2250                 destroy_session(s);
2251         if (*status != 200)
2252                 return ast_http_error(500, "Server Error", NULL, "Internal Server Error (out of memory)\n"); 
2253         return retval;
2254 }
2255
2256 static char *manager_http_callback(struct sockaddr_in *requestor, const char *uri, struct ast_variable *params, int *status, char **title, int *contentlength)
2257 {
2258         return generic_http_callback(FORMAT_HTML, requestor, uri, params, status, title, contentlength);
2259 }
2260
2261 static char *mxml_http_callback(struct sockaddr_in *requestor, const char *uri, struct ast_variable *params, int *status, char **title, int *contentlength)
2262 {
2263         return generic_http_callback(FORMAT_XML, requestor, uri, params, status, title, contentlength);
2264 }
2265
2266 static char *rawman_http_callback(struct sockaddr_in *requestor, const char *uri, struct ast_variable *params, int *status, char **title, int *contentlength)
2267 {
2268         return generic_http_callback(FORMAT_RAW, requestor, uri, params, status, title, contentlength);
2269 }
2270
2271 struct ast_http_uri rawmanuri = {
2272         .description = "Raw HTTP Manager Event Interface",
2273         .uri = "rawman",
2274         .has_subtree = 0,
2275         .callback = rawman_http_callback,
2276 };
2277
2278 struct ast_http_uri manageruri = {
2279         .description = "HTML Manager Event Interface",
2280         .uri = "manager",
2281         .has_subtree = 0,
2282         .callback = manager_http_callback,
2283 };
2284
2285 struct ast_http_uri managerxmluri = {
2286         .description = "XML Manager Event Interface",
2287         .uri = "mxml",
2288         .has_subtree = 0,
2289         .callback = mxml_http_callback,
2290 };
2291
2292 static int registered = 0;
2293 static int webregged = 0;
2294
2295 int init_manager(void)
2296 {
2297         struct ast_config *cfg;
2298         char *val;
2299         int oldportno = portno;
2300         static struct sockaddr_in ba;
2301         int x = 1;
2302         int flags;
2303         int webenabled = 0;
2304         int newhttptimeout = 60;
2305         if (!registered) {
2306                 /* Register default actions */
2307                 ast_manager_register2("Ping", 0, action_ping, "Keepalive command", mandescr_ping);
2308                 ast_manager_register2("Events", 0, action_events, "Control Event Flow", mandescr_events);
2309                 ast_manager_register2("Logoff", 0, action_logoff, "Logoff Manager", mandescr_logoff);
2310                 ast_manager_register2("Hangup", EVENT_FLAG_CALL, action_hangup, "Hangup Channel", mandescr_hangup);
2311                 ast_manager_register("Status", EVENT_FLAG_CALL, action_status, "Lists channel status" );
2312                 ast_manager_register2("Setvar", EVENT_FLAG_CALL, action_setvar, "Set Channel Variable", mandescr_setvar );
2313                 ast_manager_register2("Getvar", EVENT_FLAG_CALL, action_getvar, "Gets a Channel Variable", mandescr_getvar );
2314                 ast_manager_register2("Redirect", EVENT_FLAG_CALL, action_redirect, "Redirect (transfer) a call", mandescr_redirect );
2315                 ast_manager_register2("Originate", EVENT_FLAG_CALL, action_originate, "Originate Call", mandescr_originate);
2316                 ast_manager_register2("Command", EVENT_FLAG_COMMAND, action_command, "Execute Asterisk CLI Command", mandescr_command );
2317                 ast_manager_register2("ExtensionState", EVENT_FLAG_CALL, action_extensionstate, "Check Extension Status", mandescr_extensionstate );
2318                 ast_manager_register2("AbsoluteTimeout", EVENT_FLAG_CALL, action_timeout, "Set Absolute Timeout", mandescr_timeout );
2319                 ast_manager_register2("MailboxStatus", EVENT_FLAG_CALL, action_mailboxstatus, "Check Mailbox", mandescr_mailboxstatus );
2320                 ast_manager_register2("MailboxCount", EVENT_FLAG_CALL, action_mailboxcount, "Check Mailbox Message Count", mandescr_mailboxcount );
2321                 ast_manager_register2("ListCommands", 0, action_listcommands, "List available manager commands", mandescr_listcommands);
2322                 ast_manager_register2("WaitEvent", 0, action_waitevent, "Wait for an event to occur", mandescr_waitevent);
2323
2324                 ast_cli_register(&show_mancmd_cli);
2325                 ast_cli_register(&show_mancmds_cli);
2326                 ast_cli_register(&show_manconn_cli);
2327                 ast_cli_register(&show_maneventq_cli);
2328                 ast_extension_state_add(NULL, NULL, manager_state_cb, NULL);
2329                 registered = 1;
2330                 /* Append placeholder event so master_eventq never runs dry */
2331                 append_event("Event: Placeholder\r\n\r\n", 0);
2332         }
2333         portno = DEFAULT_MANAGER_PORT;
2334         displayconnects = 1;
2335         cfg = ast_config_load("manager.conf");
2336         if (!cfg) {
2337                 ast_log(LOG_NOTICE, "Unable to open management configuration manager.conf.  Call management disabled.\n");
2338                 return 0;
2339         }
2340         val = ast_variable_retrieve(cfg, "general", "enabled");
2341         if (val)
2342                 enabled = ast_true(val);
2343
2344         val = ast_variable_retrieve(cfg, "general", "block-sockets");
2345         if (val)
2346                 block_sockets = ast_true(val);
2347
2348         val = ast_variable_retrieve(cfg, "general", "webenabled");
2349         if (val)
2350                 webenabled = ast_true(val);
2351
2352         if ((val = ast_variable_retrieve(cfg, "general", "port"))) {
2353                 if (sscanf(val, "%d", &portno) != 1) {
2354                         ast_log(LOG_WARNING, "Invalid port number '%s'\n", val);
2355                         portno = DEFAULT_MANAGER_PORT;
2356                 }
2357         }
2358
2359         if ((val = ast_variable_retrieve(cfg, "general", "displayconnects")))
2360                 displayconnects = ast_true(val);
2361
2362         if ((val = ast_variable_retrieve(cfg, "general", "timestampevents")))
2363                 timestampevents = ast_true(val);
2364
2365         if ((val = ast_variable_retrieve(cfg, "general", "httptimeout")))
2366                 newhttptimeout = atoi(val);
2367
2368         memset(&ba, 0, sizeof(ba));
2369         ba.sin_family = AF_INET;
2370         ba.sin_port = htons(portno);
2371
2372         if ((val = ast_variable_retrieve(cfg, "general", "bindaddr"))) {
2373                 if (!inet_aton(val, &ba.sin_addr)) { 
2374                         ast_log(LOG_WARNING, "Invalid address '%s' specified, using 0.0.0.0\n", val);
2375                         memset(&ba.sin_addr, 0, sizeof(ba.sin_addr));
2376                 }
2377         }
2378         
2379
2380         if ((asock > -1) && ((portno != oldportno) || !enabled)) {
2381 #if 0
2382                 /* Can't be done yet */
2383                 close(asock);
2384                 asock = -1;
2385 #else
2386                 ast_log(LOG_WARNING, "Unable to change management port / enabled\n");
2387 #endif
2388         }
2389         ast_config_destroy(cfg);
2390         
2391         if (webenabled && enabled) {
2392                 if (!webregged) {
2393                         ast_http_uri_link(&rawmanuri);
2394                         ast_http_uri_link(&manageruri);
2395                         ast_http_uri_link(&managerxmluri);
2396                         webregged = 1;
2397                 }
2398         } else {
2399                 if (webregged) {
2400                         ast_http_uri_unlink(&rawmanuri);
2401                         ast_http_uri_unlink(&manageruri);
2402                         ast_http_uri_unlink(&managerxmluri);
2403                         webregged = 0;
2404                 }
2405         }
2406
2407         if (newhttptimeout > 0)
2408                 httptimeout = newhttptimeout;
2409
2410         /* If not enabled, do nothing */
2411         if (!enabled) {
2412                 return 0;
2413         }
2414
2415         if (asock < 0) {
2416                 asock = socket(AF_INET, SOCK_STREAM, 0);
2417                 if (asock < 0) {
2418                         ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
2419                         return -1;
2420                 }
2421                 setsockopt(asock, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x));
2422                 if (bind(asock, (struct sockaddr *)&ba, sizeof(ba))) {
2423                         ast_log(LOG_WARNING, "Unable to bind socket: %s\n", strerror(errno));
2424                         close(asock);
2425                         asock = -1;
2426                         return -1;
2427                 }
2428                 if (listen(asock, 2)) {
2429                         ast_log(LOG_WARNING, "Unable to listen on socket: %s\n", strerror(errno));
2430                         close(asock);
2431                         asock = -1;
2432                         return -1;
2433                 }
2434                 flags = fcntl(asock, F_GETFL);
2435                 fcntl(asock, F_SETFL, flags | O_NONBLOCK);
2436                 if (option_verbose)
2437                         ast_verbose("Asterisk Management interface listening on port %d\n", portno);
2438                 ast_pthread_create(&t, NULL, accept_thread, NULL);
2439         }
2440         return 0;
2441 }
2442
2443 int reload_manager(void)
2444 {
2445         manager_event(EVENT_FLAG_SYSTEM, "Reload", "Message: Reload Requested\r\n");
2446         return init_manager();
2447 }