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