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