Sat Apr 26 2014 22:02:56

Asterisk developer's documentation


message.c File Reference

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"
Include dependency graph for message.c:

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_msgast_msg_alloc (void)
 Allocate a message.
struct ast_msgast_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_msgast_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_iteratorast_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_framechan_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_channelcreate_msg_q_chan (void)
static void destroy_msg_q_chan (void *data)
static void message_shutdown (void)
static struct msg_datamsg_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_datamsg_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_datastoremsg_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_holdermsg_find_by_tech (const struct ast_msg_tech *msg_tech, int ao2_flags)
static struct ast_msg_tech_holdermsg_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_taskprocessormsg_q_tp
static struct ao2_containermsg_techs

Detailed Description

Out-of-call text message support.

Author:
Russell Bryant <russell@digium.com>

Definition in file message.c.


Function Documentation

static void __init_msg_q_chan ( void  ) [static]

Definition at line 776 of file message.c.

{
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.

Returns:
A message object. This function will return NULL if an allocation error occurs.

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().

Returns:
NULL, always.

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.

Note:
The return value is valid only as long as the ast_message is valid. Hold a reference to the message if you plan on storing the return value.
Returns:
The body of the messsage, encoded in UTF-8.

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.

Note:
The return value is valid only as long as the ast_message is valid. Hold a reference to the message if you plan on storing the return value. Do re-set the same message var name while holding a pointer to the result of this function.
Returns:
The value associated with variable "name". NULL if variable not found.

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_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.

Return values:
0message successfully queued
non-zerofailure, 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]

Bump a msg's ref count.

Definition at line 447 of file message.c.

References ao2_ref.

{
   ao2_ref(msg, 1);
   return msg;
}
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.

Return values:
0message successfully queued to be sent out
non-zerofailure, 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)

Return values:
0success
-1failure

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.

Return values:
0success
-1failure

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.

Return values:
0success
-1failure

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.

Return values:
0success
-1failure

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.

Return values:
0success
-1failure

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.

Note:
Setting a variable that already exists overwrites the existing variable value
Parameters:
nameName of variable to set
valueValue of variable to set
Return values:
0success
-1failure

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.

Note:
Setting a variable that already exists overwrites the existing variable value
Parameters:
nameName of variable to set
valueValue of variable to set
Return values:
0success
-1failure

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().

int ast_msg_tech_register ( const struct ast_msg_tech tech)

Register a message technology.

Return values:
0success
non-zerofailure

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.

Return values:
0success
non-zerofailure

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;
}

Destroy a message variable iterator.

Parameters:
iIterator 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().

struct ast_msg_var_iterator* ast_msg_var_iterator_init ( const struct ast_msg msg) [read]

Create a new message variable iterator.

Parameters:
msgA message whose variables are to be iterated over
Returns:
An opaque pointer to the new iterator

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.

Parameters:
msgThe message with the variables
iAn iterator created with ast_msg_var_iterator_init
nameA pointer to the name result pointer
valueA pointer to the value result pointer
Return values:
0No more entries
1Valid 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;
}

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]

Definition at line 324 of file message.c.

{
   return 0;
}
static struct ast_frame * chan_msg_read ( struct ast_channel chan) [static, read]

Definition at line 298 of file message.c.

References ast_null_frame.

{
   return &ast_null_frame;
}
static int chan_msg_send_digit_begin ( struct ast_channel chan,
char  digit 
) [static]

Definition at line 338 of file message.c.

{
   return 0;
}
static int chan_msg_send_digit_end ( struct ast_channel chan,
char  digit,
unsigned int  duration 
) [static]

Definition at line 351 of file message.c.

{
   return 0;
}
static int chan_msg_write ( struct ast_channel chan,
struct ast_frame fr 
) [static]

Definition at line 309 of file message.c.

{
   return 0;
}
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 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().

{
   const struct msg_data *one = obj, *two = arg;
   return !strcasecmp(one->name, two->name) ? CMP_MATCH | CMP_STOP : 0;
}
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().

{
   struct ast_msg *msg = obj;

   ast_free(msg->to);
   msg->to = NULL;

   ast_free(msg->from);
   msg->from = NULL;

   ast_free(msg->body);
   msg->body = NULL;

   ast_free(msg->context);
   msg->context = NULL;

   ast_free(msg->exten);
   msg->exten = NULL;

   ao2_ref(msg->vars, -1);
}
static void msg_ds_destroy ( void *  data) [static]

Definition at line 357 of file message.c.

References ao2_ref.

{
   struct ast_msg *msg = data;

   ao2_ref(msg, -1);
}
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;
}

Variable Documentation

const char app_msg_send[] = "MessageSend" [static]

Definition at line 234 of file message.c.

Definition at line 280 of file message.c.

Initial value:
 {
   .name = "MESSAGE_DATA",
   .read = msg_data_func_read,
   .write = msg_data_func_write,
}

Definition at line 259 of file message.c.

Initial value:
 {
   .type = "message",
   .destroy = msg_ds_destroy,
}

Definition at line 238 of file message.c.

Initial value:
 {
   .name = "MESSAGE",
   .read = msg_func_read,
   .write = msg_func_write,
}

Definition at line 248 of file message.c.

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]

Definition at line 232 of file message.c.

struct ao2_container* msg_techs [static]

Definition at line 230 of file message.c.