Out-of-call text message support. More...
#include "asterisk.h"#include "asterisk/_private.h"#include "asterisk/module.h"#include "asterisk/datastore.h"#include "asterisk/pbx.h"#include "asterisk/manager.h"#include "asterisk/strings.h"#include "asterisk/astobj2.h"#include "asterisk/app.h"#include "asterisk/taskprocessor.h"#include "asterisk/message.h"
Go to the source code of this file.
Data Structures | |
| struct | ast_msg |
| A message. More... | |
| struct | ast_msg_tech_holder |
| struct | ast_msg_var_iterator |
| struct | msg_data |
| struct | outhead |
Functions | |
| static void | __init_msg_q_chan (void) |
| static int | action_messagesend (struct mansession *s, const struct message *m) |
| struct ast_msg * | ast_msg_alloc (void) |
| Allocate a message. | |
| struct ast_msg * | ast_msg_destroy (struct ast_msg *msg) |
| Destroy an ast_msg. | |
| const char * | ast_msg_get_body (const struct ast_msg *msg) |
| Get the body of a message. | |
| const char * | ast_msg_get_var (struct ast_msg *msg, const char *name) |
| Get the specified variable on the message. | |
| int | ast_msg_init (void) |
| int | ast_msg_queue (struct ast_msg *msg) |
| Queue a message for routing through the dialplan. | |
| struct ast_msg * | ast_msg_ref (struct ast_msg *msg) |
| Bump a msg's ref count. | |
| int | ast_msg_send (struct ast_msg *msg, const char *to, const char *from) |
| Send a msg directly to an endpoint. | |
| int | ast_msg_set_body (struct ast_msg *msg, const char *fmt,...) |
| Set the 'body' text of a message (in UTF-8) | |
| int | ast_msg_set_context (struct ast_msg *msg, const char *fmt,...) |
| Set the dialplan context for this message. | |
| int | ast_msg_set_exten (struct ast_msg *msg, const char *fmt,...) |
| Set the dialplan extension for this message. | |
| int | ast_msg_set_from (struct ast_msg *msg, const char *fmt,...) |
| Set the 'from' URI of a message. | |
| int | ast_msg_set_to (struct ast_msg *msg, const char *fmt,...) |
| Set the 'to' URI of a message. | |
| int | ast_msg_set_var (struct ast_msg *msg, const char *name, const char *value) |
| Set a variable on the message going to the dialplan. | |
| int | ast_msg_set_var_outbound (struct ast_msg *msg, const char *name, const char *value) |
| Set a variable on the message being sent to a message tech directly. | |
| void | ast_msg_shutdown (void) |
| int | ast_msg_tech_register (const struct ast_msg_tech *tech) |
| Register a message technology. | |
| int | ast_msg_tech_unregister (const struct ast_msg_tech *tech) |
| Unregister a message technology. | |
| void | ast_msg_var_iterator_destroy (struct ast_msg_var_iterator *i) |
| Destroy a message variable iterator. | |
| struct ast_msg_var_iterator * | ast_msg_var_iterator_init (const struct ast_msg *msg) |
| Create a new message variable iterator. | |
| int | ast_msg_var_iterator_next (const struct ast_msg *msg, struct ast_msg_var_iterator *i, const char **name, const char **value) |
| Get the next variable name and value that is set for sending outbound. | |
| void | ast_msg_var_unref_current (struct ast_msg_var_iterator *i) |
| Unref a message var from inside an iterator loop. | |
| static void | chan_cleanup (struct ast_channel *chan) |
| static int | chan_msg_indicate (struct ast_channel *chan, int condition, const void *data, size_t datalen) |
| static struct ast_frame * | chan_msg_read (struct ast_channel *chan) |
| static int | chan_msg_send_digit_begin (struct ast_channel *chan, char digit) |
| static int | chan_msg_send_digit_end (struct ast_channel *chan, char digit, unsigned int duration) |
| static int | chan_msg_write (struct ast_channel *chan, struct ast_frame *fr) |
| static struct ast_channel * | create_msg_q_chan (void) |
| static void | destroy_msg_q_chan (void *data) |
| static void | message_shutdown (void) |
| static struct msg_data * | msg_data_alloc (void) |
| static int | msg_data_cmp_fn (void *obj, void *arg, int flags) |
| static void | msg_data_destructor (void *obj) |
| static struct msg_data * | msg_data_find (struct ao2_container *vars, const char *name) |
| static int | msg_data_func_read (struct ast_channel *chan, const char *function, char *data, char *buf, size_t len) |
| static int | msg_data_func_write (struct ast_channel *chan, const char *function, char *data, const char *value) |
| static int | msg_data_hash_fn (const void *obj, const int flags) |
| static struct ast_datastore * | msg_datastore_find_or_create (struct ast_channel *chan) |
| static void | msg_destructor (void *obj) |
| static void | msg_ds_destroy (void *data) |
| static struct ast_msg_tech_holder * | msg_find_by_tech (const struct ast_msg_tech *msg_tech, int ao2_flags) |
| static struct ast_msg_tech_holder * | msg_find_by_tech_name (const char *tech_name, int ao2_flags) |
| static int | msg_func_read (struct ast_channel *chan, const char *function, char *data, char *buf, size_t len) |
| static int | msg_func_write (struct ast_channel *chan, const char *function, char *data, const char *value) |
| static int | msg_q_cb (void *data) |
| static void | msg_route (struct ast_channel *chan, struct ast_msg *msg) |
| static int | msg_send_exec (struct ast_channel *chan, const char *data) |
| static int | msg_set_var_full (struct ast_msg *msg, const char *name, const char *value, unsigned int outbound) |
| static int | msg_tech_cmp (void *obj, void *arg, int flags) |
| static int | msg_tech_hash (const void *obj, const int flags) |
Variables | |
| static const char | app_msg_send [] = "MessageSend" |
| static struct ast_channel_tech | msg_chan_tech_hack |
| static struct ast_custom_function | msg_data_function |
| static struct ast_datastore_info | msg_datastore |
| static struct ast_custom_function | msg_function |
| static struct ast_threadstorage | msg_q_chan = { .once = PTHREAD_ONCE_INIT , .key_init = __init_msg_q_chan , .custom_init = NULL , } |
| static struct ast_taskprocessor * | msg_q_tp |
| static struct ao2_container * | msg_techs |
Out-of-call text message support.
Definition in file message.c.
| static void __init_msg_q_chan | ( | void | ) | [static] |
| static int action_messagesend | ( | struct mansession * | s, |
| const struct message * | m | ||
| ) | [static] |
Definition at line 1168 of file message.c.
References ao2_ref, ast_base64decode(), ast_msg_alloc(), ast_msg_set_body(), ast_msg_set_var_outbound(), ast_rwlock_rdlock, ast_rwlock_unlock, ast_strlen_zero(), ast_variables_destroy(), astman_get_header(), astman_get_variables(), astman_send_ack(), astman_send_error(), msg_find_by_tech_name(), ast_msg_tech::msg_send, ast_variable::name, ast_variable::next, OBJ_POINTER, S_OR, ast_msg_tech_holder::tech, ast_msg_tech_holder::tech_lock, ast_variable::value, and ast_msg::vars.
Referenced by ast_msg_init().
{
const char *to = ast_strdupa(astman_get_header(m, "To"));
const char *from = astman_get_header(m, "From");
const char *body = astman_get_header(m, "Body");
const char *base64body = astman_get_header(m, "Base64Body");
char base64decoded[1301] = { 0, };
char *tech_name = NULL;
struct ast_variable *vars = NULL;
struct ast_variable *data = NULL;
struct ast_msg_tech_holder *tech_holder = NULL;
struct ast_msg *msg;
int res = -1;
if (ast_strlen_zero(to)) {
astman_send_error(s, m, "No 'To' address specified.");
return -1;
}
if (!ast_strlen_zero(base64body)) {
ast_base64decode((unsigned char *) base64decoded, base64body, sizeof(base64decoded) - 1);
body = base64decoded;
}
tech_name = ast_strdupa(to);
tech_name = strsep(&tech_name, ":");
tech_holder = msg_find_by_tech_name(tech_name, OBJ_POINTER);
if (!tech_holder) {
astman_send_error(s, m, "Message technology not found.");
return -1;
}
if (!(msg = ast_msg_alloc())) {
ao2_ref(tech_holder, -1);
astman_send_error(s, m, "Internal failure\n");
return -1;
}
data = astman_get_variables(m);
for (vars = data; vars; vars = vars->next) {
ast_msg_set_var_outbound(msg, vars->name, vars->value);
}
ast_msg_set_body(msg, "%s", body);
ast_rwlock_rdlock(&tech_holder->tech_lock);
if (tech_holder->tech) {
res = tech_holder->tech->msg_send(msg, S_OR(to, ""), S_OR(from, ""));
}
ast_rwlock_unlock(&tech_holder->tech_lock);
ast_variables_destroy(vars);
ao2_ref(tech_holder, -1);
ao2_ref(msg, -1);
if (res) {
astman_send_error(s, m, "Message failed to send.");
} else {
astman_send_ack(s, m, "Message successfully sent");
}
return res;
}
| struct ast_msg* ast_msg_alloc | ( | void | ) | [read] |
Allocate a message.
Allocate a message for the purposes of passing it into the Asterisk core to be routed through the dialplan. If ast_msg_queue() is not called, this message must be destroyed using ast_msg_destroy(). Otherwise, the message core code will take care of it.
Definition at line 404 of file message.c.
References ao2_alloc, ao2_container_alloc, ao2_ref, ast_str_create(), ast_str_set(), ast_msg::body, ast_msg::context, ast_msg::exten, ast_msg::from, msg_data_cmp_fn(), msg_data_hash_fn(), msg_destructor(), ast_msg::to, and ast_msg::vars.
Referenced by action_messagesend(), aji_handle_message(), msg_datastore_find_or_create(), receive_message(), and xmpp_pak_message().
{
struct ast_msg *msg;
if (!(msg = ao2_alloc(sizeof(*msg), msg_destructor))) {
return NULL;
}
if (!(msg->to = ast_str_create(32))) {
ao2_ref(msg, -1);
return NULL;
}
if (!(msg->from = ast_str_create(32))) {
ao2_ref(msg, -1);
return NULL;
}
if (!(msg->body = ast_str_create(128))) {
ao2_ref(msg, -1);
return NULL;
}
if (!(msg->context = ast_str_create(16))) {
ao2_ref(msg, -1);
return NULL;
}
if (!(msg->exten = ast_str_create(16))) {
ao2_ref(msg, -1);
return NULL;
}
if (!(msg->vars = ao2_container_alloc(1, msg_data_hash_fn, msg_data_cmp_fn))) {
ao2_ref(msg, -1);
return NULL;
}
ast_str_set(&msg->context, 0, "default");
return msg;
}
| struct ast_msg* ast_msg_destroy | ( | struct ast_msg * | msg | ) | [read] |
Destroy an ast_msg.
This should only be called on a message if it was not passed on to ast_msg_queue().
Definition at line 453 of file message.c.
References ao2_ref.
Referenced by aji_handle_message(), receive_message(), and xmpp_pak_message().
{
ao2_ref(msg, -1);
return NULL;
}
| const char* ast_msg_get_body | ( | const struct ast_msg * | msg | ) |
Get the body of a message.
Definition at line 520 of file message.c.
References ast_str_buffer(), and ast_msg::body.
Referenced by msg_func_read(), msg_send_cb(), sip_msg_send(), and xmpp_send_cb().
{
return ast_str_buffer(msg->body);
}
| const char* ast_msg_get_var | ( | struct ast_msg * | msg, |
| const char * | name | ||
| ) |
Get the specified variable on the message.
Definition at line 589 of file message.c.
References ao2_ref, msg_data_find(), msg_data::value, and ast_msg::vars.
Referenced by msg_data_func_read().
{
struct msg_data *data;
const char *val = NULL;
if (!(data = msg_data_find(msg->vars, name))) {
return NULL;
}
/* Yep, this definitely looks like val would be a dangling pointer
* after the ref count is decremented. As long as the message structure
* is used in a thread safe manner, this will not be the case though.
* The ast_msg holds a reference to this object in the msg->vars container. */
val = data->value;
ao2_ref(data, -1);
return val;
}
| int ast_msg_init | ( | void | ) |
Provided by message.c
Definition at line 1351 of file message.c.
References __ast_custom_function_register(), action_messagesend(), ao2_container_alloc, ast_manager_register_xml_core, ast_register_application2(), ast_register_atexit(), ast_taskprocessor_get(), EVENT_FLAG_MESSAGE, message_shutdown(), msg_send_exec(), msg_tech_cmp(), msg_tech_hash(), and TPS_REF_DEFAULT.
Referenced by main().
{
int res;
msg_q_tp = ast_taskprocessor_get("ast_msg_queue", TPS_REF_DEFAULT);
if (!msg_q_tp) {
return -1;
}
msg_techs = ao2_container_alloc(17, msg_tech_hash, msg_tech_cmp);
if (!msg_techs) {
return -1;
}
res = __ast_custom_function_register(&msg_function, NULL);
res |= __ast_custom_function_register(&msg_data_function, NULL);
res |= ast_register_application2(app_msg_send, msg_send_exec, NULL, NULL, NULL);
res |= ast_manager_register_xml_core("MessageSend", EVENT_FLAG_MESSAGE, action_messagesend);
ast_register_atexit(message_shutdown);
return res;
}
| int ast_msg_queue | ( | struct ast_msg * | msg | ) |
Queue a message for routing through the dialplan.
Regardless of the return value of this function, this funciton will take care of ensuring that the message object is properly destroyed when needed.
| 0 | message successfully queued |
| non-zero | failure, message not sent to dialplan |
Definition at line 820 of file message.c.
References ao2_ref, ast_taskprocessor_push(), and msg_q_cb().
Referenced by aji_handle_message(), receive_message(), and xmpp_pak_message().
{
int res;
res = ast_taskprocessor_push(msg_q_tp, msg_q_cb, msg);
if (res == -1) {
ao2_ref(msg, -1);
}
return res;
}
| struct ast_msg* ast_msg_ref | ( | struct ast_msg * | msg | ) | [read] |
| int ast_msg_send | ( | struct ast_msg * | msg, |
| const char * | to, | ||
| const char * | from | ||
| ) |
Send a msg directly to an endpoint.
Regardless of the return value of this function, this funciton will take care of ensuring that the message object is properly destroyed when needed.
| 0 | message successfully queued to be sent out |
| non-zero | failure, message not get sent out. |
Definition at line 1233 of file message.c.
References ao2_ref, ast_rwlock_rdlock, ast_rwlock_unlock, ast_strlen_zero(), msg_find_by_tech_name(), ast_msg_tech::msg_send, OBJ_POINTER, S_OR, ast_msg_tech_holder::tech, and ast_msg_tech_holder::tech_lock.
{
char *tech_name = NULL;
struct ast_msg_tech_holder *tech_holder = NULL;
int res = -1;
if (ast_strlen_zero(to)) {
ao2_ref(msg, -1);
return -1;
}
tech_name = ast_strdupa(to);
tech_name = strsep(&tech_name, ":");
tech_holder = msg_find_by_tech_name(tech_name, OBJ_POINTER);
if (!tech_holder) {
ao2_ref(msg, -1);
return -1;
}
ast_rwlock_rdlock(&tech_holder->tech_lock);
if (tech_holder->tech) {
res = tech_holder->tech->msg_send(msg, S_OR(to, ""), S_OR(from, ""));
}
ast_rwlock_unlock(&tech_holder->tech_lock);
ao2_ref(tech_holder, -1);
ao2_ref(msg, -1);
return res;
}
| int ast_msg_set_body | ( | struct ast_msg * | msg, |
| const char * | fmt, | ||
| ... | |||
| ) |
Set the 'body' text of a message (in UTF-8)
| 0 | success |
| -1 | failure |
Definition at line 484 of file message.c.
References ast_str_set_va(), and ast_msg::body.
Referenced by action_messagesend(), aji_handle_message(), msg_func_write(), receive_message(), and xmpp_pak_message().
{
va_list ap;
int res;
va_start(ap, fmt);
res = ast_str_set_va(&msg->body, 0, fmt, ap);
va_end(ap);
return res < 0 ? -1 : 0;
}
| int ast_msg_set_context | ( | struct ast_msg * | msg, |
| const char * | fmt, | ||
| ... | |||
| ) |
Set the dialplan context for this message.
| 0 | success |
| -1 | failure |
Definition at line 496 of file message.c.
References ast_str_set_va(), and ast_msg::context.
Referenced by aji_handle_message(), receive_message(), and xmpp_pak_message().
{
va_list ap;
int res;
va_start(ap, fmt);
res = ast_str_set_va(&msg->context, 0, fmt, ap);
va_end(ap);
return res < 0 ? -1 : 0;
}
| int ast_msg_set_exten | ( | struct ast_msg * | msg, |
| const char * | fmt, | ||
| ... | |||
| ) |
Set the dialplan extension for this message.
| 0 | success |
| -1 | failure |
Definition at line 508 of file message.c.
References ast_str_set_va(), and ast_msg::exten.
Referenced by receive_message().
{
va_list ap;
int res;
va_start(ap, fmt);
res = ast_str_set_va(&msg->exten, 0, fmt, ap);
va_end(ap);
return res < 0 ? -1 : 0;
}
| int ast_msg_set_from | ( | struct ast_msg * | msg, |
| const char * | fmt, | ||
| ... | |||
| ) |
Set the 'from' URI of a message.
| 0 | success |
| -1 | failure |
Definition at line 472 of file message.c.
References ast_str_set_va(), and ast_msg::from.
Referenced by aji_handle_message(), msg_func_write(), receive_message(), and xmpp_pak_message().
{
va_list ap;
int res;
va_start(ap, fmt);
res = ast_str_set_va(&msg->from, 0, fmt, ap);
va_end(ap);
return res < 0 ? -1 : 0;
}
| int ast_msg_set_to | ( | struct ast_msg * | msg, |
| const char * | fmt, | ||
| ... | |||
| ) |
Set the 'to' URI of a message.
| 0 | success |
| -1 | failure |
Definition at line 460 of file message.c.
References ast_str_set_va(), and ast_msg::to.
Referenced by aji_handle_message(), msg_func_write(), receive_message(), and xmpp_pak_message().
{
va_list ap;
int res;
va_start(ap, fmt);
res = ast_str_set_va(&msg->to, 0, fmt, ap);
va_end(ap);
return res < 0 ? -1 : 0;
}
| int ast_msg_set_var | ( | struct ast_msg * | msg, |
| const char * | name, | ||
| const char * | value | ||
| ) |
Set a variable on the message going to the dialplan.
| name | Name of variable to set |
| value | Value of variable to set |
| 0 | success |
| -1 | failure |
Definition at line 584 of file message.c.
References msg_set_var_full().
Referenced by receive_message(), and set_message_vars_from_req().
{
return msg_set_var_full(msg, name, value, 0);
}
| int ast_msg_set_var_outbound | ( | struct ast_msg * | msg, |
| const char * | name, | ||
| const char * | value | ||
| ) |
Set a variable on the message being sent to a message tech directly.
| name | Name of variable to set |
| value | Value of variable to set |
| 0 | success |
| -1 | failure |
Definition at line 579 of file message.c.
References msg_set_var_full().
Referenced by action_messagesend(), and msg_data_func_write().
{
return msg_set_var_full(msg, name, value, 1);
}
| void ast_msg_shutdown | ( | void | ) |
Provided by message.c
Definition at line 1317 of file message.c.
References ast_taskprocessor_unreference().
Referenced by can_safely_quit().
{
if (msg_q_tp) {
msg_q_tp = ast_taskprocessor_unreference(msg_q_tp);
}
}
| int ast_msg_tech_register | ( | const struct ast_msg_tech * | tech | ) |
Register a message technology.
| 0 | success |
| non-zero | failure |
Definition at line 1266 of file message.c.
References ao2_alloc, ao2_link, ao2_ref, ast_log(), ast_rwlock_init, ast_verb, LOG_ERROR, msg_find_by_tech(), ast_msg_tech::name, OBJ_POINTER, ast_msg_tech_holder::tech, and ast_msg_tech_holder::tech_lock.
Referenced by load_module().
{
struct ast_msg_tech_holder *tech_holder;
if ((tech_holder = msg_find_by_tech(tech, OBJ_POINTER))) {
ao2_ref(tech_holder, -1);
ast_log(LOG_ERROR, "Message technology already registered for '%s'\n",
tech->name);
return -1;
}
if (!(tech_holder = ao2_alloc(sizeof(*tech_holder), NULL))) {
return -1;
}
ast_rwlock_init(&tech_holder->tech_lock);
tech_holder->tech = tech;
ao2_link(msg_techs, tech_holder);
ao2_ref(tech_holder, -1);
tech_holder = NULL;
ast_verb(3, "Message technology handler '%s' registered.\n", tech->name);
return 0;
}
| int ast_msg_tech_unregister | ( | const struct ast_msg_tech * | tech | ) |
Unregister a message technology.
| 0 | success |
| non-zero | failure |
Definition at line 1294 of file message.c.
References ao2_ref, ast_log(), ast_rwlock_unlock, ast_rwlock_wrlock, ast_verb, LOG_ERROR, msg_find_by_tech(), ast_msg_tech::name, OBJ_POINTER, OBJ_UNLINK, ast_msg_tech_holder::tech, and ast_msg_tech_holder::tech_lock.
Referenced by unload_module().
{
struct ast_msg_tech_holder *tech_holder;
tech_holder = msg_find_by_tech(tech, OBJ_POINTER | OBJ_UNLINK);
if (!tech_holder) {
ast_log(LOG_ERROR, "No '%s' message technology found.\n", tech->name);
return -1;
}
ast_rwlock_wrlock(&tech_holder->tech_lock);
tech_holder->tech = NULL;
ast_rwlock_unlock(&tech_holder->tech_lock);
ao2_ref(tech_holder, -1);
tech_holder = NULL;
ast_verb(3, "Message technology handler '%s' unregistered.\n", tech->name);
return 0;
}
| void ast_msg_var_iterator_destroy | ( | struct ast_msg_var_iterator * | i | ) |
Destroy a message variable iterator.
| i | Iterator to be destroyed |
Definition at line 657 of file message.c.
References ao2_iterator_destroy(), ast_free, and ast_msg_var_iterator::i.
Referenced by sip_msg_send().
{
ao2_iterator_destroy(&i->i);
ast_free(i);
}
| struct ast_msg_var_iterator* ast_msg_var_iterator_init | ( | const struct ast_msg * | msg | ) | [read] |
Create a new message variable iterator.
| msg | A message whose variables are to be iterated over |
Definition at line 613 of file message.c.
References ao2_iterator_init(), ast_calloc, ast_msg_var_iterator::i, and ast_msg::vars.
Referenced by sip_msg_send().
{
struct ast_msg_var_iterator *i;
if (!(i = ast_calloc(1, sizeof(*i)))) {
return NULL;
}
i->i = ao2_iterator_init(msg->vars, 0);
return i;
}
| int ast_msg_var_iterator_next | ( | const struct ast_msg * | msg, |
| struct ast_msg_var_iterator * | i, | ||
| const char ** | name, | ||
| const char ** | value | ||
| ) |
Get the next variable name and value that is set for sending outbound.
| msg | The message with the variables |
| i | An iterator created with ast_msg_var_iterator_init |
| name | A pointer to the name result pointer |
| value | A pointer to the value result pointer |
| 0 | No more entries |
| 1 | Valid entry |
Definition at line 625 of file message.c.
References ao2_iterator_next, ao2_ref, ast_msg_var_iterator::current_used, ast_msg_var_iterator::i, msg_data::name, msg_data::send, and msg_data::value.
Referenced by sip_msg_send().
{
struct msg_data *data;
/* Skip any that aren't marked for sending out */
while ((data = ao2_iterator_next(&i->i)) && !data->send) {
ao2_ref(data, -1);
}
if (!data) {
return 0;
}
if (data->send) {
*name = data->name;
*value = data->value;
}
/* Leave the refcount to be cleaned up by the caller with
* ast_msg_var_unref_current after they finish with the pointers to the data */
i->current_used = data;
return 1;
}
| void ast_msg_var_unref_current | ( | struct ast_msg_var_iterator * | i | ) |
Unref a message var from inside an iterator loop.
Definition at line 650 of file message.c.
References ao2_ref, and ast_msg_var_iterator::current_used.
Referenced by sip_msg_send().
{
if (i->current_used) {
ao2_ref(i->current_used, -1);
}
i->current_used = NULL;
}
| static void chan_cleanup | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 718 of file message.c.
References ao2_ref, ast_channel_clear_softhangup(), ast_channel_datastore_add(), ast_channel_datastore_find(), ast_channel_datastore_remove(), ast_channel_datastores(), ast_channel_lock, ast_channel_unlock, ast_channel_varshead(), ast_datastore_free(), AST_LIST_REMOVE_HEAD, AST_SOFTHANGUP_ALL, ast_var_delete(), ast_datastore::data, and ast_var_t::entries.
Referenced by msg_q_cb().
{
struct ast_datastore *msg_ds, *ds;
struct varshead *headp;
struct ast_var_t *vardata;
ast_channel_lock(chan);
/*
* Remove the msg datastore. Free its data but keep around the datastore
* object and just reuse it.
*/
if ((msg_ds = ast_channel_datastore_find(chan, &msg_datastore, NULL)) && msg_ds->data) {
ast_channel_datastore_remove(chan, msg_ds);
ao2_ref(msg_ds->data, -1);
msg_ds->data = NULL;
}
/*
* Destroy all other datastores.
*/
while ((ds = AST_LIST_REMOVE_HEAD(ast_channel_datastores(chan), entry))) {
ast_datastore_free(ds);
}
/*
* Destroy all channel variables.
*/
headp = ast_channel_varshead(chan);
while ((vardata = AST_LIST_REMOVE_HEAD(headp, entries))) {
ast_var_delete(vardata);
}
/*
* Restore msg datastore.
*/
if (msg_ds) {
ast_channel_datastore_add(chan, msg_ds);
}
/*
* Clear softhangup flags.
*/
ast_channel_clear_softhangup(chan, AST_SOFTHANGUP_ALL);
ast_channel_unlock(chan);
}
| static int chan_msg_indicate | ( | struct ast_channel * | chan, |
| int | condition, | ||
| const void * | data, | ||
| size_t | datalen | ||
| ) | [static] |
| static struct ast_frame * chan_msg_read | ( | struct ast_channel * | chan | ) | [static, read] |
| static int chan_msg_send_digit_begin | ( | struct ast_channel * | chan, |
| char | digit | ||
| ) | [static] |
| static int chan_msg_send_digit_end | ( | struct ast_channel * | chan, |
| char | digit, | ||
| unsigned int | duration | ||
| ) | [static] |
| static int chan_msg_write | ( | struct ast_channel * | chan, |
| struct ast_frame * | fr | ||
| ) | [static] |
| static struct ast_channel* create_msg_q_chan | ( | void | ) | [static, read] |
Definition at line 663 of file message.c.
References ast_channel_alloc(), ast_channel_datastore_add(), ast_channel_lock, ast_channel_tech_set(), ast_channel_unlink(), ast_channel_unlock, ast_datastore_alloc(), ast_hangup(), and AST_STATE_UP.
Referenced by msg_q_cb().
{
struct ast_channel *chan;
struct ast_datastore *ds;
chan = ast_channel_alloc(1, AST_STATE_UP,
NULL, NULL, NULL,
NULL, NULL, NULL, 0,
"%s", "Message/ast_msg_queue");
if (!chan) {
return NULL;
}
ast_channel_unlink(chan);
ast_channel_tech_set(chan, &msg_chan_tech_hack);
if (!(ds = ast_datastore_alloc(&msg_datastore, NULL))) {
ast_hangup(chan);
return NULL;
}
ast_channel_lock(chan);
ast_channel_datastore_add(chan, ds);
ast_channel_unlock(chan);
return chan;
}
| static void destroy_msg_q_chan | ( | void * | data | ) | [static] |
Definition at line 765 of file message.c.
References ast_channel_release(), and ast_channel::data.
{
struct ast_channel **chan = data;
if (!*chan) {
return;
}
ast_channel_release(*chan);
}
| static void message_shutdown | ( | void | ) | [static] |
Definition at line 1328 of file message.c.
References ao2_ref, ast_custom_function_unregister(), ast_manager_unregister(), and ast_unregister_application().
Referenced by ast_msg_init().
{
ast_custom_function_unregister(&msg_function);
ast_custom_function_unregister(&msg_data_function);
ast_unregister_application(app_msg_send);
ast_manager_unregister("MessageSend");
if (msg_techs) {
ao2_ref(msg_techs, -1);
msg_techs = NULL;
}
}
| static struct msg_data* msg_data_alloc | ( | void | ) | [static, read] |
Definition at line 525 of file message.c.
References ao2_alloc, ao2_ref, ast_string_field_init, and msg_data_destructor().
Referenced by msg_set_var_full().
{
struct msg_data *data;
if (!(data = ao2_alloc(sizeof(*data), msg_data_destructor))) {
return NULL;
}
if (ast_string_field_init(data, 32)) {
ao2_ref(data, -1);
return NULL;
}
return data;
}
| static int msg_data_cmp_fn | ( | void * | obj, |
| void * | arg, | ||
| int | flags | ||
| ) | [static] |
Definition at line 370 of file message.c.
References CMP_MATCH, CMP_STOP, and msg_data::name.
Referenced by ast_msg_alloc().
| static void msg_data_destructor | ( | void * | obj | ) | [static] |
Definition at line 376 of file message.c.
References ast_string_field_free_memory.
Referenced by msg_data_alloc().
{
struct msg_data *data = obj;
ast_string_field_free_memory(data);
}
| static struct msg_data* msg_data_find | ( | struct ao2_container * | vars, |
| const char * | name | ||
| ) | [static, read] |
Definition at line 541 of file message.c.
References ao2_find, name, msg_data::name, and OBJ_POINTER.
Referenced by ast_msg_get_var(), and msg_set_var_full().
{
struct msg_data tmp = {
.name = name,
};
return ao2_find(vars, &tmp, OBJ_POINTER);
}
| static int msg_data_func_read | ( | struct ast_channel * | chan, |
| const char * | function, | ||
| char * | data, | ||
| char * | buf, | ||
| size_t | len | ||
| ) | [static] |
Definition at line 965 of file message.c.
References ao2_lock, ao2_ref, ao2_unlock, ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_copy_string(), ast_log(), ast_msg_get_var(), ast_datastore::data, LOG_ERROR, and LOG_WARNING.
{
struct ast_datastore *ds;
struct ast_msg *msg;
const char *val;
if (!chan) {
ast_log(LOG_WARNING, "No channel was provided to %s function.\n", function);
return -1;
}
ast_channel_lock(chan);
if (!(ds = ast_channel_datastore_find(chan, &msg_datastore, NULL))) {
ast_channel_unlock(chan);
ast_log(LOG_ERROR, "No MESSAGE data found on the channel to read.\n");
return -1;
}
msg = ds->data;
ao2_ref(msg, +1);
ast_channel_unlock(chan);
ao2_lock(msg);
if ((val = ast_msg_get_var(msg, data))) {
ast_copy_string(buf, val, len);
}
ao2_unlock(msg);
ao2_ref(msg, -1);
return 0;
}
| static int msg_data_func_write | ( | struct ast_channel * | chan, |
| const char * | function, | ||
| char * | data, | ||
| const char * | value | ||
| ) | [static] |
Definition at line 1001 of file message.c.
References ao2_lock, ao2_ref, ao2_unlock, ast_channel_lock, ast_channel_unlock, ast_log(), ast_msg_set_var_outbound(), ast_datastore::data, LOG_WARNING, and msg_datastore_find_or_create().
{
struct ast_datastore *ds;
struct ast_msg *msg;
if (!chan) {
ast_log(LOG_WARNING, "No channel was provided to %s function.\n", function);
return -1;
}
ast_channel_lock(chan);
if (!(ds = msg_datastore_find_or_create(chan))) {
ast_channel_unlock(chan);
return -1;
}
msg = ds->data;
ao2_ref(msg, +1);
ast_channel_unlock(chan);
ao2_lock(msg);
ast_msg_set_var_outbound(msg, data, value);
ao2_unlock(msg);
ao2_ref(msg, -1);
return 0;
}
| static int msg_data_hash_fn | ( | const void * | obj, |
| const int | flags | ||
| ) | [static] |
Definition at line 364 of file message.c.
References ast_str_case_hash(), and msg_data::name.
Referenced by ast_msg_alloc().
{
const struct msg_data *data = obj;
return ast_str_case_hash(data->name);
}
| static struct ast_datastore* msg_datastore_find_or_create | ( | struct ast_channel * | chan | ) | [static, read] |
Definition at line 842 of file message.c.
References ast_channel_datastore_add(), ast_channel_datastore_find(), ast_datastore_alloc(), ast_datastore_free(), ast_msg_alloc(), and ast_datastore::data.
Referenced by msg_data_func_write(), and msg_func_write().
{
struct ast_datastore *ds;
if ((ds = ast_channel_datastore_find(chan, &msg_datastore, NULL))) {
return ds;
}
if (!(ds = ast_datastore_alloc(&msg_datastore, NULL))) {
return NULL;
}
if (!(ds->data = ast_msg_alloc())) {
ast_datastore_free(ds);
return NULL;
}
ast_channel_datastore_add(chan, ds);
return ds;
}
| static void msg_destructor | ( | void * | obj | ) | [static] |
Definition at line 382 of file message.c.
References ao2_ref, ast_free, ast_msg::body, ast_msg::context, ast_msg::exten, ast_msg::from, ast_msg::to, and ast_msg::vars.
Referenced by ast_msg_alloc().
| static void msg_ds_destroy | ( | void * | data | ) | [static] |
| static struct ast_msg_tech_holder* msg_find_by_tech | ( | const struct ast_msg_tech * | msg_tech, |
| int | ao2_flags | ||
| ) | [static, read] |
Definition at line 1064 of file message.c.
References ao2_find, ast_rwlock_destroy, ast_rwlock_init, msg_tech, ast_msg_tech_holder::tech, and ast_msg_tech_holder::tech_lock.
Referenced by ast_msg_tech_register(), ast_msg_tech_unregister(), and msg_find_by_tech_name().
{
struct ast_msg_tech_holder *tech_holder;
struct ast_msg_tech_holder tmp_tech_holder = {
.tech = msg_tech,
};
ast_rwlock_init(&tmp_tech_holder.tech_lock);
tech_holder = ao2_find(msg_techs, &tmp_tech_holder, ao2_flags);
ast_rwlock_destroy(&tmp_tech_holder.tech_lock);
return tech_holder;
}
| static struct ast_msg_tech_holder* msg_find_by_tech_name | ( | const char * | tech_name, |
| int | ao2_flags | ||
| ) | [static, read] |
Definition at line 1077 of file message.c.
References msg_find_by_tech(), and ast_msg_tech::name.
Referenced by action_messagesend(), ast_msg_send(), and msg_send_exec().
{
struct ast_msg_tech tmp_msg_tech = {
.name = tech_name,
};
return msg_find_by_tech(&tmp_msg_tech, ao2_flags);
}
| static int msg_func_read | ( | struct ast_channel * | chan, |
| const char * | function, | ||
| char * | data, | ||
| char * | buf, | ||
| size_t | len | ||
| ) | [static] |
Definition at line 864 of file message.c.
References ao2_lock, ao2_ref, ao2_unlock, ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_copy_string(), ast_log(), ast_msg_get_body(), ast_str_buffer(), ast_datastore::data, ast_msg::from, LOG_ERROR, LOG_WARNING, and ast_msg::to.
{
struct ast_datastore *ds;
struct ast_msg *msg;
if (!chan) {
ast_log(LOG_WARNING, "No channel was provided to %s function.\n", function);
return -1;
}
ast_channel_lock(chan);
if (!(ds = ast_channel_datastore_find(chan, &msg_datastore, NULL))) {
ast_channel_unlock(chan);
ast_log(LOG_ERROR, "No MESSAGE data found on the channel to read.\n");
return -1;
}
msg = ds->data;
ao2_ref(msg, +1);
ast_channel_unlock(chan);
ao2_lock(msg);
if (!strcasecmp(data, "to")) {
ast_copy_string(buf, ast_str_buffer(msg->to), len);
} else if (!strcasecmp(data, "from")) {
ast_copy_string(buf, ast_str_buffer(msg->from), len);
} else if (!strcasecmp(data, "body")) {
ast_copy_string(buf, ast_msg_get_body(msg), len);
} else {
ast_log(LOG_WARNING, "Invalid argument to MESSAGE(): '%s'\n", data);
}
ao2_unlock(msg);
ao2_ref(msg, -1);
return 0;
}
| static int msg_func_write | ( | struct ast_channel * | chan, |
| const char * | function, | ||
| char * | data, | ||
| const char * | value | ||
| ) | [static] |
Definition at line 905 of file message.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_unlock, ast_channel_lock, ast_channel_unlock, ast_log(), ast_msg_set_body(), ast_msg_set_from(), ast_msg_set_to(), ast_datastore::data, LOG_WARNING, msg_datastore_find_or_create(), msg_data::send, and ast_msg::vars.
{
struct ast_datastore *ds;
struct ast_msg *msg;
if (!chan) {
ast_log(LOG_WARNING, "No channel was provided to %s function.\n", function);
return -1;
}
ast_channel_lock(chan);
if (!(ds = msg_datastore_find_or_create(chan))) {
ast_channel_unlock(chan);
return -1;
}
msg = ds->data;
ao2_ref(msg, +1);
ast_channel_unlock(chan);
ao2_lock(msg);
if (!strcasecmp(data, "to")) {
ast_msg_set_to(msg, "%s", value);
} else if (!strcasecmp(data, "from")) {
ast_msg_set_from(msg, "%s", value);
} else if (!strcasecmp(data, "body")) {
ast_msg_set_body(msg, "%s", value);
} else if (!strcasecmp(data, "custom_data")) {
int outbound = -1;
if (!strcasecmp(value, "mark_all_outbound")) {
outbound = 1;
} else if (!strcasecmp(value, "clear_all_outbound")) {
outbound = 0;
} else {
ast_log(LOG_WARNING, "'%s' is not a valid value for custom_data\n", value);
}
if (outbound != -1) {
struct msg_data *hdr_data;
struct ao2_iterator iter = ao2_iterator_init(msg->vars, 0);
while ((hdr_data = ao2_iterator_next(&iter))) {
hdr_data->send = outbound;
ao2_ref(hdr_data, -1);
}
ao2_iterator_destroy(&iter);
}
} else {
ast_log(LOG_WARNING, "'%s' is not a valid write argument.\n", data);
}
ao2_unlock(msg);
ao2_ref(msg, -1);
return 0;
}
| static int msg_q_cb | ( | void * | data | ) | [static] |
Definition at line 787 of file message.c.
References ao2_ref, ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_threadstorage_get(), chan_cleanup(), create_msg_q_chan(), ast_datastore::data, msg_q_chan, and msg_route().
Referenced by ast_msg_queue().
{
struct ast_msg *msg = data;
struct ast_channel **chan_p, *chan;
struct ast_datastore *ds;
if (!(chan_p = ast_threadstorage_get(&msg_q_chan, sizeof(struct ast_channel *)))) {
return -1;
}
if (!*chan_p) {
if (!(*chan_p = create_msg_q_chan())) {
return -1;
}
}
chan = *chan_p;
ast_channel_lock(chan);
if (!(ds = ast_channel_datastore_find(chan, &msg_datastore, NULL))) {
ast_channel_unlock(chan);
return -1;
}
ao2_ref(msg, +1);
ds->data = msg;
ast_channel_unlock(chan);
msg_route(chan, msg);
chan_cleanup(chan);
ao2_ref(msg, -1);
return 0;
}
| static void msg_route | ( | struct ast_channel * | chan, |
| struct ast_msg * | msg | ||
| ) | [static] |
Definition at line 700 of file message.c.
References AS_OR, ast_explicit_goto(), ast_pbx_run_args(), ast_str_buffer(), ast_msg::context, ast_msg::exten, and ast_pbx_args::no_hangup_chan.
Referenced by msg_q_cb().
{
struct ast_pbx_args pbx_args;
ast_explicit_goto(chan, ast_str_buffer(msg->context), AS_OR(msg->exten, "s"), 1);
memset(&pbx_args, 0, sizeof(pbx_args));
pbx_args.no_hangup_chan = 1,
ast_pbx_run_args(chan, &pbx_args);
}
| static int msg_send_exec | ( | struct ast_channel * | chan, |
| const char * | data | ||
| ) | [static] |
Definition at line 1089 of file message.c.
References ao2_lock, ao2_ref, ao2_unlock, args, AST_APP_ARG, ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, AST_DECLARE_APP_ARGS, ast_log(), ast_rwlock_rdlock, ast_rwlock_unlock, AST_STANDARD_APP_ARGS, ast_strlen_zero(), ast_datastore::data, LOG_WARNING, msg_find_by_tech_name(), ast_msg_tech::msg_send, OBJ_POINTER, parse(), pbx_builtin_setvar_helper(), S_OR, ast_msg_tech_holder::tech, and ast_msg_tech_holder::tech_lock.
Referenced by ast_msg_init().
{
struct ast_datastore *ds;
struct ast_msg *msg;
char *tech_name;
struct ast_msg_tech_holder *tech_holder = NULL;
char *parse;
int res = -1;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(to);
AST_APP_ARG(from);
);
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "An argument is required to MessageSend()\n");
pbx_builtin_setvar_helper(chan, "MESSAGE_SEND_STATUS", "INVALID_URI");
return 0;
}
parse = ast_strdupa(data);
AST_STANDARD_APP_ARGS(args, parse);
if (ast_strlen_zero(args.to)) {
ast_log(LOG_WARNING, "A 'to' URI is required for MessageSend()\n");
pbx_builtin_setvar_helper(chan, "MESSAGE_SEND_STATUS", "INVALID_URI");
return 0;
}
ast_channel_lock(chan);
if (!(ds = ast_channel_datastore_find(chan, &msg_datastore, NULL))) {
ast_channel_unlock(chan);
ast_log(LOG_WARNING, "No message data found on channel to send.\n");
pbx_builtin_setvar_helper(chan, "MESSAGE_SEND_STATUS", "FAILURE");
return 0;
}
msg = ds->data;
ao2_ref(msg, +1);
ast_channel_unlock(chan);
tech_name = ast_strdupa(args.to);
tech_name = strsep(&tech_name, ":");
tech_holder = msg_find_by_tech_name(tech_name, OBJ_POINTER);
if (!tech_holder) {
ast_log(LOG_WARNING, "No message technology '%s' found.\n", tech_name);
pbx_builtin_setvar_helper(chan, "MESSAGE_SEND_STATUS", "INVALID_PROTOCOL");
goto exit_cleanup;
}
/*
* The message lock is held here to safely allow the technology
* implementation to access the message fields without worrying
* that they could change.
*/
ao2_lock(msg);
ast_rwlock_rdlock(&tech_holder->tech_lock);
if (tech_holder->tech) {
res = tech_holder->tech->msg_send(msg, S_OR(args.to, ""),
S_OR(args.from, ""));
}
ast_rwlock_unlock(&tech_holder->tech_lock);
ao2_unlock(msg);
pbx_builtin_setvar_helper(chan, "MESSAGE_SEND_STATUS", res ? "FAILURE" : "SUCCESS");
exit_cleanup:
if (tech_holder) {
ao2_ref(tech_holder, -1);
tech_holder = NULL;
}
ao2_ref(msg, -1);
return 0;
}
| static int msg_set_var_full | ( | struct ast_msg * | msg, |
| const char * | name, | ||
| const char * | value, | ||
| unsigned int | outbound | ||
| ) | [static] |
Definition at line 549 of file message.c.
References ao2_link, ao2_ref, ao2_unlink, ast_string_field_set, ast_strlen_zero(), msg_data_alloc(), msg_data_find(), msg_data::send, and ast_msg::vars.
Referenced by ast_msg_set_var(), and ast_msg_set_var_outbound().
{
struct msg_data *data;
if (!(data = msg_data_find(msg->vars, name))) {
if (ast_strlen_zero(value)) {
return 0;
}
if (!(data = msg_data_alloc())) {
return -1;
};
ast_string_field_set(data, name, name);
ast_string_field_set(data, value, value);
data->send = outbound;
ao2_link(msg->vars, data);
} else {
if (ast_strlen_zero(value)) {
ao2_unlink(msg->vars, data);
} else {
ast_string_field_set(data, value, value);
data->send = outbound;
}
}
ao2_ref(data, -1);
return 0;
}
| static int msg_tech_cmp | ( | void * | obj, |
| void * | arg, | ||
| int | flags | ||
| ) | [static] |
Definition at line 1046 of file message.c.
References ast_rwlock_rdlock, ast_rwlock_unlock, CMP_MATCH, CMP_STOP, ast_msg_tech::name, ast_msg_tech_holder::tech, and ast_msg_tech_holder::tech_lock.
Referenced by ast_msg_init().
{
struct ast_msg_tech_holder *tech_holder = obj;
const struct ast_msg_tech_holder *tech_holder2 = arg;
int res = 1;
ast_rwlock_rdlock(&tech_holder->tech_lock);
/*
* tech_holder2 is a temporary fake tech_holder.
*/
if (tech_holder->tech) {
res = strcasecmp(tech_holder->tech->name, tech_holder2->tech->name) ? 0 : CMP_MATCH | CMP_STOP;
}
ast_rwlock_unlock(&tech_holder->tech_lock);
return res;
}
| static int msg_tech_hash | ( | const void * | obj, |
| const int | flags | ||
| ) | [static] |
Definition at line 1032 of file message.c.
References ast_rwlock_rdlock, ast_rwlock_unlock, ast_str_case_hash(), ast_msg_tech::name, ast_msg_tech_holder::tech, and ast_msg_tech_holder::tech_lock.
Referenced by ast_msg_init().
{
struct ast_msg_tech_holder *tech_holder = (struct ast_msg_tech_holder *) obj;
int res = 0;
ast_rwlock_rdlock(&tech_holder->tech_lock);
if (tech_holder->tech) {
res = ast_str_case_hash(tech_holder->tech->name);
}
ast_rwlock_unlock(&tech_holder->tech_lock);
return res;
}
const char app_msg_send[] = "MessageSend" [static] |
struct ast_channel_tech msg_chan_tech_hack [static] |
struct ast_custom_function msg_data_function [static] |
{
.name = "MESSAGE_DATA",
.read = msg_data_func_read,
.write = msg_data_func_write,
}
struct ast_datastore_info msg_datastore [static] |
{
.type = "message",
.destroy = msg_ds_destroy,
}
struct ast_custom_function msg_function [static] |
{
.name = "MESSAGE",
.read = msg_func_read,
.write = msg_func_write,
}
struct ast_threadstorage msg_q_chan = { .once = PTHREAD_ONCE_INIT , .key_init = __init_msg_q_chan , .custom_init = NULL , } [static] |
Definition at line 776 of file message.c.
Referenced by msg_q_cb().
struct ast_taskprocessor* msg_q_tp [static] |
struct ao2_container* msg_techs [static] |