Add support for codec settings in originate via call file and manager.
[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 /*! \brief 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         int format;                             /*!< Codecs used for a call */
2115         char app[AST_MAX_APP];
2116         char appdata[AST_MAX_EXTENSION];
2117         char cid_name[AST_MAX_EXTENSION];
2118         char cid_num[AST_MAX_EXTENSION];
2119         char context[AST_MAX_CONTEXT];
2120         char exten[AST_MAX_EXTENSION];
2121         char idtext[AST_MAX_EXTENSION];
2122         char account[AST_MAX_ACCOUNT_CODE];
2123         int priority;
2124         struct ast_variable *vars;
2125 };
2126
2127 static void *fast_originate(void *data)
2128 {
2129         struct fast_originate_helper *in = data;
2130         int res;
2131         int reason = 0;
2132         struct ast_channel *chan = NULL;
2133         char requested_channel[AST_CHANNEL_NAME];
2134
2135         if (!ast_strlen_zero(in->app)) {
2136                 res = ast_pbx_outgoing_app(in->tech, in->format, in->data, in->timeout, in->app, in->appdata, &reason, 1,
2137                         S_OR(in->cid_num, NULL),
2138                         S_OR(in->cid_name, NULL),
2139                         in->vars, in->account, &chan);
2140         } else {
2141                 res = ast_pbx_outgoing_exten(in->tech, in->format, in->data, in->timeout, in->context, in->exten, in->priority, &reason, 1,
2142                         S_OR(in->cid_num, NULL),
2143                         S_OR(in->cid_name, NULL),
2144                         in->vars, in->account, &chan);
2145         }
2146
2147         if (!chan)
2148                 snprintf(requested_channel, AST_CHANNEL_NAME, "%s/%s", in->tech, in->data);     
2149         /* Tell the manager what happened with the channel */
2150         manager_event(EVENT_FLAG_CALL, "OriginateResponse",
2151                 "%s"
2152                 "Response: %s\r\n"
2153                 "Channel: %s\r\n"
2154                 "Context: %s\r\n"
2155                 "Exten: %s\r\n"
2156                 "Reason: %d\r\n"
2157                 "Uniqueid: %s\r\n"
2158                 "CallerIDNum: %s\r\n"
2159                 "CallerIDName: %s\r\n",
2160                 in->idtext, res ? "Failure" : "Success", chan ? chan->name : requested_channel, in->context, in->exten, reason, 
2161                 chan ? chan->uniqueid : "<null>",
2162                 S_OR(in->cid_num, "<unknown>"),
2163                 S_OR(in->cid_name, "<unknown>")
2164                 );
2165
2166         /* Locked by ast_pbx_outgoing_exten or ast_pbx_outgoing_app */
2167         if (chan)
2168                 ast_channel_unlock(chan);
2169         ast_free(in);
2170         return NULL;
2171 }
2172
2173 static char mandescr_originate[] =
2174 "Description: Generates an outgoing call to a Extension/Context/Priority or\n"
2175 "  Application/Data\n"
2176 "Variables: (Names marked with * are required)\n"
2177 "       *Channel: Channel name to call\n"
2178 "       Exten: Extension to use (requires 'Context' and 'Priority')\n"
2179 "       Context: Context to use (requires 'Exten' and 'Priority')\n"
2180 "       Priority: Priority to use (requires 'Exten' and 'Context')\n"
2181 "       Application: Application to use\n"
2182 "       Data: Data to use (requires 'Application')\n"
2183 "       Timeout: How long to wait for call to be answered (in ms)\n"
2184 "       CallerID: Caller ID to be set on the outgoing channel\n"
2185 "       Variable: Channel variable to set, multiple Variable: headers are allowed\n"
2186 "       Account: Account code\n"
2187 "       Async: Set to 'true' for fast origination\n";
2188
2189 static int action_originate(struct mansession *s, const struct message *m)
2190 {
2191         const char *name = astman_get_header(m, "Channel");
2192         const char *exten = astman_get_header(m, "Exten");
2193         const char *context = astman_get_header(m, "Context");
2194         const char *priority = astman_get_header(m, "Priority");
2195         const char *timeout = astman_get_header(m, "Timeout");
2196         const char *callerid = astman_get_header(m, "CallerID");
2197         const char *account = astman_get_header(m, "Account");
2198         const char *app = astman_get_header(m, "Application");
2199         const char *appdata = astman_get_header(m, "Data");
2200         const char *async = astman_get_header(m, "Async");
2201         const char *id = astman_get_header(m, "ActionID");
2202         const char *codecs = astman_get_header(m, "Codecs");
2203         struct ast_variable *vars = astman_get_variables(m);
2204         char *tech, *data;
2205         char *l = NULL, *n = NULL;
2206         int pi = 0;
2207         int res;
2208         int to = 30000;
2209         int reason = 0;
2210         char tmp[256];
2211         char tmp2[256];
2212         int format = AST_FORMAT_SLINEAR;
2213
2214         pthread_t th;
2215         if (!name) {
2216                 astman_send_error(s, m, "Channel not specified");
2217                 return 0;
2218         }
2219         if (!ast_strlen_zero(priority) && (sscanf(priority, "%d", &pi) != 1)) {
2220                 if ((pi = ast_findlabel_extension(NULL, context, exten, priority, NULL)) < 1) {
2221                         astman_send_error(s, m, "Invalid priority\n");
2222                         return 0;
2223                 }
2224         }
2225         if (!ast_strlen_zero(timeout) && (sscanf(timeout, "%d", &to) != 1)) {
2226                 astman_send_error(s, m, "Invalid timeout\n");
2227                 return 0;
2228         }
2229         ast_copy_string(tmp, name, sizeof(tmp));
2230         tech = tmp;
2231         data = strchr(tmp, '/');
2232         if (!data) {
2233                 astman_send_error(s, m, "Invalid channel\n");
2234                 return 0;
2235         }
2236         *data++ = '\0';
2237         ast_copy_string(tmp2, callerid, sizeof(tmp2));
2238         ast_callerid_parse(tmp2, &n, &l);
2239         if (n) {
2240                 if (ast_strlen_zero(n))
2241                         n = NULL;
2242         }
2243         if (l) {
2244                 ast_shrink_phone_number(l);
2245                 if (ast_strlen_zero(l))
2246                         l = NULL;
2247         }
2248         if (!ast_strlen_zero(codecs)) {
2249                 format = 0;
2250                 ast_parse_allow_disallow(NULL, &format, codecs, 1);
2251         }
2252         if (ast_true(async)) {
2253                 struct fast_originate_helper *fast = ast_calloc(1, sizeof(*fast));
2254                 if (!fast) {
2255                         res = -1;
2256                 } else {
2257                         if (!ast_strlen_zero(id))
2258                                 snprintf(fast->idtext, sizeof(fast->idtext), "ActionID: %s\r\n", id);
2259                         ast_copy_string(fast->tech, tech, sizeof(fast->tech));
2260                         ast_copy_string(fast->data, data, sizeof(fast->data));
2261                         ast_copy_string(fast->app, app, sizeof(fast->app));
2262                         ast_copy_string(fast->appdata, appdata, sizeof(fast->appdata));
2263                         if (l)
2264                                 ast_copy_string(fast->cid_num, l, sizeof(fast->cid_num));
2265                         if (n)
2266                                 ast_copy_string(fast->cid_name, n, sizeof(fast->cid_name));
2267                         fast->vars = vars;
2268                         ast_copy_string(fast->context, context, sizeof(fast->context));
2269                         ast_copy_string(fast->exten, exten, sizeof(fast->exten));
2270                         ast_copy_string(fast->account, account, sizeof(fast->account));
2271                         fast->format = format;
2272                         fast->timeout = to;
2273                         fast->priority = pi;
2274                         if (ast_pthread_create_detached(&th, NULL, fast_originate, fast)) {
2275                                 res = -1;
2276                         } else {
2277                                 res = 0;
2278                         }
2279                 }
2280         } else if (!ast_strlen_zero(app)) {
2281                 /* To run the System application (or anything else that goes to shell), you must have the additional System privilege */
2282                 if (!(s->writeperm & EVENT_FLAG_SYSTEM)
2283                         && (
2284                                 strcasestr(app, "system") == 0 || /* System(rm -rf /)
2285                                                                      TrySystem(rm -rf /)       */
2286                                 strcasestr(app, "exec") ||        /* Exec(System(rm -rf /))
2287                                                                      TryExec(System(rm -rf /)) */
2288                                 strcasestr(app, "agi") ||         /* AGI(/bin/rm,-rf /)
2289                                                                      EAGI(/bin/rm,-rf /)       */
2290                                 strstr(appdata, "SHELL") ||       /* NoOp(${SHELL(rm -rf /)})  */
2291                                 strstr(appdata, "EVAL")           /* NoOp(${EVAL(${some_var_containing_SHELL})}) */
2292                                 )) {
2293                         astman_send_error(s, m, "Originate with certain 'Application' arguments requires the additional System privilege, which you do not have.");
2294                         return 0;
2295                 }
2296                 res = ast_pbx_outgoing_app(tech, format, data, to, app, appdata, &reason, 1, l, n, vars, account, NULL);
2297         } else {
2298                 if (exten && context && pi)
2299                         res = ast_pbx_outgoing_exten(tech, format, data, to, context, exten, pi, &reason, 1, l, n, vars, account, NULL);
2300                 else {
2301                         astman_send_error(s, m, "Originate with 'Exten' requires 'Context' and 'Priority'");
2302                         return 0;
2303                 }
2304         }
2305         if (!res)
2306                 astman_send_ack(s, m, "Originate successfully queued");
2307         else
2308                 astman_send_error(s, m, "Originate failed");
2309         return 0;
2310 }
2311
2312 /*! \brief Help text for manager command mailboxstatus
2313  */
2314 static char mandescr_mailboxstatus[] =
2315 "Description: Checks a voicemail account for status.\n"
2316 "Variables: (Names marked with * are required)\n"
2317 "       *Mailbox: Full mailbox ID <mailbox>@<vm-context>\n"
2318 "       ActionID: Optional ActionID for message matching.\n"
2319 "Returns number of messages.\n"
2320 "       Message: Mailbox Status\n"
2321 "       Mailbox: <mailboxid>\n"
2322 "       Waiting: <count>\n"
2323 "\n";
2324
2325 static int action_mailboxstatus(struct mansession *s, const struct message *m)
2326 {
2327         const char *mailbox = astman_get_header(m, "Mailbox");
2328         int ret;
2329
2330         if (ast_strlen_zero(mailbox)) {
2331                 astman_send_error(s, m, "Mailbox not specified");
2332                 return 0;
2333         }
2334         ret = ast_app_has_voicemail(mailbox, NULL);
2335         astman_start_ack(s, m);
2336         astman_append(s, "Message: Mailbox Status\r\n"
2337                          "Mailbox: %s\r\n"
2338                          "Waiting: %d\r\n\r\n", mailbox, ret);
2339         return 0;
2340 }
2341
2342 static char mandescr_mailboxcount[] =
2343 "Description: Checks a voicemail account for new messages.\n"
2344 "Variables: (Names marked with * are required)\n"
2345 "       *Mailbox: Full mailbox ID <mailbox>@<vm-context>\n"
2346 "       ActionID: Optional ActionID for message matching.\n"
2347 "Returns number of urgent, new and old messages.\n"
2348 "       Message: Mailbox Message Count\n"
2349 "       Mailbox: <mailboxid>\n"
2350 "       UrgentMessages: <count>\n"
2351 "       NewMessages: <count>\n"
2352 "       OldMessages: <count>\n"
2353 "\n";
2354 static int action_mailboxcount(struct mansession *s, const struct message *m)
2355 {
2356         const char *mailbox = astman_get_header(m, "Mailbox");
2357         int newmsgs = 0, oldmsgs = 0, urgentmsgs = 0;;
2358
2359         if (ast_strlen_zero(mailbox)) {
2360                 astman_send_error(s, m, "Mailbox not specified");
2361                 return 0;
2362         }
2363         ast_app_inboxcount(mailbox, &urgentmsgs, &newmsgs, &oldmsgs);
2364         astman_start_ack(s, m);
2365         astman_append(s,   "Message: Mailbox Message Count\r\n"
2366                            "Mailbox: %s\r\n"
2367                            "UrgMessages: %d\r\n"
2368                            "NewMessages: %d\r\n"
2369                            "OldMessages: %d\r\n"
2370                            "\r\n",
2371                            mailbox, urgentmsgs, newmsgs, oldmsgs);
2372         return 0;
2373 }
2374
2375 static char mandescr_extensionstate[] =
2376 "Description: Report the extension state for given extension.\n"
2377 "  If the extension has a hint, will use devicestate to check\n"
2378 "  the status of the device connected to the extension.\n"
2379 "Variables: (Names marked with * are required)\n"
2380 "       *Exten: Extension to check state on\n"
2381 "       *Context: Context for extension\n"
2382 "       ActionId: Optional ID for this transaction\n"
2383 "Will return an \"Extension Status\" message.\n"
2384 "The response will include the hint for the extension and the status.\n";
2385
2386 static int action_extensionstate(struct mansession *s, const struct message *m)
2387 {
2388         const char *exten = astman_get_header(m, "Exten");
2389         const char *context = astman_get_header(m, "Context");
2390         char hint[256] = "";
2391         int status;
2392         if (ast_strlen_zero(exten)) {
2393                 astman_send_error(s, m, "Extension not specified");
2394                 return 0;
2395         }
2396         if (ast_strlen_zero(context))
2397                 context = "default";
2398         status = ast_extension_state(NULL, context, exten);
2399         ast_get_hint(hint, sizeof(hint) - 1, NULL, 0, NULL, context, exten);
2400         astman_start_ack(s, m);
2401         astman_append(s,   "Message: Extension Status\r\n"
2402                            "Exten: %s\r\n"
2403                            "Context: %s\r\n"
2404                            "Hint: %s\r\n"
2405                            "Status: %d\r\n\r\n",
2406                            exten, context, hint, status);
2407         return 0;
2408 }
2409
2410 static char mandescr_timeout[] =
2411 "Description: Hangup a channel after a certain time.\n"
2412 "Variables: (Names marked with * are required)\n"
2413 "       *Channel: Channel name to hangup\n"
2414 "       *Timeout: Maximum duration of the call (sec)\n"
2415 "Acknowledges set time with 'Timeout Set' message\n";
2416
2417 static int action_timeout(struct mansession *s, const struct message *m)
2418 {
2419         struct ast_channel *c;
2420         const char *name = astman_get_header(m, "Channel");
2421         double timeout = atof(astman_get_header(m, "Timeout"));
2422         struct timeval tv = { timeout, 0 };
2423
2424         if (ast_strlen_zero(name)) {
2425                 astman_send_error(s, m, "No channel specified");
2426                 return 0;
2427         }
2428         if (!timeout || timeout < 0) {
2429                 astman_send_error(s, m, "No timeout specified");
2430                 return 0;
2431         }
2432         c = ast_get_channel_by_name_locked(name);
2433         if (!c) {
2434                 astman_send_error(s, m, "No such channel");
2435                 return 0;
2436         }
2437
2438         tv.tv_usec = (timeout - tv.tv_sec) * 1000000.0;
2439         ast_channel_setwhentohangup_tv(c, tv);
2440         ast_channel_unlock(c);
2441         astman_send_ack(s, m, "Timeout Set");
2442         return 0;
2443 }
2444
2445 /*!
2446  * Send any applicable events to the client listening on this socket.
2447  * Wait only for a finite time on each event, and drop all events whether
2448  * they are successfully sent or not.
2449  */
2450 static int process_events(struct mansession *s)
2451 {
2452         int ret = 0;
2453
2454         ast_mutex_lock(&s->__lock);
2455         if (s->f != NULL) {
2456                 struct eventqent *eqe;
2457
2458                 while ( (eqe = NEW_EVENT(s)) ) {
2459                         ref_event(eqe);
2460                         if (!ret && s->authenticated &&
2461                             (s->readperm & eqe->category) == eqe->category &&
2462                             (s->send_events & eqe->category) == eqe->category) {
2463                                 if (send_string(s, eqe->eventdata) < 0)
2464                                         ret = -1;       /* don't send more */
2465                         }
2466                         s->last_ev = unref_event(s->last_ev);
2467                 }
2468         }
2469         ast_mutex_unlock(&s->__lock);
2470         return ret;
2471 }
2472
2473 static char mandescr_userevent[] =
2474 "Description: Send an event to manager sessions.\n"
2475 "Variables: (Names marked with * are required)\n"
2476 "       *UserEvent: EventStringToSend\n"
2477 "       Header1: Content1\n"
2478 "       HeaderN: ContentN\n";
2479
2480 static int action_userevent(struct mansession *s, const struct message *m)
2481 {
2482         const char *event = astman_get_header(m, "UserEvent");
2483         char body[2048] = "";
2484         int x, bodylen = 0;
2485         for (x = 0; x < m->hdrcount; x++) {
2486                 if (strncasecmp("UserEvent:", m->headers[x], strlen("UserEvent:"))) {
2487                         ast_copy_string(body + bodylen, m->headers[x], sizeof(body) - bodylen - 3);
2488                         bodylen += strlen(m->headers[x]);
2489                         ast_copy_string(body + bodylen, "\r\n", 3);
2490                         bodylen += 2;
2491                 }
2492         }
2493
2494         manager_event(EVENT_FLAG_USER, "UserEvent", "UserEvent: %s\r\n%s", event, body);
2495         return 0;
2496 }
2497
2498 static char mandescr_coresettings[] =
2499 "Description: Query for Core PBX settings.\n"
2500 "Variables: (Names marked with * are optional)\n"
2501 "       *ActionID: ActionID of this transaction\n";
2502
2503 /*! \brief Show PBX core settings information */
2504 static int action_coresettings(struct mansession *s, const struct message *m)
2505 {
2506         const char *actionid = astman_get_header(m, "ActionID");
2507         char idText[150];
2508
2509         if (!ast_strlen_zero(actionid))
2510                 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
2511         else
2512                 idText[0] = '\0';
2513
2514         astman_append(s, "Response: Success\r\n"
2515                         "%s"
2516                         "AMIversion: %s\r\n"
2517                         "AsteriskVersion: %s\r\n"
2518                         "SystemName: %s\r\n"
2519                         "CoreMaxCalls: %d\r\n"
2520                         "CoreMaxLoadAvg: %f\r\n"
2521                         "CoreRunUser: %s\r\n"
2522                         "CoreRunGroup: %s\r\n"
2523                         "CoreMaxFilehandles: %d\r\n" 
2524                         "CoreRealTimeEnabled: %s\r\n"
2525                         "CoreCDRenabled: %s\r\n"
2526                         "CoreHTTPenabled: %s\r\n"
2527                         "\r\n",
2528                         idText,
2529                         AMI_VERSION,
2530                         ast_get_version(), 
2531                         ast_config_AST_SYSTEM_NAME,
2532                         option_maxcalls,
2533                         option_maxload,
2534                         ast_config_AST_RUN_USER,
2535                         ast_config_AST_RUN_GROUP,
2536                         option_maxfiles,
2537                         ast_realtime_enabled() ? "Yes" : "No",
2538                         check_cdr_enabled() ? "Yes" : "No",
2539                         check_webmanager_enabled() ? "Yes" : "No"
2540                         );
2541         return 0;
2542 }
2543
2544 static char mandescr_corestatus[] =
2545 "Description: Query for Core PBX status.\n"
2546 "Variables: (Names marked with * are optional)\n"
2547 "       *ActionID: ActionID of this transaction\n";
2548
2549 /*! \brief Show PBX core status information */
2550 static int action_corestatus(struct mansession *s, const struct message *m)
2551 {
2552         const char *actionid = astman_get_header(m, "ActionID");
2553         char idText[150];
2554         char startuptime[150];
2555         char reloadtime[150];
2556         struct ast_tm tm;
2557
2558         if (!ast_strlen_zero(actionid))
2559                 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
2560         else
2561                 idText[0] = '\0';
2562
2563         ast_localtime(&ast_startuptime, &tm, NULL);
2564         ast_strftime(startuptime, sizeof(startuptime), "%H:%M:%S", &tm);
2565         ast_localtime(&ast_lastreloadtime, &tm, NULL);
2566         ast_strftime(reloadtime, sizeof(reloadtime), "%H:%M:%S", &tm);
2567
2568         astman_append(s, "Response: Success\r\n"
2569                         "%s"
2570                         "CoreStartupTime: %s\r\n"
2571                         "CoreReloadTime: %s\r\n"
2572                         "CoreCurrentCalls: %d\r\n"
2573                         "\r\n",
2574                         idText,
2575                         startuptime,
2576                         reloadtime,
2577                         ast_active_channels()
2578                         );
2579         return 0;
2580 }
2581
2582 static char mandescr_reload[] =
2583 "Description: Send a reload event.\n"
2584 "Variables: (Names marked with * are optional)\n"
2585 "       *ActionID: ActionID of this transaction\n"
2586 "       *Module: Name of the module to reload\n";
2587
2588 /*! \brief Send a reload event */
2589 static int action_reload(struct mansession *s, const struct message *m)
2590 {
2591         const char *module = astman_get_header(m, "Module");
2592         int res = ast_module_reload(S_OR(module, NULL));
2593
2594         if (res == 2)
2595                 astman_send_ack(s, m, "Module Reloaded");
2596         else
2597                 astman_send_error(s, m, s == 0 ? "No such module" : "Module does not support reload");
2598         return 0;
2599 }
2600
2601 static char mandescr_coreshowchannels[] =
2602 "Description: List currently defined channels and some information\n"
2603 "             about them.\n"
2604 "Variables:\n"
2605 "          ActionID: Optional Action id for message matching.\n";
2606
2607 /*! \brief  Manager command "CoreShowChannels" - List currently defined channels 
2608  *          and some information about them. */
2609 static int action_coreshowchannels(struct mansession *s, const struct message *m)
2610 {
2611         const char *actionid = astman_get_header(m, "ActionID");
2612         char actionidtext[256];
2613         struct ast_channel *c = NULL;
2614         int numchans = 0;
2615         int duration, durh, durm, durs;
2616
2617         if (!ast_strlen_zero(actionid))
2618                 snprintf(actionidtext, sizeof(actionidtext), "ActionID: %s\r\n", actionid);
2619         else
2620                 actionidtext[0] = '\0';
2621
2622         astman_send_listack(s, m, "Channels will follow", "start");     
2623
2624         while ((c = ast_channel_walk_locked(c)) != NULL) {
2625                 struct ast_channel *bc = ast_bridged_channel(c);
2626                 char durbuf[10] = "";
2627
2628                 if (c->cdr && !ast_tvzero(c->cdr->start)) {
2629                         duration = (int)(ast_tvdiff_ms(ast_tvnow(), c->cdr->start) / 1000);
2630                         durh = duration / 3600;
2631                         durm = (duration % 3600) / 60;
2632                         durs = duration % 60;
2633                         snprintf(durbuf, sizeof(durbuf), "%02d:%02d:%02d", durh, durm, durs);
2634                 }
2635
2636                 astman_append(s,
2637                         "Channel: %s\r\n"
2638                         "UniqueID: %s\r\n"
2639                         "Context: %s\r\n"
2640                         "Extension: %s\r\n"
2641                         "Priority: %d\r\n"
2642                         "ChannelState: %d\r\n"
2643                         "ChannelStateDesc: %s\r\n"
2644                         "Application: %s\r\n"
2645                         "ApplicationData: %s\r\n"
2646                         "CallerIDnum: %s\r\n"
2647                         "Duration: %s\r\n"
2648                         "AccountCode: %s\r\n"
2649                         "BridgedChannel: %s\r\n"
2650                         "BridgedUniqueID: %s\r\n"
2651                         "\r\n", c->name, c->uniqueid, c->context, c->exten, c->priority, c->_state, ast_state2str(c->_state),
2652                         c->appl ? c->appl : "", c->data ? S_OR(c->data, ""): "",
2653                         S_OR(c->cid.cid_num, ""), durbuf, S_OR(c->accountcode, ""), bc ? bc->name : "", bc ? bc->uniqueid : "");
2654                 ast_channel_unlock(c);
2655                 numchans++;
2656         }
2657
2658         astman_append(s,
2659                 "Event: CoreShowChannelsComplete\r\n"
2660                 "EventList: Complete\r\n"
2661                 "ListItems: %d\r\n"
2662                 "%s"
2663                 "\r\n", numchans, actionidtext);
2664
2665         return 0;
2666 }
2667
2668 static char mandescr_modulecheck[] = 
2669 "Description: Checks if Asterisk module is loaded\n"
2670 "Variables: \n"
2671 "  ActionID: <id>          Action ID for this transaction. Will be returned.\n"
2672 "  Module: <name>          Asterisk module name (not including extension)\n"
2673 "\n"
2674 "Will return Success/Failure\n"
2675 "For success returns, the module revision number is included.\n";
2676
2677 /* Manager function to check if module is loaded */
2678 static int manager_modulecheck(struct mansession *s, const struct message *m)
2679 {
2680         int res;
2681         const char *module = astman_get_header(m, "Module");
2682         const char *id = astman_get_header(m, "ActionID");
2683         char idText[256];
2684 #if !defined(LOW_MEMORY)
2685         const char *version;
2686 #endif
2687         char filename[PATH_MAX];
2688         char *cut;
2689
2690         ast_copy_string(filename, module, sizeof(filename));
2691         if ((cut = strchr(filename, '.'))) {
2692                 *cut = '\0';
2693         } else {
2694                 cut = filename + strlen(filename);
2695         }
2696         snprintf(cut, (sizeof(filename) - strlen(filename)) - 1, ".so");
2697         ast_log(LOG_DEBUG, "**** ModuleCheck .so file %s\n", filename);
2698         res = ast_module_check(filename);
2699         if (!res) {
2700                 astman_send_error(s, m, "Module not loaded");
2701                 return 0;
2702         }
2703         snprintf(cut, (sizeof(filename) - strlen(filename)) - 1, ".c");
2704         ast_log(LOG_DEBUG, "**** ModuleCheck .c file %s\n", filename);
2705 #if !defined(LOW_MEMORY)
2706         version = ast_file_version_find(filename);
2707 #endif
2708
2709         if (!ast_strlen_zero(id))
2710                 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
2711         else
2712                 idText[0] = '\0';
2713         astman_append(s, "Response: Success\r\n%s", idText);
2714 #if !defined(LOW_MEMORY)
2715         astman_append(s, "Version: %s\r\n\r\n", version ? version : "");
2716 #endif
2717         return 0;
2718 }
2719
2720 static char mandescr_moduleload[] = 
2721 "Description: Loads, unloads or reloads an Asterisk module in a running system.\n"
2722 "Variables: \n"
2723 "  ActionID: <id>          Action ID for this transaction. Will be returned.\n"
2724 "  Module: <name>          Asterisk module name (including .so extension)\n"
2725 "                          or subsystem identifier:\n"
2726 "                               cdr, enum, dnsmgr, extconfig, manager, rtp, http\n"
2727 "  LoadType: load | unload | reload\n"
2728 "                          The operation to be done on module\n"
2729 " If no module is specified for a reload loadtype, all modules are reloaded";
2730
2731 static int manager_moduleload(struct mansession *s, const struct message *m)
2732 {
2733         int res;
2734         const char *module = astman_get_header(m, "Module");
2735         const char *loadtype = astman_get_header(m, "LoadType");
2736
2737         if (!loadtype || strlen(loadtype) == 0)
2738                 astman_send_error(s, m, "Incomplete ModuleLoad action.");
2739         if ((!module || strlen(module) == 0) && strcasecmp(loadtype, "reload") != 0)
2740                 astman_send_error(s, m, "Need module name");
2741
2742         if (!strcasecmp(loadtype, "load")) {
2743                 res = ast_load_resource(module);
2744                 if (res)
2745                         astman_send_error(s, m, "Could not load module.");
2746                 else
2747                         astman_send_ack(s, m, "Module loaded.");
2748         } else if (!strcasecmp(loadtype, "unload")) {
2749                 res = ast_unload_resource(module, AST_FORCE_SOFT);
2750                 if (res)
2751                         astman_send_error(s, m, "Could not unload module.");
2752                 else
2753                         astman_send_ack(s, m, "Module unloaded.");
2754         } else if (!strcasecmp(loadtype, "reload")) {
2755                 if (module != NULL) {
2756                         res = ast_module_reload(module);
2757                         if (res == 0)
2758                                 astman_send_error(s, m, "No such module.");
2759                         else if (res == 1)
2760                                 astman_send_error(s, m, "Module does not support reload action.");
2761                         else
2762                                 astman_send_ack(s, m, "Module reloaded.");
2763                 } else {
2764                         ast_module_reload(NULL);        /* Reload all modules */
2765                         astman_send_ack(s, m, "All modules reloaded");
2766                 }
2767         } else 
2768                 astman_send_error(s, m, "Incomplete ModuleLoad action.");
2769         return 0;
2770 }
2771
2772 /*
2773  * Done with the action handlers here, we start with the code in charge
2774  * of accepting connections and serving them.
2775  * accept_thread() forks a new thread for each connection, session_do(),
2776  * which in turn calls get_input() repeatedly until a full message has
2777  * been accumulated, and then invokes process_message() to pass it to
2778  * the appropriate handler.
2779  */
2780
2781 /*
2782  * Process an AMI message, performing desired action.
2783  * Return 0 on success, -1 on error that require the session to be destroyed.
2784  */
2785 static int process_message(struct mansession *s, const struct message *m)
2786 {
2787         char action[80] = "";
2788         int ret = 0;
2789         struct manager_action *tmp;
2790         const char *user = astman_get_header(m, "Username");
2791
2792         ast_copy_string(action, astman_get_header(m, "Action"), sizeof(action));
2793         ast_debug(1, "Manager received command '%s'\n", action);
2794
2795         if (ast_strlen_zero(action)) {
2796                 ast_mutex_lock(&s->__lock);
2797                 astman_send_error(s, m, "Missing action in request");
2798                 ast_mutex_unlock(&s->__lock);
2799                 return 0;
2800         }
2801
2802         if (!s->authenticated && strcasecmp(action, "Login") && strcasecmp(action, "Logoff") && strcasecmp(action, "Challenge")) {
2803                 ast_mutex_lock(&s->__lock);
2804                 astman_send_error(s, m, "Permission denied");
2805                 ast_mutex_unlock(&s->__lock);
2806                 return 0;
2807         }
2808
2809         if (!allowmultiplelogin && !s->authenticated && user &&
2810                 (!strcasecmp(action, "Login") || !strcasecmp(action, "Challenge"))) {
2811                 if (check_manager_session_inuse(user)) {
2812                         sleep(1);
2813                         ast_mutex_lock(&s->__lock);
2814                         astman_send_error(s, m, "Login Already In Use");
2815                         ast_mutex_unlock(&s->__lock);
2816                         return -1;
2817                 }
2818         }
2819
2820         AST_RWLIST_RDLOCK(&actions);
2821         AST_RWLIST_TRAVERSE(&actions, tmp, list) {
2822                 if (strcasecmp(action, tmp->action))
2823                         continue;
2824                 if (s->writeperm & tmp->authority || tmp->authority == 0)
2825                         ret = tmp->func(s, m);
2826                 else
2827                         astman_send_error(s, m, "Permission denied");
2828                 break;
2829         }
2830         AST_RWLIST_UNLOCK(&actions);
2831
2832         if (!tmp) {
2833                 char buf[512];
2834                 snprintf(buf, sizeof(buf), "Invalid/unknown command: %s. Use Action: ListCommands to show available commands.", action);
2835                 ast_mutex_lock(&s->__lock);
2836                 astman_send_error(s, m, buf);
2837                 ast_mutex_unlock(&s->__lock);
2838         }
2839         if (ret)
2840                 return ret;
2841         /* Once done with our message, deliver any pending events */
2842         return process_events(s);
2843 }
2844
2845 /*!
2846  * Read one full line (including crlf) from the manager socket.
2847  * \note \verbatim
2848  * \r\n is the only valid terminator for the line.
2849  * (Note that, later, '\0' will be considered as the end-of-line marker,
2850  * so everything between the '\0' and the '\r\n' will not be used).
2851  * Also note that we assume output to have at least "maxlen" space.
2852  * \endverbatim
2853  */
2854 static int get_input(struct mansession *s, char *output)
2855 {
2856         int res, x;
2857         int maxlen = sizeof(s->inbuf) - 1;
2858         char *src = s->inbuf;
2859
2860         /*
2861          * Look for \r\n within the buffer. If found, copy to the output
2862          * buffer and return, trimming the \r\n (not used afterwards).
2863          */
2864         for (x = 0; x < s->inlen; x++) {
2865                 int cr; /* set if we have \r */
2866                 if (src[x] == '\r' && x+1 < s->inlen && src[x+1] == '\n')
2867                         cr = 2; /* Found. Update length to include \r\n */
2868                 else if (src[x] == '\n')
2869                         cr = 1; /* also accept \n only */
2870                 else
2871                         continue;
2872                 memmove(output, src, x);        /*... but trim \r\n */
2873                 output[x] = '\0';               /* terminate the string */
2874                 x += cr;                        /* number of bytes used */
2875                 s->inlen -= x;                  /* remaining size */
2876                 memmove(src, src + x, s->inlen); /* remove used bytes */
2877                 return 1;
2878         }
2879         if (s->inlen >= maxlen) {
2880                 /* no crlf found, and buffer full - sorry, too long for us */
2881                 ast_log(LOG_WARNING, "Dumping long line with no return from %s: %s\n", ast_inet_ntoa(s->sin.sin_addr), src);
2882                 s->inlen = 0;
2883         }
2884         res = 0;
2885         while (res == 0) {
2886                 /* XXX do we really need this locking ? */
2887                 ast_mutex_lock(&s->__lock);
2888                 if (s->pending_event) {
2889                         s->pending_event = 0;
2890                         ast_mutex_unlock(&s->__lock);
2891                         return 0;
2892                 }
2893                 s->waiting_thread = pthread_self();
2894                 ast_mutex_unlock(&s->__lock);
2895
2896                 res = ast_wait_for_input(s->fd, -1);    /* return 0 on timeout ? */
2897
2898                 ast_mutex_lock(&s->__lock);
2899                 s->waiting_thread = AST_PTHREADT_NULL;
2900                 ast_mutex_unlock(&s->__lock);
2901         }
2902         if (res < 0) {
2903                 /* If we get a signal from some other thread (typically because
2904                  * there are new events queued), return 0 to notify the caller.
2905                  */
2906                 if (errno == EINTR || errno == EAGAIN)
2907                         return 0;
2908                 ast_log(LOG_WARNING, "poll() returned error: %s\n", strerror(errno));
2909                 return -1;
2910         }
2911         ast_mutex_lock(&s->__lock);
2912         res = fread(src + s->inlen, 1, maxlen - s->inlen, s->f);
2913         if (res < 1)
2914                 res = -1;       /* error return */
2915         else {
2916                 s->inlen += res;
2917                 src[s->inlen] = '\0';
2918                 res = 0;
2919         }
2920         ast_mutex_unlock(&s->__lock);
2921         return res;
2922 }
2923
2924 static int do_message(struct mansession *s)
2925 {
2926         struct message m = { 0 };
2927         char header_buf[sizeof(s->inbuf)] = { '\0' };
2928         int res;
2929
2930         for (;;) {
2931                 /* Check if any events are pending and do them if needed */
2932                 if (process_events(s))
2933                         return -1;
2934                 res = get_input(s, header_buf);
2935                 if (res == 0) {
2936                         continue;
2937                 } else if (res > 0) {
2938                         if (ast_strlen_zero(header_buf))
2939                                 return process_message(s, &m) ? -1 : 0;
2940                         else if (m.hdrcount < (AST_MAX_MANHEADERS - 1))
2941                                 m.headers[m.hdrcount++] = ast_strdupa(header_buf);
2942                 } else {
2943                         return res;
2944                 }
2945         }
2946 }
2947
2948 /*! \brief The body of the individual manager session.
2949  * Call get_input() to read one line at a time
2950  * (or be woken up on new events), collect the lines in a
2951  * message until found an empty line, and execute the request.
2952  * In any case, deliver events asynchronously through process_events()
2953  * (called from here if no line is available, or at the end of
2954  * process_message(). )
2955  */
2956 static void *session_do(void *data)
2957 {
2958         struct ast_tcptls_session_instance *ser = data;
2959         struct mansession *s = ast_calloc(1, sizeof(*s));
2960         int flags;
2961         int res;
2962
2963         if (s == NULL)
2964                 goto done;
2965
2966         s->writetimeout = 100;
2967         s->waiting_thread = AST_PTHREADT_NULL;
2968
2969         flags = fcntl(ser->fd, F_GETFL);
2970         if (!block_sockets) /* make sure socket is non-blocking */
2971                 flags |= O_NONBLOCK;
2972         else
2973                 flags &= ~O_NONBLOCK;
2974         fcntl(ser->fd, F_SETFL, flags);
2975
2976         ast_mutex_init(&s->__lock);
2977         s->send_events = -1;
2978         /* these fields duplicate those in the 'ser' structure */
2979         s->fd = ser->fd;
2980         s->f = ser->f;
2981         s->sin = ser->requestor;
2982
2983         AST_LIST_LOCK(&sessions);
2984         AST_LIST_INSERT_HEAD(&sessions, s, list);
2985         ast_atomic_fetchadd_int(&num_sessions, 1);
2986         AST_LIST_UNLOCK(&sessions);
2987         /* Hook to the tail of the event queue */
2988         s->last_ev = grab_last();
2989         s->f = ser->f;
2990         astman_append(s, "Asterisk Call Manager/%s\r\n", AMI_VERSION);  /* welcome prompt */
2991         for (;;) {
2992                 if ((res = do_message(s)) < 0)
2993                         break;
2994         }
2995         /* session is over, explain why and terminate */
2996         if (s->authenticated) {
2997                         if (manager_displayconnects(s))
2998                         ast_verb(2, "Manager '%s' logged off from %s\n", s->username, ast_inet_ntoa(s->sin.sin_addr));
2999                 ast_log(LOG_EVENT, "Manager '%s' logged off from %s\n", s->username, ast_inet_ntoa(s->sin.sin_addr));
3000         } else {
3001                         if (displayconnects)
3002                         ast_verb(2, "Connect attempt from '%s' unable to authenticate\n", ast_inet_ntoa(s->sin.sin_addr));
3003                 ast_log(LOG_EVENT, "Failed attempt from %s\n", ast_inet_ntoa(s->sin.sin_addr));
3004         }
3005
3006         /* It is possible under certain circumstances for this session thread
3007            to complete its work and exit *before* the thread that created it
3008            has finished executing the ast_pthread_create_background() function.
3009            If this occurs, some versions of glibc appear to act in a buggy
3010            fashion and attempt to write data into memory that it thinks belongs
3011            to the thread but is in fact not owned by the thread (or may have
3012            been freed completely).
3013
3014            Causing this thread to yield to other threads at least one time
3015            appears to work around this bug.
3016         */
3017         usleep(1);
3018
3019         destroy_session(s);
3020
3021 done:
3022         ser = ast_tcptls_session_instance_destroy(ser);
3023         return NULL;
3024 }
3025
3026 /*! \brief remove at most n_max stale session from the list. */
3027 static void purge_sessions(int n_max)
3028 {
3029         struct mansession *s;
3030         time_t now = time(NULL);
3031
3032         AST_LIST_LOCK(&sessions);
3033         AST_LIST_TRAVERSE_SAFE_BEGIN(&sessions, s, list) {
3034                 if (s->sessiontimeout && (now > s->sessiontimeout) && !s->inuse) {
3035                         AST_LIST_REMOVE_CURRENT(list);
3036                         ast_atomic_fetchadd_int(&num_sessions, -1);
3037                         if (s->authenticated && (VERBOSITY_ATLEAST(2)) && manager_displayconnects(s)) {
3038                                 ast_verb(2, "HTTP Manager '%s' timed out from %s\n",
3039                                         s->username, ast_inet_ntoa(s->sin.sin_addr));
3040                         }
3041                         free_session(s);        /* XXX outside ? */
3042                         if (--n_max <= 0)
3043                                 break;
3044                 }
3045         }
3046         AST_LIST_TRAVERSE_SAFE_END;
3047         AST_LIST_UNLOCK(&sessions);
3048 }
3049
3050 /*
3051  * events are appended to a queue from where they
3052  * can be dispatched to clients.
3053  */
3054 static int append_event(const char *str, int category)
3055 {
3056         struct eventqent *tmp = ast_malloc(sizeof(*tmp) + strlen(str));
3057         static int seq; /* sequence number */
3058
3059         if (!tmp)
3060                 return -1;
3061
3062         /* need to init all fields, because ast_malloc() does not */
3063         tmp->usecount = 0;
3064         tmp->category = category;
3065         tmp->seq = ast_atomic_fetchadd_int(&seq, 1);
3066         AST_LIST_NEXT(tmp, eq_next) = NULL;
3067         strcpy(tmp->eventdata, str);
3068
3069         AST_LIST_LOCK(&all_events);
3070         AST_LIST_INSERT_TAIL(&all_events, tmp, eq_next);
3071         AST_LIST_UNLOCK(&all_events);
3072
3073         return 0;
3074 }
3075
3076 /* XXX see if can be moved inside the function */
3077 AST_THREADSTORAGE(manager_event_buf);
3078 #define MANAGER_EVENT_BUF_INITSIZE   256
3079
3080 /*! \brief  manager_event: Send AMI event to client */
3081 int __manager_event(int category, const char *event,
3082         const char *file, int line, const char *func, const char *fmt, ...)
3083 {
3084         struct mansession *s;
3085         struct manager_custom_hook *hook;
3086         struct ast_str *auth = ast_str_alloca(80);
3087         const char *cat_str;
3088         va_list ap;
3089         struct timeval now;
3090         struct ast_str *buf;
3091
3092         /* Abort if there aren't any manager sessions */
3093         if (!num_sessions)
3094                 return 0;
3095
3096         if (!(buf = ast_str_thread_get(&manager_event_buf, MANAGER_EVENT_BUF_INITSIZE)))
3097                 return -1;
3098
3099         cat_str = authority_to_str(category, &auth);
3100         ast_str_set(&buf, 0,
3101                         "Event: %s\r\nPrivilege: %s\r\n",
3102                          event, cat_str);
3103
3104         if (timestampevents) {
3105                 now = ast_tvnow();
3106                 ast_str_append(&buf, 0,
3107                                 "Timestamp: %ld.%06lu\r\n",
3108                                  now.tv_sec, (unsigned long) now.tv_usec);
3109         }
3110         if (manager_debug) {
3111                 static int seq;
3112                 ast_str_append(&buf, 0,
3113                                 "SequenceNumber: %d\r\n",
3114                                  ast_atomic_fetchadd_int(&seq, 1));
3115                 ast_str_append(&buf, 0,
3116                                 "File: %s\r\nLine: %d\r\nFunc: %s\r\n", file, line, func);
3117         }
3118
3119         va_start(ap, fmt);
3120         ast_str_append_va(&buf, 0, fmt, ap);
3121         va_end(ap);
3122
3123         ast_str_append(&buf, 0, "\r\n");
3124
3125         append_event(buf->str, category);
3126
3127         /* Wake up any sleeping sessions */
3128         AST_LIST_LOCK(&sessions);
3129         AST_LIST_TRAVERSE(&sessions, s, list) {
3130                 ast_mutex_lock(&s->__lock);
3131                 if (s->waiting_thread != AST_PTHREADT_NULL)
3132                         pthread_kill(s->waiting_thread, SIGURG);
3133                 else
3134                         /* We have an event to process, but the mansession is
3135                          * not waiting for it. We still need to indicate that there
3136                          * is an event waiting so that get_input processes the pending
3137                          * event instead of polling.
3138                          */
3139                         s->pending_event = 1;
3140                 ast_mutex_unlock(&s->__lock);
3141         }
3142         AST_LIST_UNLOCK(&sessions);
3143
3144         AST_RWLIST_RDLOCK(&manager_hooks);
3145         AST_RWLIST_TRAVERSE(&manager_hooks, hook, list) {
3146                 hook->helper(category, event, buf->str);
3147         }
3148         AST_RWLIST_UNLOCK(&manager_hooks);
3149
3150         return 0;
3151 }
3152
3153 /*
3154  * support functions to register/unregister AMI action handlers,
3155  */
3156 int ast_manager_unregister(char *action)
3157 {
3158         struct manager_action *cur;
3159
3160         AST_RWLIST_WRLOCK(&actions);
3161         AST_RWLIST_TRAVERSE_SAFE_BEGIN(&actions, cur, list) {
3162                 if (!strcasecmp(action, cur->action)) {
3163                         AST_RWLIST_REMOVE_CURRENT(list);
3164                         ast_free(cur);
3165                         ast_verb(2, "Manager unregistered action %s\n", action);
3166                         break;
3167                 }
3168         }
3169         AST_RWLIST_TRAVERSE_SAFE_END;
3170         AST_RWLIST_UNLOCK(&actions);
3171
3172         return 0;
3173 }
3174
3175 static int manager_state_cb(char *context, char *exten, int state, void *data)
3176 {
3177         /* Notify managers of change */
3178         char hint[512];
3179         ast_get_hint(hint, sizeof(hint), NULL, 0, NULL, context, exten);
3180
3181         manager_event(EVENT_FLAG_CALL, "ExtensionStatus", "Exten: %s\r\nContext: %s\r\nHint: %s\r\nStatus: %d\r\n", exten, context, hint, state);
3182         return 0;
3183 }
3184
3185 static int ast_manager_register_struct(struct manager_action *act)
3186 {
3187         struct manager_action *cur, *prev = NULL;
3188
3189         AST_RWLIST_WRLOCK(&actions);
3190         AST_RWLIST_TRAVERSE(&actions, cur, list) {
3191                 int ret = strcasecmp(cur->action, act->action);
3192                 if (ret == 0) {
3193                         ast_log(LOG_WARNING, "Manager: Action '%s' already registered\n", act->action);
3194                         AST_RWLIST_UNLOCK(&actions);
3195                         return -1;
3196                 }
3197                 if (ret > 0) { /* Insert these alphabetically */
3198                         prev = cur;
3199                         break;
3200                 }
3201         }
3202         
3203         if (prev)       
3204                 AST_RWLIST_INSERT_AFTER(&actions, prev, act, list);
3205         else
3206                 AST_RWLIST_INSERT_HEAD(&actions, act, list);
3207
3208         ast_verb(2, "Manager registered action %s\n", act->action);
3209
3210         AST_RWLIST_UNLOCK(&actions);
3211
3212         return 0;
3213 }
3214
3215 /*! \brief register a new command with manager, including online help. This is
3216         the preferred way to register a manager command */
3217 int ast_manager_register2(const char *action, int auth, int (*func)(struct mansession *s, const struct message *m), const char *synopsis, const char *description)
3218 {
3219         struct manager_action *cur = NULL;
3220
3221         if (!(cur = ast_calloc(1, sizeof(*cur))))
3222                 return -1;
3223
3224         cur->action = action;
3225         cur->authority = auth;
3226         cur->func = func;
3227         cur->synopsis = synopsis;
3228         cur->description = description;
3229
3230         ast_manager_register_struct(cur);
3231
3232         return 0;
3233 }
3234 /*! @}
3235  END Doxygen group */
3236
3237 /*
3238  * The following are support functions for AMI-over-http.
3239  * The common entry point is generic_http_callback(),
3240  * which extracts HTTP header and URI fields and reformats
3241  * them into AMI messages, locates a proper session
3242  * (using the mansession_id Cookie or GET variable),
3243  * and calls process_message() as for regular AMI clients.
3244  * When done, the output (which goes to a temporary file)
3245  * is read back into a buffer and reformatted as desired,
3246  * then fed back to the client over the original socket.
3247  */