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