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