Wed Mar 3 23:01:47 2010

Asterisk developer's documentation


manager.c File Reference

The Asterisk Management Interface - AMI. More...

#include "asterisk.h"
#include "asterisk/_private.h"
#include "asterisk/paths.h"
#include <ctype.h>
#include <sys/time.h>
#include <signal.h>
#include <sys/mman.h>
#include "asterisk/channel.h"
#include "asterisk/file.h"
#include "asterisk/manager.h"
#include "asterisk/module.h"
#include "asterisk/config.h"
#include "asterisk/callerid.h"
#include "asterisk/lock.h"
#include "asterisk/cli.h"
#include "asterisk/app.h"
#include "asterisk/pbx.h"
#include "asterisk/md5.h"
#include "asterisk/acl.h"
#include "asterisk/utils.h"
#include "asterisk/tcptls.h"
#include "asterisk/http.h"
#include "asterisk/ast_version.h"
#include "asterisk/threadstorage.h"
#include "asterisk/linkedlists.h"
#include "asterisk/version.h"
#include "asterisk/term.h"
#include "asterisk/astobj2.h"
#include "asterisk/features.h"
Include dependency graph for manager.c:

Go to the source code of this file.

Data Structures

struct  ast_manager_user
 user descriptor, as read from the config file. More...
struct  eventqent
struct  fast_originate_helper
 helper function for originate More...
struct  mansession
struct  mansession_session
struct  permalias
struct  variable_count

Defines

#define ASTMAN_APPEND_BUF_INITSIZE   256
 initial allocated size for the astman_append_buf
#define GET_HEADER_FIRST_MATCH   0
#define GET_HEADER_LAST_MATCH   1
#define GET_HEADER_SKIP_EMPTY   2
#define HSMC_FORMAT   " %-15.15s %-15.15s %-55.55s\n"
#define HSMCONN_FORMAT1   " %-15.15s %-15.15s %-10.10s %-10.10s %-8.8s %-8.8s %-5.5s %-5.5s\n"
#define HSMCONN_FORMAT2   " %-15.15s %-15.15s %-10d %-10d %-8d %-8d %-5.5d %-5.5d\n"
#define MANAGER_EVENT_BUF_INITSIZE   256
#define MAX_BLACKLIST_CMD_LEN   2
 Descriptor for a manager session, either on the AMI socket or over HTTP.
#define MSG_MOREDATA   ((char *)astman_send_response)
 send a response with an optional message, and terminate it with an empty line. m is used only to grab the 'ActionID' field.
#define NEW_EVENT(m)   (AST_LIST_NEXT(m->session->last_ev, eq_next))
#define ROW_FMT   "<tr><td colspan=\"2\" bgcolor=\"#f1f1ff\">%s</td></tr>\r\n"
#define TEST_STRING   "<form action=\"manager\">\n\ Action: <select name=\"action\">\n\ <option value=\"\">-----&gt;</option>\n\ <option value=\"login\">login</option>\n\ <option value=\"command\">Command</option>\n\ <option value=\"waitevent\">waitevent</option>\n\ <option value=\"listcommands\">listcommands</option>\n\ </select>\n\ or <input name=\"action\"><br/>\n\ CLI Command <input name=\"command\"><br>\n\ user <input name=\"username\"> pass <input type=\"password\" name=\"secret\"><br>\n\ <input type=\"submit\">\n</form>\n"

Enumerations

enum  error_type {
  UNKNOWN_ACTION = 1, UNKNOWN_CATEGORY, UNSPECIFIED_CATEGORY, UNSPECIFIED_ARGUMENT,
  FAILURE_ALLOCATION, FAILURE_NEWCAT, FAILURE_DELCAT, FAILURE_EMPTYCAT,
  FAILURE_UPDATE, FAILURE_DELETE, FAILURE_APPEND
}
enum  output_format { FORMAT_RAW, FORMAT_HTML, FORMAT_XML }

Functions

static const char * __astman_get_header (const struct message *m, char *var, int mode)
static int __init_manager (int reload)
int __manager_event (int category, const char *event, const char *file, int line, const char *func, const char *fmt,...)
 manager_event: Send AMI event to client
static int action_atxfer (struct mansession *s, const struct message *m)
static int action_challenge (struct mansession *s, const struct message *m)
static int action_command (struct mansession *s, const struct message *m)
 Manager command "command" - execute CLI command.
static int action_coresettings (struct mansession *s, const struct message *m)
 Show PBX core settings information.
static int action_coreshowchannels (struct mansession *s, const struct message *m)
 Manager command "CoreShowChannels" - List currently defined channels and some information about them.
static int action_corestatus (struct mansession *s, const struct message *m)
 Show PBX core status information.
static int action_createconfig (struct mansession *s, const struct message *m)
static int action_events (struct mansession *s, const struct message *m)
static int action_extensionstate (struct mansession *s, const struct message *m)
static int action_getconfig (struct mansession *s, const struct message *m)
static int action_getconfigjson (struct mansession *s, const struct message *m)
static int action_getvar (struct mansession *s, const struct message *m)
static int action_hangup (struct mansession *s, const struct message *m)
static int action_listcategories (struct mansession *s, const struct message *m)
static int action_listcommands (struct mansession *s, const struct message *m)
static int action_login (struct mansession *s, const struct message *m)
static int action_logoff (struct mansession *s, const struct message *m)
static int action_mailboxcount (struct mansession *s, const struct message *m)
static int action_mailboxstatus (struct mansession *s, const struct message *m)
static int action_originate (struct mansession *s, const struct message *m)
static int action_ping (struct mansession *s, const struct message *m)
static int action_redirect (struct mansession *s, const struct message *m)
 action_redirect: The redirect manager command
static int action_reload (struct mansession *s, const struct message *m)
 Send a reload event.
static int action_sendtext (struct mansession *s, const struct message *m)
static int action_setvar (struct mansession *s, const struct message *m)
static int action_status (struct mansession *s, const struct message *m)
 Manager "status" command to show channels.
static int action_timeout (struct mansession *s, const struct message *m)
static int action_updateconfig (struct mansession *s, const struct message *m)
static int action_userevent (struct mansession *s, const struct message *m)
static int action_waitevent (struct mansession *s, const struct message *m)
static int append_event (const char *str, int category)
static int ast_instring (const char *bigstr, const char *smallstr, const char delim)
static AST_LIST_HEAD_STATIC (sessions, mansession_session)
static AST_LIST_HEAD_STATIC (all_events, eventqent)
int ast_manager_register2 (const char *action, int auth, int(*func)(struct mansession *s, const struct message *m), const char *synopsis, const char *description)
 register a new command with manager, including online help. This is the preferred way to register a manager command
void ast_manager_register_hook (struct manager_custom_hook *hook)
 Add a custom hook to be called when an event is fired.
static int ast_manager_register_struct (struct manager_action *act)
int ast_manager_unregister (char *action)
 Unregister a registered manager command.
void ast_manager_unregister_hook (struct manager_custom_hook *hook)
 Delete a custom hook to be called when an event is fired.
static AST_RWLIST_HEAD_STATIC (manager_hooks, manager_custom_hook)
 list of hooks registered
static AST_RWLIST_HEAD_STATIC (actions, manager_action)
 list of actions registered
static AST_RWLIST_HEAD_STATIC (users, ast_manager_user)
 list of users found in the config file
 AST_THREADSTORAGE (manager_event_buf)
 AST_THREADSTORAGE (userevent_buf)
 AST_THREADSTORAGE (astman_append_buf)
 thread local buffer for astman_append
void astman_append (struct mansession *s, const char *fmt,...)
int astman_datastore_add (struct mansession *s, struct ast_datastore *datastore)
 Add a datastore to a session.
struct ast_datastoreastman_datastore_find (struct mansession *s, const struct ast_datastore_info *info, const char *uid)
 Find a datastore on a session.
int astman_datastore_remove (struct mansession *s, struct ast_datastore *datastore)
 Remove a datastore from a session.
const char * astman_get_header (const struct message *m, char *var)
 Get header from mananger transaction.
struct ast_variableastman_get_variables (const struct message *m)
 Get a linked list of the Variable: headers.
int astman_is_authed (uint32_t ident)
 Determinie if a manager session ident is authenticated.
void astman_send_ack (struct mansession *s, const struct message *m, char *msg)
 Send ack in manager transaction.
void astman_send_error (struct mansession *s, const struct message *m, char *error)
 Send error in manager transaction.
void astman_send_listack (struct mansession *s, const struct message *m, char *msg, char *listflag)
 Send ack in manager list transaction.
void astman_send_response (struct mansession *s, const struct message *m, char *resp, char *msg)
 Send response in manager transaction.
static void astman_send_response_full (struct mansession *s, const struct message *m, char *resp, char *msg, char *listflag)
static void astman_start_ack (struct mansession *s, const struct message *m)
int astman_verify_session_readpermissions (uint32_t ident, int perm)
 Verify a session's read permissions against a permission mask.
int astman_verify_session_writepermissions (uint32_t ident, int perm)
 Verify a session's write permissions against a permission mask.
static int authenticate (struct mansession *s, const struct message *m)
static char * authority_to_str (int authority, struct ast_str **res)
 Convert authority code to a list of options.
static int check_blacklist (const char *cmd)
int check_manager_enabled ()
 Event list management functions. We assume that the event list always has at least one element, and the delete code will not remove the last entry even if the.
static int check_manager_session_inuse (const char *name)
int check_webmanager_enabled ()
 Check if AMI/HTTP is enabled.
static int compress_char (char c)
static void destroy_session (struct mansession_session *session)
static int do_message (struct mansession *s)
static void * fast_originate (void *data)
static struct mansession_sessionfind_session (uint32_t ident, int incinuse)
static void free_session (struct mansession_session *session)
static struct ast_strgeneric_http_callback (enum output_format format, struct sockaddr_in *remote_address, const char *uri, enum ast_http_method method, struct ast_variable *params, int *status, char **title, int *contentlength)
static int get_input (struct mansession *s, char *output)
static struct ast_manager_userget_manager_by_name_locked (const char *name)
static int get_perm (const char *instr)
static struct eventqentgrab_last (void)
static char * handle_manager_reload (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 CLI command manager reload.
static char * handle_mandebug (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_showmanager (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_showmanagers (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_showmancmd (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_showmancmds (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 CLI command manager list commands.
static char * handle_showmanconn (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 CLI command manager list connected.
static char * handle_showmaneventq (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 CLI command manager list eventq.
static enum error_type handle_updates (struct mansession *s, const struct message *m, struct ast_config *cfg, const char *dfn)
int init_manager (void)
 Called by Asterisk initialization.
static void json_escape (char *out, const char *in)
static int manager_displayconnects (struct mansession_session *session)
 Get displayconnects config option.
static struct ast_strmanager_http_callback (struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *params, struct ast_variable *headers, int *status, char **title, int *contentlength)
static int manager_modulecheck (struct mansession *s, const struct message *m)
static int manager_moduleload (struct mansession *s, const struct message *m)
static int manager_state_cb (char *context, char *exten, int state, void *data)
static struct ast_strmxml_http_callback (struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *params, struct ast_variable *headers, int *status, char **title, int *contentlength)
static int process_events (struct mansession *s)
static int process_message (struct mansession *s, const struct message *m)
static void purge_events (void)
static void purge_old_stuff (void *data)
 cleanup code called at each iteration of server_root, guaranteed to happen every 5 seconds at most
static void purge_sessions (int n_max)
 remove at most n_max stale session from the list.
static struct ast_strrawman_http_callback (struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *params, struct ast_variable *headers, int *status, char **title, int *contentlength)
static void ref_event (struct eventqent *e)
int reload_manager (void)
 Called by Asterisk module functions and the CLI command.
static int send_string (struct mansession *s, char *string)
static void * session_do (void *data)
 The body of the individual manager session. Call get_input() to read one line at a time (or be woken up on new events), collect the lines in a message until found an empty line, and execute the request. In any case, deliver events asynchronously through process_events() (called from here if no line is available, or at the end of process_message(). ).
static int set_eventmask (struct mansession *s, const char *eventmask)
 Rather than braindead on,off this now can also accept a specific int mask value or a ',' delim list of mask strings (the same as manager.conf) -anthm.
static int strings_to_mask (const char *string)
static struct eventqentunref_event (struct eventqent *e)
static int variable_count_cmp_fn (void *obj, void *vstr, int flags)
static int variable_count_hash_fn (const void *vvc, const int flags)
static void xml_copy_escape (struct ast_str **out, const char *src, int mode)
static void xml_translate (struct ast_str **out, char *in, struct ast_variable *vars, enum output_format format)
 Convert the input into XML or HTML. The input is supposed to be a sequence of lines of the form Name: value optionally followed by a blob of unformatted text. A blank line is a section separator. Basically, this is a mixture of the format of Manager Interface and CLI commands. The unformatted text is considered as a single value of a field named 'Opaque-data'.

Variables

static int allowmultiplelogin = 1
static struct
ast_tcptls_session_args 
ami_desc
struct ast_tls_config ami_tls_cfg
static struct
ast_tcptls_session_args 
amis_desc
static int block_sockets
static struct ast_cli_entry cli_manager []
struct {
   char *   words [AST_MAX_CMD_LEN]
command_blacklist []
static char * contenttype []
static int displayconnects = 1
static int httptimeout = 60
static int manager_debug
static int manager_enabled = 0
struct ast_http_uri manageruri
struct ast_http_uri managerxmluri
static char mandescr_atxfer []
static char mandescr_command []
static char mandescr_coresettings []
static char mandescr_coreshowchannels []
static char mandescr_corestatus []
static char mandescr_createconfig []
static char mandescr_events []
static char mandescr_extensionstate []
static char mandescr_getconfig []
static char mandescr_getconfigjson []
static char mandescr_getvar []
static char mandescr_hangup []
static char mandescr_listcategories []
static char mandescr_listcommands []
static char mandescr_logoff []
static char mandescr_mailboxcount []
static char mandescr_mailboxstatus []
 Help text for manager command mailboxstatus.
static char mandescr_modulecheck []
static char mandescr_moduleload []
static char mandescr_originate []
static char mandescr_ping []
 Manager PING.
static char mandescr_redirect []
static char mandescr_reload []
static char mandescr_sendtext []
static char mandescr_setvar []
static char mandescr_status []
static char mandescr_timeout []
static char mandescr_updateconfig []
static char mandescr_userevent []
static char mandescr_waitevent []
 Manager WAITEVENT.
static int num_sessions
static struct permalias perms []
struct ast_http_uri rawmanuri
static int registered = 0
static int timestampevents
static int webmanager_enabled = 0
static int webregged = 0

Detailed Description

The Asterisk Management Interface - AMI.

Author:
Mark Spencer <markster@digium.com>
ExtRef:
OpenSSL http://www.openssl.org - for AMI/SSL

At the moment this file contains a number of functions, namely:

manager.conf

Definition in file manager.c.


Define Documentation

#define HSMC_FORMAT   " %-15.15s %-15.15s %-55.55s\n"

Referenced by handle_showmancmds().

#define HSMCONN_FORMAT1   " %-15.15s %-15.15s %-10.10s %-10.10s %-8.8s %-8.8s %-5.5s %-5.5s\n"

Referenced by handle_showmanconn().

#define HSMCONN_FORMAT2   " %-15.15s %-15.15s %-10d %-10d %-8d %-8d %-5.5d %-5.5d\n"

Referenced by handle_showmanconn().

#define ROW_FMT   "<tr><td colspan=\"2\" bgcolor=\"#f1f1ff\">%s</td></tr>\r\n"

Referenced by generic_http_callback().

#define TEST_STRING   "<form action=\"manager\">\n\ Action: <select name=\"action\">\n\ <option value=\"\">-----&gt;</option>\n\ <option value=\"login\">login</option>\n\ <option value=\"command\">Command</option>\n\ <option value=\"waitevent\">waitevent</option>\n\ <option value=\"listcommands\">listcommands</option>\n\ </select>\n\ or <input name=\"action\"><br/>\n\ CLI Command <input name=\"command\"><br>\n\ user <input name=\"username\"> pass <input type=\"password\" name=\"secret\"><br>\n\ <input type=\"submit\">\n</form>\n"

Referenced by generic_http_callback().


Enumeration Type Documentation

END Doxygen group

Enumerator:
FORMAT_RAW 
FORMAT_HTML 
FORMAT_XML 

Definition at line 3444 of file manager.c.

03444                    {
03445    FORMAT_RAW,
03446    FORMAT_HTML,
03447    FORMAT_XML,
03448 };


Function Documentation

static int __init_manager ( int  reload  )  [static]

Definition at line 4020 of file manager.c.

References action_atxfer(), action_challenge(), action_command(), action_coresettings(), action_coreshowchannels(), action_corestatus(), action_createconfig(), action_events(), action_extensionstate(), action_getconfig(), action_getconfigjson(), action_getvar(), action_hangup(), action_listcategories(), action_listcommands(), action_login(), action_logoff(), action_mailboxcount(), action_mailboxstatus(), action_originate(), action_ping(), action_redirect(), action_reload(), action_sendtext(), action_setvar(), action_status(), action_timeout(), action_updateconfig(), action_userevent(), action_waitevent(), ahp, ami_desc, ami_tls_cfg, amis_desc, append_event(), ast_append_ha(), ast_calloc, ast_category_browse(), AST_CERTFILE, ast_cli_register_multiple(), ast_config_destroy(), ast_config_load2(), ast_copy_string(), ast_debug, ast_extension_state_add(), ast_free, ast_free_ha(), ast_gethostbyname(), ast_http_uri_link(), ast_http_uri_unlink(), AST_LIST_INSERT_TAIL, ast_log(), ast_manager_register2(), AST_RWLIST_INSERT_TAIL, AST_RWLIST_REMOVE_CURRENT, AST_RWLIST_TRAVERSE_SAFE_BEGIN, AST_RWLIST_TRAVERSE_SAFE_END, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_ssl_setup(), ast_strdup, ast_strlen_zero(), ast_tcptls_server_start(), ast_true(), ast_variable_browse(), ast_variable_retrieve(), ast_tls_config::certfile, ast_tls_config::cipher, cli_manager, CONFIG_FLAG_FILEUNCHANGED, config_flags, CONFIG_STATUS_FILEUNCHANGED, DEFAULT_MANAGER_PORT, ast_manager_user::displayconnects, ast_tls_config::enabled, EVENT_FLAG_CALL, EVENT_FLAG_COMMAND, EVENT_FLAG_CONFIG, EVENT_FLAG_ORIGINATE, EVENT_FLAG_REPORTING, EVENT_FLAG_SYSTEM, EVENT_FLAG_USER, get_manager_by_name_locked(), get_perm(), ast_manager_user::ha, hp, ast_manager_user::keep, ast_variable::lineno, ast_tcptls_session_args::local_address, LOG_NOTICE, LOG_WARNING, manager_event, manager_modulecheck(), manager_moduleload(), manager_state_cb(), manageruri, managerxmluri, mandescr_atxfer, mandescr_command, mandescr_coresettings, mandescr_coreshowchannels, mandescr_corestatus, mandescr_createconfig, mandescr_events, mandescr_extensionstate, mandescr_getconfig, mandescr_getconfigjson, mandescr_getvar, mandescr_hangup, mandescr_listcategories, mandescr_listcommands, mandescr_logoff, mandescr_mailboxcount, mandescr_mailboxstatus, mandescr_modulecheck, mandescr_moduleload, mandescr_originate, mandescr_ping, mandescr_redirect, mandescr_reload, mandescr_sendtext, mandescr_setvar, mandescr_status, mandescr_timeout, mandescr_updateconfig, mandescr_userevent, mandescr_waitevent, ast_variable::name, ast_variable::next, rawmanuri, ast_manager_user::readperm, registered, ast_manager_user::secret, ast_tcptls_session_args::tls_cfg, ast_manager_user::username, ast_variable::value, var, webregged, ast_manager_user::writeperm, and ast_manager_user::writetimeout.

Referenced by init_manager(), and reload_manager().

04021 {
04022    struct ast_config *ucfg = NULL, *cfg = NULL;
04023    const char *val;
04024    char *cat = NULL;
04025    int newhttptimeout = 60;
04026    int have_sslbindaddr = 0;
04027    struct hostent *hp;
04028    struct ast_hostent ahp;
04029    struct ast_manager_user *user = NULL;
04030    struct ast_variable *var;
04031    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
04032 
04033    manager_enabled = 0;
04034 
04035    if (!registered) {
04036       /* Register default actions */
04037       ast_manager_register2("Ping", 0, action_ping, "Keepalive command", mandescr_ping);
04038       ast_manager_register2("Events", 0, action_events, "Control Event Flow", mandescr_events);
04039       ast_manager_register2("Logoff", 0, action_logoff, "Logoff Manager", mandescr_logoff);
04040       ast_manager_register2("Login", 0, action_login, "Login Manager", NULL);
04041       ast_manager_register2("Challenge", 0, action_challenge, "Generate Challenge for MD5 Auth", NULL);
04042       ast_manager_register2("Hangup", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL, action_hangup, "Hangup Channel", mandescr_hangup);
04043       ast_manager_register2("Status", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_status, "Lists channel status", mandescr_status);
04044       ast_manager_register2("Setvar", EVENT_FLAG_CALL, action_setvar, "Set Channel Variable", mandescr_setvar);
04045       ast_manager_register2("Getvar", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_getvar, "Gets a Channel Variable", mandescr_getvar);
04046       ast_manager_register2("GetConfig", EVENT_FLAG_SYSTEM | EVENT_FLAG_CONFIG, action_getconfig, "Retrieve configuration", mandescr_getconfig);
04047       ast_manager_register2("GetConfigJSON", EVENT_FLAG_SYSTEM | EVENT_FLAG_CONFIG, action_getconfigjson, "Retrieve configuration (JSON format)", mandescr_getconfigjson);
04048       ast_manager_register2("UpdateConfig", EVENT_FLAG_CONFIG, action_updateconfig, "Update basic configuration", mandescr_updateconfig);
04049       ast_manager_register2("CreateConfig", EVENT_FLAG_CONFIG, action_createconfig, "Creates an empty file in the configuration directory", mandescr_createconfig);
04050       ast_manager_register2("ListCategories", EVENT_FLAG_CONFIG, action_listcategories, "List categories in configuration file", mandescr_listcategories);
04051       ast_manager_register2("Redirect", EVENT_FLAG_CALL, action_redirect, "Redirect (transfer) a call", mandescr_redirect );
04052       ast_manager_register2("Atxfer", EVENT_FLAG_CALL, action_atxfer, "Attended transfer", mandescr_atxfer);
04053       ast_manager_register2("Originate", EVENT_FLAG_ORIGINATE, action_originate, "Originate Call", mandescr_originate);
04054       ast_manager_register2("Command", EVENT_FLAG_COMMAND, action_command, "Execute Asterisk CLI Command", mandescr_command );
04055       ast_manager_register2("ExtensionState", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_extensionstate, "Check Extension Status", mandescr_extensionstate );
04056       ast_manager_register2("AbsoluteTimeout", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL, action_timeout, "Set Absolute Timeout", mandescr_timeout );
04057       ast_manager_register2("MailboxStatus", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_mailboxstatus, "Check Mailbox", mandescr_mailboxstatus );
04058       ast_manager_register2("MailboxCount", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_mailboxcount, "Check Mailbox Message Count", mandescr_mailboxcount );
04059       ast_manager_register2("ListCommands", 0, action_listcommands, "List available manager commands", mandescr_listcommands);
04060       ast_manager_register2("SendText", EVENT_FLAG_CALL, action_sendtext, "Send text message to channel", mandescr_sendtext);
04061       ast_manager_register2("UserEvent", EVENT_FLAG_USER, action_userevent, "Send an arbitrary event", mandescr_userevent);
04062       ast_manager_register2("WaitEvent", 0, action_waitevent, "Wait for an event to occur", mandescr_waitevent);
04063       ast_manager_register2("CoreSettings", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_coresettings, "Show PBX core settings (version etc)", mandescr_coresettings);
04064       ast_manager_register2("CoreStatus", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_corestatus, "Show PBX core status variables", mandescr_corestatus);
04065       ast_manager_register2("Reload", EVENT_FLAG_CONFIG | EVENT_FLAG_SYSTEM, action_reload, "Send a reload event", mandescr_reload);
04066       ast_manager_register2("CoreShowChannels", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_coreshowchannels, "List currently active channels", mandescr_coreshowchannels);
04067       ast_manager_register2("ModuleLoad", EVENT_FLAG_SYSTEM, manager_moduleload, "Module management", mandescr_moduleload);
04068       ast_manager_register2("ModuleCheck", EVENT_FLAG_SYSTEM, manager_modulecheck, "Check if module is loaded", mandescr_modulecheck);
04069 
04070       ast_cli_register_multiple(cli_manager, sizeof(cli_manager) / sizeof(struct ast_cli_entry));
04071       ast_extension_state_add(NULL, NULL, manager_state_cb, NULL);
04072       registered = 1;
04073       /* Append placeholder event so master_eventq never runs dry */
04074       append_event("Event: Placeholder\r\n\r\n", 0);
04075    }
04076    if ((cfg = ast_config_load2("manager.conf", "manager", config_flags)) == CONFIG_STATUS_FILEUNCHANGED)
04077       return 0;
04078 
04079    displayconnects = 1;
04080    if (!cfg) {
04081       ast_log(LOG_NOTICE, "Unable to open AMI configuration manager.conf. Asterisk management interface (AMI) disabled.\n");
04082       return 0;
04083    }
04084 
04085    /* default values */
04086    memset(&ami_desc.local_address, 0, sizeof(struct sockaddr_in));
04087    memset(&amis_desc.local_address, 0, sizeof(amis_desc.local_address));
04088    amis_desc.local_address.sin_port = htons(5039);
04089    ami_desc.local_address.sin_port = htons(DEFAULT_MANAGER_PORT);
04090 
04091    ami_tls_cfg.enabled = 0;
04092    if (ami_tls_cfg.certfile)
04093       ast_free(ami_tls_cfg.certfile);
04094    ami_tls_cfg.certfile = ast_strdup(AST_CERTFILE);
04095    if (ami_tls_cfg.cipher)
04096       ast_free(ami_tls_cfg.cipher);
04097    ami_tls_cfg.cipher = ast_strdup("");
04098 
04099    for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
04100       val = var->value;
04101       if (!strcasecmp(var->name, "sslenable"))
04102          ami_tls_cfg.enabled = ast_true(val);
04103       else if (!strcasecmp(var->name, "sslbindport"))
04104          amis_desc.local_address.sin_port = htons(atoi(val));
04105       else if (!strcasecmp(var->name, "sslbindaddr")) {
04106          if ((hp = ast_gethostbyname(val, &ahp))) {
04107             memcpy(&amis_desc.local_address.sin_addr, hp->h_addr, sizeof(amis_desc.local_address.sin_addr));
04108             have_sslbindaddr = 1;
04109          } else {
04110             ast_log(LOG_WARNING, "Invalid bind address '%s'\n", val);
04111          }
04112       } else if (!strcasecmp(var->name, "sslcert")) {
04113          ast_free(ami_tls_cfg.certfile);
04114          ami_tls_cfg.certfile = ast_strdup(val);
04115       } else if (!strcasecmp(var->name, "sslcipher")) {
04116          ast_free(ami_tls_cfg.cipher);
04117          ami_tls_cfg.cipher = ast_strdup(val);
04118       } else if (!strcasecmp(var->name, "enabled")) {
04119          manager_enabled = ast_true(val);
04120       } else if (!strcasecmp(var->name, "block-sockets")) {
04121          block_sockets = ast_true(val);
04122       } else if (!strcasecmp(var->name, "webenabled")) {
04123          webmanager_enabled = ast_true(val);
04124       } else if (!strcasecmp(var->name, "port")) {
04125          ami_desc.local_address.sin_port = htons(atoi(val));
04126       } else if (!strcasecmp(var->name, "bindaddr")) {
04127          if (!inet_aton(val, &ami_desc.local_address.sin_addr)) {
04128             ast_log(LOG_WARNING, "Invalid address '%s' specified, using 0.0.0.0\n", val);
04129             memset(&ami_desc.local_address.sin_addr, 0, sizeof(ami_desc.local_address.sin_addr));
04130          }
04131       } else if (!strcasecmp(var->name, "allowmultiplelogin")) { 
04132          allowmultiplelogin = ast_true(val);
04133       } else if (!strcasecmp(var->name, "displayconnects")) {
04134          displayconnects = ast_true(val);
04135       } else if (!strcasecmp(var->name, "timestampevents")) {
04136          timestampevents = ast_true(val);
04137       } else if (!strcasecmp(var->name, "debug")) {
04138          manager_debug = ast_true(val);
04139       } else if (!strcasecmp(var->name, "httptimeout")) {
04140          newhttptimeout = atoi(val);
04141       } else {
04142          ast_log(LOG_NOTICE, "Invalid keyword <%s> = <%s> in manager.conf [general]\n",
04143             var->name, val);
04144       }  
04145    }
04146 
04147    if (manager_enabled)
04148       ami_desc.local_address.sin_family = AF_INET;
04149    if (!have_sslbindaddr)
04150       amis_desc.local_address.sin_addr = ami_desc.local_address.sin_addr;
04151    if (ami_tls_cfg.enabled)
04152       amis_desc.local_address.sin_family = AF_INET;
04153 
04154    
04155    AST_RWLIST_WRLOCK(&users);
04156 
04157    /* First, get users from users.conf */
04158    ucfg = ast_config_load2("users.conf", "manager", config_flags);
04159    if (ucfg && (ucfg != CONFIG_STATUS_FILEUNCHANGED)) {
04160       const char *hasmanager;
04161       int genhasmanager = ast_true(ast_variable_retrieve(ucfg, "general", "hasmanager"));
04162 
04163       while ((cat = ast_category_browse(ucfg, cat))) {
04164          if (!strcasecmp(cat, "general"))
04165             continue;
04166          
04167          hasmanager = ast_variable_retrieve(ucfg, cat, "hasmanager");
04168          if ((!hasmanager && genhasmanager) || ast_true(hasmanager)) {
04169             const char *user_secret = ast_variable_retrieve(ucfg, cat, "secret");
04170             const char *user_read = ast_variable_retrieve(ucfg, cat, "read");
04171             const char *user_write = ast_variable_retrieve(ucfg, cat, "write");
04172             const char *user_displayconnects = ast_variable_retrieve(ucfg, cat, "displayconnects");
04173             const char *user_writetimeout = ast_variable_retrieve(ucfg, cat, "writetimeout");
04174             
04175             /* Look for an existing entry,
04176              * if none found - create one and add it to the list
04177              */
04178             if (!(user = get_manager_by_name_locked(cat))) {
04179                if (!(user = ast_calloc(1, sizeof(*user))))
04180                   break;
04181 
04182                /* Copy name over */
04183                ast_copy_string(user->username, cat, sizeof(user->username));
04184                /* Insert into list */
04185                AST_LIST_INSERT_TAIL(&users, user, list);
04186                user->ha = NULL;
04187                user->keep = 1;
04188                user->readperm = -1;
04189                user->writeperm = -1;
04190                /* Default displayconnect from [general] */
04191                user->displayconnects = displayconnects;
04192                user->writetimeout = 100;
04193             }
04194 
04195             if (!user_secret)
04196                user_secret = ast_variable_retrieve(ucfg, "general", "secret");
04197             if (!user_read)
04198                user_read = ast_variable_retrieve(ucfg, "general", "read");
04199             if (!user_write)
04200                user_write = ast_variable_retrieve(ucfg, "general", "write");
04201             if (!user_displayconnects)
04202                user_displayconnects = ast_variable_retrieve(ucfg, "general", "displayconnects");
04203             if (!user_writetimeout)
04204                user_writetimeout = ast_variable_retrieve(ucfg, "general", "writetimeout");
04205 
04206             if (!ast_strlen_zero(user_secret)) {
04207                if (user->secret)
04208                   ast_free(user->secret);
04209                user->secret = ast_strdup(user_secret);
04210             }
04211 
04212             if (user_read)
04213                user->readperm = get_perm(user_read);
04214             if (user_write)
04215                user->writeperm = get_perm(user_write);
04216             if (user_displayconnects)
04217                user->displayconnects = ast_true(user_displayconnects);
04218 
04219             if (user_writetimeout) {
04220                int value = atoi(user_writetimeout);
04221                if (value < 100)
04222                   ast_log(LOG_WARNING, "Invalid writetimeout value '%s' at users.conf line %d\n", var->value, var->lineno);
04223                else
04224                   user->writetimeout = value;
04225             }
04226          }
04227       }
04228       ast_config_destroy(ucfg);
04229    }
04230 
04231    /* cat is NULL here in any case */
04232 
04233    while ((cat = ast_category_browse(cfg, cat))) {
04234       struct ast_ha *oldha;
04235 
04236       if (!strcasecmp(cat, "general"))
04237          continue;
04238 
04239       /* Look for an existing entry, if none found - create one and add it to the list */
04240       if (!(user = get_manager_by_name_locked(cat))) {
04241          if (!(user = ast_calloc(1, sizeof(*user))))
04242             break;
04243          /* Copy name over */
04244          ast_copy_string(user->username, cat, sizeof(user->username));
04245 
04246          user->ha = NULL;
04247          user->readperm = 0;
04248          user->writeperm = 0;
04249          /* Default displayconnect from [general] */
04250          user->displayconnects = displayconnects;
04251          user->writetimeout = 100;
04252 
04253          /* Insert into list */
04254          AST_RWLIST_INSERT_TAIL(&users, user, list);
04255       }
04256 
04257       /* Make sure we keep this user and don't destroy it during cleanup */
04258       user->keep = 1;
04259       oldha = user->ha;
04260       user->ha = NULL;
04261 
04262       var = ast_variable_browse(cfg, cat);
04263       for (; var; var = var->next) {
04264          if (!strcasecmp(var->name, "secret")) {
04265             if (user->secret)
04266                ast_free(user->secret);
04267             user->secret = ast_strdup(var->value);
04268          } else if (!strcasecmp(var->name, "deny") ||
04269                    !strcasecmp(var->name, "permit")) {
04270             user->ha = ast_append_ha(var->name, var->value, user->ha, NULL);
04271          }  else if (!strcasecmp(var->name, "read") ) {
04272             user->readperm = get_perm(var->value);
04273          }  else if (!strcasecmp(var->name, "write") ) {
04274             user->writeperm = get_perm(var->value);
04275          }  else if (!strcasecmp(var->name, "displayconnects") ) {
04276             user->displayconnects = ast_true(var->value);
04277          } else if (!strcasecmp(var->name, "writetimeout")) {
04278             int value = atoi(var->value);
04279             if (value < 100)
04280                ast_log(LOG_WARNING, "Invalid writetimeout value '%s' at line %d\n", var->value, var->lineno);
04281             else
04282                user->writetimeout = value;
04283          } else
04284             ast_debug(1, "%s is an unknown option.\n", var->name);
04285       }
04286       ast_free_ha(oldha);
04287    }
04288    ast_config_destroy(cfg);
04289 
04290    /* Perform cleanup - essentially prune out old users that no longer exist */
04291    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&users, user, list) {
04292       if (user->keep) { /* valid record. clear flag for the next round */
04293          user->keep = 0;
04294          continue;
04295       }
04296       /* We do not need to keep this user so take them out of the list */
04297       AST_RWLIST_REMOVE_CURRENT(list);
04298       /* Free their memory now */
04299       if (user->secret)
04300          ast_free(user->secret);
04301       ast_free_ha(user->ha);
04302       ast_free(user);
04303    }
04304    AST_RWLIST_TRAVERSE_SAFE_END;
04305 
04306    AST_RWLIST_UNLOCK(&users);
04307 
04308    if (webmanager_enabled && manager_enabled) {
04309       if (!webregged) {
04310          ast_http_uri_link(&rawmanuri);
04311          ast_http_uri_link(&manageruri);
04312          ast_http_uri_link(&managerxmluri);
04313          webregged = 1;
04314       }
04315    } else {
04316       if (webregged) {
04317          ast_http_uri_unlink(&rawmanuri);
04318          ast_http_uri_unlink(&manageruri);
04319          ast_http_uri_unlink(&managerxmluri);
04320          webregged = 0;
04321       }
04322    }
04323 
04324    if (newhttptimeout > 0)
04325       httptimeout = newhttptimeout;
04326 
04327    manager_event(EVENT_FLAG_SYSTEM, "Reload", "Module: Manager\r\nStatus: %s\r\nMessage: Manager reload Requested\r\n", manager_enabled ? "Enabled" : "Disabled");
04328 
04329    ast_tcptls_server_start(&ami_desc);
04330    if (ast_ssl_setup(amis_desc.tls_cfg))
04331       ast_tcptls_server_start(&amis_desc);
04332    return 0;
04333 }

int astman_datastore_add ( struct mansession s,
struct ast_datastore datastore 
)

Add a datastore to a session.

Return values:
0 success
non-zero failure
Since:
1.6.1

Definition at line 4345 of file manager.c.

References AST_LIST_INSERT_HEAD, and mansession::session.

04346 {
04347    AST_LIST_INSERT_HEAD(&s->session->datastores, datastore, entry);
04348 
04349    return 0;
04350 }

struct ast_datastore* astman_datastore_find ( struct mansession s,
const struct ast_datastore_info info,
const char *  uid 
) [read]

Find a datastore on a session.

Return values:
pointer to the datastore if found
NULL if not found
Since:
1.6.1

Definition at line 4357 of file manager.c.

References AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_datastore::info, mansession::session, and ast_datastore::uid.

04358 {
04359    struct ast_datastore *datastore = NULL;
04360    
04361    if (info == NULL)
04362       return NULL;
04363 
04364    AST_LIST_TRAVERSE_SAFE_BEGIN(&s->session->datastores, datastore, entry) {
04365       if (datastore->info != info) {
04366          continue;
04367       }
04368 
04369       if (uid == NULL) {
04370          /* matched by type only */
04371          break;
04372       }
04373 
04374       if ((datastore->uid != NULL) && !strcasecmp(uid, datastore->uid)) {
04375          /* Matched by type AND uid */
04376          break;
04377       }
04378    }
04379    AST_LIST_TRAVERSE_SAFE_END;
04380 
04381    return datastore;
04382 }

int astman_datastore_remove ( struct mansession s,
struct ast_datastore datastore 
)

Remove a datastore from a session.

Return values:
0 success
non-zero failure
Since:
1.6.1

Definition at line 4352 of file manager.c.

References AST_LIST_REMOVE, and mansession::session.

04353 {
04354    return AST_LIST_REMOVE(&s->session->datastores, datastore, entry) ? 0 : -1;
04355 }

int astman_is_authed ( uint32_t  ident  ) 

Determinie if a manager session ident is authenticated.

Definition at line 3482 of file manager.c.

References mansession_session::__lock, ast_mutex_unlock(), mansession_session::authenticated, and find_session().

Referenced by handle_uri(), and static_callback().

03483 {
03484    int authed;
03485    struct mansession_session *session;
03486 
03487    if (!(session = find_session(ident, 0)))
03488       return 0;
03489 
03490    authed = (session->authenticated != 0);
03491 
03492    ast_mutex_unlock(&session->__lock);
03493 
03494    return authed;
03495 }

int astman_verify_session_readpermissions ( uint32_t  ident,
int  perm 
)

Verify a session's read permissions against a permission mask.

Parameters:
ident session identity
perm permission mask to verify
Return values:
1 if the session has the permission mask capabilities
0 otherwise

Definition at line 3497 of file manager.c.

References mansession_session::__lock, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), mansession_session::managerid, and mansession_session::readperm.

03498 {
03499    int result = 0;
03500    struct mansession_session *session;
03501 
03502    AST_LIST_LOCK(&sessions);
03503    AST_LIST_TRAVERSE(&sessions, session, list) {
03504       ast_mutex_lock(&session->__lock);
03505       if ((session->managerid == ident) && (session->readperm & perm)) {
03506          result = 1;
03507          ast_mutex_unlock(&session->__lock);
03508          break;
03509       }
03510       ast_mutex_unlock(&session->__lock);
03511    }
03512    AST_LIST_UNLOCK(&sessions);
03513    return result;
03514 }

int astman_verify_session_writepermissions ( uint32_t  ident,
int  perm 
)

Verify a session's write permissions against a permission mask.

Parameters:
ident session identity
perm permission mask to verify
Return values:
1 if the session has the permission mask capabilities, otherwise 0
0 otherwise

Definition at line 3516 of file manager.c.

References mansession_session::__lock, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), mansession_session::managerid, and mansession_session::writeperm.

Referenced by http_post_callback().

03517 {
03518    int result = 0;
03519    struct mansession_session *session;
03520 
03521    AST_LIST_LOCK(&sessions);
03522    AST_LIST_TRAVERSE(&sessions, session, list) {
03523       ast_mutex_lock(&session->__lock);
03524       if ((session->managerid == ident) && (session->writeperm & perm)) {
03525          result = 1;
03526          ast_mutex_unlock(&session->__lock);
03527          break;
03528       }
03529       ast_mutex_unlock(&session->__lock);
03530    }
03531    AST_LIST_UNLOCK(&sessions);
03532    return result;
03533 }

static int compress_char ( char  c  )  [static]

Definition at line 3601 of file manager.c.

Referenced by variable_count_hash_fn().

03602 {
03603    c &= 0x7f;
03604    if (c < 32)
03605       return 0;
03606    else if (c >= 'a' && c <= 'z')
03607       return c - 64;
03608    else if (c > 'z')
03609       return '_';
03610    else
03611       return c - 32;
03612 }

static struct mansession_session* find_session ( uint32_t  ident,
int  incinuse 
) [static, read]

locate an http session in the list. The search key (ident) is the value of the mansession_id cookie (0 is not valid and means a session on the AMI socket).

Definition at line 3461 of file manager.c.

References mansession_session::__lock, ast_atomic_fetchadd_int(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), mansession_session::inuse, mansession_session::managerid, and mansession_session::needdestroy.

Referenced by astman_is_authed(), and generic_http_callback().

03462 {
03463    struct mansession_session *session;
03464 
03465    if (ident == 0)
03466       return NULL;
03467 
03468    AST_LIST_LOCK(&sessions);
03469    AST_LIST_TRAVERSE(&sessions, session, list) {
03470       ast_mutex_lock(&session->__lock);
03471       if (session->managerid == ident && !session->needdestroy) {
03472          ast_atomic_fetchadd_int(&session->inuse, incinuse ? 1 : 0);
03473          break;
03474       }
03475       ast_mutex_unlock(&session->__lock);
03476    }
03477    AST_LIST_UNLOCK(&sessions);
03478 
03479    return session;
03480 }

static struct ast_str* generic_http_callback ( enum output_format  format,
struct sockaddr_in *  remote_address,
const char *  uri,
enum ast_http_method  method,
struct ast_variable params,
int *  status,
char **  title,
int *  contentlength 
) [static, read]

Note:
There is approximately a 1 in 1.8E19 chance that the following calculation will produce 0, which is an invalid ID, but due to the properties of the rand() function (and the constantcy of s), that won't happen twice in a row.

Definition at line 3765 of file manager.c.

References mansession_session::__lock, ast_atomic_fetchadd_int(), ast_calloc, ast_debug, ast_http_error(), ast_inet_ntoa(), AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), AST_MAX_MANHEADERS, ast_mutex_init(), ast_mutex_lock(), ast_mutex_unlock(), AST_PTHREADT_NULL, ast_random(), ast_str_append(), ast_str_create(), ast_verb, mansession_session::authenticated, buf, contenttype, destroy_session(), mansession::f, mansession::fd, mansession_session::fd, find_session(), FORMAT_HTML, FORMAT_XML, grab_last(), message::hdrcount, message::headers, mansession_session::inuse, LOG_EVENT, LOG_WARNING, manager_displayconnects(), mansession_session::managerid, ast_variable::name, mansession_session::needdestroy, ast_variable::next, process_message(), ROW_FMT, s, mansession_session::send_events, mansession::session, mansession_session::sessiontimeout, mansession_session::sin, TEST_STRING, mansession_session::username, ast_variable::value, mansession_session::waiting_thread, and xml_translate().

Referenced by manager_http_callback(), mxml_http_callback(), and rawman_http_callback().

03769 {
03770    struct mansession s = {.session = NULL, };
03771    struct mansession_session *session = NULL;
03772    uint32_t ident = 0;
03773    int blastaway = 0;
03774    struct ast_variable *v;
03775    char template[] = "/tmp/ast-http-XXXXXX"; /* template for temporary file */
03776    struct ast_str *out = NULL;
03777    struct message m = { 0 };
03778    unsigned int x;
03779    size_t hdrlen;
03780 
03781    for (v = params; v; v = v->next) {
03782       if (!strcasecmp(v->name, "mansession_id")) {
03783          sscanf(v->value, "%30x", &ident);
03784          break;
03785       }
03786    }
03787 
03788    if (!(session = find_session(ident, 1))) {
03789       /* Create new session.
03790        * While it is not in the list we don't need any locking
03791        */
03792       if (!(session = ast_calloc(1, sizeof(*session)))) {
03793          *status = 500;
03794          goto generic_callback_out;
03795       }
03796       session->sin = *remote_address;
03797       session->fd = -1;
03798       session->waiting_thread = AST_PTHREADT_NULL;
03799       session->send_events = 0;
03800       ast_mutex_init(&session->__lock);
03801       ast_mutex_lock(&session->__lock);
03802       session->inuse = 1;
03803       /*!\note There is approximately a 1 in 1.8E19 chance that the following
03804        * calculation will produce 0, which is an invalid ID, but due to the
03805        * properties of the rand() function (and the constantcy of s), that
03806        * won't happen twice in a row.
03807        */
03808       while ((session->managerid = ast_random() ^ (unsigned long) session) == 0);
03809       session->last_ev = grab_last();
03810       AST_LIST_HEAD_INIT_NOLOCK(&session->datastores);
03811       AST_LIST_LOCK(&sessions);
03812       AST_LIST_INSERT_HEAD(&sessions, session, list);
03813       ast_atomic_fetchadd_int(&num_sessions, 1);
03814       AST_LIST_UNLOCK(&sessions);
03815    }
03816 
03817    s.session = session;
03818 
03819    ast_mutex_unlock(&session->__lock);
03820 
03821    if (!(out = ast_str_create(1024))) {
03822       *status = 500;
03823       goto generic_callback_out;
03824    }
03825 
03826    s.fd = mkstemp(template);  /* create a temporary file for command output */
03827    unlink(template);
03828    s.f = fdopen(s.fd, "w+");
03829 
03830    for (x = 0, v = params; v && (x < AST_MAX_MANHEADERS); x++, v = v->next) {
03831       hdrlen = strlen(v->name) + strlen(v->value) + 3;
03832       m.headers[m.hdrcount] = alloca(hdrlen);
03833       snprintf((char *) m.headers[m.hdrcount], hdrlen, "%s: %s", v->name, v->value);
03834       ast_verb(4, "HTTP Manager add header %s\n", m.headers[m.hdrcount]);
03835       m.hdrcount = x + 1;
03836    }
03837 
03838    if (process_message(&s, &m)) {
03839       if (session->authenticated) {
03840          if (manager_displayconnects(session)) {
03841             ast_verb(2, "HTTP Manager '%s' logged off from %s\n", session->username, ast_inet_ntoa(session->sin.sin_addr));
03842          }
03843          ast_log(LOG_EVENT, "HTTP Manager '%s' logged off from %s\n", session->username, ast_inet_ntoa(session->sin.sin_addr));
03844       } else {
03845          if (displayconnects) {
03846             ast_verb(2, "HTTP Connect attempt from '%s' unable to authenticate\n", ast_inet_ntoa(session->sin.sin_addr));
03847          }
03848          ast_log(LOG_EVENT, "HTTP Failed attempt from %s\n", ast_inet_ntoa(session->sin.sin_addr));
03849       }
03850       session->needdestroy = 1;
03851    }
03852 
03853    ast_str_append(&out, 0,
03854              "Content-type: text/%s\r\n"
03855              "Cache-Control: no-cache;\r\n"
03856              "Set-Cookie: mansession_id=\"%08x\"; Version=\"1\"; Max-Age=%d\r\n"
03857              "\r\n",
03858          contenttype[format],
03859          session->managerid, httptimeout);
03860 
03861    if (format == FORMAT_XML) {
03862       ast_str_append(&out, 0, "<ajax-response>\n");
03863    } else if (format == FORMAT_HTML) {
03864       /*
03865        * When handling AMI-over-HTTP in HTML format, we provide a simple form for
03866        * debugging purposes. This HTML code should not be here, we
03867        * should read from some config file...
03868        */
03869 
03870 #define ROW_FMT   "<tr><td colspan=\"2\" bgcolor=\"#f1f1ff\">%s</td></tr>\r\n"
03871 #define TEST_STRING \
03872    "<form action=\"manager\">\n\
03873    Action: <select name=\"action\">\n\
03874       <option value=\"\">-----&gt;</option>\n\
03875       <option value=\"login\">login</option>\n\
03876       <option value=\"command\">Command</option>\n\
03877       <option value=\"waitevent\">waitevent</option>\n\
03878       <option value=\"listcommands\">listcommands</option>\n\
03879    </select>\n\
03880    or <input name=\"action\"><br/>\n\
03881    CLI Command <input name=\"command\"><br>\n\
03882    user <input name=\"username\"> pass <input type=\"password\" name=\"secret\"><br>\n\
03883    <input type=\"submit\">\n</form>\n"
03884 
03885       ast_str_append(&out, 0, "<title>Asterisk&trade; Manager Interface</title>");
03886       ast_str_append(&out, 0, "<body bgcolor=\"#ffffff\"><table align=center bgcolor=\"#f1f1f1\" width=\"500\">\r\n");
03887       ast_str_append(&out, 0, ROW_FMT, "<h1>Manager Tester</h1>");
03888       ast_str_append(&out, 0, ROW_FMT, TEST_STRING);
03889    }
03890 
03891    if (s.f != NULL) {   /* have temporary output */
03892       char *buf;
03893       size_t l = ftell(s.f);
03894       
03895       if (l) {
03896          if (MAP_FAILED == (buf = mmap(NULL, l, PROT_READ | PROT_WRITE, MAP_PRIVATE, s.fd, 0))) {
03897             ast_log(LOG_WARNING, "mmap failed.  Manager output was not processed\n");
03898          } else {
03899             if (format == FORMAT_XML || format == FORMAT_HTML)
03900                xml_translate(&out, buf, params, format);
03901             else
03902                ast_str_append(&out, 0, "%s", buf);
03903             munmap(buf, l);
03904          }
03905       } else if (format == FORMAT_XML || format == FORMAT_HTML) {
03906          xml_translate(&out, "", params, format);
03907       }
03908       fclose(s.f);
03909       s.f = NULL;
03910       s.fd = -1;
03911    }
03912 
03913    if (format == FORMAT_XML) {
03914       ast_str_append(&out, 0, "</ajax-response>\n");
03915    } else if (format == FORMAT_HTML)
03916       ast_str_append(&out, 0, "</table></body>\r\n");
03917 
03918    ast_mutex_lock(&session->__lock);
03919    /* Reset HTTP timeout.  If we're not authenticated, keep it extremely short */
03920    session->sessiontimeout = time(NULL) + ((session->authenticated || httptimeout < 5) ? httptimeout : 5);
03921 
03922    if (session->needdestroy) {
03923       if (session->inuse == 1) {
03924          ast_debug(1, "Need destroy, doing it now!\n");
03925          blastaway = 1;
03926       } else {
03927          ast_debug(1, "Need destroy, but can't do it yet!\n");
03928          if (session->waiting_thread != AST_PTHREADT_NULL)
03929             pthread_kill(session->waiting_thread, SIGURG);
03930          session->inuse--;
03931       }
03932    } else
03933       session->inuse--;
03934    ast_mutex_unlock(&session->__lock);
03935 
03936    if (blastaway)
03937       destroy_session(session);
03938 generic_callback_out:
03939    if (*status != 200)
03940       return ast_http_error(500, "Server Error", NULL, "Internal Server Error (out of memory)\n");
03941    return out;
03942 }

int init_manager ( void   ) 

Called by Asterisk initialization.

Definition at line 4335 of file manager.c.

References __init_manager().

Referenced by main().

04336 {
04337    return __init_manager(0);
04338 }

static struct ast_str* manager_http_callback ( struct ast_tcptls_session_instance ser,
const struct ast_http_uri urih,
const char *  uri,
enum ast_http_method  method,
struct ast_variable params,
struct ast_variable headers,
int *  status,
char **  title,
int *  contentlength 
) [static, read]

Definition at line 3944 of file manager.c.

References FORMAT_HTML, generic_http_callback(), and ast_tcptls_session_instance::remote_address.

03945 {
03946    return generic_http_callback(FORMAT_HTML, &ser->remote_address, uri, method, params, status, title, contentlength);
03947 }

static struct ast_str* mxml_http_callback ( struct ast_tcptls_session_instance ser,
const struct ast_http_uri urih,
const char *  uri,
enum ast_http_method  method,
struct ast_variable params,
struct ast_variable headers,
int *  status,
char **  title,
int *  contentlength 
) [static, read]

Definition at line 3949 of file manager.c.

References FORMAT_XML, generic_http_callback(), and ast_tcptls_session_instance::remote_address.

03950 {
03951    return generic_http_callback(FORMAT_XML, &ser->remote_address, uri, method, params, status, title, contentlength);
03952 }

static void purge_old_stuff ( void *  data  )  [static]

cleanup code called at each iteration of server_root, guaranteed to happen every 5 seconds at most

Definition at line 3992 of file manager.c.

References purge_events(), and purge_sessions().

03993 {
03994    purge_sessions(1);
03995    purge_events();
03996 }

static struct ast_str* rawman_http_callback ( struct ast_tcptls_session_instance ser,
const struct ast_http_uri urih,
const char *  uri,
enum ast_http_method  method,
struct ast_variable params,
struct ast_variable headers,
int *  status,
char **  title,
int *  contentlength 
) [static, read]

Definition at line 3954 of file manager.c.

References FORMAT_RAW, generic_http_callback(), and ast_tcptls_session_instance::remote_address.

03955 {
03956    return generic_http_callback(FORMAT_RAW, &ser->remote_address, uri, method, params, status, title, contentlength);
03957 }

int reload_manager ( void   ) 

Called by Asterisk module functions and the CLI command.

Definition at line 4340 of file manager.c.

References __init_manager().

Referenced by handle_manager_reload().

04341 {
04342    return __init_manager(1);
04343 }

static int variable_count_cmp_fn ( void *  obj,
void *  vstr,
int  flags 
) [static]

Definition at line 3626 of file manager.c.

References CMP_MATCH, CMP_STOP, str, and variable_count::varname.

Referenced by xml_translate().

03627 {
03628    /* Due to the simplicity of struct variable_count, it makes no difference
03629     * if you pass in objects or strings, the same operation applies. This is
03630     * due to the fact that the hash occurs on the first element, which means
03631     * the address of both the struct and the string are exactly the same. */
03632    struct variable_count *vc = obj;
03633    char *str = vstr;
03634    return !strcmp(vc->varname, str) ? CMP_MATCH | CMP_STOP : 0;
03635 }

static int variable_count_hash_fn ( const void *  vvc,
const int  flags 
) [static]

Definition at line 3614 of file manager.c.

References compress_char(), and variable_count::varname.

Referenced by xml_translate().

03615 {
03616    const struct variable_count *vc = vvc;
03617    int res = 0, i;
03618    for (i = 0; i < 5; i++) {
03619       if (vc->varname[i] == '\0')
03620          break;
03621       res += compress_char(vc->varname[i]) << (i * 6);
03622    }
03623    return res;
03624 }

static void xml_copy_escape ( struct ast_str **  out,
const char *  src,
int  mode 
) [static]

Definition at line 3540 of file manager.c.

References ast_str_append(), and buf.

Referenced by xml_translate().

03541 {
03542    /* store in a local buffer to avoid calling ast_str_append too often */
03543    char buf[256];
03544    char *dst = buf;
03545    int space = sizeof(buf);
03546    /* repeat until done and nothing to flush */
03547    for ( ; *src || dst != buf ; src++) {
03548       if (*src == '\0' || space < 10) {   /* flush */
03549          *dst++ = '\0';
03550          ast_str_append(out, 0, "%s", buf);
03551          dst = buf;
03552          space = sizeof(buf);
03553          if (*src == '\0')
03554             break;
03555       }
03556          
03557       if ( (mode & 2) && !isalnum(*src)) {
03558          *dst++ = '_';
03559          space--;
03560          continue;
03561       }
03562       switch (*src) {
03563       case '<':
03564          strcpy(dst, "&lt;");
03565          dst += 4;
03566          space -= 4;
03567          break;
03568       case '>':
03569          strcpy(dst, "&gt;");
03570          dst += 4;
03571          space -= 4;
03572          break;
03573       case '\"':
03574          strcpy(dst, "&quot;");
03575          dst += 6;
03576          space -= 6;
03577          break;
03578       case '\'':
03579          strcpy(dst, "&apos;");
03580          dst += 6;
03581          space -= 6;
03582          break;
03583       case '&':
03584          strcpy(dst, "&amp;");
03585          dst += 5;
03586          space -= 5;
03587          break;
03588 
03589       default:
03590          *dst++ = mode ? tolower(*src) : *src;
03591          space--;
03592       }
03593    }
03594 }

static void xml_translate ( struct ast_str **  out,
char *  in,
struct ast_variable vars,
enum output_format  format 
) [static]

Convert the input into XML or HTML. The input is supposed to be a sequence of lines of the form Name: value optionally followed by a blob of unformatted text. A blank line is a section separator. Basically, this is a mixture of the format of Manager Interface and CLI commands. The unformatted text is considered as a single value of a field named 'Opaque-data'.

At the moment the output format is the following (but it may change depending on future requirements so don't count too much on it when writing applications):

General: the unformatted text is used as a value of XML output: to be completed

 *   Each section is within <response type="object" id="xxx">
 *   where xxx is taken from ajaxdest variable or defaults to unknown
 *   Each row is reported as an attribute Name="value" of an XML
 *   entity named from the variable ajaxobjtype, default to "generic"
 * 

HTML output: each Name-value pair is output as a single row of a two-column table. Sections (blank lines in the input) are separated by a


Definition at line 3665 of file manager.c.

References ao2_alloc, ao2_container_alloc, ao2_find, ao2_link, ao2_ref, ast_debug, ast_skip_blanks(), ast_str_append(), ast_strlen_zero(), ast_trim_blanks(), variable_count::count, FORMAT_XML, ast_variable::name, ast_variable::next, strsep(), ast_variable::value, var, variable_count_cmp_fn(), variable_count_hash_fn(), variable_count::varname, and xml_copy_escape().

Referenced by generic_http_callback().

03666 {
03667    struct ast_variable *v;
03668    const char *dest = NULL;
03669    char *var, *val;
03670    const char *objtype = NULL;
03671    int in_data = 0;  /* parsing data */
03672    int inobj = 0;
03673    int xml = (format == FORMAT_XML);
03674    struct variable_count *vc = NULL;
03675    struct ao2_container *vco = NULL;
03676 
03677    for (v = vars; v; v = v->next) {
03678       if (!dest && !strcasecmp(v->name, "ajaxdest"))
03679          dest = v->value;
03680       else if (!objtype && !strcasecmp(v->name, "ajaxobjtype"))
03681          objtype = v->value;
03682    }
03683    if (!dest)
03684       dest = "unknown";
03685    if (!objtype)
03686       objtype = "generic";
03687 
03688    /* we want to stop when we find an empty line */
03689    while (in && *in) {
03690       val = strsep(&in, "\r\n"); /* mark start and end of line */
03691       if (in && *in == '\n')     /* remove trailing \n if any */
03692          in++;
03693       ast_trim_blanks(val);
03694       ast_debug(5, "inobj %d in_data %d line <%s>\n", inobj, in_data, val);
03695       if (ast_strlen_zero(val)) {
03696          if (in_data) { /* close data */
03697             ast_str_append(out, 0, xml ? "'" : "</td></tr>\n");
03698             in_data = 0;
03699          }
03700          if (inobj) {
03701             ast_str_append(out, 0, xml ? " /></response>\n" :
03702                "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
03703             inobj = 0;
03704             ao2_ref(vco, -1);
03705             vco = NULL;
03706          }
03707          continue;
03708       }
03709 
03710       /* we expect Name: value lines */
03711       if (in_data) {
03712          var = NULL;
03713       } else {
03714          var = strsep(&val, ":");
03715          if (val) {  /* found the field name */
03716             val = ast_skip_blanks(val);
03717             ast_trim_blanks(var);
03718          } else {    /* field name not found, move to opaque mode */
03719             val = var;
03720             var = "Opaque-data";
03721          }
03722       }
03723 
03724       if (!inobj) {
03725          if (xml)
03726             ast_str_append(out, 0, "<response type='object' id='%s'><%s", dest, objtype);
03727          else
03728             ast_str_append(out, 0, "<body>\n");
03729          vco = ao2_container_alloc(37, variable_count_hash_fn, variable_count_cmp_fn);
03730          inobj = 1;
03731       }
03732 
03733       if (!in_data) {   /* build appropriate line start */
03734          ast_str_append(out, 0, xml ? " " : "<tr><td>");
03735          if ((vc = ao2_find(vco, var, 0)))
03736             vc->count++;
03737          else {
03738             /* Create a new entry for this one */
03739             vc = ao2_alloc(sizeof(*vc), NULL);
03740             vc->varname = var;
03741             vc->count = 1;
03742             ao2_link(vco, vc);
03743          }
03744          xml_copy_escape(out, var, xml ? 1 | 2 : 0);
03745          if (vc->count > 1)
03746             ast_str_append(out, 0, "-%d", vc->count);
03747          ao2_ref(vc, -1);
03748          ast_str_append(out, 0, xml ? "='" : "</td><td>");
03749          if (!strcmp(var, "Opaque-data"))
03750             in_data = 1;
03751       }
03752       xml_copy_escape(out, val, 0); /* data field */
03753       if (!in_data)
03754          ast_str_append(out, 0, xml ? "'" : "</td></tr>\n");
03755       else
03756          ast_str_append(out, 0, xml ? "\n" : "<br>\n");
03757    }
03758    if (inobj) {
03759       ast_str_append(out, 0, xml ? " /></response>\n" :
03760          "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
03761       ao2_ref(vco, -1);
03762    }
03763 }


Variable Documentation

Definition at line 3999 of file manager.c.

Referenced by __init_manager().

Definition at line 3998 of file manager.c.

Referenced by __init_manager().

Definition at line 4010 of file manager.c.

Referenced by __init_manager().

char* contenttype[] [static]
Initial value:
 {
   [FORMAT_RAW] = "plain",
   [FORMAT_HTML] = "html",
   [FORMAT_XML] =  "xml",
}

Definition at line 3450 of file manager.c.

Referenced by generic_http_callback().

Definition at line 3968 of file manager.c.

Referenced by __init_manager().

Definition at line 3977 of file manager.c.

Referenced by __init_manager().

Definition at line 3959 of file manager.c.

Referenced by __init_manager().

int registered = 0 [static]

Definition at line 3986 of file manager.c.

Referenced by __init_manager().

int webregged = 0 [static]

Definition at line 3987 of file manager.c.

Referenced by __init_manager().

char* words[AST_MAX_CMD_LEN]

Definition at line 145 of file manager.c.

Referenced by check_blacklist().


Generated on 3 Mar 2010 for Asterisk - the Open Source PBX by  doxygen 1.6.1