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