Fix a bug where we tried to send events out when no sessions container was present.
[asterisk/asterisk.git] / main / manager.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2006, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief The Asterisk Management Interface - AMI
22  *
23  * \author Mark Spencer <markster@digium.com>
24  *
25  * \extref OpenSSL http://www.openssl.org - for AMI/SSL
26  *
27  * At the moment this file contains a number of functions, namely:
28  *
29  * - data structures storing AMI state
30  * - AMI-related API functions, used by internal asterisk components
31  * - handlers for AMI-related CLI functions
32  * - handlers for AMI functions (available through the AMI socket)
33  * - the code for the main AMI listener thread and individual session threads
34  * - the http handlers invoked for AMI-over-HTTP by the threads in main/http.c
35  *
36  * \ref amiconf
37  */
38
39 /*! \addtogroup Group_AMI AMI functions
40 */
41 /*! @{
42  Doxygen group */
43
44 #include "asterisk.h"
45
46 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
47
48 #include "asterisk/_private.h"
49 #include "asterisk/paths.h"     /* use various ast_config_AST_* */
50 #include <ctype.h>
51 #include <sys/time.h>
52 #include <signal.h>
53 #include <sys/mman.h>
54
55 #include "asterisk/channel.h"
56 #include "asterisk/file.h"
57 #include "asterisk/manager.h"
58 #include "asterisk/module.h"
59 #include "asterisk/config.h"
60 #include "asterisk/callerid.h"
61 #include "asterisk/lock.h"
62 #include "asterisk/cli.h"
63 #include "asterisk/app.h"
64 #include "asterisk/pbx.h"
65 #include "asterisk/md5.h"
66 #include "asterisk/acl.h"
67 #include "asterisk/utils.h"
68 #include "asterisk/tcptls.h"
69 #include "asterisk/http.h"
70 #include "asterisk/ast_version.h"
71 #include "asterisk/threadstorage.h"
72 #include "asterisk/linkedlists.h"
73 #include "asterisk/version.h"
74 #include "asterisk/term.h"
75 #include "asterisk/astobj2.h"
76 #include "asterisk/features.h"
77
78 enum error_type {
79         UNKNOWN_ACTION = 1,
80         UNKNOWN_CATEGORY,
81         UNSPECIFIED_CATEGORY,
82         UNSPECIFIED_ARGUMENT,
83         FAILURE_ALLOCATION,
84         FAILURE_NEWCAT,
85         FAILURE_DELCAT,
86         FAILURE_EMPTYCAT,
87         FAILURE_UPDATE,
88         FAILURE_DELETE,
89         FAILURE_APPEND
90 };
91
92
93 /*!
94  * Linked list of events.
95  * Global events are appended to the list by append_event().
96  * The usecount is the number of stored pointers to the element,
97  * excluding the list pointers. So an element that is only in
98  * the list has a usecount of 0, not 1.
99  *
100  * Clients have a pointer to the last event processed, and for each
101  * of these clients we track the usecount of the elements.
102  * If we have a pointer to an entry in the list, it is safe to navigate
103  * it forward because elements will not be deleted, but only appended.
104  * The worst that can happen is seeing the pointer still NULL.
105  *
106  * When the usecount of an element drops to 0, and the element is the
107  * first in the list, we can remove it. Removal is done within the
108  * main thread, which is woken up for the purpose.
109  *
110  * For simplicity of implementation, we make sure the list is never empty.
111  */
112 struct eventqent {
113         int usecount;           /*!< # of clients who still need the event */
114         int category;
115         unsigned int seq;       /*!< sequence number */
116         AST_LIST_ENTRY(eventqent) eq_next;
117         char eventdata[1];      /*!< really variable size, allocated by append_event() */
118 };
119
120 static AST_LIST_HEAD_STATIC(all_events, eventqent);
121
122 static int displayconnects = 1;
123 static int allowmultiplelogin = 1;
124 static int timestampevents;
125 static int httptimeout = 60;
126 static int manager_enabled = 0;
127 static int webmanager_enabled = 0;
128
129 #define DEFAULT_REALM           "asterisk"
130 static char global_realm[MAXHOSTNAMELEN];       /*!< Default realm */
131
132 static int block_sockets;
133
134 static int manager_debug;       /*!< enable some debugging code in the manager */
135
136 /*! \brief
137  * Descriptor for a manager session, either on the AMI socket or over HTTP.
138  *
139  * \note
140  * AMI session have managerid == 0; the entry is created upon a connect,
141  * and destroyed with the socket.
142  * HTTP sessions have managerid != 0, the value is used as a search key
143  * to lookup sessions (using the mansession_id cookie, or nonce key from
144  * Digest Authentication http header).
145  */
146 #define MAX_BLACKLIST_CMD_LEN 2
147 static struct {
148         char *words[AST_MAX_CMD_LEN];
149 } command_blacklist[] = {
150         {{ "module", "load", NULL }},
151         {{ "module", "unload", NULL }},
152         {{ "restart", "gracefully", NULL }},
153 };
154
155 /* In order to understand what the heck is going on with the
156  * mansession_session and mansession structs, we need to have a bit of a history
157  * lesson.
158  *
159  * In the beginning, there was the mansession. The mansession contained data that was
160  * intrinsic to a manager session, such as the time that it started, the name of the logged-in
161  * user, etc. In addition to these parameters were the f and fd parameters. For typical manager
162  * sessions, these were used to represent the TCP socket over which the AMI session was taking
163  * place. It makes perfect sense for these fields to be a part of the session-specific data since
164  * the session actually defines this information.
165  *
166  * Then came the HTTP AMI sessions. With these, the f and fd fields need to be opened and closed
167  * for every single action that occurs. Thus the f and fd fields aren't really specific to the session
168  * but rather to the action that is being executed. Because a single session may execute many commands
169  * at once, some sort of safety needed to be added in order to be sure that we did not end up with fd
170  * leaks from one action overwriting the f and fd fields used by a previous action before the previous action
171  * has had a chance to properly close its handles.
172  *
173  * The initial idea to solve this was to use thread synchronization, but this prevented multiple actions
174  * from being run at the same time in a single session. Some manager actions may block for a long time, thus
175  * creating a large queue of actions to execute. In addition, this fix did not address the basic architectural
176  * issue that for HTTP manager sessions, the f and fd variables are not really a part of the session, but are
177  * part of the action instead.
178  *
179  * The new idea was to create a structure on the stack for each HTTP Manager action. This structure would
180  * contain the action-specific information, such as which file to write to. In order to maintain expectations
181  * of action handlers and not have to change the public API of the manager code, we would need to name this
182  * new stacked structure 'mansession' and contain within it the old mansession struct that we used to use.
183  * We renamed the old mansession struct 'mansession_session' to hopefully convey that what is in this structure
184  * is session-specific data. The structure that it is wrapped in, called a 'mansession' really contains action-specific
185  * data.
186  */
187 struct mansession_session {
188         pthread_t ms_t;         /*!< Execution thread, basically useless */
189                                 /* XXX need to document which fields it is protecting */
190         struct sockaddr_in sin; /*!< address we are connecting from */
191         FILE *f;                /*!< fdopen() on the underlying fd */
192         int fd;                 /*!< descriptor used for output. Either the socket (AMI) or a temporary file (HTTP) */
193         int inuse;              /*!< number of HTTP sessions using this entry */
194         int needdestroy;        /*!< Whether an HTTP session should be destroyed */
195         pthread_t waiting_thread;       /*!< Sleeping thread using this descriptor */
196         uint32_t managerid;     /*!< Unique manager identifier, 0 for AMI sessions */
197         time_t sessionstart;    /*!< Session start time */
198         time_t sessiontimeout;  /*!< Session timeout if HTTP */
199         char username[80];      /*!< Logged in username */
200         char challenge[10];     /*!< Authentication challenge */
201         int authenticated;      /*!< Authentication status */
202         int readperm;           /*!< Authorization for reading */
203         int writeperm;          /*!< Authorization for writing */
204         char inbuf[1025];       /*!< Buffer */
205                                 /* we use the extra byte to add a '\0' and simplify parsing */
206         int inlen;              /*!< number of buffered bytes */
207         int send_events;        /*!<  XXX what ? */
208         struct eventqent *last_ev;      /*!< last event processed. */
209         int writetimeout;       /*!< Timeout for ast_carefulwrite() */
210         int pending_event;         /*!< Pending events indicator in case when waiting_thread is NULL */
211         time_t noncetime;       /*!< Timer for nonce value expiration */
212         unsigned long oldnonce; /*!< Stale nonce value */
213         unsigned long nc;       /*!< incremental  nonce counter */
214         AST_LIST_HEAD_NOLOCK(mansession_datastores, ast_datastore) datastores; /*!< Data stores on the session */
215         AST_LIST_ENTRY(mansession_session) list;
216 };
217
218 /* In case you didn't read that giant block of text above the mansession_session struct, the
219  * 'mansession' struct is named this solely to keep the API the same in Asterisk. This structure really
220  * represents data that is different from Manager action to Manager action. The mansession_session pointer
221  * contained within points to session-specific data.
222  */
223 struct mansession {
224         struct mansession_session *session;
225         FILE *f;
226         int fd;
227 };
228
229 static struct ao2_container *sessions = NULL;
230
231 #define NEW_EVENT(m)    (AST_LIST_NEXT(m->session->last_ev, eq_next))
232
233 /*! \brief user descriptor, as read from the config file.
234  *
235  * \note It is still missing some fields -- e.g. we can have multiple permit and deny
236  * lines which are not supported here, and readperm/writeperm/writetimeout
237  * are not stored.
238  */
239 struct ast_manager_user {
240         char username[80];
241         char *secret;
242         struct ast_ha *ha;              /*!< ACL setting */
243         int readperm;                   /*! Authorization for reading */
244         int writeperm;                  /*! Authorization for writing */
245         int writetimeout;               /*! Per user Timeout for ast_carefulwrite() */
246         int displayconnects;            /*!< XXX unused */
247         int keep;                       /*!< mark entries created on a reload */
248         char *a1_hash;                  /*!< precalculated A1 for Digest auth */
249         AST_RWLIST_ENTRY(ast_manager_user) list;
250 };
251
252 /*! \brief list of users found in the config file */
253 static AST_RWLIST_HEAD_STATIC(users, ast_manager_user);
254
255 /*! \brief list of actions registered */
256 static AST_RWLIST_HEAD_STATIC(actions, manager_action);
257
258 /*! \brief list of hooks registered */
259 static AST_RWLIST_HEAD_STATIC(manager_hooks, manager_custom_hook);
260
261 static struct eventqent *unref_event(struct eventqent *e);
262 static void ref_event(struct eventqent *e);
263
264 /*! \brief Add a custom hook to be called when an event is fired */
265 void ast_manager_register_hook(struct manager_custom_hook *hook)
266 {
267         AST_RWLIST_WRLOCK(&manager_hooks);
268         AST_RWLIST_INSERT_TAIL(&manager_hooks, hook, list);
269         AST_RWLIST_UNLOCK(&manager_hooks);
270         return;
271 }
272
273 /*! \brief Delete a custom hook to be called when an event is fired */
274 void ast_manager_unregister_hook(struct manager_custom_hook *hook)
275 {
276         AST_RWLIST_WRLOCK(&manager_hooks);
277         AST_RWLIST_REMOVE(&manager_hooks, hook, list);
278         AST_RWLIST_UNLOCK(&manager_hooks);
279         return;
280 }
281
282 /*! \brief
283  * Event list management functions.
284  * We assume that the event list always has at least one element,
285  * and the delete code will not remove the last entry even if the
286  *
287  */
288 #if 0
289 static time_t __deb(time_t start, const char *msg)
290 {
291         time_t now = time(NULL);
292         ast_verbose("%4d th %p %s\n", (int)(now % 3600), pthread_self(), msg);
293         if (start != 0 && now - start > 5)
294                 ast_verbose("+++ WOW, %s took %d seconds\n", msg, (int)(now - start));
295         return now;
296 }
297
298 static void LOCK_EVENTS(void)
299 {
300         time_t start = __deb(0, "about to lock events");
301         AST_LIST_LOCK(&all_events);
302         __deb(start, "done lock events");
303 }
304
305 static void UNLOCK_EVENTS(void)
306 {
307         __deb(0, "about to unlock events");
308         AST_LIST_UNLOCK(&all_events);
309 }
310
311 static void LOCK_SESS(void)
312 {
313         time_t start = __deb(0, "about to lock sessions");
314         AST_LIST_LOCK(&sessions);
315         __deb(start, "done lock sessions");
316 }
317
318 static void UNLOCK_SESS(void)
319 {
320         __deb(0, "about to unlock sessions");
321         AST_LIST_UNLOCK(&sessions);
322 }
323 #endif
324
325 int check_manager_enabled()
326 {
327         return manager_enabled;
328 }
329
330 int check_webmanager_enabled()
331 {
332         return (webmanager_enabled && manager_enabled);
333 }
334
335 /*!
336  * Grab a reference to the last event, update usecount as needed.
337  * Can handle a NULL pointer.
338  */
339 static struct eventqent *grab_last(void)
340 {
341         struct eventqent *ret;
342
343         AST_LIST_LOCK(&all_events);
344         ret = AST_LIST_LAST(&all_events);
345         /* the list is never empty now, but may become so when
346          * we optimize it in the future, so be prepared.
347          */
348         if (ret) {
349                 ast_atomic_fetchadd_int(&ret->usecount, 1);
350         }
351         AST_LIST_UNLOCK(&all_events);
352         return ret;
353 }
354
355 /*!
356  * Purge unused events. Remove elements from the head
357  * as long as their usecount is 0 and there is a next element.
358  */
359 static void purge_events(void)
360 {
361         struct eventqent *ev;
362
363         AST_LIST_LOCK(&all_events);
364         while ( (ev = AST_LIST_FIRST(&all_events)) &&
365             ev->usecount == 0 && AST_LIST_NEXT(ev, eq_next)) {
366                 AST_LIST_REMOVE_HEAD(&all_events, eq_next);
367                 ast_free(ev);
368         }
369         AST_LIST_UNLOCK(&all_events);
370 }
371
372 /*!
373  * helper functions to convert back and forth between
374  * string and numeric representation of set of flags
375  */
376 static struct permalias {
377         int num;
378         char *label;
379 } perms[] = {
380         { EVENT_FLAG_SYSTEM, "system" },
381         { EVENT_FLAG_CALL, "call" },
382         { EVENT_FLAG_LOG, "log" },
383         { EVENT_FLAG_VERBOSE, "verbose" },
384         { EVENT_FLAG_COMMAND, "command" },
385         { EVENT_FLAG_AGENT, "agent" },
386         { EVENT_FLAG_USER, "user" },
387         { EVENT_FLAG_CONFIG, "config" },
388         { EVENT_FLAG_DTMF, "dtmf" },
389         { EVENT_FLAG_REPORTING, "reporting" },
390         { EVENT_FLAG_CDR, "cdr" },
391         { EVENT_FLAG_DIALPLAN, "dialplan" },
392         { EVENT_FLAG_ORIGINATE, "originate" },
393         { EVENT_FLAG_AGI, "agi" },
394         { -1, "all" },
395         { 0, "none" },
396 };
397
398 /*! \brief Convert authority code to a list of options */
399 static char *authority_to_str(int authority, struct ast_str **res)
400 {
401         int i;
402         char *sep = "";
403
404         ast_str_reset(*res);
405         for (i = 0; i < ARRAY_LEN(perms) - 1; i++) {
406                 if (authority & perms[i].num) {
407                         ast_str_append(res, 0, "%s%s", sep, perms[i].label);
408                         sep = ",";
409                 }
410         }
411
412         if (ast_str_strlen(*res) == 0)  /* replace empty string with something sensible */
413                 ast_str_append(res, 0, "<none>");
414
415         return ast_str_buffer(*res);
416 }
417
418 /*! Tells you if smallstr exists inside bigstr
419    which is delim by delim and uses no buf or stringsep
420    ast_instring("this|that|more","this",'|') == 1;
421
422    feel free to move this to app.c -anthm */
423 static int ast_instring(const char *bigstr, const char *smallstr, const char delim)
424 {
425         const char *val = bigstr, *next;
426
427         do {
428                 if ((next = strchr(val, delim))) {
429                         if (!strncmp(val, smallstr, (next - val))) {
430                                 return 1;
431                         } else {
432                                 continue;
433                         }
434                 } else {
435                         return !strcmp(smallstr, val);
436                 }
437         } while (*(val = (next + 1)));
438
439         return 0;
440 }
441
442 static int get_perm(const char *instr)
443 {
444         int x = 0, ret = 0;
445
446         if (!instr) {
447                 return 0;
448         }
449
450         for (x = 0; x < ARRAY_LEN(perms); x++) {
451                 if (ast_instring(instr, perms[x].label, ',')) {
452                         ret |= perms[x].num;
453                 }
454         }
455
456         return ret;
457 }
458
459 /*!
460  * A number returns itself, false returns 0, true returns all flags,
461  * other strings return the flags that are set.
462  */
463 static int strings_to_mask(const char *string)
464 {
465         const char *p;
466
467         if (ast_strlen_zero(string)) {
468                 return -1;
469         }
470
471         for (p = string; *p; p++) {
472                 if (*p < '0' || *p > '9') {
473                         break;
474                 }
475         }
476         if (!p) { /* all digits */
477                 return atoi(string);
478         }
479         if (ast_false(string)) {
480                 return 0;
481         }
482         if (ast_true(string)) { /* all permissions */
483                 int x, ret = 0;
484                 for (x = 0; x < ARRAY_LEN(perms); x++) {
485                         ret |= perms[x].num;
486                 }
487                 return ret;
488         }
489         return get_perm(string);
490 }
491
492 /*! \brief Unreference manager session object.
493      If no more references, then go ahead and delete it */
494 static struct mansession_session *unref_mansession(struct mansession_session *s)
495 {
496         int refcount = ao2_ref(s, -1);
497         if (manager_debug) {
498                 ast_log(LOG_DEBUG, "Mansession: %p refcount now %d\n", s, refcount - 1);
499         }
500         return s;
501 }
502
503 static void session_destructor(void *obj)
504 {
505         struct mansession_session *session = obj;
506         struct eventqent *eqe = session->last_ev;
507
508         if (session->f != NULL) {
509                 fclose(session->f);
510         }
511         unref_event(eqe);
512 }
513
514 /*! \brief Allocate manager session structure and add it to the list of sessions */
515 static struct mansession_session *build_mansession(struct sockaddr_in sin)
516 {
517         struct mansession_session *newsession;
518
519         if (!(newsession = ao2_alloc(sizeof(*newsession), session_destructor))) {
520                 return NULL;
521         }
522         memset(newsession, 0, sizeof(*newsession));
523         newsession->fd = -1;
524         newsession->waiting_thread = AST_PTHREADT_NULL;
525         newsession->writetimeout = 100;
526         newsession->send_events = -1;
527         newsession->sin = sin;
528
529         ao2_link(sessions, newsession);
530
531         return unref_mansession(newsession);
532 }
533
534 static int mansession_cmp_fn(void *obj, void *arg, int flags)
535 {
536         struct mansession_session *s = obj;
537         char *str = arg;
538         return !strcasecmp(s->username, str) ? CMP_MATCH : 0;
539 }
540
541 static void session_destroy(struct mansession_session *s)
542 {
543         ao2_unlink(sessions, s);
544 }
545
546
547 static int check_manager_session_inuse(const char *name)
548 {
549         struct mansession_session *session = ao2_find(sessions, (char*) name, OBJ_POINTER);
550
551         if (session) {
552                 unref_mansession(session);
553         }
554         return session ? 1 : 0;
555 }
556
557
558 /*!
559  * lookup an entry in the list of registered users.
560  * must be called with the list lock held.
561  */
562 static struct ast_manager_user *get_manager_by_name_locked(const char *name)
563 {
564         struct ast_manager_user *user = NULL;
565
566         AST_RWLIST_TRAVERSE(&users, user, list)
567                 if (!strcasecmp(user->username, name)) {
568                         break;
569                 }
570         return user;
571 }
572
573 /*! \brief Get displayconnects config option.
574  *  \param session manager session to get parameter from.
575  *  \return displayconnects config option value.
576  */
577 static int manager_displayconnects (struct mansession_session *session)
578 {
579         struct ast_manager_user *user = NULL;
580         int ret = 0;
581
582         AST_RWLIST_RDLOCK(&users);
583         if ((user = get_manager_by_name_locked (session->username))) {
584                 ret = user->displayconnects;
585         }
586         AST_RWLIST_UNLOCK(&users);
587
588         return ret;
589 }
590
591 static char *handle_showmancmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
592 {
593         struct manager_action *cur;
594         struct ast_str *authority;
595         int num, l, which;
596         char *ret = NULL;
597         switch (cmd) {
598         case CLI_INIT:
599                 e->command = "manager show command";
600                 e->usage =
601                         "Usage: manager show command <actionname>\n"
602                         "       Shows the detailed description for a specific Asterisk manager interface command.\n";
603                 return NULL;
604         case CLI_GENERATE:
605                 l = strlen(a->word);
606                 which = 0;
607                 AST_RWLIST_RDLOCK(&actions);
608                 AST_RWLIST_TRAVERSE(&actions, cur, list) {
609                         if (!strncasecmp(a->word, cur->action, l) && ++which > a->n) {
610                                 ret = ast_strdup(cur->action);
611                                 break;  /* make sure we exit even if ast_strdup() returns NULL */
612                         }
613                 }
614                 AST_RWLIST_UNLOCK(&actions);
615                 return ret;
616         }
617         authority = ast_str_alloca(80);
618         if (a->argc != 4) {
619                 return CLI_SHOWUSAGE;
620         }
621
622         AST_RWLIST_RDLOCK(&actions);
623         AST_RWLIST_TRAVERSE(&actions, cur, list) {
624                 for (num = 3; num < a->argc; num++) {
625                         if (!strcasecmp(cur->action, a->argv[num])) {
626                                 ast_cli(a->fd, "Action: %s\nSynopsis: %s\nPrivilege: %s\n%s\n",
627                                         cur->action, cur->synopsis,
628                                         authority_to_str(cur->authority, &authority),
629                                         S_OR(cur->description, ""));
630                         }
631                 }
632         }
633         AST_RWLIST_UNLOCK(&actions);
634
635         return CLI_SUCCESS;
636 }
637
638 static char *handle_mandebug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
639 {
640         switch (cmd) {
641         case CLI_INIT:
642                 e->command = "manager set debug [on|off]";
643                 e->usage = "Usage: manager set debug [on|off]\n Show, enable, disable debugging of the manager code.\n";
644                 return NULL;
645         case CLI_GENERATE:
646                 return NULL;
647         }
648
649         if (a->argc == 3) {
650                 ast_cli(a->fd, "manager debug is %s\n", manager_debug? "on" : "off");
651         } else if (a->argc == 4) {
652                 if (!strcasecmp(a->argv[3], "on")) {
653                         manager_debug = 1;
654                 } else if (!strcasecmp(a->argv[3], "off")) {
655                         manager_debug = 0;
656                 } else {
657                         return CLI_SHOWUSAGE;
658                 }
659         }
660         return CLI_SUCCESS;
661 }
662
663 static char *handle_showmanager(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
664 {
665         struct ast_manager_user *user = NULL;
666         int l, which;
667         char *ret = NULL;
668         struct ast_str *rauthority = ast_str_alloca(128);
669         struct ast_str *wauthority = ast_str_alloca(128);
670
671         switch (cmd) {
672         case CLI_INIT:
673                 e->command = "manager show user";
674                 e->usage =
675                         " Usage: manager show user <user>\n"
676                         "        Display all information related to the manager user specified.\n";
677                 return NULL;
678         case CLI_GENERATE:
679                 l = strlen(a->word);
680                 which = 0;
681                 if (a->pos != 3) {
682                         return NULL;
683                 }
684                 AST_RWLIST_RDLOCK(&users);
685                 AST_RWLIST_TRAVERSE(&users, user, list) {
686                         if ( !strncasecmp(a->word, user->username, l) && ++which > a->n ) {
687                                 ret = ast_strdup(user->username);
688                                 break;
689                         }
690                 }
691                 AST_RWLIST_UNLOCK(&users);
692                 return ret;
693         }
694
695         if (a->argc != 4) {
696                 return CLI_SHOWUSAGE;
697         }
698
699         AST_RWLIST_RDLOCK(&users);
700
701         if (!(user = get_manager_by_name_locked(a->argv[3]))) {
702                 ast_cli(a->fd, "There is no manager called %s\n", a->argv[3]);
703                 AST_RWLIST_UNLOCK(&users);
704                 return CLI_SUCCESS;
705         }
706
707         ast_cli(a->fd, "\n");
708         ast_cli(a->fd,
709                 "       username: %s\n"
710                 "         secret: %s\n"
711                 "            acl: %s\n"
712                 "      read perm: %s\n"
713                 "     write perm: %s\n"
714                 "displayconnects: %s\n",
715                 (user->username ? user->username : "(N/A)"),
716                 (user->secret ? "<Set>" : "(N/A)"),
717                 (user->ha ? "yes" : "no"),
718                 authority_to_str(user->readperm, &rauthority),
719                 authority_to_str(user->writeperm, &wauthority),
720                 (user->displayconnects ? "yes" : "no"));
721
722         AST_RWLIST_UNLOCK(&users);
723
724         return CLI_SUCCESS;
725 }
726
727
728 static char *handle_showmanagers(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
729 {
730         struct ast_manager_user *user = NULL;
731         int count_amu = 0;
732         switch (cmd) {
733         case CLI_INIT:
734                 e->command = "manager show users";
735                 e->usage =
736                         "Usage: manager show users\n"
737                         "       Prints a listing of all managers that are currently configured on that\n"
738                         " system.\n";
739                 return NULL;
740         case CLI_GENERATE:
741                 return NULL;
742         }
743         if (a->argc != 3) {
744                 return CLI_SHOWUSAGE;
745         }
746
747         AST_RWLIST_RDLOCK(&users);
748
749         /* If there are no users, print out something along those lines */
750         if (AST_RWLIST_EMPTY(&users)) {
751                 ast_cli(a->fd, "There are no manager users.\n");
752                 AST_RWLIST_UNLOCK(&users);
753                 return CLI_SUCCESS;
754         }
755
756         ast_cli(a->fd, "\nusername\n--------\n");
757
758         AST_RWLIST_TRAVERSE(&users, user, list) {
759                 ast_cli(a->fd, "%s\n", user->username);
760                 count_amu++;
761         }
762
763         AST_RWLIST_UNLOCK(&users);
764
765         ast_cli(a->fd,"-------------------\n"
766                       "%d manager users configured.\n", count_amu);
767         return CLI_SUCCESS;
768 }
769
770
771 /*! \brief  CLI command  manager list commands */
772 static char *handle_showmancmds(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
773 {
774         struct manager_action *cur;
775         struct ast_str *authority;
776 #define HSMC_FORMAT "  %-15.15s  %-15.15s  %-55.55s\n"
777         switch (cmd) {
778         case CLI_INIT:
779                 e->command = "manager show commands";
780                 e->usage =
781                         "Usage: manager show commands\n"
782                         "       Prints a listing of all the available Asterisk manager interface commands.\n";
783                 return NULL;
784         case CLI_GENERATE:
785                 return NULL;
786         }
787         authority = ast_str_alloca(80);
788         ast_cli(a->fd, HSMC_FORMAT, "Action", "Privilege", "Synopsis");
789         ast_cli(a->fd, HSMC_FORMAT, "------", "---------", "--------");
790
791         AST_RWLIST_RDLOCK(&actions);
792         AST_RWLIST_TRAVERSE(&actions, cur, list)
793                 ast_cli(a->fd, HSMC_FORMAT, cur->action, authority_to_str(cur->authority, &authority), cur->synopsis);
794         AST_RWLIST_UNLOCK(&actions);
795
796         return CLI_SUCCESS;
797 }
798
799 /*! \brief CLI command manager list connected */
800 static char *handle_showmanconn(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
801 {
802         struct mansession_session *session;
803         time_t now = time(NULL);
804 #define HSMCONN_FORMAT1 "  %-15.15s  %-15.15s  %-10.10s  %-10.10s  %-8.8s  %-8.8s  %-5.5s  %-5.5s\n"
805 #define HSMCONN_FORMAT2 "  %-15.15s  %-15.15s  %-10d  %-10d  %-8d  %-8d  %-5.5d  %-5.5d\n"
806         int count = 0;
807         struct ao2_iterator i;
808
809         switch (cmd) {
810         case CLI_INIT:
811                 e->command = "manager show connected";
812                 e->usage =
813                         "Usage: manager show connected\n"
814                         "       Prints a listing of the users that are currently connected to the\n"
815                         "Asterisk manager interface.\n";
816                 return NULL;
817         case CLI_GENERATE:
818                 return NULL;
819         }
820
821         ast_cli(a->fd, HSMCONN_FORMAT1, "Username", "IP Address", "Start", "Elapsed", "FileDes", "HttpCnt", "Read", "Write");
822
823         i = ao2_iterator_init(sessions, 0);
824         while ((session = ao2_iterator_next(&i))) {
825                 ao2_lock(session);
826                 ast_cli(a->fd, HSMCONN_FORMAT2, session->username, ast_inet_ntoa(session->sin.sin_addr), (int)(session->sessionstart), (int)(now - session->sessionstart), session->fd, session->inuse, session->readperm, session->writeperm);
827                 count++;
828                 ao2_unlock(session);
829                 unref_mansession(session);
830         }
831
832         ast_cli(a->fd, "%d users connected.\n", count);
833
834         return CLI_SUCCESS;
835 }
836
837 /*! \brief CLI command manager list eventq */
838 /* Should change to "manager show connected" */
839 static char *handle_showmaneventq(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
840 {
841         struct eventqent *s;
842         switch (cmd) {
843         case CLI_INIT:
844                 e->command = "manager show eventq";
845                 e->usage =
846                         "Usage: manager show eventq\n"
847                         "       Prints a listing of all events pending in the Asterisk manger\n"
848                         "event queue.\n";
849                 return NULL;
850         case CLI_GENERATE:
851                 return NULL;
852         }
853         AST_LIST_LOCK(&all_events);
854         AST_LIST_TRAVERSE(&all_events, s, eq_next) {
855                 ast_cli(a->fd, "Usecount: %d\n", s->usecount);
856                 ast_cli(a->fd, "Category: %d\n", s->category);
857                 ast_cli(a->fd, "Event:\n%s", s->eventdata);
858         }
859         AST_LIST_UNLOCK(&all_events);
860
861         return CLI_SUCCESS;
862 }
863
864 /*! \brief CLI command manager reload */
865 static char *handle_manager_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
866 {
867         switch (cmd) {
868         case CLI_INIT:
869                 e->command = "manager reload";
870                 e->usage =
871                         "Usage: manager reload\n"
872                         "       Reloads the manager configuration.\n";
873                 return NULL;
874         case CLI_GENERATE:
875                 return NULL;
876         }
877         if (a->argc > 2) {
878                 return CLI_SHOWUSAGE;
879         }
880         reload_manager();
881         return CLI_SUCCESS;
882 }
883
884
885 static struct ast_cli_entry cli_manager[] = {
886         AST_CLI_DEFINE(handle_showmancmd, "Show a manager interface command"),
887         AST_CLI_DEFINE(handle_showmancmds, "List manager interface commands"),
888         AST_CLI_DEFINE(handle_showmanconn, "List connected manager interface users"),
889         AST_CLI_DEFINE(handle_showmaneventq, "List manager interface queued events"),
890         AST_CLI_DEFINE(handle_showmanagers, "List configured manager users"),
891         AST_CLI_DEFINE(handle_showmanager, "Display information on a specific manager user"),
892         AST_CLI_DEFINE(handle_mandebug, "Show, enable, disable debugging of the manager code"),
893         AST_CLI_DEFINE(handle_manager_reload, "Reload manager configurations"),
894 };
895
896 static struct eventqent *unref_event(struct eventqent *e)
897 {
898         ast_atomic_fetchadd_int(&e->usecount, -1);
899         return AST_LIST_NEXT(e, eq_next);
900 }
901
902 static void ref_event(struct eventqent *e)
903 {
904         ast_atomic_fetchadd_int(&e->usecount, 1);
905 }
906
907 /*
908  * destroy a session, leaving the usecount
909  */
910 static void free_session(struct mansession_session *session)
911 {
912         struct eventqent *eqe = session->last_ev;
913         struct ast_datastore *datastore;
914
915         /* Get rid of each of the data stores on the session */
916         while ((datastore = AST_LIST_REMOVE_HEAD(&session->datastores, entry))) {
917                 /* Free the data store */
918                 ast_datastore_free(datastore);
919         }
920
921         if (session->f != NULL)
922                 fclose(session->f);
923         ast_free(session);
924         unref_event(eqe);
925 }
926
927 static void destroy_session(struct mansession_session *session)
928 {
929         ao2_unlink(sessions, session);
930         free_session(session);
931 }
932
933 /*
934  * Generic function to return either the first or the last matching header
935  * from a list of variables, possibly skipping empty strings.
936  * At the moment there is only one use of this function in this file,
937  * so we make it static.
938  */
939 #define GET_HEADER_FIRST_MATCH  0
940 #define GET_HEADER_LAST_MATCH   1
941 #define GET_HEADER_SKIP_EMPTY   2
942 static const char *__astman_get_header(const struct message *m, char *var, int mode)
943 {
944         int x, l = strlen(var);
945         const char *result = "";
946
947         for (x = 0; x < m->hdrcount; x++) {
948                 const char *h = m->headers[x];
949                 if (!strncasecmp(var, h, l) && h[l] == ':' && h[l+1] == ' ') {
950                         const char *value = h + l + 2;
951                         /* found a potential candidate */
952                         if (mode & GET_HEADER_SKIP_EMPTY && ast_strlen_zero(value))
953                                 continue;       /* not interesting */
954                         if (mode & GET_HEADER_LAST_MATCH)
955                                 result = value; /* record the last match so far */
956                         else
957                                 return value;
958                 }
959         }
960
961         return "";
962 }
963
964 /*
965  * Return the first matching variable from an array.
966  * This is the legacy function and is implemented in therms of
967  * __astman_get_header().
968  */
969 const char *astman_get_header(const struct message *m, char *var)
970 {
971         return __astman_get_header(m, var, GET_HEADER_FIRST_MATCH);
972 }
973
974
975 struct ast_variable *astman_get_variables(const struct message *m)
976 {
977         int varlen, x, y;
978         struct ast_variable *head = NULL, *cur;
979
980         AST_DECLARE_APP_ARGS(args,
981                 AST_APP_ARG(vars)[32];
982         );
983
984         varlen = strlen("Variable: ");
985
986         for (x = 0; x < m->hdrcount; x++) {
987                 char *parse, *var, *val;
988
989                 if (strncasecmp("Variable: ", m->headers[x], varlen)) {
990                         continue;
991                 }
992                 parse = ast_strdupa(m->headers[x] + varlen);
993
994                 AST_STANDARD_APP_ARGS(args, parse);
995                 if (!args.argc) {
996                         continue;
997                 }
998                 for (y = 0; y < args.argc; y++) {
999                         if (!args.vars[y]) {
1000                                 continue;
1001                         }
1002                         var = val = ast_strdupa(args.vars[y]);
1003                         strsep(&val, "=");
1004                         if (!val || ast_strlen_zero(var)) {
1005                                 continue;
1006                         }
1007                         cur = ast_variable_new(var, val, "");
1008                         cur->next = head;
1009                         head = cur;
1010                 }
1011         }
1012
1013         return head;
1014 }
1015
1016 /*!
1017  * helper function to send a string to the socket.
1018  * Return -1 on error (e.g. buffer full).
1019  */
1020 static int send_string(struct mansession *s, char *string)
1021 {
1022         if (s->f) {
1023                 return ast_careful_fwrite(s->f, s->fd, string, strlen(string), s->session->writetimeout);
1024         } else {
1025                 return ast_careful_fwrite(s->session->f, s->session->fd, string, strlen(string), s->session->writetimeout);
1026         }
1027 }
1028
1029 /*!
1030  * \brief thread local buffer for astman_append
1031  *
1032  * \note This can not be defined within the astman_append() function
1033  *       because it declares a couple of functions that get used to
1034  *       initialize the thread local storage key.
1035  */
1036 AST_THREADSTORAGE(astman_append_buf);
1037 AST_THREADSTORAGE(userevent_buf);
1038
1039 /*! \brief initial allocated size for the astman_append_buf */
1040 #define ASTMAN_APPEND_BUF_INITSIZE   256
1041
1042 /*!
1043  * utility functions for creating AMI replies
1044  */
1045 void astman_append(struct mansession *s, const char *fmt, ...)
1046 {
1047         va_list ap;
1048         struct ast_str *buf;
1049
1050         if (!(buf = ast_str_thread_get(&astman_append_buf, ASTMAN_APPEND_BUF_INITSIZE))) {
1051                 return;
1052         }
1053
1054         va_start(ap, fmt);
1055         ast_str_set_va(&buf, 0, fmt, ap);
1056         va_end(ap);
1057
1058         if (s->f != NULL || s->session->f != NULL) {
1059                 send_string(s, ast_str_buffer(buf));
1060         } else {
1061                 ast_verbose("fd == -1 in astman_append, should not happen\n");
1062         }
1063 }
1064
1065 /*! \note NOTE: XXX this comment is unclear and possibly wrong.
1066    Callers of astman_send_error(), astman_send_response() or astman_send_ack() must EITHER
1067    hold the session lock _or_ be running in an action callback (in which case s->session->busy will
1068    be non-zero). In either of these cases, there is no need to lock-protect the session's
1069    fd, since no other output will be sent (events will be queued), and no input will
1070    be read until either the current action finishes or get_input() obtains the session
1071    lock.
1072  */
1073
1074 /*! \brief send a response with an optional message,
1075  * and terminate it with an empty line.
1076  * m is used only to grab the 'ActionID' field.
1077  *
1078  * Use the explicit constant MSG_MOREDATA to remove the empty line.
1079  * XXX MSG_MOREDATA should go to a header file.
1080  */
1081 #define MSG_MOREDATA    ((char *)astman_send_response)
1082 static void astman_send_response_full(struct mansession *s, const struct message *m, char *resp, char *msg, char *listflag)
1083 {
1084         const char *id = astman_get_header(m, "ActionID");
1085
1086         astman_append(s, "Response: %s\r\n", resp);
1087         if (!ast_strlen_zero(id)) {
1088                 astman_append(s, "ActionID: %s\r\n", id);
1089         }
1090         if (listflag) {
1091                 astman_append(s, "Eventlist: %s\r\n", listflag);        /* Start, complete, cancelled */
1092         }
1093         if (msg == MSG_MOREDATA) {
1094                 return;
1095         } else if (msg) {
1096                 astman_append(s, "Message: %s\r\n\r\n", msg);
1097         } else {
1098                 astman_append(s, "\r\n");
1099         }
1100 }
1101
1102 void astman_send_response(struct mansession *s, const struct message *m, char *resp, char *msg)
1103 {
1104         astman_send_response_full(s, m, resp, msg, NULL);
1105 }
1106
1107 void astman_send_error(struct mansession *s, const struct message *m, char *error)
1108 {
1109         astman_send_response_full(s, m, "Error", error, NULL);
1110 }
1111
1112 void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
1113 {
1114         astman_send_response_full(s, m, "Success", msg, NULL);
1115 }
1116
1117 static void astman_start_ack(struct mansession *s, const struct message *m)
1118 {
1119         astman_send_response_full(s, m, "Success", MSG_MOREDATA, NULL);
1120 }
1121
1122 void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
1123 {
1124         astman_send_response_full(s, m, "Success", msg, listflag);
1125 }
1126
1127
1128 /*! \brief
1129    Rather than braindead on,off this now can also accept a specific int mask value
1130    or a ',' delim list of mask strings (the same as manager.conf) -anthm
1131 */
1132 static int set_eventmask(struct mansession *s, const char *eventmask)
1133 {
1134         int maskint = strings_to_mask(eventmask);
1135
1136         ao2_lock(s);
1137         if (maskint >= 0) {
1138                 s->session->send_events = maskint;
1139         }
1140         ao2_unlock(s);
1141
1142         return maskint;
1143 }
1144
1145 /*
1146  * Here we start with action_ handlers for AMI actions,
1147  * and the internal functions used by them.
1148  * Generally, the handlers are called action_foo()
1149  */
1150
1151 /* helper function for action_login() */
1152 static int authenticate(struct mansession *s, const struct message *m)
1153 {
1154         const char *username = astman_get_header(m, "Username");
1155         const char *password = astman_get_header(m, "Secret");
1156         int error = -1;
1157         struct ast_manager_user *user = NULL;
1158
1159         if (ast_strlen_zero(username)) {        /* missing username */
1160                 return -1;
1161         }
1162
1163         /* locate user in locked state */
1164         AST_RWLIST_WRLOCK(&users);
1165
1166         if (!(user = get_manager_by_name_locked(username))) {
1167                 ast_log(LOG_NOTICE, "%s tried to authenticate with nonexistent user '%s'\n", ast_inet_ntoa(s->session->sin.sin_addr), username);
1168         } else if (user->ha && !ast_apply_ha(user->ha, &(s->session->sin))) {
1169                 ast_log(LOG_NOTICE, "%s failed to pass IP ACL as '%s'\n", ast_inet_ntoa(s->session->sin.sin_addr), username);
1170         } else if (!strcasecmp(astman_get_header(m, "AuthType"), "MD5")) {
1171                 const char *key = astman_get_header(m, "Key");
1172                 if (!ast_strlen_zero(key) && !ast_strlen_zero(s->session->challenge) && user->secret) {
1173                         int x;
1174                         int len = 0;
1175                         char md5key[256] = "";
1176                         struct MD5Context md5;
1177                         unsigned char digest[16];
1178
1179                         MD5Init(&md5);
1180                         MD5Update(&md5, (unsigned char *) s->session->challenge, strlen(s->session->challenge));
1181                         MD5Update(&md5, (unsigned char *) user->secret, strlen(user->secret));
1182                         MD5Final(digest, &md5);
1183                         for (x = 0; x < 16; x++)
1184                                 len += sprintf(md5key + len, "%2.2x", digest[x]);
1185                         if (!strcmp(md5key, key)) {
1186                                 error = 0;
1187                         }
1188                 } else {
1189                         ast_debug(1, "MD5 authentication is not possible.  challenge: '%s'\n",
1190                                 S_OR(s->session->challenge, ""));
1191                 }
1192         } else if (password && user->secret && !strcmp(password, user->secret)) {
1193                 error = 0;
1194         }
1195
1196         if (error) {
1197                 ast_log(LOG_NOTICE, "%s failed to authenticate as '%s'\n", ast_inet_ntoa(s->session->sin.sin_addr), username);
1198                 AST_RWLIST_UNLOCK(&users);
1199                 return -1;
1200         }
1201
1202         /* auth complete */
1203
1204         ast_copy_string(s->session->username, username, sizeof(s->session->username));
1205         s->session->readperm = user->readperm;
1206         s->session->writeperm = user->writeperm;
1207         s->session->writetimeout = user->writetimeout;
1208         s->session->sessionstart = time(NULL);
1209         set_eventmask(s, astman_get_header(m, "Events"));
1210
1211         AST_RWLIST_UNLOCK(&users);
1212         return 0;
1213 }
1214
1215 /*! \brief Manager PING */
1216 static char mandescr_ping[] =
1217 "Description: A 'Ping' action will ellicit a 'Pong' response.  Used to keep the\n"
1218 "  manager connection open.\n"
1219 "Variables: NONE\n";
1220
1221 static int action_ping(struct mansession *s, const struct message *m)
1222 {
1223         const char *actionid = astman_get_header(m, "ActionID");
1224
1225         astman_append(s, "Response: Success\r\n");
1226         if (!ast_strlen_zero(actionid)){
1227                 astman_append(s, "ActionID: %s\r\n", actionid);
1228         }
1229         astman_append(s, "Ping: Pong\r\n\r\n");
1230         return 0;
1231 }
1232
1233 static char mandescr_getconfig[] =
1234 "Description: A 'GetConfig' action will dump the contents of a configuration\n"
1235 "file by category and contents or optionally by specified category only.\n"
1236 "Variables: (Names marked with * are required)\n"
1237 "   *Filename: Configuration filename (e.g. foo.conf)\n"
1238 "   Category: Category in configuration file\n";
1239
1240 static int action_getconfig(struct mansession *s, const struct message *m)
1241 {
1242         struct ast_config *cfg;
1243         const char *fn = astman_get_header(m, "Filename");
1244         const char *category = astman_get_header(m, "Category");
1245         int catcount = 0;
1246         int lineno = 0;
1247         char *cur_category = NULL;
1248         struct ast_variable *v;
1249         struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS | CONFIG_FLAG_NOCACHE };
1250
1251         if (ast_strlen_zero(fn)) {
1252                 astman_send_error(s, m, "Filename not specified");
1253                 return 0;
1254         }
1255         cfg = ast_config_load2(fn, "manager", config_flags);
1256         if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) {
1257                 astman_send_error(s, m, "Config file not found");
1258                 return 0;
1259         }
1260
1261         astman_start_ack(s, m);
1262         while ((cur_category = ast_category_browse(cfg, cur_category))) {
1263                 if (ast_strlen_zero(category) || (!ast_strlen_zero(category) && !strcmp(category, cur_category))) {
1264                         lineno = 0;
1265                         astman_append(s, "Category-%06d: %s\r\n", catcount, cur_category);
1266                         for (v = ast_variable_browse(cfg, cur_category); v; v = v->next) {
1267                                 astman_append(s, "Line-%06d-%06d: %s=%s\r\n", catcount, lineno++, v->name, v->value);
1268                         }
1269                         catcount++;
1270                 }
1271         }
1272         if (!ast_strlen_zero(category) && catcount == 0) { /* TODO: actually, a config with no categories doesn't even get loaded */
1273                 astman_append(s, "No categories found\r\n");
1274         }
1275         ast_config_destroy(cfg);
1276         astman_append(s, "\r\n");
1277
1278         return 0;
1279 }
1280
1281 static char mandescr_listcategories[] =
1282 "Description: A 'ListCategories' action will dump the categories in\n"
1283 "a given file.\n"
1284 "Variables:\n"
1285 "   Filename: Configuration filename (e.g. foo.conf)\n";
1286
1287 static int action_listcategories(struct mansession *s, const struct message *m)
1288 {
1289         struct ast_config *cfg;
1290         const char *fn = astman_get_header(m, "Filename");
1291         char *category = NULL;
1292         struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS | CONFIG_FLAG_NOCACHE };
1293         int catcount = 0;
1294
1295         if (ast_strlen_zero(fn)) {
1296                 astman_send_error(s, m, "Filename not specified");
1297                 return 0;
1298         }
1299         if (!(cfg = ast_config_load2(fn, "manager", config_flags))) {
1300                 astman_send_error(s, m, "Config file not found or file has invalid syntax");
1301                 return 0;
1302         }
1303         astman_start_ack(s, m);
1304         while ((category = ast_category_browse(cfg, category))) {
1305                 astman_append(s, "Category-%06d: %s\r\n", catcount, category);
1306                 catcount++;
1307         }
1308         if (catcount == 0) { /* TODO: actually, a config with no categories doesn't even get loaded */
1309                 astman_append(s, "Error: no categories found\r\n");
1310         }
1311         ast_config_destroy(cfg);
1312         astman_append(s, "\r\n");
1313
1314         return 0;
1315 }
1316
1317
1318
1319
1320 /*! The amount of space in out must be at least ( 2 * strlen(in) + 1 ) */
1321 static void json_escape(char *out, const char *in)
1322 {
1323         for (; *in; in++) {
1324                 if (*in == '\\' || *in == '\"') {
1325                         *out++ = '\\';
1326                 }
1327                 *out++ = *in;
1328         }
1329         *out = '\0';
1330 }
1331
1332 static char mandescr_getconfigjson[] =
1333 "Description: A 'GetConfigJSON' action will dump the contents of a configuration\n"
1334 "file by category and contents in JSON format.  This only makes sense to be used\n"
1335 "using rawman over the HTTP interface.\n"
1336 "Variables:\n"
1337 "   Filename: Configuration filename (e.g. foo.conf)\n";
1338
1339 static int action_getconfigjson(struct mansession *s, const struct message *m)
1340 {
1341         struct ast_config *cfg;
1342         const char *fn = astman_get_header(m, "Filename");
1343         char *category = NULL;
1344         struct ast_variable *v;
1345         int comma1 = 0;
1346         char *buf = NULL;
1347         unsigned int buf_len = 0;
1348         struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS | CONFIG_FLAG_NOCACHE };
1349
1350         if (ast_strlen_zero(fn)) {
1351                 astman_send_error(s, m, "Filename not specified");
1352                 return 0;
1353         }
1354
1355         if (!(cfg = ast_config_load2(fn, "manager", config_flags))) {
1356                 astman_send_error(s, m, "Config file not found");
1357                 return 0;
1358         }
1359
1360         buf_len = 512;
1361         buf = alloca(buf_len);
1362
1363         astman_start_ack(s, m);
1364         astman_append(s, "JSON: {");
1365         while ((category = ast_category_browse(cfg, category))) {
1366                 int comma2 = 0;
1367                 if (buf_len < 2 * strlen(category) + 1) {
1368                         buf_len *= 2;
1369                         buf = alloca(buf_len);
1370                 }
1371                 json_escape(buf, category);
1372                 astman_append(s, "%s\"%s\":[", comma1 ? "," : "", buf);
1373                 if (!comma1) {
1374                         comma1 = 1;
1375                 }
1376                 for (v = ast_variable_browse(cfg, category); v; v = v->next) {
1377                         if (comma2) {
1378                                 astman_append(s, ",");
1379                         }
1380                         if (buf_len < 2 * strlen(v->name) + 1) {
1381                                 buf_len *= 2;
1382                                 buf = alloca(buf_len);
1383                         }
1384                         json_escape(buf, v->name);
1385                         astman_append(s, "\"%s", buf);
1386                         if (buf_len < 2 * strlen(v->value) + 1) {
1387                                 buf_len *= 2;
1388                                 buf = alloca(buf_len);
1389                         }
1390                         json_escape(buf, v->value);
1391                         astman_append(s, "%s\"", buf);
1392                         if (!comma2) {
1393                                 comma2 = 1;
1394                         }
1395                 }
1396                 astman_append(s, "]");
1397         }
1398         astman_append(s, "}\r\n\r\n");
1399
1400         ast_config_destroy(cfg);
1401
1402         return 0;
1403 }
1404
1405 /* helper function for action_updateconfig */
1406 static enum error_type handle_updates(struct mansession *s, const struct message *m, struct ast_config *cfg, const char *dfn)
1407 {
1408         int x;
1409         char hdr[40];
1410         const char *action, *cat, *var, *value, *match, *line;
1411         struct ast_category *category;
1412         struct ast_variable *v;
1413         struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
1414         enum error_type result = 0;
1415
1416         for (x = 0; x < 100000; x++) {  /* 100000 = the max number of allowed updates + 1 */
1417                 unsigned int object = 0;
1418
1419                 snprintf(hdr, sizeof(hdr), "Action-%06d", x);
1420                 action = astman_get_header(m, hdr);
1421                 if (ast_strlen_zero(action))            /* breaks the for loop if no action header */
1422                         break;                          /* this could cause problems if actions come in misnumbered */
1423
1424                 snprintf(hdr, sizeof(hdr), "Cat-%06d", x);
1425                 cat = astman_get_header(m, hdr);
1426                 if (ast_strlen_zero(cat)) {             /* every action needs a category */
1427                         result =  UNSPECIFIED_CATEGORY;
1428                         break;
1429                 }
1430
1431                 snprintf(hdr, sizeof(hdr), "Var-%06d", x);
1432                 var = astman_get_header(m, hdr);
1433
1434                 snprintf(hdr, sizeof(hdr), "Value-%06d", x);
1435                 value = astman_get_header(m, hdr);
1436
1437                 if (!ast_strlen_zero(value) && *value == '>') {
1438                         object = 1;
1439                         value++;
1440                 }
1441
1442                 snprintf(hdr, sizeof(hdr), "Match-%06d", x);
1443                 match = astman_get_header(m, hdr);
1444
1445                 snprintf(hdr, sizeof(hdr), "Line-%06d", x);
1446                 line = astman_get_header(m, hdr);
1447
1448                 if (!strcasecmp(action, "newcat")) {
1449                         if (ast_category_get(cfg,cat)) {        /* check to make sure the cat doesn't */
1450                                 result = FAILURE_NEWCAT;        /* already exist */
1451                                 break;
1452                         }
1453                         if (!(category = ast_category_new(cat, dfn, -1))) {
1454                                 result = FAILURE_ALLOCATION;
1455                                 break;
1456                         }
1457                         if (ast_strlen_zero(match)) {
1458                                 ast_category_append(cfg, category);
1459                         } else {
1460                                 ast_category_insert(cfg, category, match);
1461                         }
1462                 } else if (!strcasecmp(action, "renamecat")) {
1463                         if (ast_strlen_zero(value)) {
1464                                 result = UNSPECIFIED_ARGUMENT;
1465                                 break;
1466                         }
1467                         if (!(category = ast_category_get(cfg, cat))) {
1468                                 result = UNKNOWN_CATEGORY;
1469                                 break;
1470                         }
1471                         ast_category_rename(category, value);
1472                 } else if (!strcasecmp(action, "delcat")) {
1473                         if (ast_category_delete(cfg, cat)) {
1474                                 result = FAILURE_DELCAT;
1475                                 break;
1476                         }
1477                 } else if (!strcasecmp(action, "emptycat")) {
1478                         if (ast_category_empty(cfg, cat)) {
1479                                 result = FAILURE_EMPTYCAT;
1480                                 break;
1481                         }
1482                 } else if (!strcasecmp(action, "update")) {
1483                         if (ast_strlen_zero(var)) {
1484                                 result = UNSPECIFIED_ARGUMENT;
1485                                 break;
1486                         }
1487                         if (!(category = ast_category_get(cfg,cat))) {
1488                                 result = UNKNOWN_CATEGORY;
1489                                 break;
1490                         }
1491                         if (ast_variable_update(category, var, value, match, object)) {
1492                                 result = FAILURE_UPDATE;
1493                                 break;
1494                         }
1495                 } else if (!strcasecmp(action, "delete")) {
1496                         if ((ast_strlen_zero(var) && ast_strlen_zero(line))) {
1497                                 result = UNSPECIFIED_ARGUMENT;
1498                                 break;
1499                         }
1500                         if (!(category = ast_category_get(cfg, cat))) {
1501                                 result = UNKNOWN_CATEGORY;
1502                                 break;
1503                         }
1504                         if (ast_variable_delete(category, var, match, line)) {
1505                                 result = FAILURE_DELETE;
1506                                 break;
1507                         }
1508                 } else if (!strcasecmp(action, "append")) {
1509                         if (ast_strlen_zero(var)) {
1510                                 result = UNSPECIFIED_ARGUMENT;
1511                                 break;
1512                         }
1513                         if (!(category = ast_category_get(cfg, cat))) {
1514                                 result = UNKNOWN_CATEGORY;
1515                                 break;
1516                         }
1517                         if (!(v = ast_variable_new(var, value, dfn))) {
1518                                 result = FAILURE_ALLOCATION;
1519                                 break;
1520                         }
1521                         if (object || (match && !strcasecmp(match, "object"))) {
1522                                 v->object = 1;
1523                         }
1524                         ast_variable_append(category, v);
1525                 } else if (!strcasecmp(action, "insert")) {
1526                         if (ast_strlen_zero(var) || ast_strlen_zero(line)) {
1527                                 result = UNSPECIFIED_ARGUMENT;
1528                                 break;
1529                         }
1530                         if (!(category = ast_category_get(cfg, cat))) {
1531                                 result = UNKNOWN_CATEGORY;
1532                                 break;
1533                         }
1534                         if (!(v = ast_variable_new(var, value, dfn))) {
1535                                 result = FAILURE_ALLOCATION;
1536                                 break;
1537                         }
1538                         ast_variable_insert(category, v, line);
1539                 }
1540                 else {
1541                         ast_log(LOG_WARNING, "Action-%06d: %s not handled\n", x, action);
1542                         result = UNKNOWN_ACTION;
1543                         break;
1544                 }
1545         }
1546         ast_free(str1);
1547         ast_free(str2);
1548         return result;
1549 }
1550
1551 static char mandescr_updateconfig[] =
1552 "Description: A 'UpdateConfig' action will modify, create, or delete\n"
1553 "configuration elements in Asterisk configuration files.\n"
1554 "Variables (X's represent 6 digit number beginning with 000000):\n"
1555 "   SrcFilename:   Configuration filename to read(e.g. foo.conf)\n"
1556 "   DstFilename:   Configuration filename to write(e.g. foo.conf)\n"
1557 "   Reload:        Whether or not a reload should take place (or name of specific module)\n"
1558 "   Action-XXXXXX: Action to Take (NewCat,RenameCat,DelCat,EmptyCat,Update,Delete,Append,Insert)\n"
1559 "   Cat-XXXXXX:    Category to operate on\n"
1560 "   Var-XXXXXX:    Variable to work on\n"
1561 "   Value-XXXXXX:  Value to work on\n"
1562 "   Match-XXXXXX:  Extra match required to match line\n"
1563 "   Line-XXXXXX:   Line in category to operate on (used with delete and insert actions)\n";
1564
1565 static int action_updateconfig(struct mansession *s, const struct message *m)
1566 {
1567         struct ast_config *cfg;
1568         const char *sfn = astman_get_header(m, "SrcFilename");
1569         const char *dfn = astman_get_header(m, "DstFilename");
1570         int res;
1571         const char *rld = astman_get_header(m, "Reload");
1572         struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS | CONFIG_FLAG_NOCACHE };
1573         enum error_type result;
1574
1575         if (ast_strlen_zero(sfn) || ast_strlen_zero(dfn)) {
1576                 astman_send_error(s, m, "Filename not specified");
1577                 return 0;
1578         }
1579         if (!(cfg = ast_config_load2(sfn, "manager", config_flags))) {
1580                 astman_send_error(s, m, "Config file not found");
1581                 return 0;
1582         }
1583         result = handle_updates(s, m, cfg, dfn);
1584         if (!result) {
1585                 ast_include_rename(cfg, sfn, dfn); /* change the include references from dfn to sfn, so things match up */
1586                 res = ast_config_text_file_save(dfn, cfg, "Manager");
1587                 ast_config_destroy(cfg);
1588                 if (res) {
1589                         astman_send_error(s, m, "Save of config failed");
1590                         return 0;
1591                 }
1592                 astman_send_ack(s, m, NULL);
1593                 if (!ast_strlen_zero(rld)) {
1594                         if (ast_true(rld)) {
1595                                 rld = NULL;
1596                         }
1597                         ast_module_reload(rld);
1598                 }
1599         } else {
1600                 ast_config_destroy(cfg);
1601                 switch(result) {
1602                 case UNKNOWN_ACTION:
1603                         astman_send_error(s, m, "Unknown action command");
1604                         break;
1605                 case UNKNOWN_CATEGORY:
1606                         astman_send_error(s, m, "Given category does not exist");
1607                         break;
1608                 case UNSPECIFIED_CATEGORY:
1609                         astman_send_error(s, m, "Category not specified");
1610                         break;
1611                 case UNSPECIFIED_ARGUMENT:
1612                         astman_send_error(s, m, "Problem with category, value, or line (if required)");
1613                         break;
1614                 case FAILURE_ALLOCATION:
1615                         astman_send_error(s, m, "Memory allocation failure, this should not happen");
1616                         break;
1617                 case FAILURE_NEWCAT:
1618                         astman_send_error(s, m, "Create category did not complete successfully");
1619                         break;
1620                 case FAILURE_DELCAT:
1621                         astman_send_error(s, m, "Delete category did not complete successfully");
1622                         break;
1623                 case FAILURE_EMPTYCAT:
1624                         astman_send_error(s, m, "Empty category did not complete successfully");
1625                         break;
1626                 case FAILURE_UPDATE:
1627                         astman_send_error(s, m, "Update did not complete successfully");
1628                         break;
1629                 case FAILURE_DELETE:
1630                         astman_send_error(s, m, "Delete did not complete successfully");
1631                         break;
1632                 case FAILURE_APPEND:
1633                         astman_send_error(s, m, "Append did not complete successfully");
1634                         break;
1635                 }
1636         }
1637         return 0;
1638 }
1639
1640 static char mandescr_createconfig[] =
1641 "Description: A 'CreateConfig' action will create an empty file in the\n"
1642 "configuration directory. This action is intended to be used before an\n"
1643 "UpdateConfig action.\n"
1644 "Variables\n"
1645 "   Filename:   The configuration filename to create (e.g. foo.conf)\n";
1646
1647 static int action_createconfig(struct mansession *s, const struct message *m)
1648 {
1649         int fd;
1650         const char *fn = astman_get_header(m, "Filename");
1651         struct ast_str *filepath = ast_str_alloca(PATH_MAX);
1652         ast_str_set(&filepath, 0, "%s/", ast_config_AST_CONFIG_DIR);
1653         ast_str_append(&filepath, 0, "%s", fn);
1654
1655         if ((fd = open(ast_str_buffer(filepath), O_CREAT | O_EXCL, AST_FILE_MODE)) != -1) {
1656                 close(fd);
1657                 astman_send_ack(s, m, "New configuration file created successfully");
1658         } else {
1659                 astman_send_error(s, m, strerror(errno));
1660         }
1661
1662         return 0;
1663 }
1664
1665 /*! \brief Manager WAITEVENT */
1666 static char mandescr_waitevent[] =
1667 "Description: A 'WaitEvent' action will ellicit a 'Success' response.  Whenever\n"
1668 "a manager event is queued.  Once WaitEvent has been called on an HTTP manager\n"
1669 "session, events will be generated and queued.\n"
1670 "Variables: \n"
1671 "   Timeout: Maximum time (in seconds) to wait for events, -1 means forever.\n";
1672
1673 static int action_waitevent(struct mansession *s, const struct message *m)
1674 {
1675         const char *timeouts = astman_get_header(m, "Timeout");
1676         int timeout = -1;
1677         int x;
1678         int needexit = 0;
1679         const char *id = astman_get_header(m, "ActionID");
1680         char idText[256];
1681
1682         if (!ast_strlen_zero(id)) {
1683                 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
1684         } else {
1685                 idText[0] = '\0';
1686         }
1687
1688         if (!ast_strlen_zero(timeouts)) {
1689                 sscanf(timeouts, "%i", &timeout);
1690                 if (timeout < -1) {
1691                         timeout = -1;
1692                 }
1693                 /* XXX maybe put an upper bound, or prevent the use of 0 ? */
1694         }
1695
1696         ao2_lock(s);
1697         if (s->session->waiting_thread != AST_PTHREADT_NULL) {
1698                 pthread_kill(s->session->waiting_thread, SIGURG);
1699         }
1700
1701         if (s->session->managerid) { /* AMI-over-HTTP session */
1702                 /*
1703                  * Make sure the timeout is within the expire time of the session,
1704                  * as the client will likely abort the request if it does not see
1705                  * data coming after some amount of time.
1706                  */
1707                 time_t now = time(NULL);
1708                 int max = s->session->sessiontimeout - now - 10;
1709
1710                 if (max < 0) {  /* We are already late. Strange but possible. */
1711                         max = 0;
1712                 }
1713                 if (timeout < 0 || timeout > max) {
1714                         timeout = max;
1715                 }
1716                 if (!s->session->send_events) { /* make sure we record events */
1717                         s->session->send_events = -1;
1718                 }
1719         }
1720         ao2_unlock(s);
1721
1722         /* XXX should this go inside the lock ? */
1723         s->session->waiting_thread = pthread_self();    /* let new events wake up this thread */
1724         ast_debug(1, "Starting waiting for an event!\n");
1725
1726         for (x = 0; x < timeout || timeout < 0; x++) {
1727                 ao2_lock(s);
1728                 if (NEW_EVENT(s)) {
1729                         needexit = 1;
1730                 }
1731                 /* We can have multiple HTTP session point to the same mansession entry.
1732                  * The way we deal with it is not very nice: newcomers kick out the previous
1733                  * HTTP session. XXX this needs to be improved.
1734                  */
1735                 if (s->session->waiting_thread != pthread_self()) {
1736                         needexit = 1;
1737                 }
1738                 if (s->session->needdestroy) {
1739                         needexit = 1;
1740                 }
1741                 ao2_unlock(s);
1742                 if (needexit) {
1743                         break;
1744                 }
1745                 if (s->session->managerid == 0) {       /* AMI session */
1746                         if (ast_wait_for_input(s->session->fd, 1000)) {
1747                                 break;
1748                         }
1749                 } else {        /* HTTP session */
1750                         sleep(1);
1751                 }
1752         }
1753         ast_debug(1, "Finished waiting for an event!\n");
1754
1755         ao2_lock(s);
1756         if (s->session->waiting_thread == pthread_self()) {
1757                 struct eventqent *eqe;
1758                 astman_send_response(s, m, "Success", "Waiting for Event completed.");
1759                 while ( (eqe = NEW_EVENT(s)) ) {
1760                         ref_event(eqe);
1761                         if (((s->session->readperm & eqe->category) == eqe->category) &&
1762                             ((s->session->send_events & eqe->category) == eqe->category)) {
1763                                 astman_append(s, "%s", eqe->eventdata);
1764                         }
1765                         s->session->last_ev = unref_event(s->session->last_ev);
1766                 }
1767                 astman_append(s,
1768                         "Event: WaitEventComplete\r\n"
1769                         "%s"
1770                         "\r\n", idText);
1771                 s->session->waiting_thread = AST_PTHREADT_NULL;
1772         } else {
1773                 ast_debug(1, "Abandoning event request!\n");
1774         }
1775         ao2_unlock(s);
1776         return 0;
1777 }
1778
1779 static char mandescr_listcommands[] =
1780 "Description: Returns the action name and synopsis for every\n"
1781 "  action that is available to the user\n"
1782 "Variables: NONE\n";
1783
1784 /*! \note The actionlock is read-locked by the caller of this function */
1785 static int action_listcommands(struct mansession *s, const struct message *m)
1786 {
1787         struct manager_action *cur;
1788         struct ast_str *temp = ast_str_alloca(BUFSIZ); /* XXX very large ? */
1789
1790         astman_start_ack(s, m);
1791         AST_RWLIST_TRAVERSE(&actions, cur, list) {
1792                 if (s->session->writeperm & cur->authority || cur->authority == 0) {
1793                         astman_append(s, "%s: %s (Priv: %s)\r\n",
1794                                 cur->action, cur->synopsis, authority_to_str(cur->authority, &temp));
1795                 }
1796         }
1797         astman_append(s, "\r\n");
1798
1799         return 0;
1800 }
1801
1802 static char mandescr_events[] =
1803 "Description: Enable/Disable sending of events to this manager\n"
1804 "  client.\n"
1805 "Variables:\n"
1806 "       EventMask: 'on' if all events should be sent,\n"
1807 "               'off' if no events should be sent,\n"
1808 "               'system,call,log' to select which flags events should have to be sent.\n";
1809
1810 static int action_events(struct mansession *s, const struct message *m)
1811 {
1812         const char *mask = astman_get_header(m, "EventMask");
1813         int res;
1814
1815         res = set_eventmask(s, mask);
1816         if (res > 0)
1817                 astman_append(s, "Response: Success\r\n"
1818                                  "Events: On\r\n");
1819         else if (res == 0)
1820                 astman_append(s, "Response: Success\r\n"
1821                                  "Events: Off\r\n");
1822         return 0;
1823 }
1824
1825 static char mandescr_logoff[] =
1826 "Description: Logoff this manager session\n"
1827 "Variables: NONE\n";
1828
1829 static int action_logoff(struct mansession *s, const struct message *m)
1830 {
1831         astman_send_response(s, m, "Goodbye", "Thanks for all the fish.");
1832         return -1;
1833 }
1834
1835 static int action_login(struct mansession *s, const struct message *m)
1836 {
1837
1838         /* still authenticated - don't process again */
1839         if (s->session->authenticated) {
1840                 astman_send_ack(s, m, "Already authenticated");
1841                 return 0;
1842         }
1843
1844         if (authenticate(s, m)) {
1845                 sleep(1);
1846                 astman_send_error(s, m, "Authentication failed");
1847                 return -1;
1848         }
1849         s->session->authenticated = 1;
1850         if (manager_displayconnects(s->session)) {
1851                 ast_verb(2, "%sManager '%s' logged on from %s\n", (s->session->managerid ? "HTTP " : ""), s->session->username, ast_inet_ntoa(s->session->sin.sin_addr));
1852         }
1853         ast_log(LOG_EVENT, "%sManager '%s' logged on from %s\n", (s->session->managerid ? "HTTP " : ""), s->session->username, ast_inet_ntoa(s->session->sin.sin_addr));
1854         astman_send_ack(s, m, "Authentication accepted");
1855         return 0;
1856 }
1857
1858 static int action_challenge(struct mansession *s, const struct message *m)
1859 {
1860         const char *authtype = astman_get_header(m, "AuthType");
1861
1862         if (!strcasecmp(authtype, "MD5")) {
1863                 if (ast_strlen_zero(s->session->challenge)) {
1864                         snprintf(s->session->challenge, sizeof(s->session->challenge), "%ld", ast_random());
1865                 }
1866                 ao2_lock(s);
1867                 astman_start_ack(s, m);
1868                 astman_append(s, "Challenge: %s\r\n\r\n", s->session->challenge);
1869                 ao2_unlock(s);
1870         } else {
1871                 astman_send_error(s, m, "Must specify AuthType");
1872         }
1873         return 0;
1874 }
1875
1876 static char mandescr_hangup[] =
1877 "Description: Hangup a channel\n"
1878 "Variables: \n"
1879 "       Channel: The channel name to be hungup\n"
1880 "       Cause: numeric hangup cause\n";
1881
1882 static int action_hangup(struct mansession *s, const struct message *m)
1883 {
1884         struct ast_channel *c = NULL;
1885         int causecode = 0; /* all values <= 0 mean 'do not set hangupcause in channel' */
1886         const char *name = astman_get_header(m, "Channel");
1887         const char *cause = astman_get_header(m, "Cause");
1888
1889         if (ast_strlen_zero(name)) {
1890                 astman_send_error(s, m, "No channel specified");
1891                 return 0;
1892         }
1893
1894         if (!ast_strlen_zero(cause)) {
1895                 char *endptr;
1896                 causecode = strtol(cause, &endptr, 10);
1897                 if (causecode < 0 || causecode > 127 || *endptr != '\0') {
1898                         ast_log(LOG_NOTICE, "Invalid 'Cause: %s' in manager action Hangup\n", cause);
1899                         /* keep going, better to hangup without cause than to not hang up at all */
1900                         causecode = 0; /* do not set channel's hangupcause */
1901                 }
1902         }
1903
1904         if (!(c = ast_channel_get_by_name(name))) {
1905                 astman_send_error(s, m, "No such channel");
1906                 return 0;
1907         }
1908
1909         ast_channel_lock(c);
1910         if (causecode > 0) {
1911                 ast_debug(1, "Setting hangupcause of channel %s to %d (is %d now)\n",
1912                                 c->name, causecode, c->hangupcause);
1913                 c->hangupcause = causecode;
1914         }
1915         ast_softhangup_nolock(c, AST_SOFTHANGUP_EXPLICIT);
1916         ast_channel_unlock(c);
1917
1918         c = ast_channel_unref(c);
1919
1920         astman_send_ack(s, m, "Channel Hungup");
1921
1922         return 0;
1923 }
1924
1925 static char mandescr_setvar[] =
1926 "Description: Set a global or local channel variable.\n"
1927 "Variables: (Names marked with * are required)\n"
1928 "       Channel: Channel to set variable for\n"
1929 "       *Variable: Variable name\n"
1930 "       *Value: Value\n";
1931
1932 static int action_setvar(struct mansession *s, const struct message *m)
1933 {
1934         struct ast_channel *c = NULL;
1935         const char *name = astman_get_header(m, "Channel");
1936         const char *varname = astman_get_header(m, "Variable");
1937         const char *varval = astman_get_header(m, "Value");
1938
1939         if (ast_strlen_zero(varname)) {
1940                 astman_send_error(s, m, "No variable specified");
1941                 return 0;
1942         }
1943
1944         if (!ast_strlen_zero(name)) {
1945                 if (!(c = ast_channel_get_by_name(name))) {
1946                         astman_send_error(s, m, "No such channel");
1947                         return 0;
1948                 }
1949         }
1950
1951         pbx_builtin_setvar_helper(c, varname, S_OR(varval, ""));
1952
1953         if (c) {
1954                 c = ast_channel_unref(c);
1955         }
1956
1957         astman_send_ack(s, m, "Variable Set");
1958
1959         return 0;
1960 }
1961
1962 static char mandescr_getvar[] =
1963 "Description: Get the value of a global or local channel variable.\n"
1964 "Variables: (Names marked with * are required)\n"
1965 "       Channel: Channel to read variable from\n"
1966 "       *Variable: Variable name\n"
1967 "       ActionID: Optional Action id for message matching.\n";
1968
1969 static int action_getvar(struct mansession *s, const struct message *m)
1970 {
1971         struct ast_channel *c = NULL;
1972         const char *name = astman_get_header(m, "Channel");
1973         const char *varname = astman_get_header(m, "Variable");
1974         char *varval;
1975         char workspace[1024] = "";
1976
1977         if (ast_strlen_zero(varname)) {
1978                 astman_send_error(s, m, "No variable specified");
1979                 return 0;
1980         }
1981
1982         if (!ast_strlen_zero(name)) {
1983                 if (!(c = ast_channel_get_by_name(name))) {
1984                         astman_send_error(s, m, "No such channel");
1985                         return 0;
1986                 }
1987         }
1988
1989         if (varname[strlen(varname) - 1] == ')') {
1990                 if (!c) {
1991                         c = ast_channel_alloc(0, 0, "", "", "", "", "", 0, "Bogus/manager");
1992                         if (c) {
1993                                 ast_func_read(c, (char *) varname, workspace, sizeof(workspace));
1994                                 c = ast_channel_release(c);
1995                         } else
1996                                 ast_log(LOG_ERROR, "Unable to allocate bogus channel for variable substitution.  Function results may be blank.\n");
1997                 } else {
1998                         ast_func_read(c, (char *) varname, workspace, sizeof(workspace));
1999                 }
2000                 varval = workspace;
2001         } else {
2002                 pbx_retrieve_variable(c, varname, &varval, workspace, sizeof(workspace), NULL);
2003         }
2004
2005         if (c) {
2006                 c = ast_channel_unref(c);
2007         }
2008
2009         astman_start_ack(s, m);
2010         astman_append(s, "Variable: %s\r\nValue: %s\r\n\r\n", varname, varval);
2011
2012         return 0;
2013 }
2014
2015 static char mandescr_status[] =
2016 "Description: Lists channel status along with requested channel vars.\n"
2017 "Variables: (Names marked with * are required)\n"
2018 "       *Channel: Name of the channel to query for status\n"
2019 "       Variables: Comma ',' separated list of variables to include\n"
2020 "       ActionID: Optional ID for this transaction\n"
2021 "Will return the status information of each channel along with the\n"
2022 "value for the specified channel variables.\n";
2023
2024
2025 /*! \brief Manager "status" command to show channels */
2026 /* Needs documentation... */
2027 static int action_status(struct mansession *s, const struct message *m)
2028 {
2029         const char *name = astman_get_header(m, "Channel");
2030         const char *cvariables = astman_get_header(m, "Variables");
2031         char *variables = ast_strdupa(S_OR(cvariables, ""));
2032         struct ast_channel *c;
2033         char bridge[256];
2034         struct timeval now = ast_tvnow();
2035         long elapsed_seconds = 0;
2036         int channels = 0;
2037         int all = ast_strlen_zero(name); /* set if we want all channels */
2038         const char *id = astman_get_header(m, "ActionID");
2039         char idText[256];
2040         AST_DECLARE_APP_ARGS(vars,
2041                 AST_APP_ARG(name)[100];
2042         );
2043         struct ast_str *str = ast_str_create(1000);
2044         struct ast_channel_iterator *iter = NULL;
2045
2046         if (!ast_strlen_zero(id)) {
2047                 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
2048         } else {
2049                 idText[0] = '\0';
2050         }
2051
2052         if (all) {
2053                 if (!(iter = ast_channel_iterator_all_new(0))) {
2054                         ast_free(str);
2055                         astman_send_error(s, m, "Memory Allocation Failure");
2056                         return 1;
2057                 }
2058                 c = ast_channel_iterator_next(iter);
2059         } else {
2060                 if (!(c = ast_channel_get_by_name(name))) {
2061                         astman_send_error(s, m, "No such channel");
2062                         ast_free(str);
2063                         return 0;
2064                 }
2065         }
2066
2067         astman_send_ack(s, m, "Channel status will follow");
2068
2069         if (!ast_strlen_zero(cvariables)) {
2070                 AST_STANDARD_APP_ARGS(vars, variables);
2071         }
2072
2073         /* if we look by name, we break after the first iteration */
2074         for (; c; c = ast_channel_iterator_next(iter)) {
2075                 ast_channel_lock(c);
2076
2077                 if (!ast_strlen_zero(cvariables)) {
2078                         int i;
2079                         ast_str_reset(str);
2080                         for (i = 0; i < vars.argc; i++) {
2081                                 char valbuf[512], *ret = NULL;
2082
2083                                 if (vars.name[i][strlen(vars.name[i]) - 1] == ')') {
2084                                         if (ast_func_read(c, vars.name[i], valbuf, sizeof(valbuf)) < 0) {
2085                                                 valbuf[0] = '\0';
2086                                         }
2087                                         ret = valbuf;
2088                                 } else {
2089                                         pbx_retrieve_variable(c, vars.name[i], &ret, valbuf, sizeof(valbuf), NULL);
2090                                 }
2091
2092                                 ast_str_append(&str, 0, "Variable: %s=%s\r\n", vars.name[i], ret);
2093                         }
2094                 }
2095
2096                 channels++;
2097                 if (c->_bridge) {
2098                         snprintf(bridge, sizeof(bridge), "BridgedChannel: %s\r\nBridgedUniqueid: %s\r\n", c->_bridge->name, c->_bridge->uniqueid);
2099                 } else {
2100                         bridge[0] = '\0';
2101                 }
2102                 if (c->pbx) {
2103                         if (c->cdr) {
2104                                 elapsed_seconds = now.tv_sec - c->cdr->start.tv_sec;
2105                         }
2106                         astman_append(s,
2107                         "Event: Status\r\n"
2108                         "Privilege: Call\r\n"
2109                         "Channel: %s\r\n"
2110                         "CallerIDNum: %s\r\n"
2111                         "CallerIDName: %s\r\n"
2112                         "Accountcode: %s\r\n"
2113                         "ChannelState: %d\r\n"
2114                         "ChannelStateDesc: %s\r\n"
2115                         "Context: %s\r\n"
2116                         "Extension: %s\r\n"
2117                         "Priority: %d\r\n"
2118                         "Seconds: %ld\r\n"
2119                         "%s"
2120                         "Uniqueid: %s\r\n"
2121                         "%s"
2122                         "%s"
2123                         "\r\n",
2124                         c->name,
2125                         S_OR(c->cid.cid_num, ""),
2126                         S_OR(c->cid.cid_name, ""),
2127                         c->accountcode,
2128                         c->_state,
2129                         ast_state2str(c->_state), c->context,
2130                         c->exten, c->priority, (long)elapsed_seconds, bridge, c->uniqueid, ast_str_buffer(str), idText);
2131                 } else {
2132                         astman_append(s,
2133                                 "Event: Status\r\n"
2134                                 "Privilege: Call\r\n"
2135                                 "Channel: %s\r\n"
2136                                 "CallerIDNum: %s\r\n"
2137                                 "CallerIDName: %s\r\n"
2138                                 "Account: %s\r\n"
2139                                 "State: %s\r\n"
2140                                 "%s"
2141                                 "Uniqueid: %s\r\n"
2142                                 "%s"
2143                                 "%s"
2144                                 "\r\n",
2145                                 c->name,
2146                                 S_OR(c->cid.cid_num, "<unknown>"),
2147                                 S_OR(c->cid.cid_name, "<unknown>"),
2148                                 c->accountcode,
2149                                 ast_state2str(c->_state), bridge, c->uniqueid,
2150                                 ast_str_buffer(str), idText);
2151                 }
2152
2153                 ast_channel_unlock(c);
2154                 c = ast_channel_unref(c);
2155
2156                 if (!all) {
2157                         break;
2158                 }
2159         }
2160
2161         astman_append(s,
2162                 "Event: StatusComplete\r\n"
2163                 "%s"
2164                 "Items: %d\r\n"
2165                 "\r\n", idText, channels);
2166
2167         ast_free(str);
2168
2169         return 0;
2170 }
2171
2172 static char mandescr_sendtext[] =
2173 "Description: Sends A Text Message while in a call.\n"
2174 "Variables: (Names marked with * are required)\n"
2175 "       *Channel: Channel to send message to\n"
2176 "       *Message: Message to send\n"
2177 "       ActionID: Optional Action id for message matching.\n";
2178
2179 static int action_sendtext(struct mansession *s, const struct message *m)
2180 {
2181         struct ast_channel *c = NULL;
2182         const char *name = astman_get_header(m, "Channel");
2183         const char *textmsg = astman_get_header(m, "Message");
2184         int res = 0;
2185
2186         if (ast_strlen_zero(name)) {
2187                 astman_send_error(s, m, "No channel specified");
2188                 return 0;
2189         }
2190
2191         if (ast_strlen_zero(textmsg)) {
2192                 astman_send_error(s, m, "No Message specified");
2193                 return 0;
2194         }
2195
2196         if (!(c = ast_channel_get_by_name(name))) {
2197                 astman_send_error(s, m, "No such channel");
2198                 return 0;
2199         }
2200
2201         ast_channel_lock(c);
2202         res = ast_sendtext(c, textmsg);
2203         ast_channel_unlock(c);
2204         c = ast_channel_unref(c);
2205
2206         if (res > 0) {
2207                 astman_send_ack(s, m, "Success");
2208         } else {
2209                 astman_send_error(s, m, "Failure");
2210         }
2211
2212         return res;
2213 }
2214
2215 static char mandescr_redirect[] =
2216 "Description: Redirect (transfer) a call.\n"
2217 "Variables: (Names marked with * are required)\n"
2218 "       *Channel: Channel to redirect\n"
2219 "       ExtraChannel: Second call leg to transfer (optional)\n"
2220 "       *Exten: Extension to transfer to\n"
2221 "       *Context: Context to transfer to\n"
2222 "       *Priority: Priority to transfer to\n"
2223 "       ActionID: Optional Action id for message matching.\n";
2224
2225 /*! \brief  action_redirect: The redirect manager command */
2226 static int action_redirect(struct mansession *s, const struct message *m)
2227 {
2228         const char *name = astman_get_header(m, "Channel");
2229         const char *name2 = astman_get_header(m, "ExtraChannel");
2230         const char *exten = astman_get_header(m, "Exten");
2231         const char *context = astman_get_header(m, "Context");
2232         const char *priority = astman_get_header(m, "Priority");
2233         struct ast_channel *chan, *chan2 = NULL;
2234         int pi = 0;
2235         int res;
2236
2237         if (ast_strlen_zero(name)) {
2238                 astman_send_error(s, m, "Channel not specified");
2239                 return 0;
2240         }
2241
2242         if (!ast_strlen_zero(priority) && (sscanf(priority, "%d", &pi) != 1)) {
2243                 if ((pi = ast_findlabel_extension(NULL, context, exten, priority, NULL)) < 1) {
2244                         astman_send_error(s, m, "Invalid priority");
2245                         return 0;
2246                 }
2247         }
2248
2249         if (!(chan = ast_channel_get_by_name(name))) {
2250                 char buf[256];
2251                 snprintf(buf, sizeof(buf), "Channel does not exist: %s", name);
2252                 astman_send_error(s, m, buf);
2253                 return 0;
2254         }
2255
2256         if (ast_check_hangup_locked(chan)) {
2257                 astman_send_error(s, m, "Redirect failed, channel not up.");
2258                 chan = ast_channel_unref(chan);
2259                 return 0;
2260         }
2261
2262         if (!ast_strlen_zero(name2)) {
2263                 chan2 = ast_channel_get_by_name(name2);
2264         }
2265
2266         if (chan2 && ast_check_hangup_locked(chan2)) {
2267                 astman_send_error(s, m, "Redirect failed, extra channel not up.");
2268                 chan = ast_channel_unref(chan);
2269                 chan2 = ast_channel_unref(chan2);
2270                 return 0;
2271         }
2272
2273         if (chan->pbx) {
2274                 ast_channel_lock(chan);
2275                 ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_DONT); /* don't let the after-bridge code run the h-exten */
2276                 ast_channel_unlock(chan);
2277         }
2278
2279         res = ast_async_goto(chan, context, exten, pi);
2280         if (!res) {
2281                 if (!ast_strlen_zero(name2)) {
2282                         if (chan2) {
2283                                 if (chan2->pbx) {
2284                                         ast_channel_lock(chan2);
2285                                         ast_set_flag(chan2, AST_FLAG_BRIDGE_HANGUP_DONT); /* don't let the after-bridge code run the h-exten */
2286                                         ast_channel_unlock(chan2);
2287                                 }
2288                                 res = ast_async_goto(chan2, context, exten, pi);
2289                         } else {
2290                                 res = -1;
2291                         }
2292                         if (!res) {
2293                                 astman_send_ack(s, m, "Dual Redirect successful");
2294                         } else {
2295                                 astman_send_error(s, m, "Secondary redirect failed");
2296                         }
2297                 } else {
2298                         astman_send_ack(s, m, "Redirect successful");
2299                 }
2300         } else {
2301                 astman_send_error(s, m, "Redirect failed");
2302         }
2303
2304         if (chan) {
2305                 chan = ast_channel_unref(chan);
2306         }
2307
2308         if (chan2) {
2309                 chan2 = ast_channel_unref(chan2);
2310         }
2311
2312         return 0;
2313 }
2314
2315 static char mandescr_atxfer[] =
2316 "Description: Attended transfer.\n"
2317 "Variables: (Names marked with * are required)\n"
2318 "       *Channel: Transferer's channel\n"
2319 "       *Exten: Extension to transfer to\n"
2320 "       *Context: Context to transfer to\n"
2321 "       *Priority: Priority to transfer to\n"
2322 "       ActionID: Optional Action id for message matching.\n";
2323
2324 static int action_atxfer(struct mansession *s, const struct message *m)
2325 {
2326         const char *name = astman_get_header(m, "Channel");
2327         const char *exten = astman_get_header(m, "Exten");
2328         const char *context = astman_get_header(m, "Context");
2329         struct ast_channel *chan = NULL;
2330         struct ast_call_feature *atxfer_feature = NULL;
2331         char *feature_code = NULL;
2332
2333         if (ast_strlen_zero(name)) {
2334                 astman_send_error(s, m, "No channel specified");
2335                 return 0;
2336         }
2337         if (ast_strlen_zero(exten)) {
2338                 astman_send_error(s, m, "No extension specified");
2339                 return 0;
2340         }
2341
2342         if (!(atxfer_feature = ast_find_call_feature("atxfer"))) {
2343                 astman_send_error(s, m, "No attended transfer feature found");
2344                 return 0;
2345         }
2346
2347         if (!(chan = ast_channel_get_by_name(name))) {
2348                 astman_send_error(s, m, "Channel specified does not exist");
2349                 return 0;
2350         }
2351
2352         if (!ast_strlen_zero(context)) {
2353                 pbx_builtin_setvar_helper(chan, "TRANSFER_CONTEXT", context);
2354         }
2355
2356         for (feature_code = atxfer_feature->exten; feature_code && *feature_code; ++feature_code) {
2357                 struct ast_frame f = { AST_FRAME_DTMF, *feature_code };
2358                 ast_queue_frame(chan, &f);
2359         }
2360
2361         for (feature_code = (char *)exten; feature_code && *feature_code; ++feature_code) {
2362                 struct ast_frame f = { AST_FRAME_DTMF, *feature_code };
2363                 ast_queue_frame(chan, &f);
2364         }
2365
2366         chan = ast_channel_unref(chan);
2367
2368         astman_send_ack(s, m, "Atxfer successfully queued");
2369
2370         return 0;
2371 }
2372
2373 static int check_blacklist(const char *cmd)
2374 {
2375         char *cmd_copy, *cur_cmd;
2376         char *cmd_words[MAX_BLACKLIST_CMD_LEN] = { NULL, };
2377         int i;
2378
2379         cmd_copy = ast_strdupa(cmd);
2380         for (i = 0; i < MAX_BLACKLIST_CMD_LEN && (cur_cmd = strsep(&cmd_copy, " ")); i++) {
2381                 cur_cmd = ast_strip(cur_cmd);
2382                 if (ast_strlen_zero(cur_cmd)) {
2383                         i--;
2384                         continue;
2385                 }
2386
2387                 cmd_words[i] = cur_cmd;
2388         }
2389
2390         for (i = 0; i < ARRAY_LEN(command_blacklist); i++) {
2391                 int j, match = 1;
2392
2393                 for (j = 0; command_blacklist[i].words[j]; j++) {
2394                         if (ast_strlen_zero(cmd_words[j]) || strcasecmp(cmd_words[j], command_blacklist[i].words[j])) {
2395                                 match = 0;
2396                                 break;
2397                         }
2398                 }
2399
2400                 if (match) {
2401                         return 1;
2402                 }
2403         }
2404
2405         return 0;
2406 }
2407
2408 static char mandescr_command[] =
2409 "Description: Run a CLI command.\n"
2410 "Variables: (Names marked with * are required)\n"
2411 "       *Command: Asterisk CLI command to run\n"
2412 "       ActionID: Optional Action id for message matching.\n";
2413
2414 /*! \brief  Manager command "command" - execute CLI command */
2415 static int action_command(struct mansession *s, const struct message *m)
2416 {
2417         const char *cmd = astman_get_header(m, "Command");
2418         const char *id = astman_get_header(m, "ActionID");
2419         char *buf, *final_buf;
2420         char template[] = "/tmp/ast-ami-XXXXXX";        /* template for temporary file */
2421         int fd = mkstemp(template);
2422         off_t l;
2423
2424         if (ast_strlen_zero(cmd)) {
2425                 astman_send_error(s, m, "No command provided");
2426                 return 0;
2427         }
2428
2429         if (check_blacklist(cmd)) {
2430                 astman_send_error(s, m, "Command blacklisted");
2431                 return 0;
2432         }
2433
2434         astman_append(s, "Response: Follows\r\nPrivilege: Command\r\n");
2435         if (!ast_strlen_zero(id)) {
2436                 astman_append(s, "ActionID: %s\r\n", id);
2437         }
2438         /* FIXME: Wedge a ActionID response in here, waiting for later changes */
2439         ast_cli_command(fd, cmd);       /* XXX need to change this to use a FILE * */
2440         l = lseek(fd, 0, SEEK_END);     /* how many chars available */
2441
2442         /* This has a potential to overflow the stack.  Hence, use the heap. */
2443         buf = ast_calloc(1, l + 1);
2444         final_buf = ast_calloc(1, l + 1);
2445         if (buf) {
2446                 lseek(fd, 0, SEEK_SET);
2447                 if (read(fd, buf, l) < 0) {
2448                         ast_log(LOG_WARNING, "read() failed: %s\n", strerror(errno));
2449                 }
2450                 buf[l] = '\0';
2451                 if (final_buf) {
2452                         term_strip(final_buf, buf, l);
2453                         final_buf[l] = '\0';
2454                 }
2455                 astman_append(s, "%s", S_OR(final_buf, buf));
2456                 ast_free(buf);
2457         }
2458         close(fd);
2459         unlink(template);
2460         astman_append(s, "--END COMMAND--\r\n\r\n");
2461         if (final_buf) {
2462                 ast_free(final_buf);
2463         }
2464         return 0;
2465 }
2466
2467 /*! \brief helper function for originate */
2468 struct fast_originate_helper {
2469         char tech[AST_MAX_EXTENSION];
2470         /*! data can contain a channel name, extension number, username, password, etc. */
2471         char data[512];
2472         int timeout;
2473         int format;                             /*!< Codecs used for a call */
2474         char app[AST_MAX_APP];
2475         char appdata[AST_MAX_EXTENSION];
2476         char cid_name[AST_MAX_EXTENSION];
2477         char cid_num[AST_MAX_EXTENSION];
2478         char context[AST_MAX_CONTEXT];
2479         char exten[AST_MAX_EXTENSION];
2480         char idtext[AST_MAX_EXTENSION];
2481         char account[AST_MAX_ACCOUNT_CODE];
2482         int priority;
2483         struct ast_variable *vars;
2484 };
2485
2486 static void *fast_originate(void *data)
2487 {
2488         struct fast_originate_helper *in = data;
2489         int res;
2490         int reason = 0;
2491         struct ast_channel *chan = NULL;
2492         char requested_channel[AST_CHANNEL_NAME];
2493
2494         if (!ast_strlen_zero(in->app)) {
2495                 res = ast_pbx_outgoing_app(in->tech, in->format, in->data, in->timeout, in->app, in->appdata, &reason, 1,
2496                         S_OR(in->cid_num, NULL),
2497                         S_OR(in->cid_name, NULL),
2498                         in->vars, in->account, &chan);
2499         } else {
2500                 res = ast_pbx_outgoing_exten(in->tech, in->format, in->data, in->timeout, in->context, in->exten, in->priority, &reason, 1,
2501                         S_OR(in->cid_num, NULL),
2502                         S_OR(in->cid_name, NULL),
2503                         in->vars, in->account, &chan);
2504         }
2505
2506         if (!chan) {
2507                 snprintf(requested_channel, AST_CHANNEL_NAME, "%s/%s", in->tech, in->data);
2508         }
2509         /* Tell the manager what happened with the channel */
2510         manager_event(EVENT_FLAG_CALL, "OriginateResponse",
2511                 "%s%s"
2512                 "Response: %s\r\n"
2513                 "Channel: %s\r\n"
2514                 "Context: %s\r\n"
2515                 "Exten: %s\r\n"
2516                 "Reason: %d\r\n"
2517                 "Uniqueid: %s\r\n"
2518                 "CallerIDNum: %s\r\n"
2519                 "CallerIDName: %s\r\n",
2520                 in->idtext, ast_strlen_zero(in->idtext) ? "" : "\r\n", res ? "Failure" : "Success",
2521                 chan ? chan->name : requested_channel, in->context, in->exten, reason,
2522                 chan ? chan->uniqueid : "<null>",
2523                 S_OR(in->cid_num, "<unknown>"),
2524                 S_OR(in->cid_name, "<unknown>")
2525                 );
2526
2527         /* Locked by ast_pbx_outgoing_exten or ast_pbx_outgoing_app */
2528         if (chan) {
2529                 ast_channel_unlock(chan);
2530         }
2531         ast_free(in);
2532         return NULL;
2533 }
2534
2535 static char mandescr_originate[] =
2536 "Description: Generates an outgoing call to a Extension/Context/Priority or\n"
2537 "  Application/Data\n"
2538 "Variables: (Names marked with * are required)\n"
2539 "       *Channel: Channel name to call\n"
2540 "       Exten: Extension to use (requires 'Context' and 'Priority')\n"
2541 "       Context: Context to use (requires 'Exten' and 'Priority')\n"
2542 "       Priority: Priority to use (requires 'Exten' and 'Context')\n"
2543 "       Application: Application to use\n"
2544 "       Data: Data to use (requires 'Application')\n"
2545 "       Timeout: How long to wait for call to be answered (in ms)\n"
2546 "       CallerID: Caller ID to be set on the outgoing channel\n"
2547 "       Variable: Channel variable to set, multiple Variable: headers are allowed\n"
2548 "       Account: Account code\n"
2549 "       Async: Set to 'true' for fast origination\n";
2550
2551 static int action_originate(struct mansession *s, const struct message *m)
2552 {
2553         const char *name = astman_get_header(m, "Channel");
2554         const char *exten = astman_get_header(m, "Exten");
2555         const char *context = astman_get_header(m, "Context");
2556         const char *priority = astman_get_header(m, "Priority");
2557         const char *timeout = astman_get_header(m, "Timeout");
2558         const char *callerid = astman_get_header(m, "CallerID");
2559         const char *account = astman_get_header(m, "Account");
2560         const char *app = astman_get_header(m, "Application");
2561         const char *appdata = astman_get_header(m, "Data");
2562         const char *async = astman_get_header(m, "Async");
2563         const char *id = astman_get_header(m, "ActionID");
2564         const char *codecs = astman_get_header(m, "Codecs");
2565         struct ast_variable *vars = astman_get_variables(m);
2566         char *tech, *data;
2567         char *l = NULL, *n = NULL;
2568         int pi = 0;
2569         int res;
2570         int to = 30000;
2571         int reason = 0;
2572         char tmp[256];
2573         char tmp2[256];
2574         int format = AST_FORMAT_SLINEAR;
2575
2576         pthread_t th;
2577         if (ast_strlen_zero(name)) {
2578                 astman_send_error(s, m, "Channel not specified");
2579                 return 0;
2580         }
2581         if (!ast_strlen_zero(priority) && (sscanf(priority, "%d", &pi) != 1)) {
2582                 if ((pi = ast_findlabel_extension(NULL, context, exten, priority, NULL)) < 1) {
2583                         astman_send_error(s, m, "Invalid priority");
2584                         return 0;
2585                 }
2586         }
2587         if (!ast_strlen_zero(timeout) && (sscanf(timeout, "%d", &to) != 1)) {
2588                 astman_send_error(s, m, "Invalid timeout");
2589                 return 0;
2590         }
2591         ast_copy_string(tmp, name, sizeof(tmp));
2592         tech = tmp;
2593         data = strchr(tmp, '/');
2594         if (!data) {
2595                 astman_send_error(s, m, "Invalid channel");
2596                 return 0;
2597         }
2598         *data++ = '\0';
2599         ast_copy_string(tmp2, callerid, sizeof(tmp2));
2600         ast_callerid_parse(tmp2, &n, &l);
2601         if (n) {
2602                 if (ast_strlen_zero(n)) {
2603                         n = NULL;
2604                 }
2605         }
2606         if (l) {
2607                 ast_shrink_phone_number(l);
2608                 if (ast_strlen_zero(l)) {
2609                         l = NULL;
2610                 }
2611         }
2612         if (!ast_strlen_zero(codecs)) {
2613                 format = 0;
2614                 ast_parse_allow_disallow(NULL, &format, codecs, 1);
2615         }
2616         if (ast_true(async)) {
2617                 struct fast_originate_helper *fast = ast_calloc(1, sizeof(*fast));
2618                 if (!fast) {
2619                         res = -1;
2620                 } else {
2621                         if (!ast_strlen_zero(id))
2622                                 snprintf(fast->idtext, sizeof(fast->idtext), "ActionID: %s", id);
2623                         ast_copy_string(fast->tech, tech, sizeof(fast->tech));
2624                         ast_copy_string(fast->data, data, sizeof(fast->data));
2625                         ast_copy_string(fast->app, app, sizeof(fast->app));
2626                         ast_copy_string(fast->appdata, appdata, sizeof(fast->appdata));
2627                         if (l) {
2628                                 ast_copy_string(fast->cid_num, l, sizeof(fast->cid_num));
2629                         }
2630                         if (n) {
2631                                 ast_copy_string(fast->cid_name, n, sizeof(fast->cid_name));
2632                         }
2633                         fast->vars = vars;
2634                         ast_copy_string(fast->context, context, sizeof(fast->context));
2635                         ast_copy_string(fast->exten, exten, sizeof(fast->exten));
2636                         ast_copy_string(fast->account, account, sizeof(fast->account));
2637                         fast->format = format;
2638                         fast->timeout = to;
2639                         fast->priority = pi;
2640                         if (ast_pthread_create_detached(&th, NULL, fast_originate, fast)) {
2641                                 ast_free(fast);
2642                                 res = -1;
2643                         } else {
2644                                 res = 0;
2645                         }
2646                 }
2647         } else if (!ast_strlen_zero(app)) {
2648                 /* To run the System application (or anything else that goes to shell), you must have the additional System privilege */
2649                 if (!(s->session->writeperm & EVENT_FLAG_SYSTEM)
2650                         && (
2651                                 strcasestr(app, "system") == 0 || /* System(rm -rf /)
2652                                                                      TrySystem(rm -rf /)       */
2653                                 strcasestr(app, "exec") ||        /* Exec(System(rm -rf /))
2654                                                                      TryExec(System(rm -rf /)) */
2655                                 strcasestr(app, "agi") ||         /* AGI(/bin/rm,-rf /)
2656                                                                      EAGI(/bin/rm,-rf /)       */
2657                                 strstr(appdata, "SHELL") ||       /* NoOp(${SHELL(rm -rf /)})  */
2658                                 strstr(appdata, "EVAL")           /* NoOp(${EVAL(${some_var_containing_SHELL})}) */
2659                                 )) {
2660                         astman_send_error(s, m, "Originate with certain 'Application' arguments requires the additional System privilege, which you do not have.");
2661                         return 0;
2662                 }
2663                 res = ast_pbx_outgoing_app(tech, format, data, to, app, appdata, &reason, 1, l, n, vars, account, NULL);
2664         } else {
2665                 if (exten && context && pi) {
2666                         res = ast_pbx_outgoing_exten(tech, format, data, to, context, exten, pi, &reason, 1, l, n, vars, account, NULL);
2667                 } else {
2668                         astman_send_error(s, m, "Originate with 'Exten' requires 'Context' and 'Priority'");
2669                         return 0;
2670                 }
2671         }
2672         if (!res) {
2673                 astman_send_ack(s, m, "Originate successfully queued");
2674         } else {
2675                 astman_send_error(s, m, "Originate failed");
2676         }
2677         return 0;
2678 }
2679
2680 /*! \brief Help text for manager command mailboxstatus
2681  */
2682 static char mandescr_mailboxstatus[] =
2683 "Description: Checks a voicemail account for status.\n"
2684 "Variables: (Names marked with * are required)\n"
2685 "       *Mailbox: Full mailbox ID <mailbox>@<vm-context>\n"
2686 "       ActionID: Optional ActionID for message matching.\n"
2687 "Returns number of messages.\n"
2688 "       Message: Mailbox Status\n"
2689 "       Mailbox: <mailboxid>\n"
2690 "       Waiting: <count>\n"
2691 "\n";
2692
2693 static int action_mailboxstatus(struct mansession *s, const struct message *m)
2694 {
2695         const char *mailbox = astman_get_header(m, "Mailbox");
2696         int ret;
2697
2698         if (ast_strlen_zero(mailbox)) {
2699                 astman_send_error(s, m, "Mailbox not specified");
2700                 return 0;
2701         }
2702         ret = ast_app_has_voicemail(mailbox, NULL);
2703         astman_start_ack(s, m);
2704         astman_append(s, "Message: Mailbox Status\r\n"
2705                          "Mailbox: %s\r\n"
2706                          "Waiting: %d\r\n\r\n", mailbox, ret);
2707         return 0;
2708 }
2709
2710 static char mandescr_mailboxcount[] =
2711 "Description: Checks a voicemail account for new messages.\n"
2712 "Variables: (Names marked with * are required)\n"
2713 "       *Mailbox: Full mailbox ID <mailbox>@<vm-context>\n"
2714 "       ActionID: Optional ActionID for message matching.\n"
2715 "Returns number of urgent, new and old messages.\n"
2716 "       Message: Mailbox Message Count\n"
2717 "       Mailbox: <mailboxid>\n"
2718 "       UrgentMessages: <count>\n"
2719 "       NewMessages: <count>\n"
2720 "       OldMessages: <count>\n"
2721 "\n";
2722 static int action_mailboxcount(struct mansession *s, const struct message *m)
2723 {
2724         const char *mailbox = astman_get_header(m, "Mailbox");
2725         int newmsgs = 0, oldmsgs = 0, urgentmsgs = 0;;
2726
2727         if (ast_strlen_zero(mailbox)) {
2728                 astman_send_error(s, m, "Mailbox not specified");
2729                 return 0;
2730         }
2731         ast_app_inboxcount2(mailbox, &urgentmsgs, &newmsgs, &oldmsgs);
2732         astman_start_ack(s, m);
2733         astman_append(s,   "Message: Mailbox Message Count\r\n"
2734                            "Mailbox: %s\r\n"
2735                            "UrgMessages: %d\r\n"
2736                            "NewMessages: %d\r\n"
2737                            "OldMessages: %d\r\n"
2738                            "\r\n",
2739                            mailbox, urgentmsgs, newmsgs, oldmsgs);
2740         return 0;
2741 }
2742
2743 static char mandescr_extensionstate[] =
2744 "Description: Report the extension state for given extension.\n"
2745 "  If the extension has a hint, will use devicestate to check\n"
2746 "  the status of the device connected to the extension.\n"
2747 "Variables: (Names marked with * are required)\n"
2748 "       *Exten: Extension to check state on\n"
2749 "       *Context: Context for extension\n"
2750 "       ActionId: Optional ID for this transaction\n"
2751 "Will return an \"Extension Status\" message.\n"
2752 "The response will include the hint for the extension and the status.\n";
2753
2754 static int action_extensionstate(struct mansession *s, const struct message *m)
2755 {
2756         const char *exten = astman_get_header(m, "Exten");
2757         const char *context = astman_get_header(m, "Context");
2758         char hint[256] = "";
2759         int status;
2760         if (ast_strlen_zero(exten)) {
2761                 astman_send_error(s, m, "Extension not specified");
2762                 return 0;
2763         }
2764         if (ast_strlen_zero(context)) {
2765                 context = "default";
2766         }
2767         status = ast_extension_state(NULL, context, exten);
2768         ast_get_hint(hint, sizeof(hint) - 1, NULL, 0, NULL, context, exten);
2769         astman_start_ack(s, m);
2770         astman_append(s,   "Message: Extension Status\r\n"
2771                            "Exten: %s\r\n"
2772                            "Context: %s\r\n"
2773                            "Hint: %s\r\n"
2774                            "Status: %d\r\n\r\n",
2775                            exten, context, hint, status);
2776         return 0;
2777 }
2778
2779 static char mandescr_timeout[] =
2780 "Description: Hangup a channel after a certain time.\n"
2781 "Variables: (Names marked with * are required)\n"
2782 "       *Channel: Channel name to hangup\n"
2783 "       *Timeout: Maximum duration of the call (sec)\n"
2784 "Acknowledges set time with 'Timeout Set' message\n";
2785
2786 static int action_timeout(struct mansession *s, const struct message *m)
2787 {
2788         struct ast_channel *c;
2789         const char *name = astman_get_header(m, "Channel");
2790         double timeout = atof(astman_get_header(m, "Timeout"));
2791         struct timeval when = { timeout, 0 };
2792
2793         if (ast_strlen_zero(name)) {
2794                 astman_send_error(s, m, "No channel specified");
2795                 return 0;
2796         }
2797
2798         if (!timeout || timeout < 0) {
2799                 astman_send_error(s, m, "No timeout specified");
2800                 return 0;
2801         }
2802
2803         if (!(c = ast_channel_get_by_name(name))) {
2804                 astman_send_error(s, m, "No such channel");
2805                 return 0;
2806         }
2807
2808         when.tv_usec = (timeout - when.tv_sec) * 1000000.0;
2809
2810         ast_channel_lock(c);
2811         ast_channel_setwhentohangup_tv(c, when);
2812         ast_channel_unlock(c);
2813         c = ast_channel_unref(c);
2814
2815         astman_send_ack(s, m, "Timeout Set");
2816
2817         return 0;
2818 }
2819
2820 /*!
2821  * Send any applicable events to the client listening on this socket.
2822  * Wait only for a finite time on each event, and drop all events whether
2823  * they are successfully sent or not.
2824  */
2825 static int process_events(struct mansession *s)
2826 {
2827         int ret = 0;
2828
2829         ao2_lock(s->session);
2830         if (s->session->f != NULL) {
2831                 struct eventqent *eqe;
2832
2833                 while ( (eqe = NEW_EVENT(s)) ) {
2834                         ref_event(eqe);
2835                         if (!ret && s->session->authenticated &&
2836                             (s->session->readperm & eqe->category) == eqe->category &&
2837                             (s->session->send_events & eqe->category) == eqe->category) {
2838                                 if (send_string(s, eqe->eventdata) < 0)
2839                                         ret = -1;       /* don't send more */
2840                         }
2841                         s->session->last_ev = unref_event(s->session->last_ev);
2842                 }
2843         }
2844         ao2_unlock(s->session);
2845         return ret;
2846 }
2847
2848 static char mandescr_userevent[] =
2849 "Description: Send an event to manager sessions.\n"
2850 "Variables: (Names marked with * are required)\n"
2851 "       *UserEvent: EventStringToSend\n"
2852 "       Header1: Content1\n"
2853 "       HeaderN: ContentN\n";
2854
2855 static int action_userevent(struct mansession *s, const struct message *m)
2856 {
2857         const char *event = astman_get_header(m, "UserEvent");
2858         struct ast_str *body = ast_str_thread_get(&userevent_buf, 16);
2859         int x;
2860
2861         ast_str_reset(body);
2862
2863         for (x = 0; x < m->hdrcount; x++) {
2864                 if (strncasecmp("UserEvent:", m->headers[x], strlen("UserEvent:"))) {
2865                         ast_str_append(&body, 0, "%s\r\n", m->headers[x]);
2866                 }
2867         }
2868
2869         manager_event(EVENT_FLAG_USER, "UserEvent", "UserEvent: %s\r\n%s", event, ast_str_buffer(body));
2870         return 0;
2871 }
2872
2873 static char mandescr_coresettings[] =
2874 "Description: Query for Core PBX settings.\n"
2875 "Variables: (Names marked with * are optional)\n"
2876 "       *ActionID: ActionID of this transaction\n";
2877
2878 /*! \brief Show PBX core settings information */
2879 static int action_coresettings(struct mansession *s, const struct message *m)
2880 {
2881         const char *actionid = astman_get_header(m, "ActionID");
2882         char idText[150];
2883
2884         if (!ast_strlen_zero(actionid)) {
2885                 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
2886         } else {
2887                 idText[0] = '\0';
2888         }
2889
2890         astman_append(s, "Response: Success\r\n"
2891                         "%s"
2892                         "AMIversion: %s\r\n"
2893                         "AsteriskVersion: %s\r\n"
2894                         "SystemName: %s\r\n"
2895                         "CoreMaxCalls: %d\r\n"
2896                         "CoreMaxLoadAvg: %f\r\n"
2897                         "CoreRunUser: %s\r\n"
2898                         "CoreRunGroup: %s\r\n"
2899                         "CoreMaxFilehandles: %d\r\n"
2900                         "CoreRealTimeEnabled: %s\r\n"
2901                         "CoreCDRenabled: %s\r\n"
2902                         "CoreHTTPenabled: %s\r\n"
2903                         "\r\n",
2904                         idText,
2905                         AMI_VERSION,
2906                         ast_get_version(),
2907                         ast_config_AST_SYSTEM_NAME,
2908                         option_maxcalls,
2909                         option_maxload,
2910                         ast_config_AST_RUN_USER,
2911                         ast_config_AST_RUN_GROUP,
2912                         option_maxfiles,
2913                         ast_realtime_enabled() ? "Yes" : "No",
2914                         check_cdr_enabled() ? "Yes" : "No",
2915                         check_webmanager_enabled() ? "Yes" : "No"
2916                         );
2917         return 0;
2918 }
2919
2920 static char mandescr_corestatus[] =
2921 "Description: Query for Core PBX status.\n"
2922 "Variables: (Names marked with * are optional)\n"
2923 "       *ActionID: ActionID of this transaction\n";
2924
2925 /*! \brief Show PBX core status information */
2926 static int action_corestatus(struct mansession *s, const struct message *m)
2927 {
2928         const char *actionid = astman_get_header(m, "ActionID");
2929         char idText[150];
2930         char startuptime[150];
2931         char reloadtime[150];
2932         struct ast_tm tm;
2933
2934         if (!ast_strlen_zero(actionid)) {
2935                 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
2936         } else {
2937                 idText[0] = '\0';
2938         }
2939
2940         ast_localtime(&ast_startuptime, &tm, NULL);
2941         ast_strftime(startuptime, sizeof(startuptime), "%H:%M:%S", &tm);
2942         ast_localtime(&ast_lastreloadtime, &tm, NULL);
2943         ast_strftime(reloadtime, sizeof(reloadtime), "%H:%M:%S", &tm);
2944
2945         astman_append(s, "Response: Success\r\n"
2946                         "%s"
2947                         "CoreStartupTime: %s\r\n"
2948                         "CoreReloadTime: %s\r\n"
2949                         "CoreCurrentCalls: %d\r\n"
2950                         "\r\n",
2951                         idText,
2952                         startuptime,
2953                         reloadtime,
2954                         ast_active_channels()
2955                         );
2956         return 0;
2957 }
2958
2959 static char mandescr_reload[] =
2960 "Description: Send a reload event.\n"
2961 "Variables: (Names marked with * are optional)\n"
2962 "       *ActionID: ActionID of this transaction\n"
2963 "       *Module: Name of the module to reload\n";
2964
2965 /*! \brief Send a reload event */
2966 static int action_reload(struct mansession *s, const struct message *m)
2967 {
2968         const char *module = astman_get_header(m, "Module");
2969         int res = ast_module_reload(S_OR(module, NULL));
2970
2971         if (res == 2) {
2972                 astman_send_ack(s, m, "Module Reloaded");
2973         } else {
2974                 astman_send_error(s, m, s == 0 ? "No such module" : "Module does not support reload");
2975         }
2976         return 0;
2977 }
2978
2979 static char mandescr_coreshowchannels[] =
2980 "Description: List currently defined channels and some information\n"
2981 "             about them.\n"
2982 "Variables:\n"
2983 "          ActionID: Optional Action id for message matching.\n";
2984
2985 /*! \brief  Manager command "CoreShowChannels" - List currently defined channels
2986  *          and some information about them. */
2987 static int action_coreshowchannels(struct mansession *s, const struct message *m)
2988 {
2989         const char *actionid = astman_get_header(m, "ActionID");
2990         char actionidtext[256];
2991         struct ast_channel *c = NULL;
2992         int numchans = 0;
2993         int duration, durh, durm, durs;
2994         struct ast_channel_iterator *iter;
2995
2996         if (!ast_strlen_zero(actionid)) {
2997                 snprintf(actionidtext, sizeof(actionidtext), "ActionID: %s\r\n", actionid);
2998         } else {
2999                 actionidtext[0] = '\0';
3000         }
3001
3002         if (!(iter = ast_channel_iterator_all_new(0))) {
3003                 astman_send_error(s, m, "Memory Allocation Failure");
3004                 return 1;
3005         }
3006
3007         astman_send_listack(s, m, "Channels will follow", "start");
3008
3009         for (; (c = ast_channel_iterator_next(iter)); ast_channel_unref(c)) {
3010                 struct ast_channel *bc;
3011                 char durbuf[10] = "";
3012
3013                 ast_channel_lock(c);
3014
3015                 bc = ast_bridged_channel(c);
3016                 if (c->cdr && !ast_tvzero(c->cdr->start)) {
3017                         duration = (int)(ast_tvdiff_ms(ast_tvnow(), c->cdr->start) / 1000);
3018                         durh = duration / 3600;
3019                         durm = (duration % 3600) / 60;
3020                         durs = duration % 60;
3021                         snprintf(durbuf, sizeof(durbuf), "%02d:%02d:%02d", durh, durm, durs);
3022                 }
3023
3024                 astman_append(s,
3025                         "Event: CoreShowChannel\r\n"
3026                         "Channel: %s\r\n"
3027                         "UniqueID: %s\r\n"
3028                         "Context: %s\r\n"
3029                         "Extension: %s\r\n"
3030                         "Priority: %d\r\n"
3031                         "ChannelState: %d\r\n"
3032                         "ChannelStateDesc: %s\r\n"
3033                         "Application: %s\r\n"
3034                         "ApplicationData: %s\r\n"
3035                         "CallerIDnum: %s\r\n"
3036                         "Duration: %s\r\n"
3037                         "AccountCode: %s\r\n"
3038                         "BridgedChannel: %s\r\n"
3039                         "BridgedUniqueID: %s\r\n"
3040                         "\r\n", c->name, c->uniqueid, c->context, c->exten, c->priority, c->_state, ast_state2str(c->_state),
3041                         c->appl ? c->appl : "", c->data ? S_OR(c->data, ""): "",
3042                         S_OR(c->cid.cid_num, ""), durbuf, S_OR(c->accountcode, ""), bc ? bc->name : "", bc ? bc->uniqueid : "");
3043
3044                 ast_channel_unlock(c);
3045
3046                 numchans++;
3047         }
3048
3049         astman_append(s,
3050                 "Event: CoreShowChannelsComplete\r\n"
3051                 "EventList: Complete\r\n"
3052                 "ListItems: %d\r\n"
3053                 "%s"
3054                 "\r\n", numchans, actionidtext);
3055
3056         ast_channel_iterator_destroy(iter);
3057
3058         return 0;
3059 }
3060
3061 static char mandescr_modulecheck[] =
3062 "Description: Checks if Asterisk module is loaded\n"
3063 "Variables: \n"
3064 "  ActionID: <id>          Action ID for this transaction. Will be returned.\n"
3065 "  Module: <name>          Asterisk module name (not including extension)\n"
3066 "\n"
3067 "Will return Success/Failure\n"
3068 "For success returns, the module revision number is included.\n";
3069
3070 /* Manager function to check if module is loaded */
3071 static int manager_modulecheck(struct mansession *s, const struct message *m)
3072 {
3073         int res;
3074         const char *module = astman_get_header(m, "Module");
3075         const char *id = astman_get_header(m, "ActionID");
3076         char idText[256];
3077 #if !defined(LOW_MEMORY)
3078         const char *version;
3079 #endif
3080         char filename[PATH_MAX];
3081         char *cut;
3082
3083         ast_copy_string(filename, module, sizeof(filename));
3084         if ((cut = strchr(filename, '.'))) {
3085                 *cut = '\0';
3086         } else {
3087                 cut = filename + strlen(filename);
3088         }
3089         snprintf(cut, (sizeof(filename) - strlen(filename)) - 1, ".so");
3090         ast_log(LOG_DEBUG, "**** ModuleCheck .so file %s\n", filename);
3091         res = ast_module_check(filename);
3092         if (!res) {
3093                 astman_send_error(s, m, "Module not loaded");
3094                 return 0;
3095         }
3096         snprintf(cut, (sizeof(filename) - strlen(filename)) - 1, ".c");
3097         ast_log(LOG_DEBUG, "**** ModuleCheck .c file %s\n", filename);
3098 #if !defined(LOW_MEMORY)
3099         version = ast_file_version_find(filename);
3100 #endif
3101
3102         if (!ast_strlen_zero(id)) {
3103                 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
3104         } else {
3105                 idText[0] = '\0';
3106         }
3107         astman_append(s, "Response: Success\r\n%s", idText);
3108 #if !defined(LOW_MEMORY)
3109         astman_append(s, "Version: %s\r\n\r\n", version ? version : "");
3110 #endif
3111         return 0;
3112 }
3113
3114 static char mandescr_moduleload[] =
3115 "Description: Loads, unloads or reloads an Asterisk module in a running system.\n"
3116 "Variables: \n"
3117 "  ActionID: <id>          Action ID for this transaction. Will be returned.\n"
3118 "  Module: <name>          Asterisk module name (including .so extension)\n"
3119 "                          or subsystem identifier:\n"
3120 "                               cdr, enum, dnsmgr, extconfig, manager, rtp, http\n"
3121 "  LoadType: load | unload | reload\n"
3122 "                          The operation to be done on module\n"
3123 " If no module is specified for a reload loadtype, all modules are reloaded";
3124
3125 static int manager_moduleload(struct mansession *s, const struct message *m)
3126 {
3127         int res;
3128         const char *module = astman_get_header(m, "Module");
3129         const char *loadtype = astman_get_header(m, "LoadType");
3130
3131         if (!loadtype || strlen(loadtype) == 0) {
3132                 astman_send_error(s, m, "Incomplete ModuleLoad action.");
3133         }
3134         if ((!module || strlen(module) == 0) && strcasecmp(loadtype, "reload") != 0) {
3135                 astman_send_error(s, m, "Need module name");
3136         }
3137
3138         if (!strcasecmp(loadtype, "load")) {
3139                 res = ast_load_resource(module);
3140                 if (res) {
3141                         astman_send_error(s, m, "Could not load module.");
3142                 } else {
3143                         astman_send_ack(s, m, "Module loaded.");
3144                 }
3145         } else if (!strcasecmp(loadtype, "unload")) {
3146                 res = ast_unload_resource(module, AST_FORCE_SOFT);
3147                 if (res) {
3148                         astman_send_error(s, m, "Could not unload module.");
3149                 } else {
3150                         astman_send_ack(s, m, "Module unloaded.");
3151                 }
3152         } else if (!strcasecmp(loadtype, "reload")) {
3153                 if (module != NULL) {
3154                         res = ast_module_reload(module);
3155                         if (res == 0) {
3156                                 astman_send_error(s, m, "No such module.");
3157                         } else if (res == 1) {
3158                                 astman_send_error(s, m, "Module does not support reload action.");
3159                         } else {
3160                                 astman_send_ack(s, m, "Module reloaded.");
3161                         }
3162                 } else {
3163                         ast_module_reload(NULL);        /* Reload all modules */
3164                         astman_send_ack(s, m, "All modules reloaded");
3165                 }
3166         } else
3167                 astman_send_error(s, m, "Incomplete ModuleLoad action.");
3168         return 0;
3169 }
3170
3171 /*
3172  * Done with the action handlers here, we start with the code in charge
3173  * of accepting connections and serving them.
3174  * accept_thread() forks a new thread for each connection, session_do(),
3175  * which in turn calls get_input() repeatedly until a full message has
3176  * been accumulated, and then invokes process_message() to pass it to
3177  * the appropriate handler.
3178  */
3179
3180 /*
3181  * Process an AMI message, performing desired action.
3182  * Return 0 on success, -1 on error that require the session to be destroyed.
3183  */
3184 static int process_message(struct mansession *s, const struct message *m)
3185 {
3186         char action[80] = "";
3187         int ret = 0;
3188         struct manager_action *tmp;
3189         const char *user = astman_get_header(m, "Username");
3190         int (*call_func)(struct mansession *s, const struct message *m) = NULL;
3191
3192         ast_copy_string(action, __astman_get_header(m, "Action", GET_HEADER_SKIP_EMPTY), sizeof(action));
3193
3194         if (ast_strlen_zero(action)) {
3195                 ao2_lock(s);
3196                 astman_send_error(s, m, "Missing action in request");
3197                 ao2_unlock(s);
3198                 return 0;
3199         }
3200
3201         if (!s->session->authenticated && strcasecmp(action, "Login") && strcasecmp(action, "Logoff") && strcasecmp(action, "Challenge")) {
3202                 ao2_lock(s);
3203                 astman_send_error(s, m, "Permission denied");
3204                 ao2_unlock(s);
3205                 return 0;
3206         }
3207
3208         if (!allowmultiplelogin && !s->session->authenticated && user &&
3209                 (!strcasecmp(action, "Login") || !strcasecmp(action, "Challenge"))) {
3210                 if (check_manager_session_inuse(user)) {
3211                         sleep(1);
3212                         ao2_lock(s);
3213                         astman_send_error(s, m, "Login Already In Use");
3214                         ao2_unlock(s);
3215                         return -1;
3216                 }
3217         }
3218
3219         AST_RWLIST_RDLOCK(&actions);
3220         AST_RWLIST_TRAVERSE(&actions, tmp, list) {
3221                 if (strcasecmp(action, tmp->action)) {
3222                         continue;
3223                 }
3224                 if (s->session->writeperm & tmp->authority || tmp->authority == 0) {
3225                         call_func = tmp->func;
3226                 } else {
3227                         astman_send_error(s, m, "Permission denied");
3228                         tmp = NULL;
3229                 }
3230                 break;
3231         }
3232         AST_RWLIST_UNLOCK(&actions);
3233
3234         if (tmp && call_func) {
3235                 /* call AMI function after actions list are unlocked */
3236                 ast_debug(1, "Running action '%s'\n", tmp->action);
3237                 ret = call_func(s, m);
3238         } else {
3239                 char buf[512];
3240                 snprintf(buf, sizeof(buf), "Invalid/unknown command: %s. Use Action: ListCommands to show available commands.", action);
3241                 ao2_lock(s);
3242                 astman_send_error(s, m, buf);
3243                 ao2_unlock(s);