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