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