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