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