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