4c2a340b7d1de9033fd629c0ee2cf156c00e26fb
[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 /*
2362  * Done with the action handlers here, we start with the code in charge
2363  * of accepting connections and serving them.
2364  * accept_thread() forks a new thread for each connection, session_do(),
2365  * which in turn calls get_input() repeatedly until a full message has
2366  * been accumulated, and then invokes process_message() to pass it to
2367  * the appropriate handler.
2368  */
2369
2370 /*
2371  * Process an AMI message, performing desired action.
2372  * Return 0 on success, -1 on error that require the session to be destroyed.
2373  */
2374 static int process_message(struct mansession *s, const struct message *m)
2375 {
2376         char action[80] = "";
2377         int ret = 0;
2378         struct manager_action *tmp;
2379         const char *user = astman_get_header(m, "Username");
2380
2381         ast_copy_string(action, astman_get_header(m, "Action"), sizeof(action));
2382         ast_debug(1, "Manager received command '%s'\n", action);
2383
2384         if (ast_strlen_zero(action)) {
2385                 ast_mutex_lock(&s->__lock);
2386                 astman_send_error(s, m, "Missing action in request");
2387                 ast_mutex_unlock(&s->__lock);
2388                 return 0;
2389         }
2390
2391         if (!s->authenticated && strcasecmp(action, "Login") && strcasecmp(action, "Logoff") && strcasecmp(action, "Challenge")) {
2392                 ast_mutex_lock(&s->__lock);
2393                 astman_send_error(s, m, "Permission denied");
2394                 ast_mutex_unlock(&s->__lock);
2395                 return 0;
2396         }
2397
2398         if (!allowmultiplelogin && !s->authenticated && user &&
2399                 (!strcasecmp(action, "Login") || !strcasecmp(action, "Challenge"))) {
2400                 if (check_manager_session_inuse(user)) {
2401                         sleep(1);
2402                         ast_mutex_lock(&s->__lock);
2403                         astman_send_error(s, m, "Login Already In Use");
2404                         ast_mutex_unlock(&s->__lock);
2405                         return -1;
2406                 }
2407         }
2408
2409         AST_RWLIST_RDLOCK(&actions);
2410         AST_RWLIST_TRAVERSE(&actions, tmp, list) {
2411                 if (strcasecmp(action, tmp->action))
2412                         continue;
2413                 if ((s->writeperm & tmp->authority) == tmp->authority)
2414                         ret = tmp->func(s, m);
2415                 else
2416                         astman_send_error(s, m, "Permission denied");
2417                 break;
2418         }
2419         AST_RWLIST_UNLOCK(&actions);
2420
2421         if (!tmp) {
2422                 ast_mutex_lock(&s->__lock);
2423                 astman_send_error(s, m, "Invalid/unknown command. Use Action: ListCommands to show available commands.");
2424                 ast_mutex_unlock(&s->__lock);
2425         }
2426         if (ret)
2427                 return ret;
2428         /* Once done with our message, deliver any pending events */
2429         return process_events(s);
2430 }
2431
2432 /*!
2433  * Read one full line (including crlf) from the manager socket.
2434  * \note \verbatim
2435  * \r\n is the only valid terminator for the line.
2436  * (Note that, later, '\0' will be considered as the end-of-line marker,
2437  * so everything between the '\0' and the '\r\n' will not be used).
2438  * Also note that we assume output to have at least "maxlen" space.
2439  * \endverbatim
2440  */
2441 static int get_input(struct mansession *s, char *output)
2442 {
2443         int res, x;
2444         int maxlen = sizeof(s->inbuf) - 1;
2445         char *src = s->inbuf;
2446
2447         /*
2448          * Look for \r\n within the buffer. If found, copy to the output
2449          * buffer and return, trimming the \r\n (not used afterwards).
2450          */
2451         for (x = 0; x < s->inlen; x++) {
2452                 int cr; /* set if we have \r */
2453                 if (src[x] == '\r' && x+1 < s->inlen && src[x+1] == '\n')
2454                         cr = 2; /* Found. Update length to include \r\n */
2455                 else if (src[x] == '\n')
2456                         cr = 1; /* also accept \n only */
2457                 else
2458                         continue;
2459                 memmove(output, src, x);        /*... but trim \r\n */
2460                 output[x] = '\0';               /* terminate the string */
2461                 x += cr;                        /* number of bytes used */
2462                 s->inlen -= x;                  /* remaining size */
2463                 memmove(src, src + x, s->inlen); /* remove used bytes */
2464                 return 1;
2465         }
2466         if (s->inlen >= maxlen) {
2467                 /* no crlf found, and buffer full - sorry, too long for us */
2468                 ast_log(LOG_WARNING, "Dumping long line with no return from %s: %s\n", ast_inet_ntoa(s->sin.sin_addr), src);
2469                 s->inlen = 0;
2470         }
2471         res = 0;
2472         while (res == 0) {
2473                 /* XXX do we really need this locking ? */
2474                 ast_mutex_lock(&s->__lock);
2475                 s->waiting_thread = pthread_self();
2476                 ast_mutex_unlock(&s->__lock);
2477
2478                 res = ast_wait_for_input(s->fd, -1);    /* return 0 on timeout ? */
2479
2480                 ast_mutex_lock(&s->__lock);
2481                 s->waiting_thread = AST_PTHREADT_NULL;
2482                 ast_mutex_unlock(&s->__lock);
2483         }
2484         if (res < 0) {
2485                 /* If we get a signal from some other thread (typically because
2486                  * there are new events queued), return 0 to notify the caller.
2487                  */
2488                 if (errno == EINTR)
2489                         return 0;
2490                 ast_log(LOG_WARNING, "poll() returned error: %s\n", strerror(errno));
2491                 return -1;
2492         }
2493         ast_mutex_lock(&s->__lock);
2494         res = fread(src + s->inlen, 1, maxlen - s->inlen, s->f);
2495         if (res < 1)
2496                 res = -1;       /* error return */
2497         else {
2498                 s->inlen += res;
2499                 src[s->inlen] = '\0';
2500                 res = 0;
2501         }
2502         ast_mutex_unlock(&s->__lock);
2503         return res;
2504 }
2505
2506 static int do_message(struct mansession *s)
2507 {
2508         struct message m = { 0 };
2509         char header_buf[sizeof(s->inbuf)] = { '\0' };
2510         int res;
2511
2512         for (;;) {
2513                 /* Check if any events are pending and do them if needed */
2514                 if (process_events(s))
2515                         return -1;
2516                 res = get_input(s, header_buf);
2517                 if (res == 0) {
2518                         continue;
2519                 } else if (res > 0) {
2520                         if (ast_strlen_zero(header_buf))
2521                                 return process_message(s, &m) ? -1 : 0;
2522                         else if (m.hdrcount < (AST_MAX_MANHEADERS - 1))
2523                                 m.headers[m.hdrcount++] = ast_strdupa(header_buf);
2524                 } else {
2525                         return res;
2526                 }
2527         }
2528 }
2529
2530 /*! \brief The body of the individual manager session.
2531  * Call get_input() to read one line at a time
2532  * (or be woken up on new events), collect the lines in a
2533  * message until found an empty line, and execute the request.
2534  * In any case, deliver events asynchronously through process_events()
2535  * (called from here if no line is available, or at the end of
2536  * process_message(). )
2537  */
2538 static void *session_do(void *data)
2539 {
2540         struct server_instance *ser = data;
2541         struct mansession *s = ast_calloc(1, sizeof(*s));
2542         int flags;
2543         int res;
2544
2545         if (s == NULL)
2546                 goto done;
2547
2548         s->writetimeout = 100;
2549         s->waiting_thread = AST_PTHREADT_NULL;
2550
2551         flags = fcntl(ser->fd, F_GETFL);
2552         if (!block_sockets) /* make sure socket is non-blocking */
2553                 flags |= O_NONBLOCK;
2554         else
2555                 flags &= ~O_NONBLOCK;
2556         fcntl(ser->fd, F_SETFL, flags);
2557
2558         ast_mutex_init(&s->__lock);
2559         s->send_events = -1;
2560         /* these fields duplicate those in the 'ser' structure */
2561         s->fd = ser->fd;
2562         s->f = ser->f;
2563         s->sin = ser->requestor;
2564
2565         AST_LIST_LOCK(&sessions);
2566         AST_LIST_INSERT_HEAD(&sessions, s, list);
2567         ast_atomic_fetchadd_int(&num_sessions, 1);
2568         AST_LIST_UNLOCK(&sessions);
2569         /* Hook to the tail of the event queue */
2570         s->last_ev = grab_last();
2571         s->f = ser->f;
2572         astman_append(s, "Asterisk Call Manager/%s\r\n", AMI_VERSION);  /* welcome prompt */
2573         for (;;) {
2574                 if ((res = do_message(s)) < 0)
2575                         break;
2576         }
2577         /* session is over, explain why and terminate */
2578         if (s->authenticated) {
2579                         if (manager_displayconnects(s))
2580                         ast_verb(2, "Manager '%s' logged off from %s\n", s->username, ast_inet_ntoa(s->sin.sin_addr));
2581                 ast_log(LOG_EVENT, "Manager '%s' logged off from %s\n", s->username, ast_inet_ntoa(s->sin.sin_addr));
2582         } else {
2583                         if (displayconnects)
2584                         ast_verb(2, "Connect attempt from '%s' unable to authenticate\n", ast_inet_ntoa(s->sin.sin_addr));
2585                 ast_log(LOG_EVENT, "Failed attempt from %s\n", ast_inet_ntoa(s->sin.sin_addr));
2586         }
2587         destroy_session(s);
2588
2589 done:
2590         ast_free(ser);
2591         return NULL;
2592 }
2593
2594 /*! \brief remove at most n_max stale session from the list. */
2595 static void purge_sessions(int n_max)
2596 {
2597         struct mansession *s;
2598         time_t now = time(NULL);
2599
2600         AST_LIST_LOCK(&sessions);
2601         AST_LIST_TRAVERSE_SAFE_BEGIN(&sessions, s, list) {
2602                 if (s->sessiontimeout && (now > s->sessiontimeout) && !s->inuse) {
2603                         AST_LIST_REMOVE_CURRENT(list);
2604                         ast_atomic_fetchadd_int(&num_sessions, -1);
2605                         if (s->authenticated && (option_verbose > 1) && manager_displayconnects(s)) {
2606                                 ast_verb(2, "HTTP Manager '%s' timed out from %s\n",
2607                                         s->username, ast_inet_ntoa(s->sin.sin_addr));
2608                         }
2609                         free_session(s);        /* XXX outside ? */
2610                         if (--n_max <= 0)
2611                                 break;
2612                 }
2613         }
2614         AST_LIST_TRAVERSE_SAFE_END;
2615         AST_LIST_UNLOCK(&sessions);
2616 }
2617
2618 /*
2619  * events are appended to a queue from where they
2620  * can be dispatched to clients.
2621  */
2622 static int append_event(const char *str, int category)
2623 {
2624         struct eventqent *tmp = ast_malloc(sizeof(*tmp) + strlen(str));
2625         static int seq; /* sequence number */
2626
2627         if (!tmp)
2628                 return -1;
2629
2630         /* need to init all fields, because ast_malloc() does not */
2631         tmp->usecount = 0;
2632         tmp->category = category;
2633         tmp->seq = ast_atomic_fetchadd_int(&seq, 1);
2634         AST_LIST_NEXT(tmp, eq_next) = NULL;
2635         strcpy(tmp->eventdata, str);
2636
2637         AST_LIST_LOCK(&all_events);
2638         AST_LIST_INSERT_TAIL(&all_events, tmp, eq_next);
2639         AST_LIST_UNLOCK(&all_events);
2640
2641         return 0;
2642 }
2643
2644 /* XXX see if can be moved inside the function */
2645 AST_THREADSTORAGE(manager_event_buf);
2646 #define MANAGER_EVENT_BUF_INITSIZE   256
2647
2648 /*! \brief  manager_event: Send AMI event to client */
2649 int __manager_event(int category, const char *event,
2650         const char *file, int line, const char *func, const char *fmt, ...)
2651 {
2652         struct mansession *s;
2653         struct manager_custom_hook *hook;
2654         struct ast_str *auth = ast_str_alloca(80);
2655         const char *cat_str;
2656         va_list ap;
2657         struct timeval now;
2658         struct ast_str *buf;
2659
2660         /* Abort if there aren't any manager sessions */
2661         if (!num_sessions)
2662                 return 0;
2663
2664         if (!(buf = ast_str_thread_get(&manager_event_buf, MANAGER_EVENT_BUF_INITSIZE)))
2665                 return -1;
2666
2667         cat_str = authority_to_str(category, &auth);
2668         ast_str_set(&buf, 0,
2669                         "Event: %s\r\nPrivilege: %s\r\n",
2670                          event, cat_str);
2671
2672         if (timestampevents) {
2673                 now = ast_tvnow();
2674                 ast_str_append(&buf, 0,
2675                                 "Timestamp: %ld.%06lu\r\n",
2676                                  now.tv_sec, (unsigned long) now.tv_usec);
2677         }
2678         if (manager_debug) {
2679                 static int seq;
2680                 ast_str_append(&buf, 0,
2681                                 "SequenceNumber: %d\r\n",
2682                                  ast_atomic_fetchadd_int(&seq, 1));
2683                 ast_str_append(&buf, 0,
2684                                 "File: %s\r\nLine: %d\r\nFunc: %s\r\n", file, line, func);
2685         }
2686
2687         va_start(ap, fmt);
2688         ast_str_append_va(&buf, 0, fmt, ap);
2689         va_end(ap);
2690
2691         ast_str_append(&buf, 0, "\r\n");
2692
2693         append_event(buf->str, category);
2694
2695         /* Wake up any sleeping sessions */
2696         AST_LIST_LOCK(&sessions);
2697         AST_LIST_TRAVERSE(&sessions, s, list) {
2698                 ast_mutex_lock(&s->__lock);
2699                 if (s->waiting_thread != AST_PTHREADT_NULL)
2700                         pthread_kill(s->waiting_thread, SIGURG);
2701                 ast_mutex_unlock(&s->__lock);
2702         }
2703         AST_LIST_UNLOCK(&sessions);
2704
2705         AST_RWLIST_RDLOCK(&manager_hooks);
2706         AST_RWLIST_TRAVERSE(&manager_hooks, hook, list) {
2707                 hook->helper(category, event, buf->str);
2708         }
2709         AST_RWLIST_UNLOCK(&manager_hooks);
2710
2711         return 0;
2712 }
2713
2714 /*
2715  * support functions to register/unregister AMI action handlers,
2716  */
2717 int ast_manager_unregister(char *action)
2718 {
2719         struct manager_action *cur;
2720
2721         AST_RWLIST_WRLOCK(&actions);
2722         AST_RWLIST_TRAVERSE_SAFE_BEGIN(&actions, cur, list) {
2723                 if (!strcasecmp(action, cur->action)) {
2724                         AST_RWLIST_REMOVE_CURRENT(list);
2725                         ast_free(cur);
2726                         ast_verb(2, "Manager unregistered action %s\n", action);
2727                         break;
2728                 }
2729         }
2730         AST_RWLIST_TRAVERSE_SAFE_END;
2731         AST_RWLIST_UNLOCK(&actions);
2732
2733         return 0;
2734 }
2735
2736 static int manager_state_cb(char *context, char *exten, int state, void *data)
2737 {
2738         /* Notify managers of change */
2739         char hint[BUFSIZ];
2740         ast_get_hint(hint, sizeof(hint), NULL, 0, NULL, context, exten);
2741
2742         manager_event(EVENT_FLAG_CALL, "ExtensionStatus", "Exten: %s\r\nContext: %s\r\nHint: %s\r\nStatus: %d\r\n", exten, context, hint, state);
2743         return 0;
2744 }
2745
2746 static int ast_manager_register_struct(struct manager_action *act)
2747 {
2748         struct manager_action *cur, *prev = NULL;
2749
2750         AST_RWLIST_WRLOCK(&actions);
2751         AST_RWLIST_TRAVERSE(&actions, cur, list) {
2752                 int ret = strcasecmp(cur->action, act->action);
2753                 if (ret == 0) {
2754                         ast_log(LOG_WARNING, "Manager: Action '%s' already registered\n", act->action);
2755                         AST_RWLIST_UNLOCK(&actions);
2756                         return -1;
2757                 }
2758                 if (ret > 0) { /* Insert these alphabetically */
2759                         prev = cur;
2760                         break;
2761                 }
2762         }
2763         
2764         if (prev)       
2765                 AST_RWLIST_INSERT_AFTER(&actions, prev, act, list);
2766         else
2767                 AST_RWLIST_INSERT_HEAD(&actions, act, list);
2768
2769         ast_verb(2, "Manager registered action %s\n", act->action);
2770
2771         AST_RWLIST_UNLOCK(&actions);
2772
2773         return 0;
2774 }
2775
2776 /*! \brief register a new command with manager, including online help. This is
2777         the preferred way to register a manager command */
2778 int ast_manager_register2(const char *action, int auth, int (*func)(struct mansession *s, const struct message *m), const char *synopsis, const char *description)
2779 {
2780         struct manager_action *cur = NULL;
2781
2782         if (!(cur = ast_calloc(1, sizeof(*cur))))
2783                 return -1;
2784
2785         cur->action = action;
2786         cur->authority = auth;
2787         cur->func = func;
2788         cur->synopsis = synopsis;
2789         cur->description = description;
2790
2791         ast_manager_register_struct(cur);
2792
2793         return 0;
2794 }
2795 /*! @}
2796  END Doxygen group */
2797
2798 /*
2799  * The following are support functions for AMI-over-http.
2800  * The common entry point is generic_http_callback(),
2801  * which extracts HTTP header and URI fields and reformats
2802  * them into AMI messages, locates a proper session
2803  * (using the mansession_id Cookie or GET variable),
2804  * and calls process_message() as for regular AMI clients.
2805  * When done, the output (which goes to a temporary file)
2806  * is read back into a buffer and reformatted as desired,
2807  * then fed back to the client over the original socket.
2808  */
2809
2810 enum output_format {
2811         FORMAT_RAW,
2812         FORMAT_HTML,
2813         FORMAT_XML,
2814 };
2815
2816 static char *contenttype[] = {
2817         [FORMAT_RAW] = "plain",
2818         [FORMAT_HTML] = "html",
2819         [FORMAT_XML] =  "xml",
2820 };
2821
2822 /*!
2823  * locate an http session in the list. The search key (ident) is
2824  * the value of the mansession_id cookie (0 is not valid and means
2825  * a session on the AMI socket).
2826  */
2827 static struct mansession *find_session(unsigned long ident)
2828 {
2829         struct mansession *s;
2830
2831         if (ident == 0)
2832                 return NULL;
2833
2834         AST_LIST_LOCK(&sessions);
2835         AST_LIST_TRAVERSE(&sessions, s, list) {
2836                 ast_mutex_lock(&s->__lock);
2837                 if (s->managerid == ident && !s->needdestroy) {
2838                         ast_atomic_fetchadd_int(&s->inuse, 1);
2839                         break;
2840                 }
2841                 ast_mutex_unlock(&s->__lock);
2842         }
2843         AST_LIST_UNLOCK(&sessions);
2844
2845         return s;
2846 }
2847
2848 int astman_verify_session_readpermissions(unsigned long ident, int perm)
2849 {
2850         int result = 0;
2851         struct mansession *s;
2852
2853         AST_LIST_LOCK(&sessions);
2854         AST_LIST_TRAVERSE(&sessions, s, list) {
2855                 ast_mutex_lock(&s->__lock);
2856                 if ((s->managerid == ident) && (s->readperm & perm)) {
2857                         result = 1;
2858                         ast_mutex_unlock(&s->__lock);
2859                         break;
2860                 }
2861                 ast_mutex_unlock(&s->__lock);
2862         }
2863         AST_LIST_UNLOCK(&sessions);
2864         return result;
2865 }
2866
2867 int astman_verify_session_writepermissions(unsigned long ident, int perm)
2868 {
2869         int result = 0;
2870         struct mansession *s;
2871
2872         AST_LIST_LOCK(&sessions);
2873         AST_LIST_TRAVERSE(&sessions, s, list) {
2874                 ast_mutex_lock(&s->__lock);
2875                 if ((s->managerid == ident) && (s->writeperm & perm)) {
2876                         result = 1;
2877                         ast_mutex_unlock(&s->__lock);
2878                         break;
2879                 }
2880                 ast_mutex_unlock(&s->__lock);
2881         }
2882         AST_LIST_UNLOCK(&sessions);
2883         return result;
2884 }
2885
2886 /*
2887  * convert to xml with various conversion:
2888  * mode & 1     -> lowercase;
2889  * mode & 2     -> replace non-alphanumeric chars with underscore
2890  */
2891 static void xml_copy_escape(struct ast_str **out, const char *src, int mode)
2892 {
2893         /* store in a local buffer to avoid calling ast_str_append too often */
2894         char buf[256];
2895         char *dst = buf;
2896         int space = sizeof(buf);
2897         /* repeat until done and nothing to flush */
2898         for ( ; *src || dst != buf ; src++) {
2899                 if (*src == '\0' || space < 10) {       /* flush */
2900                         *dst++ = '\0';
2901                         ast_str_append(out, 0, "%s", buf);
2902                         dst = buf;
2903                         space = sizeof(buf);
2904                         if (*src == '\0')
2905                                 break;
2906                 }
2907                         
2908                 if ( (mode & 2) && !isalnum(*src)) {
2909                         *dst++ = '_';
2910                         space--;
2911                         continue;
2912                 }
2913                 switch (*src) {
2914                 case '<':
2915                         strcpy(dst, "&lt;");
2916                         dst += 4;
2917                         space -= 4;
2918                         break;
2919                 case '>':
2920                         strcpy(dst, "&gt;");
2921                         dst += 4;
2922                         space -= 4;
2923                         break;
2924                 case '\"':
2925                         strcpy(dst, "&quot;");
2926                         dst += 6;
2927                         space -= 6;
2928                         break;
2929                 case '\'':
2930                         strcpy(dst, "&apos;");
2931                         dst += 6;
2932                         space -= 6;
2933                         break;
2934                 case '&':
2935                         strcpy(dst, "&amp;");
2936                         dst += 5;
2937                         space -= 5;
2938                         break;
2939
2940                 default:
2941                         *dst++ = mode ? tolower(*src) : *src;
2942                         space--;
2943                 }
2944         }
2945 }
2946
2947 struct variable_count {
2948         char *varname;
2949         int count;
2950 };
2951
2952 static int compress_char(char c)
2953 {
2954         c &= 0x7f;
2955         if (c < 32)
2956                 return 0;
2957         else if (c >= 'a' && c <= 'z')
2958                 return c - 64;
2959         else if (c > 'z')
2960                 return '_';
2961         else
2962                 return c - 32;
2963 }
2964
2965 static int variable_count_hash_fn(const void *vvc, const int flags)
2966 {
2967         const struct variable_count *vc = vvc;
2968         int res = 0, i;
2969         for (i = 0; i < 5; i++) {
2970                 if (vc->varname[i] == '\0')
2971                         break;
2972                 res += compress_char(vc->varname[i]) << (i * 6);
2973         }
2974         return res;
2975 }
2976
2977 static int variable_count_cmp_fn(void *obj, void *vstr, int flags)
2978 {
2979         /* Due to the simplicity of struct variable_count, it makes no difference
2980          * if you pass in objects or strings, the same operation applies. This is
2981          * due to the fact that the hash occurs on the first element, which means
2982          * the address of both the struct and the string are exactly the same. */
2983         struct variable_count *vc = obj;
2984         char *str = vstr;
2985         return !strcmp(vc->varname, str) ? CMP_MATCH : 0;
2986 }
2987
2988 /*! \brief Convert the input into XML or HTML.
2989  * The input is supposed to be a sequence of lines of the form
2990  *      Name: value
2991  * optionally followed by a blob of unformatted text.
2992  * A blank line is a section separator. Basically, this is a
2993  * mixture of the format of Manager Interface and CLI commands.
2994  * The unformatted text is considered as a single value of a field
2995  * named 'Opaque-data'.
2996  *
2997  * At the moment the output format is the following (but it may
2998  * change depending on future requirements so don't count too
2999  * much on it when writing applications):
3000  *
3001  * General: the unformatted text is used as a value of
3002  * XML output:  to be completed
3003  * 
3004  * \verbatim
3005  *   Each section is within <response type="object" id="xxx">
3006  *   where xxx is taken from ajaxdest variable or defaults to unknown
3007  *   Each row is reported as an attribute Name="value" of an XML
3008  *   entity named from the variable ajaxobjtype, default to "generic"
3009  * \endverbatim
3010  *
3011  * HTML output:
3012  *   each Name-value pair is output as a single row of a two-column table.
3013  *   Sections (blank lines in the input) are separated by a <HR>
3014  *
3015  */
3016 static void xml_translate(struct ast_str **out, char *in, struct ast_variable *vars, enum output_format format)
3017 {
3018         struct ast_variable *v;
3019         const char *dest = NULL;
3020         char *var, *val;
3021         const char *objtype = NULL;
3022         int in_data = 0;        /* parsing data */
3023         int inobj = 0;
3024         int xml = (format == FORMAT_XML);
3025         struct variable_count *vc = NULL;
3026         struct ao2_container *vco = NULL;
3027
3028         for (v = vars; v; v = v->next) {
3029                 if (!dest && !strcasecmp(v->name, "ajaxdest"))
3030                         dest = v->value;
3031                 else if (!objtype && !strcasecmp(v->name, "ajaxobjtype"))
3032                         objtype = v->value;
3033         }
3034         if (!dest)
3035                 dest = "unknown";
3036         if (!objtype)
3037                 objtype = "generic";
3038
3039         /* we want to stop when we find an empty line */
3040         while (in && *in) {
3041                 val = strsep(&in, "\r\n");      /* mark start and end of line */
3042                 if (in && *in == '\n')          /* remove trailing \n if any */
3043                         in++;
3044                 ast_trim_blanks(val);
3045                 ast_debug(5, "inobj %d in_data %d line <%s>\n", inobj, in_data, val);
3046                 if (ast_strlen_zero(val)) {
3047                         if (in_data) { /* close data */
3048                                 ast_str_append(out, 0, xml ? "'" : "</td></tr>\n");
3049                                 in_data = 0;
3050                         }
3051                         ast_str_append(out, 0, xml ? " /></response>\n" :
3052                                 "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
3053                         inobj = 0;
3054                         ao2_ref(vco, -1);
3055                         vco = NULL;
3056                         continue;
3057                 }
3058
3059                 /* we expect Name: value lines */
3060                 if (in_data) {
3061                         var = NULL;
3062                 } else {
3063                         var = strsep(&val, ":");
3064                         if (val) {      /* found the field name */
3065                                 val = ast_skip_blanks(val);
3066                                 ast_trim_blanks(var);
3067                         } else {                /* field name not found, move to opaque mode */
3068                                 val = var;
3069                                 var = "Opaque-data";
3070                         }
3071                 }
3072
3073                 if (!inobj) {
3074                         if (xml)
3075                                 ast_str_append(out, 0, "<response type='object' id='%s'><%s", dest, objtype);
3076                         else
3077                                 ast_str_append(out, 0, "<body>\n");
3078                         vco = ao2_container_alloc(37, variable_count_hash_fn, variable_count_cmp_fn);
3079                         inobj = 1;
3080                 }
3081
3082                 if (!in_data) { /* build appropriate line start */
3083                         ast_str_append(out, 0, xml ? " " : "<tr><td>");
3084                         if ((vc = ao2_find(vco, var, 0)))
3085                                 vc->count++;
3086                         else {
3087                                 /* Create a new entry for this one */
3088                                 vc = ao2_alloc(sizeof(*vc), NULL);
3089                                 vc->varname = var;
3090                                 vc->count = 1;
3091                                 ao2_link(vco, vc);
3092                         }
3093                         xml_copy_escape(out, var, xml ? 1 | 2 : 0);
3094                         if (vc->count > 1)
3095                                 ast_str_append(out, 0, "-%d", vc->count);
3096                         ao2_ref(vc, -1);
3097                         ast_str_append(out, 0, xml ? "='" : "</td><td>");
3098                         if (!strcmp(var, "Opaque-data"))
3099                                 in_data = 1;
3100                 }
3101                 xml_copy_escape(out, val, 0);   /* data field */
3102                 if (!in_data)
3103                         ast_str_append(out, 0, xml ? "'" : "</td></tr>\n");
3104                 else
3105                         ast_str_append(out, 0, xml ? "\n" : "<br>\n");
3106         }
3107         if (inobj) {
3108                 ast_str_append(out, 0, xml ? " /></response>\n" :
3109                         "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
3110                 ao2_ref(vco, -1);
3111         }
3112 }
3113
3114 static struct ast_str *generic_http_callback(enum output_format format,
3115                                              struct sockaddr_in *requestor, const char *uri,
3116                                              struct ast_variable *params, int *status,
3117                                              char **title, int *contentlength)
3118 {
3119         struct mansession *s = NULL;
3120         unsigned long ident = 0; /* invalid, so find_session will fail if not set through the cookie */
3121         int blastaway = 0;
3122         struct ast_variable *v;
3123         char template[] = "/tmp/ast-http-XXXXXX";       /* template for temporary file */
3124         struct ast_str *out = NULL;
3125         struct message m = { 0 };
3126         unsigned int x;
3127         size_t hdrlen;
3128
3129         for (v = params; v; v = v->next) {
3130                 if (!strcasecmp(v->name, "mansession_id")) {
3131                         sscanf(v->value, "%lx", &ident);
3132                         break;
3133                 }
3134         }
3135
3136         if (!(s = find_session(ident))) {
3137                 /* Create new session.
3138                  * While it is not in the list we don't need any locking
3139                  */
3140                 if (!(s = ast_calloc(1, sizeof(*s)))) {
3141                         *status = 500;
3142                         goto generic_callback_out;
3143                 }
3144                 s->sin = *requestor;
3145                 s->fd = -1;
3146                 s->waiting_thread = AST_PTHREADT_NULL;
3147                 s->send_events = 0;
3148                 ast_mutex_init(&s->__lock);
3149                 ast_mutex_lock(&s->__lock);
3150                 s->inuse = 1;
3151                 s->managerid = rand() | 1;      /* make sure it is non-zero */
3152                 s->last_ev = grab_last();
3153                 AST_LIST_LOCK(&sessions);
3154                 AST_LIST_INSERT_HEAD(&sessions, s, list);
3155                 ast_atomic_fetchadd_int(&num_sessions, 1);
3156                 AST_LIST_UNLOCK(&sessions);
3157         }
3158
3159         ast_mutex_unlock(&s->__lock);
3160
3161         if (!(out = ast_str_create(1024))) {
3162                 *status = 500;
3163                 goto generic_callback_out;
3164         }
3165
3166         s->fd = mkstemp(template);      /* create a temporary file for command output */
3167         unlink(template);
3168         s->f = fdopen(s->fd, "w+");
3169
3170         for (x = 0, v = params; v && (x < AST_MAX_MANHEADERS); x++, v = v->next) {
3171                 hdrlen = strlen(v->name) + strlen(v->value) + 3;
3172                 m.headers[m.hdrcount] = alloca(hdrlen);
3173                 snprintf((char *) m.headers[m.hdrcount], hdrlen, "%s: %s", v->name, v->value);
3174                 m.hdrcount = x + 1;
3175         }
3176
3177         if (process_message(s, &m)) {
3178                 if (s->authenticated) {
3179                                 if (manager_displayconnects(s))
3180                                 ast_verb(2, "HTTP Manager '%s' logged off from %s\n", s->username, ast_inet_ntoa(s->sin.sin_addr));
3181                         ast_log(LOG_EVENT, "HTTP Manager '%s' logged off from %s\n", s->username, ast_inet_ntoa(s->sin.sin_addr));
3182                 } else {
3183                                 if (displayconnects)
3184                                 ast_verb(2, "HTTP Connect attempt from '%s' unable to authenticate\n", ast_inet_ntoa(s->sin.sin_addr));
3185                         ast_log(LOG_EVENT, "HTTP Failed attempt from %s\n", ast_inet_ntoa(s->sin.sin_addr));
3186                 }
3187                 s->needdestroy = 1;
3188         }
3189
3190         ast_str_append(&out, 0,
3191                        "Content-type: text/%s\r\n"
3192                        "Cache-Control: no-cache;\r\n"
3193                        "Set-Cookie: mansession_id=\"%08lx\"; Version=\"1\"; Max-Age=%d\r\n"
3194                        "\r\n",
3195                         contenttype[format],
3196                         s->managerid, httptimeout);
3197
3198         if (format == FORMAT_XML) {
3199                 ast_str_append(&out, 0, "<ajax-response>\n");
3200         } else if (format == FORMAT_HTML) {
3201
3202 #define ROW_FMT "<tr><td colspan=\"2\" bgcolor=\"#f1f1ff\">%s</td></tr>\r\n"
3203 #define TEST_STRING \
3204         "<form action=\"manager\">action: <input name=\"action\"> cmd <input name=\"command\"><br> \
3205         user <input name=\"username\"> pass <input type=\"password\" name=\"secret\"><br> \
3206         <input type=\"submit\"></form>"
3207
3208                 ast_str_append(&out, 0, "<title>Asterisk&trade; Manager Interface</title>");
3209                 ast_str_append(&out, 0, "<body bgcolor=\"#ffffff\"><table align=center bgcolor=\"#f1f1f1\" width=\"500\">\r\n");
3210                 ast_str_append(&out, 0, ROW_FMT, "<h1>Manager Tester</h1>");
3211                 ast_str_append(&out, 0, ROW_FMT, TEST_STRING);
3212         }
3213
3214         if (s->f != NULL) {     /* have temporary output */
3215                 char *buf;
3216                 size_t l = ftell(s->f);
3217                 
3218                 if (l) {
3219                         if ((buf = mmap(NULL, l, PROT_READ | PROT_WRITE, MAP_SHARED, s->fd, 0))) {
3220                                 if (format == FORMAT_XML || format == FORMAT_HTML)
3221                                         xml_translate(&out, buf, params, format);
3222                                 else
3223                                         ast_str_append(&out, 0, buf);
3224                                 munmap(buf, l);
3225                         }
3226                 } else if (format == FORMAT_XML || format == FORMAT_HTML) {
3227                         xml_translate(&out, "", params, format);
3228                 }
3229                 fclose(s->f);
3230                 s->f = NULL;
3231                 s->fd = -1;
3232         }
3233
3234         if (format == FORMAT_XML) {
3235                 ast_str_append(&out, 0, "</ajax-response>\n");
3236         } else if (format == FORMAT_HTML)
3237                 ast_str_append(&out, 0, "</table></body>\r\n");
3238
3239         ast_mutex_lock(&s->__lock);
3240         /* Reset HTTP timeout.  If we're not authenticated, keep it extremely short */
3241         s->sessiontimeout = time(NULL) + ((s->authenticated || httptimeout < 5) ? httptimeout : 5);
3242
3243         if (s->needdestroy) {
3244                 if (s->inuse == 1) {
3245                         ast_debug(1, "Need destroy, doing it now!\n");
3246                         blastaway = 1;
3247                 } else {
3248                         ast_debug(1, "Need destroy, but can't do it yet!\n");
3249                         if (s->waiting_thread != AST_PTHREADT_NULL)
3250                                 pthread_kill(s->waiting_thread, SIGURG);
3251                         s->inuse--;
3252                 }
3253         } else
3254                 s->inuse--;
3255         ast_mutex_unlock(&s->__lock);
3256
3257         if (blastaway)
3258                 destroy_session(s);
3259 generic_callback_out:
3260         if (*status != 200)
3261                 return ast_http_error(500, "Server Error", NULL, "Internal Server Error (out of memory)\n");
3262         return out;
3263 }
3264
3265 static struct ast_str *manager_http_callback(struct server_instance *ser, const char *uri, struct ast_variable *params, int *status, char **title, int *contentlength)
3266 {
3267         return generic_http_callback(FORMAT_HTML, &ser->requestor, uri, params, status, title, contentlength);
3268 }
3269
3270 static struct ast_str *mxml_http_callback(struct server_instance *ser, const char *uri, struct ast_variable *params, int *status, char **title, int *contentlength)
3271 {
3272         return generic_http_callback(FORMAT_XML, &ser->requestor, uri, params, status, title, contentlength);
3273 }
3274
3275 static struct ast_str *rawman_http_callback(struct server_instance *ser, const char *uri, struct ast_variable *params, int *status, char **title, int *contentlength)
3276 {
3277         return generic_http_callback(FORMAT_RAW, &ser->requestor, uri, params, status, title, contentlength);
3278 }
3279
3280 struct ast_http_uri rawmanuri = {
3281         .description = "Raw HTTP Manager Event Interface",
3282         .uri = "rawman",
3283         .has_subtree = 0,
3284         .callback = rawman_http_callback,
3285 };
3286
3287 struct ast_http_uri manageruri = {
3288         .description = "HTML Manager Event Interface",
3289         .uri = "manager",
3290         .has_subtree = 0,
3291         .callback = manager_http_callback,
3292 };
3293
3294 struct ast_http_uri managerxmluri = {
3295         .description = "XML Manager Event Interface",
3296         .uri = "mxml",
3297         .has_subtree = 0,
3298         .callback = mxml_http_callback,
3299 };
3300
3301 static int registered = 0;
3302 static int webregged = 0;
3303
3304 /*! \brief cleanup code called at each iteration of server_root,
3305  * guaranteed to happen every 5 seconds at most
3306  */
3307 static void purge_old_stuff(void *data)
3308 {
3309         purge_sessions(1);
3310         purge_events();
3311 }
3312
3313 struct tls_config ami_tls_cfg;
3314 static struct server_args ami_desc = {
3315         .accept_fd = -1,
3316         .master = AST_PTHREADT_NULL,
3317         .tls_cfg = NULL, 
3318         .poll_timeout = 5000,   /* wake up every 5 seconds */
3319         .periodic_fn = purge_old_stuff,
3320         .name = "AMI server",
3321         .accept_fn = server_root,       /* thread doing the accept() */
3322         .worker_fn = session_do,        /* thread handling the session */
3323 };
3324
3325 static struct server_args amis_desc = {
3326         .accept_fd = -1,
3327         .master = AST_PTHREADT_NULL,
3328         .tls_cfg = &ami_tls_cfg, 
3329         .poll_timeout = -1,     /* the other does the periodic cleanup */
3330         .name = "AMI TLS server",
3331         .accept_fn = server_root,       /* thread doing the accept() */
3332         .worker_fn = session_do,        /* thread handling the session */
3333 };
3334
3335 static int __init_manager(int reload)
3336 {
3337         struct ast_config *cfg = NULL;
3338         const char *val;
3339         char *cat = NULL;
3340         int newhttptimeout = 60;
3341         int have_sslbindaddr = 0;
3342         struct hostent *hp;
3343         struct ast_hostent ahp;
3344         struct ast_manager_user *user = NULL;
3345         struct ast_variable *var;
3346         struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
3347
3348         if (!registered) {
3349                 /* Register default actions */
3350                 ast_manager_register2("Ping", 0, action_ping, "Keepalive command", mandescr_ping);
3351                 ast_manager_register2("Events", 0, action_events, "Control Event Flow", mandescr_events);
3352                 ast_manager_register2("Logoff", 0, action_logoff, "Logoff Manager", mandescr_logoff);
3353                 ast_manager_register2("Login", 0, action_login, "Login Manager", NULL);
3354                 ast_manager_register2("Challenge", 0, action_challenge, "Generate Challenge for MD5 Auth", NULL);
3355                 ast_manager_register2("Hangup", EVENT_FLAG_CALL, action_hangup, "Hangup Channel", mandescr_hangup);
3356                 ast_manager_register("Status", EVENT_FLAG_CALL, action_status, "Lists channel status" );
3357                 ast_manager_register2("Setvar", EVENT_FLAG_CALL, action_setvar, "Set Channel Variable", mandescr_setvar );
3358                 ast_manager_register2("Getvar", EVENT_FLAG_CALL, action_getvar, "Gets a Channel Variable", mandescr_getvar );
3359                 ast_manager_register2("GetConfig", EVENT_FLAG_CONFIG, action_getconfig, "Retrieve configuration", mandescr_getconfig);
3360                 ast_manager_register2("GetConfigJSON", EVENT_FLAG_CONFIG, action_getconfigjson, "Retrieve configuration (JSON format)", mandescr_getconfigjson);
3361                 ast_manager_register2("UpdateConfig", EVENT_FLAG_CONFIG, action_updateconfig, "Update basic configuration", mandescr_updateconfig);
3362                 ast_manager_register2("Redirect", EVENT_FLAG_CALL, action_redirect, "Redirect (transfer) a call", mandescr_redirect );
3363                 ast_manager_register2("Originate", EVENT_FLAG_CALL, action_originate, "Originate Call", mandescr_originate);
3364                 ast_manager_register2("Command", EVENT_FLAG_COMMAND, action_command, "Execute Asterisk CLI Command", mandescr_command );
3365                 ast_manager_register2("ExtensionState", EVENT_FLAG_CALL, action_extensionstate, "Check Extension Status", mandescr_extensionstate );
3366                 ast_manager_register2("AbsoluteTimeout", EVENT_FLAG_CALL, action_timeout, "Set Absolute Timeout", mandescr_timeout );
3367                 ast_manager_register2("MailboxStatus", EVENT_FLAG_CALL, action_mailboxstatus, "Check Mailbox", mandescr_mailboxstatus );
3368                 ast_manager_register2("MailboxCount", EVENT_FLAG_CALL, action_mailboxcount, "Check Mailbox Message Count", mandescr_mailboxcount );
3369                 ast_manager_register2("ListCommands", 0, action_listcommands, "List available manager commands", mandescr_listcommands);
3370                 ast_manager_register2("SendText", EVENT_FLAG_CALL, action_sendtext, "Send text message to channel", mandescr_sendtext);
3371                 ast_manager_register2("UserEvent", EVENT_FLAG_USER, action_userevent, "Send an arbitrary event", mandescr_userevent);
3372                 ast_manager_register2("WaitEvent", 0, action_waitevent, "Wait for an event to occur", mandescr_waitevent);
3373                 ast_manager_register2("CoreSettings", EVENT_FLAG_SYSTEM, action_coresettings, "Show PBX core settings (version etc)", mandescr_coresettings);
3374                 ast_manager_register2("CoreStatus", EVENT_FLAG_SYSTEM, action_corestatus, "Show PBX core status variables", mandescr_corestatus);
3375                 ast_manager_register2("Reload", EVENT_FLAG_CONFIG, action_reload, "Send a reload event", mandescr_reload);
3376
3377                 ast_cli_register_multiple(cli_manager, sizeof(cli_manager) / sizeof(struct ast_cli_entry));
3378                 ast_extension_state_add(NULL, NULL, manager_state_cb, NULL);
3379                 registered = 1;
3380                 /* Append placeholder event so master_eventq never runs dry */
3381                 append_event("Event: Placeholder\r\n\r\n", 0);
3382         }
3383         if ((cfg = ast_config_load("manager.conf", config_flags)) == CONFIG_STATUS_FILEUNCHANGED)
3384                 return 0;
3385
3386         displayconnects = 1;
3387         if (!cfg) {
3388                 ast_log(LOG_NOTICE, "Unable to open management configuration manager.conf.  Call management disabled.\n");
3389                 return 0;
3390         }
3391
3392         /* default values */
3393         memset(&ami_desc.sin, 0, sizeof(struct sockaddr_in));
3394         memset(&amis_desc.sin, 0, sizeof(amis_desc.sin));
3395         amis_desc.sin.sin_port = htons(5039);
3396         ami_desc.sin.sin_port = htons(DEFAULT_MANAGER_PORT);
3397
3398         ami_tls_cfg.enabled = 0;
3399         if (ami_tls_cfg.certfile)
3400                 ast_free(ami_tls_cfg.certfile);
3401         ami_tls_cfg.certfile = ast_strdup(AST_CERTFILE);
3402         if (ami_tls_cfg.cipher)
3403                 ast_free(ami_tls_cfg.cipher);
3404         ami_tls_cfg.cipher = ast_strdup("");
3405
3406         for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
3407                 val = var->value;
3408                 if (!strcasecmp(var->name, "sslenable"))
3409                         ami_tls_cfg.enabled = ast_true(val);
3410                 else if (!strcasecmp(var->name, "sslbindport"))
3411                         amis_desc.sin.sin_port = htons(atoi(val));
3412                 else if (!strcasecmp(var->name, "sslbindaddr")) {
3413                         if ((hp = ast_gethostbyname(val, &ahp))) {
3414                                 memcpy(&amis_desc.sin.sin_addr, hp->h_addr, sizeof(amis_desc.sin.sin_addr));
3415                                 have_sslbindaddr = 1;
3416                         } else {
3417                                 ast_log(LOG_WARNING, "Invalid bind address '%s'\n", val);
3418                         }
3419                 } else if (!strcasecmp(var->name, "sslcert")) {
3420                         ast_free(ami_tls_cfg.certfile);
3421                         ami_tls_cfg.certfile = ast_strdup(val);
3422                 } else if (!strcasecmp(var->name, "sslcipher")) {
3423                         ast_free(ami_tls_cfg.cipher);
3424                         ami_tls_cfg.cipher = ast_strdup(val);
3425                 } else if (!strcasecmp(var->name, "enabled")) {
3426                         manager_enabled = ast_true(val);
3427                 } else if (!strcasecmp(var->name, "block-sockets")) {
3428                         block_sockets = ast_true(val);
3429                 } else if (!strcasecmp(var->name, "webenabled")) {
3430                         webmanager_enabled = ast_true(val);
3431                 } else if (!strcasecmp(var->name, "port")) {
3432                         ami_desc.sin.sin_port = htons(atoi(val));
3433                 } else if (!strcasecmp(var->name, "bindaddr")) {
3434                         if (!inet_aton(val, &ami_desc.sin.sin_addr)) {
3435                                 ast_log(LOG_WARNING, "Invalid address '%s' specified, using 0.0.0.0\n", val);
3436                                 memset(&ami_desc.sin.sin_addr, 0, sizeof(ami_desc.sin.sin_addr));
3437                         }
3438                 } else if (!strcasecmp(var->name, "allowmultiplelogin")) { 
3439                         allowmultiplelogin = ast_true(val);
3440                 } else if (!strcasecmp(var->name, "displayconnects")) {
3441                         displayconnects = ast_true(val);
3442                 } else if (!strcasecmp(var->name, "timestampevents")) {
3443                         timestampevents = ast_true(val);
3444                 } else if (!strcasecmp(var->name, "debug")) {
3445                         manager_debug = ast_true(val);
3446                 } else if (!strcasecmp(var->name, "httptimeout")) {
3447                         newhttptimeout = atoi(val);
3448                 } else {
3449                         ast_log(LOG_NOTICE, "Invalid keyword <%s> = <%s> in manager.conf [general]\n",
3450                                 var->name, val);
3451                 }       
3452         }
3453
3454         if (manager_enabled)
3455                 ami_desc.sin.sin_family = AF_INET;
3456         if (!have_sslbindaddr)
3457                 amis_desc.sin.sin_addr = ami_desc.sin.sin_addr;
3458         if (ami_tls_cfg.enabled)
3459                 amis_desc.sin.sin_family = AF_INET;
3460
3461         
3462         AST_RWLIST_WRLOCK(&users);
3463
3464         while ((cat = ast_category_browse(cfg, cat))) {
3465
3466                 if (!strcasecmp(cat, "general"))
3467                         continue;
3468
3469                 /* Look for an existing entry, if none found - create one and add it to the list */
3470                 if (!(user = get_manager_by_name_locked(cat))) {
3471                         if (!(user = ast_calloc(1, sizeof(*user))))
3472                                 break;
3473                         /* Copy name over */
3474                         ast_copy_string(user->username, cat, sizeof(user->username));
3475                         /* Insert into list */
3476                         AST_RWLIST_INSERT_TAIL(&users, user, list);
3477                 }
3478
3479                 /* Make sure we keep this user and don't destroy it during cleanup */
3480                 user->keep = 1;
3481                 /* Default displayconnect to [general] */
3482                 user->displayconnects = displayconnects;
3483
3484                 var = ast_variable_browse(cfg, cat);
3485                 while (var) {
3486                         if (!strcasecmp(var->name, "secret")) {
3487                                 if (user->secret)
3488                                         ast_free(user->secret);
3489                                 user->secret = ast_strdup(var->value);
3490                         } else if (!strcasecmp(var->name, "deny") ) {
3491                                 if (user->deny)
3492                                         ast_free(user->deny);
3493                                 user->deny = ast_strdup(var->value);
3494                         } else if (!strcasecmp(var->name, "permit") ) {
3495                                 if (user->permit)
3496                                         ast_free(user->permit);
3497                                 user->permit = ast_strdup(var->value);
3498                         }  else if (!strcasecmp(var->name, "read") ) {
3499                                 if (user->read)
3500                                         ast_free(user->read);
3501                                 user->read = ast_strdup(var->value);
3502                         }  else if (!strcasecmp(var->name, "write") ) {
3503                                 if (user->write)
3504                                         ast_free(user->write);
3505                                 user->write = ast_strdup(var->value);
3506                         }  else if (!strcasecmp(var->name, "displayconnects") )
3507                                 user->displayconnects = ast_true(var->value);
3508                         else {
3509                                 ast_debug(1, "%s is an unknown option.\n", var->name);
3510                         }
3511                         var = var->next;
3512                 }
3513         }
3514
3515         /* Perform cleanup - essentially prune out old users that no longer exist */
3516         AST_RWLIST_TRAVERSE_SAFE_BEGIN(&users, user, list) {
3517                 if (user->keep) {       /* valid record. clear flag for the next round */
3518                         user->keep = 0;
3519                         continue;
3520                 }
3521                 /* We do not need to keep this user so take them out of the list */
3522                 AST_RWLIST_REMOVE_CURRENT(list);
3523                 /* Free their memory now */
3524                 if (user->secret)
3525                         ast_free(user->secret);
3526                 if (user->deny)
3527                         ast_free(user->deny);
3528                 if (user->permit)
3529                         ast_free(user->permit);
3530                 if (user->read)
3531                         ast_free(user->read);
3532                 if (user->write)
3533                         ast_free(user->write);
3534                 ast_free(user);
3535         }
3536         AST_RWLIST_TRAVERSE_SAFE_END;
3537
3538         AST_RWLIST_UNLOCK(&users);
3539
3540         ast_config_destroy(cfg);
3541
3542         if (webmanager_enabled && manager_enabled) {
3543                 if (!webregged) {
3544                         ast_http_uri_link(&rawmanuri);
3545                         ast_http_uri_link(&manageruri);
3546                         ast_http_uri_link(&managerxmluri);
3547                         webregged = 1;
3548                 }
3549         } else {
3550                 if (webregged) {
3551                         ast_http_uri_unlink(&rawmanuri);
3552                         ast_http_uri_unlink(&manageruri);
3553                         ast_http_uri_unlink(&managerxmluri);
3554                         webregged = 0;
3555                 }
3556         }
3557
3558         if (newhttptimeout > 0)
3559                 httptimeout = newhttptimeout;
3560
3561         server_start(&ami_desc);
3562         if (ssl_setup(amis_desc.tls_cfg))
3563                 server_start(&amis_desc);
3564         return 0;
3565 }
3566
3567 int init_manager(void)
3568 {
3569         return __init_manager(0);
3570 }
3571
3572 int reload_manager(void)
3573 {
3574         manager_event(EVENT_FLAG_SYSTEM, "Reload", "Message: Reload Requested\r\n");
3575         return __init_manager(1);
3576 }