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