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