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