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