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