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