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