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