Make sure when the timeout occurs that we actually break the bridge (bug #5252)
[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 global or 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(varname)) {
708                 astman_send_error(s, m, "No variable specified");
709                 return 0;
710         }
711
712         if (strlen(name)) {
713                 c = ast_get_channel_by_name_locked(name);
714                 if (!c) {
715                         astman_send_error(s, m, "No such channel");
716                         return 0;
717                 }
718         }
719         
720         varval=pbx_builtin_getvar_helper(c,varname);
721         if (varval)
722                 varval2 = ast_strdupa(varval);
723         if (!varval2)
724                 varval2 = "";
725         if (c)
726                 ast_mutex_unlock(&c->lock);
727         ast_cli(s->fd, "Response: Success\r\n"
728                 "Variable: %s\r\nValue: %s\r\n" ,varname,varval2);
729         if (id && !ast_strlen_zero(id))
730                 ast_cli(s->fd, "ActionID: %s\r\n",id);
731         ast_cli(s->fd, "\r\n");
732
733         return 0;
734 }
735
736
737 /*--- action_status: Manager "status" command to show channels */
738 /* Needs documentation... */
739 static int action_status(struct mansession *s, struct message *m)
740 {
741         char *id = astman_get_header(m,"ActionID");
742         char *name = astman_get_header(m,"Channel");
743         char idText[256] = "";
744         struct ast_channel *c;
745         char bridge[256];
746         struct timeval now = ast_tvnow();
747         long elapsed_seconds=0;
748         int all = !name || ast_strlen_zero(name); /* set if we want all channels */
749
750         astman_send_ack(s, m, "Channel status will follow");
751         if (id && !ast_strlen_zero(id))
752                 snprintf(idText,256,"ActionID: %s\r\n",id);
753         if (all)
754                 c = ast_channel_walk_locked(NULL);
755         else {
756                 c = ast_get_channel_by_name_locked(name);
757                 if (!c) {
758                         astman_send_error(s, m, "No such channel");
759                         return 0;
760                 }
761         }
762         /* if we look by name, we break after the first iteration */
763         while(c) {
764                 if (c->_bridge)
765                         snprintf(bridge, sizeof(bridge), "Link: %s\r\n", c->_bridge->name);
766                 else
767                         bridge[0] = '\0';
768                 if (c->pbx) {
769                         if (c->cdr) {
770                                 elapsed_seconds = now.tv_sec - c->cdr->start.tv_sec;
771                         }
772                         ast_cli(s->fd,
773                         "Event: Status\r\n"
774                         "Privilege: Call\r\n"
775                         "Channel: %s\r\n"
776                         "CallerID: %s\r\n"
777                         "CallerIDName: %s\r\n"
778                         "Account: %s\r\n"
779                         "State: %s\r\n"
780                         "Context: %s\r\n"
781                         "Extension: %s\r\n"
782                         "Priority: %d\r\n"
783                         "Seconds: %ld\r\n"
784                         "%s"
785                         "Uniqueid: %s\r\n"
786                         "%s"
787                         "\r\n",
788                         c->name, 
789                         c->cid.cid_num ? c->cid.cid_num : "<unknown>", 
790                         c->cid.cid_name ? c->cid.cid_name : "<unknown>", 
791                         c->accountcode,
792                         ast_state2str(c->_state), c->context,
793                         c->exten, c->priority, (long)elapsed_seconds, bridge, c->uniqueid, idText);
794                 } else {
795                         ast_cli(s->fd,
796                         "Event: Status\r\n"
797                         "Privilege: Call\r\n"
798                         "Channel: %s\r\n"
799                         "CallerID: %s\r\n"
800                         "CallerIDName: %s\r\n"
801                         "Account: %s\r\n"
802                         "State: %s\r\n"
803                         "%s"
804                         "Uniqueid: %s\r\n"
805                         "%s"
806                         "\r\n",
807                         c->name, 
808                         c->cid.cid_num ? c->cid.cid_num : "<unknown>", 
809                         c->cid.cid_name ? c->cid.cid_name : "<unknown>", 
810                         c->accountcode,
811                         ast_state2str(c->_state), bridge, c->uniqueid, idText);
812                 }
813                 ast_mutex_unlock(&c->lock);
814                 if (!all)
815                         break;
816                 c = ast_channel_walk_locked(c);
817         }
818         ast_cli(s->fd,
819         "Event: StatusComplete\r\n"
820         "%s"
821         "\r\n",idText);
822         return 0;
823 }
824
825 static char mandescr_redirect[] = 
826 "Description: Redirect (transfer) a call.\n"
827 "Variables: (Names marked with * are required)\n"
828 "       *Channel: Channel to redirect\n"
829 "       ExtraChannel: Second call leg to transfer (optional)\n"
830 "       *Exten: Extension to transfer to\n"
831 "       *Context: Context to transfer to\n"
832 "       *Priority: Priority to transfer to\n"
833 "       ActionID: Optional Action id for message matching.\n";
834
835 /*--- action_redirect: The redirect manager command */
836 static int action_redirect(struct mansession *s, struct message *m)
837 {
838         char *name = astman_get_header(m, "Channel");
839         char *name2 = astman_get_header(m, "ExtraChannel");
840         char *exten = astman_get_header(m, "Exten");
841         char *context = astman_get_header(m, "Context");
842         char *priority = astman_get_header(m, "Priority");
843         struct ast_channel *chan, *chan2 = NULL;
844         int pi = 0;
845         int res;
846
847         if (!name || ast_strlen_zero(name)) {
848                 astman_send_error(s, m, "Channel not specified");
849                 return 0;
850         }
851         if (!ast_strlen_zero(priority) && (sscanf(priority, "%d", &pi) != 1)) {
852                 astman_send_error(s, m, "Invalid priority\n");
853                 return 0;
854         }
855         chan = ast_get_channel_by_name_locked(name);
856         if (!chan) {
857                 char buf[BUFSIZ];
858                 snprintf(buf, sizeof(buf), "Channel does not exist: %s", name);
859                 astman_send_error(s, m, buf);
860                 return 0;
861         }
862         if (!ast_strlen_zero(name2))
863                 chan2 = ast_get_channel_by_name_locked(name2);
864         res = ast_async_goto(chan, context, exten, pi);
865         if (!res) {
866                 if (!ast_strlen_zero(name2)) {
867                         if (chan2)
868                                 res = ast_async_goto(chan2, context, exten, pi);
869                         else
870                                 res = -1;
871                         if (!res)
872                                 astman_send_ack(s, m, "Dual Redirect successful");
873                         else
874                                 astman_send_error(s, m, "Secondary redirect failed");
875                 } else
876                         astman_send_ack(s, m, "Redirect successful");
877         } else
878                 astman_send_error(s, m, "Redirect failed");
879         if (chan)
880                 ast_mutex_unlock(&chan->lock);
881         if (chan2)
882                 ast_mutex_unlock(&chan2->lock);
883         return 0;
884 }
885
886 static char mandescr_command[] = 
887 "Description: Run a CLI command.\n"
888 "Variables: (Names marked with * are required)\n"
889 "       *Command: Asterisk CLI command to run\n"
890 "       ActionID: Optional Action id for message matching.\n";
891
892 /*--- action_command: Manager command "command" - execute CLI command */
893 static int action_command(struct mansession *s, struct message *m)
894 {
895         char *cmd = astman_get_header(m, "Command");
896         char *id = astman_get_header(m, "ActionID");
897         ast_cli(s->fd, "Response: Follows\r\nPrivilege: Command\r\n");
898         if (id && !ast_strlen_zero(id))
899                 ast_cli(s->fd, "ActionID: %s\r\n", id);
900         /* FIXME: Wedge a ActionID response in here, waiting for later changes */
901         ast_cli_command(s->fd, cmd);
902         ast_cli(s->fd, "--END COMMAND--\r\n\r\n");
903         return 0;
904 }
905
906 static void *fast_originate(void *data)
907 {
908         struct fast_originate_helper *in = data;
909         int res;
910         int reason = 0;
911         struct ast_channel *chan = NULL;
912
913         if (!ast_strlen_zero(in->app)) {
914                 res = ast_pbx_outgoing_app(in->tech, AST_FORMAT_SLINEAR, in->data, in->timeout, in->app, in->appdata, &reason, 1, 
915                         !ast_strlen_zero(in->cid_num) ? in->cid_num : NULL, 
916                         !ast_strlen_zero(in->cid_name) ? in->cid_name : NULL,
917                         in->vars, &chan);
918         } else {
919                 res = ast_pbx_outgoing_exten(in->tech, AST_FORMAT_SLINEAR, in->data, in->timeout, in->context, in->exten, in->priority, &reason, 1, 
920                         !ast_strlen_zero(in->cid_num) ? in->cid_num : NULL, 
921                         !ast_strlen_zero(in->cid_name) ? in->cid_name : NULL,
922                         in->vars, &chan);
923         }   
924         if (!res)
925                 manager_event(EVENT_FLAG_CALL,
926                         "OriginateSuccess",
927                         "%s"
928                         "Channel: %s/%s\r\n"
929                         "Context: %s\r\n"
930                         "Exten: %s\r\n"
931                         "Reason: %d\r\n"
932                         "Uniqueid: %s\r\n",
933                         in->idtext, in->tech, in->data, in->context, in->exten, reason, chan ? chan->uniqueid : "<null>");
934         else
935                 manager_event(EVENT_FLAG_CALL,
936                         "OriginateFailure",
937                         "%s"
938                         "Channel: %s/%s\r\n"
939                         "Context: %s\r\n"
940                         "Exten: %s\r\n"
941                         "Reason: %d\r\n"
942                         "Uniqueid: %s\r\n",
943                         in->idtext, in->tech, in->data, in->context, in->exten, reason, chan ? chan->uniqueid : "<null>");
944
945         /* Locked by ast_pbx_outgoing_exten or ast_pbx_outgoing_app */
946         if (chan)
947                 ast_mutex_unlock(&chan->lock);
948         free(in);
949         return NULL;
950 }
951
952 static char mandescr_originate[] = 
953 "Description: Generates an outgoing call to a Extension/Context/Priority or\n"
954 "  Application/Data\n"
955 "Variables: (Names marked with * are required)\n"
956 "       *Channel: Channel name to call\n"
957 "       Exten: Extension to use (requires 'Context' and 'Priority')\n"
958 "       Context: Context to use (requires 'Exten' and 'Priority')\n"
959 "       Priority: Priority to use (requires 'Exten' and 'Context')\n"
960 "       Application: Application to use\n"
961 "       Data: Data to use (requires 'Application')\n"
962 "       Timeout: How long to wait for call to be answered (in ms)\n"
963 "       CallerID: Caller ID to be set on the outgoing channel\n"
964 "       Variable: Channel variable to set, multiple Variable: headers are allowed\n"
965 "       Account: Account code\n"
966 "       Async: Set to 'true' for fast origination\n";
967
968 static int action_originate(struct mansession *s, struct message *m)
969 {
970         char *name = astman_get_header(m, "Channel");
971         char *exten = astman_get_header(m, "Exten");
972         char *context = astman_get_header(m, "Context");
973         char *priority = astman_get_header(m, "Priority");
974         char *timeout = astman_get_header(m, "Timeout");
975         char *callerid = astman_get_header(m, "CallerID");
976         char *account = astman_get_header(m, "Account");
977         char *app = astman_get_header(m, "Application");
978         char *appdata = astman_get_header(m, "Data");
979         char *async = astman_get_header(m, "Async");
980         char *id = astman_get_header(m, "ActionID");
981         struct ast_variable *vars = astman_get_variables(m);
982         char *tech, *data;
983         char *l=NULL, *n=NULL;
984         int pi = 0;
985         int res;
986         int to = 30000;
987         int reason = 0;
988         char tmp[256];
989         char tmp2[256];
990         
991         pthread_t th;
992         pthread_attr_t attr;
993         if (!name) {
994                 astman_send_error(s, m, "Channel not specified");
995                 return 0;
996         }
997         if (!ast_strlen_zero(priority) && (sscanf(priority, "%d", &pi) != 1)) {
998                 astman_send_error(s, m, "Invalid priority\n");
999                 return 0;
1000         }
1001         if (!ast_strlen_zero(timeout) && (sscanf(timeout, "%d", &to) != 1)) {
1002                 astman_send_error(s, m, "Invalid timeout\n");
1003                 return 0;
1004         }
1005         ast_copy_string(tmp, name, sizeof(tmp));
1006         tech = tmp;
1007         data = strchr(tmp, '/');
1008         if (!data) {
1009                 astman_send_error(s, m, "Invalid channel\n");
1010                 return 0;
1011         }
1012         *data = '\0';
1013         data++;
1014         ast_copy_string(tmp2, callerid, sizeof(tmp2));
1015         ast_callerid_parse(tmp2, &n, &l);
1016         if (n) {
1017                 if (ast_strlen_zero(n))
1018                         n = NULL;
1019         }
1020         if (l) {
1021                 ast_shrink_phone_number(l);
1022                 if (ast_strlen_zero(l))
1023                         l = NULL;
1024         }
1025         if (account) {
1026                 struct ast_variable *newvar;
1027                 newvar = ast_variable_new("CDR(accountcode|r)", account);
1028                 newvar->next = vars;
1029                 vars = newvar;
1030         }
1031         if (ast_true(async)) {
1032                 struct fast_originate_helper *fast = malloc(sizeof(struct fast_originate_helper));
1033                 if (!fast) {
1034                         res = -1;
1035                 } else {
1036                         memset(fast, 0, sizeof(struct fast_originate_helper));
1037                         if (id && !ast_strlen_zero(id))
1038                                 snprintf(fast->idtext, sizeof(fast->idtext), "ActionID: %s\r\n", id);
1039                         ast_copy_string(fast->tech, tech, sizeof(fast->tech));
1040                         ast_copy_string(fast->data, data, sizeof(fast->data));
1041                         ast_copy_string(fast->app, app, sizeof(fast->app));
1042                         ast_copy_string(fast->appdata, appdata, sizeof(fast->appdata));
1043                         if (l)
1044                                 ast_copy_string(fast->cid_num, l, sizeof(fast->cid_num));
1045                         if (n)
1046                                 ast_copy_string(fast->cid_name, n, sizeof(fast->cid_name));
1047                         fast->vars = vars;      
1048                         ast_copy_string(fast->context, context, sizeof(fast->context));
1049                         ast_copy_string(fast->exten, exten, sizeof(fast->exten));
1050                         fast->timeout = to;
1051                         fast->priority = pi;
1052                         pthread_attr_init(&attr);
1053                         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1054                         if (ast_pthread_create(&th, &attr, fast_originate, fast)) {
1055                                 res = -1;
1056                         } else {
1057                                 res = 0;
1058                         }
1059                 }
1060         } else if (!ast_strlen_zero(app)) {
1061                 res = ast_pbx_outgoing_app(tech, AST_FORMAT_SLINEAR, data, to, app, appdata, &reason, 1, l, n, vars, NULL);
1062         } else {
1063                 if (exten && context && pi)
1064                         res = ast_pbx_outgoing_exten(tech, AST_FORMAT_SLINEAR, data, to, context, exten, pi, &reason, 1, l, n, vars, NULL);
1065                 else {
1066                         astman_send_error(s, m, "Originate with 'Exten' requires 'Context' and 'Priority'");
1067                         return 0;
1068                 }
1069         }   
1070         if (!res)
1071                 astman_send_ack(s, m, "Originate successfully queued");
1072         else
1073                 astman_send_error(s, m, "Originate failed");
1074         return 0;
1075 }
1076
1077 static char mandescr_mailboxstatus[] = 
1078 "Description: Checks a voicemail account for status.\n"
1079 "Variables: (Names marked with * are required)\n"
1080 "       *Mailbox: Full mailbox ID <mailbox>@<vm-context>\n"
1081 "       ActionID: Optional ActionID for message matching.\n"
1082 "Returns number of messages.\n"
1083 "       Message: Mailbox Status\n"
1084 "       Mailbox: <mailboxid>\n"
1085 "       Waiting: <count>\n"
1086 "\n";
1087 static int action_mailboxstatus(struct mansession *s, struct message *m)
1088 {
1089         char *mailbox = astman_get_header(m, "Mailbox");
1090         char *id = astman_get_header(m,"ActionID");
1091         char idText[256] = "";
1092         int ret;
1093         if (!mailbox || ast_strlen_zero(mailbox)) {
1094                 astman_send_error(s, m, "Mailbox not specified");
1095                 return 0;
1096         }
1097         if (id && !ast_strlen_zero(id))
1098                 snprintf(idText,256,"ActionID: %s\r\n",id);
1099         ret = ast_app_has_voicemail(mailbox, NULL);
1100         ast_cli(s->fd, "Response: Success\r\n"
1101                                    "%s"
1102                                    "Message: Mailbox Status\r\n"
1103                                    "Mailbox: %s\r\n"
1104                                    "Waiting: %d\r\n\r\n", idText, mailbox, ret);
1105         return 0;
1106 }
1107
1108 static char mandescr_mailboxcount[] = 
1109 "Description: Checks a voicemail account for new messages.\n"
1110 "Variables: (Names marked with * are required)\n"
1111 "       *Mailbox: Full mailbox ID <mailbox>@<vm-context>\n"
1112 "       ActionID: Optional ActionID for message matching.\n"
1113 "Returns number of new and old messages.\n"
1114 "       Message: Mailbox Message Count\n"
1115 "       Mailbox: <mailboxid>\n"
1116 "       NewMessages: <count>\n"
1117 "       OldMessages: <count>\n"
1118 "\n";
1119 static int action_mailboxcount(struct mansession *s, struct message *m)
1120 {
1121         char *mailbox = astman_get_header(m, "Mailbox");
1122         char *id = astman_get_header(m,"ActionID");
1123         char idText[256] = "";
1124         int newmsgs = 0, oldmsgs = 0;
1125         if (!mailbox || ast_strlen_zero(mailbox)) {
1126                 astman_send_error(s, m, "Mailbox not specified");
1127                 return 0;
1128         }
1129         ast_app_messagecount(mailbox, &newmsgs, &oldmsgs);
1130         if (id && !ast_strlen_zero(id)) {
1131                 snprintf(idText,256,"ActionID: %s\r\n",id);
1132         }
1133         ast_cli(s->fd, "Response: Success\r\n"
1134                                    "%s"
1135                                    "Message: Mailbox Message Count\r\n"
1136                                    "Mailbox: %s\r\n"
1137                                    "NewMessages: %d\r\n"
1138                                    "OldMessages: %d\r\n" 
1139                                    "\r\n",
1140                                     idText,mailbox, newmsgs, oldmsgs);
1141         return 0;
1142 }
1143
1144 static char mandescr_extensionstate[] = 
1145 "Description: Report the extension state for given extension.\n"
1146 "  If the extension has a hint, will use devicestate to check\n"
1147 "  the status of the device connected to the extension.\n"
1148 "Variables: (Names marked with * are required)\n"
1149 "       *Exten: Extension to check state on\n"
1150 "       *Context: Context for extension\n"
1151 "       ActionId: Optional ID for this transaction\n"
1152 "Will return an \"Extension Status\" message.\n"
1153 "The response will include the hint for the extension and the status.\n";
1154
1155 static int action_extensionstate(struct mansession *s, struct message *m)
1156 {
1157         char *exten = astman_get_header(m, "Exten");
1158         char *context = astman_get_header(m, "Context");
1159         char *id = astman_get_header(m,"ActionID");
1160         char idText[256] = "";
1161         char hint[256] = "";
1162         int status;
1163         if (!exten || ast_strlen_zero(exten)) {
1164                 astman_send_error(s, m, "Extension not specified");
1165                 return 0;
1166         }
1167         if (!context || ast_strlen_zero(context))
1168                 context = "default";
1169         status = ast_extension_state(NULL, context, exten);
1170         ast_get_hint(hint, sizeof(hint) - 1, NULL, 0, NULL, context, exten);
1171         if (id && !ast_strlen_zero(id)) {
1172                 snprintf(idText,256,"ActionID: %s\r\n",id);
1173         }
1174         ast_cli(s->fd, "Response: Success\r\n"
1175                                    "%s"
1176                                    "Message: Extension Status\r\n"
1177                                    "Exten: %s\r\n"
1178                                    "Context: %s\r\n"
1179                                    "Hint: %s\r\n"
1180                                    "Status: %d\r\n\r\n",
1181                                    idText,exten, context, hint, status);
1182         return 0;
1183 }
1184
1185 static char mandescr_timeout[] = 
1186 "Description: Hangup a channel after a certain time.\n"
1187 "Variables: (Names marked with * are required)\n"
1188 "       *Channel: Channel name to hangup\n"
1189 "       *Timeout: Maximum duration of the call (sec)\n"
1190 "Acknowledges set time with 'Timeout Set' message\n";
1191
1192 static int action_timeout(struct mansession *s, struct message *m)
1193 {
1194         struct ast_channel *c = NULL;
1195         char *name = astman_get_header(m, "Channel");
1196         int timeout = atoi(astman_get_header(m, "Timeout"));
1197         if (ast_strlen_zero(name)) {
1198                 astman_send_error(s, m, "No channel specified");
1199                 return 0;
1200         }
1201         if (!timeout) {
1202                 astman_send_error(s, m, "No timeout specified");
1203                 return 0;
1204         }
1205         c = ast_get_channel_by_name_locked(name);
1206         if (!c) {
1207                 astman_send_error(s, m, "No such channel");
1208                 return 0;
1209         }
1210         ast_channel_setwhentohangup(c, timeout);
1211         ast_mutex_unlock(&c->lock);
1212         astman_send_ack(s, m, "Timeout Set");
1213         return 0;
1214 }
1215
1216 static int process_message(struct mansession *s, struct message *m)
1217 {
1218         char action[80] = "";
1219         struct manager_action *tmp = first_action;
1220         char *id = astman_get_header(m,"ActionID");
1221         char idText[256] = "";
1222         char iabuf[INET_ADDRSTRLEN];
1223
1224         ast_copy_string(action, astman_get_header(m, "Action"), sizeof(action));
1225         ast_log( LOG_DEBUG, "Manager received command '%s'\n", action );
1226
1227         if (ast_strlen_zero(action)) {
1228                 astman_send_error(s, m, "Missing action in request");
1229                 return 0;
1230         }
1231         if (id && !ast_strlen_zero(id)) {
1232                 snprintf(idText,256,"ActionID: %s\r\n",id);
1233         }
1234         if (!s->authenticated) {
1235                 if (!strcasecmp(action, "Challenge")) {
1236                         char *authtype;
1237                         authtype = astman_get_header(m, "AuthType");
1238                         if (!strcasecmp(authtype, "MD5")) {
1239                                 if (!s->challenge || ast_strlen_zero(s->challenge))
1240                                         snprintf(s->challenge, sizeof(s->challenge), "%d", rand());
1241                                 ast_mutex_lock(&s->__lock);
1242                                 ast_cli(s->fd, "Response: Success\r\n"
1243                                                 "%s"
1244                                                 "Challenge: %s\r\n\r\n",
1245                                                 idText,s->challenge);
1246                                 ast_mutex_unlock(&s->__lock);
1247                                 return 0;
1248                         } else {
1249                                 astman_send_error(s, m, "Must specify AuthType");
1250                                 return 0;
1251                         }
1252                 } else if (!strcasecmp(action, "Login")) {
1253                         if (authenticate(s, m)) {
1254                                 sleep(1);
1255                                 astman_send_error(s, m, "Authentication failed");
1256                                 return -1;
1257                         } else {
1258                                 s->authenticated = 1;
1259                                 if (option_verbose > 1) {
1260                                         if ( displayconnects ) {
1261                                                 ast_verbose(VERBOSE_PREFIX_2 "Manager '%s' logged on from %s\n", s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
1262                                         }
1263                                 }
1264                                 ast_log(LOG_EVENT, "Manager '%s' logged on from %s\n", s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
1265                                 astman_send_ack(s, m, "Authentication accepted");
1266                         }
1267                 } else if (!strcasecmp(action, "Logoff")) {
1268                         astman_send_ack(s, m, "See ya");
1269                         return -1;
1270                 } else
1271                         astman_send_error(s, m, "Authentication Required");
1272         } else {
1273                 int ret=0;
1274                 struct eventqent *eqe;
1275                 ast_mutex_lock(&s->__lock);
1276                 s->busy = 1;
1277                 ast_mutex_unlock(&s->__lock);
1278                 while( tmp ) {          
1279                         if (!strcasecmp(action, tmp->action)) {
1280                                 if ((s->writeperm & tmp->authority) == tmp->authority) {
1281                                         if (tmp->func(s, m))
1282                                                 ret = -1;
1283                                 } else {
1284                                         astman_send_error(s, m, "Permission denied");
1285                                 }
1286                                 break;
1287                         }
1288                         tmp = tmp->next;
1289                 }
1290                 if (!tmp)
1291                         astman_send_error(s, m, "Invalid/unknown command");
1292                 ast_mutex_lock(&s->__lock);
1293                 s->busy = 0;
1294                 while(s->eventq) {
1295                         if (ast_carefulwrite(s->fd, s->eventq->eventdata, strlen(s->eventq->eventdata), s->writetimeout)) {
1296                                 ret = -1;
1297                                 break;
1298                         }
1299                         eqe = s->eventq;
1300                         s->eventq = s->eventq->next;
1301                         free(eqe);
1302                 }
1303                 ast_mutex_unlock(&s->__lock);
1304                 return ret;
1305         }
1306         return 0;
1307 }
1308
1309 static int get_input(struct mansession *s, char *output)
1310 {
1311         /* output must have at least sizeof(s->inbuf) space */
1312         int res;
1313         int x;
1314         struct pollfd fds[1];
1315         char iabuf[INET_ADDRSTRLEN];
1316         for (x=1;x<s->inlen;x++) {
1317                 if ((s->inbuf[x] == '\n') && (s->inbuf[x-1] == '\r')) {
1318                         /* Copy output data up to and including \r\n */
1319                         memcpy(output, s->inbuf, x + 1);
1320                         /* Add trailing \0 */
1321                         output[x+1] = '\0';
1322                         /* Move remaining data back to the front */
1323                         memmove(s->inbuf, s->inbuf + x + 1, s->inlen - x);
1324                         s->inlen -= (x + 1);
1325                         return 1;
1326                 }
1327         } 
1328         if (s->inlen >= sizeof(s->inbuf) - 1) {
1329                 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);
1330                 s->inlen = 0;
1331         }
1332         fds[0].fd = s->fd;
1333         fds[0].events = POLLIN;
1334         do {
1335                 res = poll(fds, 1, -1);
1336                 if (res < 0) {
1337                         if (errno == EINTR) {
1338                                 if (s->dead)
1339                                         return -1;
1340                                 continue;
1341                         }
1342                         ast_log(LOG_WARNING, "Select returned error: %s\n", strerror(errno));
1343                         return -1;
1344                 } else if (res > 0) {
1345                         ast_mutex_lock(&s->__lock);
1346                         res = read(s->fd, s->inbuf + s->inlen, sizeof(s->inbuf) - 1 - s->inlen);
1347                         ast_mutex_unlock(&s->__lock);
1348                         if (res < 1)
1349                                 return -1;
1350                         break;
1351                 }
1352         } while(1);
1353         s->inlen += res;
1354         s->inbuf[s->inlen] = '\0';
1355         return 0;
1356 }
1357
1358 static void *session_do(void *data)
1359 {
1360         struct mansession *s = data;
1361         struct message m;
1362         char iabuf[INET_ADDRSTRLEN];
1363         int res;
1364         
1365         ast_mutex_lock(&s->__lock);
1366         ast_cli(s->fd, "Asterisk Call Manager/1.0\r\n");
1367         ast_mutex_unlock(&s->__lock);
1368         memset(&m, 0, sizeof(m));
1369         for (;;) {
1370                 res = get_input(s, m.headers[m.hdrcount]);
1371                 if (res > 0) {
1372                         /* Strip trailing \r\n */
1373                         if (strlen(m.headers[m.hdrcount]) < 2)
1374                                 continue;
1375                         m.headers[m.hdrcount][strlen(m.headers[m.hdrcount]) - 2] = '\0';
1376                         if (ast_strlen_zero(m.headers[m.hdrcount])) {
1377                                 if (process_message(s, &m))
1378                                         break;
1379                                 memset(&m, 0, sizeof(m));
1380                         } else if (m.hdrcount < MAX_HEADERS - 1)
1381                                 m.hdrcount++;
1382                 } else if (res < 0)
1383                         break;
1384         }
1385         if (s->authenticated) {
1386                 if (option_verbose > 1) {
1387                         if (displayconnects) 
1388                                 ast_verbose(VERBOSE_PREFIX_2 "Manager '%s' logged off from %s\n", s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));    
1389                 }
1390                 ast_log(LOG_EVENT, "Manager '%s' logged off from %s\n", s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
1391         } else {
1392                 if (option_verbose > 1) {
1393                         if ( displayconnects )
1394                                 ast_verbose(VERBOSE_PREFIX_2 "Connect attempt from '%s' unable to authenticate\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
1395                 }
1396                 ast_log(LOG_EVENT, "Failed attempt from %s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
1397         }
1398         destroy_session(s);
1399         return NULL;
1400 }
1401
1402 static void *accept_thread(void *ignore)
1403 {
1404         int as;
1405         struct sockaddr_in sin;
1406         socklen_t sinlen;
1407         struct mansession *s;
1408         struct protoent *p;
1409         int arg = 1;
1410         int flags;
1411         pthread_attr_t attr;
1412
1413         pthread_attr_init(&attr);
1414         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1415
1416         for (;;) {
1417                 sinlen = sizeof(sin);
1418                 as = accept(asock, (struct sockaddr *)&sin, &sinlen);
1419                 if (as < 0) {
1420                         ast_log(LOG_NOTICE, "Accept returned -1: %s\n", strerror(errno));
1421                         continue;
1422                 }
1423                 p = getprotobyname("tcp");
1424                 if (p) {
1425                         if( setsockopt(as, p->p_proto, TCP_NODELAY, (char *)&arg, sizeof(arg) ) < 0 ) {
1426                                 ast_log(LOG_WARNING, "Failed to set manager tcp connection to TCP_NODELAY mode: %s\n", strerror(errno));
1427                         }
1428                 }
1429                 s = malloc(sizeof(struct mansession));
1430                 if (!s) {
1431                         ast_log(LOG_WARNING, "Failed to allocate management session: %s\n", strerror(errno));
1432                         continue;
1433                 } 
1434                 memset(s, 0, sizeof(struct mansession));
1435                 memcpy(&s->sin, &sin, sizeof(sin));
1436                 s->writetimeout = 100;
1437
1438                 if(! block_sockets) {
1439                         /* For safety, make sure socket is non-blocking */
1440                         flags = fcntl(as, F_GETFL);
1441                         fcntl(as, F_SETFL, flags | O_NONBLOCK);
1442                 }
1443                 ast_mutex_init(&s->__lock);
1444                 s->fd = as;
1445                 s->send_events = -1;
1446                 ast_mutex_lock(&sessionlock);
1447                 s->next = sessions;
1448                 sessions = s;
1449                 ast_mutex_unlock(&sessionlock);
1450                 if (ast_pthread_create(&s->t, &attr, session_do, s))
1451                         destroy_session(s);
1452         }
1453         pthread_attr_destroy(&attr);
1454         return NULL;
1455 }
1456
1457 static int append_event(struct mansession *s, const char *str)
1458 {
1459         struct eventqent *tmp, *prev=NULL;
1460         tmp = malloc(sizeof(struct eventqent) + strlen(str));
1461         if (tmp) {
1462                 tmp->next = NULL;
1463                 strcpy(tmp->eventdata, str);
1464                 if (s->eventq) {
1465                         prev = s->eventq;
1466                         while(prev->next) 
1467                                 prev = prev->next;
1468                         prev->next = tmp;
1469                 } else {
1470                         s->eventq = tmp;
1471                 }
1472                 return 0;
1473         }
1474         return -1;
1475 }
1476
1477 /*--- manager_event: Send AMI event to client */
1478 int manager_event(int category, char *event, char *fmt, ...)
1479 {
1480         struct mansession *s;
1481         char auth[80];
1482         char tmp[4096] = "";
1483         char *tmp_next = tmp;
1484         size_t tmp_left = sizeof(tmp) - 2;
1485         va_list ap;
1486
1487         ast_mutex_lock(&sessionlock);
1488         for (s = sessions; s; s = s->next) {
1489                 if ((s->readperm & category) != category)
1490                         continue;
1491
1492                 if ((s->send_events & category) != category)
1493                         continue;
1494
1495                 if (ast_strlen_zero(tmp)) {
1496                         ast_build_string(&tmp_next, &tmp_left, "Event: %s\r\nPrivilege: %s\r\n",
1497                                          event, authority_to_str(category, auth, sizeof(auth)));
1498                         va_start(ap, fmt);
1499                         ast_build_string_va(&tmp_next, &tmp_left, fmt, ap);
1500                         va_end(ap);
1501                         *tmp_next++ = '\r';
1502                         *tmp_next++ = '\n';
1503                         *tmp_next = '\0';
1504                 }
1505
1506                 ast_mutex_lock(&s->__lock);
1507                 if (s->busy) {
1508                         append_event(s, tmp);
1509                 } else if (!s->dead) {
1510                         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                 }
1516                 ast_mutex_unlock(&s->__lock);
1517         }
1518         ast_mutex_unlock(&sessionlock);
1519
1520         return 0;
1521 }
1522
1523 int ast_manager_unregister( char *action ) 
1524 {
1525         struct manager_action *cur = first_action, *prev = first_action;
1526
1527         ast_mutex_lock(&actionlock);
1528         while( cur ) {          
1529                 if (!strcasecmp(action, cur->action)) {
1530                         prev->next = cur->next;
1531                         free(cur);
1532                         if (option_verbose > 1) 
1533                                 ast_verbose(VERBOSE_PREFIX_2 "Manager unregistered action %s\n", action);
1534                         ast_mutex_unlock(&actionlock);
1535                         return 0;
1536                 }
1537                 prev = cur;
1538                 cur = cur->next;
1539         }
1540         ast_mutex_unlock(&actionlock);
1541         return 0;
1542 }
1543
1544 static int manager_state_cb(char *context, char *exten, int state, void *data)
1545 {
1546         /* Notify managers of change */
1547         manager_event(EVENT_FLAG_CALL, "ExtensionStatus", "Exten: %s\r\nContext: %s\r\nStatus: %d\r\n", exten, context, state);
1548         return 0;
1549 }
1550
1551 static int ast_manager_register_struct(struct manager_action *act)
1552 {
1553         struct manager_action *cur = first_action, *prev = NULL;
1554         int ret;
1555
1556         ast_mutex_lock(&actionlock);
1557         while(cur) { /* Walk the list of actions */
1558                 ret = strcasecmp(cur->action, act->action);
1559                 if (ret == 0) {
1560                         ast_log(LOG_WARNING, "Manager: Action '%s' already registered\n", act->action);
1561                         ast_mutex_unlock(&actionlock);
1562                         return -1;
1563                 } else if (ret > 0) {
1564                         /* Insert these alphabetically */
1565                         if (prev) {
1566                                 act->next = prev->next;
1567                                 prev->next = act;
1568                         } else {
1569                                 act->next = first_action;
1570                                 first_action = act;
1571                         }
1572                         break;
1573                 }
1574                 prev = cur; 
1575                 cur = cur->next;
1576         }
1577         
1578         if (!cur) {
1579                 if (prev)
1580                         prev->next = act;
1581                 else
1582                         first_action = act;
1583                 act->next = NULL;
1584         }
1585
1586         if (option_verbose > 1) 
1587                 ast_verbose(VERBOSE_PREFIX_2 "Manager registered action %s\n", act->action);
1588         ast_mutex_unlock(&actionlock);
1589         return 0;
1590 }
1591
1592 int ast_manager_register2(const char *action, int auth, int (*func)(struct mansession *s, struct message *m), const char *synopsis, const char *description)
1593 {
1594         struct manager_action *cur;
1595
1596         cur = malloc(sizeof(struct manager_action));
1597         if (!cur) {
1598                 ast_log(LOG_WARNING, "Manager: out of memory trying to register action\n");
1599                 ast_mutex_unlock(&actionlock);
1600                 return -1;
1601         }
1602         cur->action = action;
1603         cur->authority = auth;
1604         cur->func = func;
1605         cur->synopsis = synopsis;
1606         cur->description = description;
1607         cur->next = NULL;
1608
1609         ast_manager_register_struct(cur);
1610
1611         return 0;
1612 }
1613
1614 static int registered = 0;
1615
1616 int init_manager(void)
1617 {
1618         struct ast_config *cfg;
1619         char *val;
1620         int oldportno = portno;
1621         static struct sockaddr_in ba;
1622         int x = 1;
1623         if (!registered) {
1624                 /* Register default actions */
1625                 ast_manager_register2("Ping", 0, action_ping, "Keepalive command", mandescr_ping);
1626                 ast_manager_register2("Events", 0, action_events, "Control Event Flow", mandescr_events);
1627                 ast_manager_register2("Logoff", 0, action_logoff, "Logoff Manager", mandescr_logoff);
1628                 ast_manager_register2("Hangup", EVENT_FLAG_CALL, action_hangup, "Hangup Channel", mandescr_hangup);
1629                 ast_manager_register("Status", EVENT_FLAG_CALL, action_status, "Lists channel status" );
1630                 ast_manager_register2("Setvar", EVENT_FLAG_CALL, action_setvar, "Set Channel Variable", mandescr_setvar );
1631                 ast_manager_register2("Getvar", EVENT_FLAG_CALL, action_getvar, "Gets a Channel Variable", mandescr_getvar );
1632                 ast_manager_register2("Redirect", EVENT_FLAG_CALL, action_redirect, "Redirect (transfer) a call", mandescr_redirect );
1633                 ast_manager_register2("Originate", EVENT_FLAG_CALL, action_originate, "Originate Call", mandescr_originate);
1634                 ast_manager_register2("Command", EVENT_FLAG_COMMAND, action_command, "Execute Asterisk CLI Command", mandescr_command );
1635                 ast_manager_register2("ExtensionState", EVENT_FLAG_CALL, action_extensionstate, "Check Extension Status", mandescr_extensionstate );
1636                 ast_manager_register2("AbsoluteTimeout", EVENT_FLAG_CALL, action_timeout, "Set Absolute Timeout", mandescr_timeout );
1637                 ast_manager_register2("MailboxStatus", EVENT_FLAG_CALL, action_mailboxstatus, "Check Mailbox", mandescr_mailboxstatus );
1638                 ast_manager_register2("MailboxCount", EVENT_FLAG_CALL, action_mailboxcount, "Check Mailbox Message Count", mandescr_mailboxcount );
1639                 ast_manager_register2("ListCommands", 0, action_listcommands, "List available manager commands", mandescr_listcommands);
1640
1641                 ast_cli_register(&show_mancmd_cli);
1642                 ast_cli_register(&show_mancmds_cli);
1643                 ast_cli_register(&show_manconn_cli);
1644                 ast_extension_state_add(NULL, NULL, manager_state_cb, NULL);
1645                 registered = 1;
1646         }
1647         portno = DEFAULT_MANAGER_PORT;
1648         displayconnects = 1;
1649         cfg = ast_config_load("manager.conf");
1650         if (!cfg) {
1651                 ast_log(LOG_NOTICE, "Unable to open management configuration manager.conf.  Call management disabled.\n");
1652                 return 0;
1653         }
1654         memset(&ba, 0, sizeof(ba));
1655         val = ast_variable_retrieve(cfg, "general", "enabled");
1656         if (val)
1657                 enabled = ast_true(val);
1658
1659         val = ast_variable_retrieve(cfg, "general", "block-sockets");
1660         if(val)
1661                 block_sockets = ast_true(val);
1662
1663         if ((val = ast_variable_retrieve(cfg, "general", "port"))) {
1664                 if (sscanf(val, "%d", &portno) != 1) {
1665                         ast_log(LOG_WARNING, "Invalid port number '%s'\n", val);
1666                         portno = DEFAULT_MANAGER_PORT;
1667                 }
1668         } else if ((val = ast_variable_retrieve(cfg, "general", "portno"))) {
1669                 if (sscanf(val, "%d", &portno) != 1) {
1670                         ast_log(LOG_WARNING, "Invalid port number '%s'\n", val);
1671                         portno = DEFAULT_MANAGER_PORT;
1672                 }
1673                 ast_log(LOG_NOTICE, "Use of portno in manager.conf deprecated.  Please use 'port=%s' instead.\n", val);
1674         }
1675         /* Parsing the displayconnects */
1676         if ((val = ast_variable_retrieve(cfg, "general", "displayconnects"))) {
1677                         displayconnects = ast_true(val);;
1678         }
1679                                 
1680         
1681         ba.sin_family = AF_INET;
1682         ba.sin_port = htons(portno);
1683         memset(&ba.sin_addr, 0, sizeof(ba.sin_addr));
1684         
1685         if ((val = ast_variable_retrieve(cfg, "general", "bindaddr"))) {
1686                 if (!inet_aton(val, &ba.sin_addr)) { 
1687                         ast_log(LOG_WARNING, "Invalid address '%s' specified, using 0.0.0.0\n", val);
1688                         memset(&ba.sin_addr, 0, sizeof(ba.sin_addr));
1689                 }
1690         }
1691         
1692         if ((asock > -1) && ((portno != oldportno) || !enabled)) {
1693 #if 0
1694                 /* Can't be done yet */
1695                 close(asock);
1696                 asock = -1;
1697 #else
1698                 ast_log(LOG_WARNING, "Unable to change management port / enabled\n");
1699 #endif
1700         }
1701         ast_config_destroy(cfg);
1702         
1703         /* If not enabled, do nothing */
1704         if (!enabled) {
1705                 return 0;
1706         }
1707         if (asock < 0) {
1708                 asock = socket(AF_INET, SOCK_STREAM, 0);
1709                 if (asock < 0) {
1710                         ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
1711                         return -1;
1712                 }
1713                 setsockopt(asock, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x));
1714                 if (bind(asock, (struct sockaddr *)&ba, sizeof(ba))) {
1715                         ast_log(LOG_WARNING, "Unable to bind socket: %s\n", strerror(errno));
1716                         close(asock);
1717                         asock = -1;
1718                         return -1;
1719                 }
1720                 if (listen(asock, 2)) {
1721                         ast_log(LOG_WARNING, "Unable to listen on socket: %s\n", strerror(errno));
1722                         close(asock);
1723                         asock = -1;
1724                         return -1;
1725                 }
1726                 if (option_verbose)
1727                         ast_verbose("Asterisk Management interface listening on port %d\n", portno);
1728                 ast_pthread_create(&t, NULL, accept_thread, NULL);
1729         }
1730         return 0;
1731 }
1732
1733 int reload_manager(void)
1734 {
1735         manager_event(EVENT_FLAG_SYSTEM, "Reload", "Message: Reload Requested\r\n");
1736         return init_manager();
1737 }