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