[svn-commits] mmichelson: branch group/ari-greedy-atxfer r420096 - in /team/group/ari-greed...
SVN commits to the Digium repositories
svn-commits at lists.digium.com
Tue Aug 5 15:26:44 CDT 2014
Author: mmichelson
Date: Tue Aug 5 15:26:40 2014
New Revision: 420096
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=420096
Log:
Resolve conflicts and reset automerge.
Added:
team/group/ari-greedy-atxfer/res/stasis/messaging.c
- copied unchanged from r420090, branches/12/res/stasis/messaging.c
team/group/ari-greedy-atxfer/res/stasis/messaging.h
- copied unchanged from r420090, branches/12/res/stasis/messaging.h
team/group/ari-greedy-atxfer/tests/test_message.c
- copied unchanged from r420090, branches/12/tests/test_message.c
Modified:
team/group/ari-greedy-atxfer/ (props changed)
team/group/ari-greedy-atxfer/CHANGES
team/group/ari-greedy-atxfer/channels/chan_sip.c
team/group/ari-greedy-atxfer/include/asterisk/json.h
team/group/ari-greedy-atxfer/include/asterisk/manager.h
team/group/ari-greedy-atxfer/include/asterisk/message.h
team/group/ari-greedy-atxfer/include/asterisk/vector.h
team/group/ari-greedy-atxfer/main/json.c
team/group/ari-greedy-atxfer/main/message.c
team/group/ari-greedy-atxfer/res/ari/ari_model_validators.c
team/group/ari-greedy-atxfer/res/ari/ari_model_validators.h
team/group/ari-greedy-atxfer/res/ari/resource_channels.c
team/group/ari-greedy-atxfer/res/ari/resource_endpoints.c
team/group/ari-greedy-atxfer/res/ari/resource_endpoints.h
team/group/ari-greedy-atxfer/res/res_ari_endpoints.c
team/group/ari-greedy-atxfer/res/res_pjsip_messaging.c
team/group/ari-greedy-atxfer/res/res_stasis.c
team/group/ari-greedy-atxfer/res/res_xmpp.c
team/group/ari-greedy-atxfer/res/stasis/app.c
team/group/ari-greedy-atxfer/rest-api/api-docs/endpoints.json
team/group/ari-greedy-atxfer/rest-api/api-docs/events.json
Propchange: team/group/ari-greedy-atxfer/
------------------------------------------------------------------------------
automerge = *
Propchange: team/group/ari-greedy-atxfer/
------------------------------------------------------------------------------
--- svnmerge-integrated (original)
+++ svnmerge-integrated Tue Aug 5 15:26:40 2014
@@ -1,1 +1,1 @@
-/branches/12:1-420065
+/branches/12:1-420095
Modified: team/group/ari-greedy-atxfer/CHANGES
URL: http://svnview.digium.com/svn/asterisk/team/group/ari-greedy-atxfer/CHANGES?view=diff&rev=420096&r1=420095&r2=420096
==============================================================================
--- team/group/ari-greedy-atxfer/CHANGES (original)
+++ team/group/ari-greedy-atxfer/CHANGES Tue Aug 5 15:26:40 2014
@@ -28,6 +28,17 @@
recording. This is only available if max_silence_seconds was specified
when the recording was started.
Note that all duration values are reported in seconds.
+
+ * Users of ARI can now send and receive out of call text messages. Messages
+ can be sent directly to a particular endpoint, or can be sent to the
+ endpoints resource directly and inferred from the URI scheme. Text
+ messages are passed to ARI clients as TextMessageReceived events. ARI
+ clients can choose to receive text messages by subscribing to the particular
+ endpoint technology or endpoints that they are interested in.
+
+ * The applications resource now supports subscriptions to all endpoints of
+ a particular channel technology. For example, subscribing to an eventSource
+ of 'endpoint:PJSIP' will subscribe to all PJSIP endpoints.
res_pjsip
------------------
Modified: team/group/ari-greedy-atxfer/channels/chan_sip.c
URL: http://svnview.digium.com/svn/asterisk/team/group/ari-greedy-atxfer/channels/chan_sip.c?view=diff&rev=420096&r1=420095&r2=420096
==============================================================================
--- team/group/ari-greedy-atxfer/channels/chan_sip.c (original)
+++ team/group/ari-greedy-atxfer/channels/chan_sip.c Tue Aug 5 15:26:40 2014
@@ -19030,6 +19030,7 @@
char *to;
char from_name[50];
char stripped[SIPBUFSIZE];
+ enum sip_get_dest_result dest_result;
if (strncmp(content_type, "text/plain", strlen("text/plain"))) { /* No text/plain attachment */
transmit_response(p, "415 Unsupported Media Type", req); /* Good enough, or? */
@@ -19139,7 +19140,8 @@
ast_string_field_set(p, context, sip_cfg.messagecontext);
}
- switch (get_destination(p, NULL, NULL)) {
+ dest_result = get_destination(p, NULL, NULL);
+ switch (dest_result) {
case SIP_GET_DEST_REFUSED:
/* Okay to send 403 since this is after auth processing */
transmit_response(p, "403 Forbidden", req);
@@ -19149,12 +19151,9 @@
transmit_response(p, "416 Unsupported URI Scheme", req);
sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
return;
- case SIP_GET_DEST_EXTEN_NOT_FOUND:
- case SIP_GET_DEST_EXTEN_MATCHMORE:
- transmit_response(p, "404 Not Found", req);
- sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
- return;
- case SIP_GET_DEST_EXTEN_FOUND:
+ default:
+ /* We may have something other than dialplan who wants
+ * the message, so defer further error handling for now */
break;
}
@@ -19182,7 +19181,9 @@
res |= ast_msg_set_context(msg, "%s", p->context);
res |= ast_msg_set_var(msg, "SIP_RECVADDR", ast_sockaddr_stringify(&p->recv));
+ res |= ast_msg_set_tech(msg, "%s", "SIP");
if (!ast_strlen_zero(p->peername)) {
+ res |= ast_msg_set_endpoint(msg, "%s", p->peername);
res |= ast_msg_set_var(msg, "SIP_PEERNAME", p->peername);
}
@@ -19195,12 +19196,32 @@
if (res) {
ast_msg_destroy(msg);
transmit_response(p, "500 Internal Server Error", req);
- } else {
+ sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
+ return;
+ }
+
+ if (ast_msg_has_destination(msg)) {
ast_msg_queue(msg);
transmit_response(p, "202 Accepted", req);
- }
-
+ sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
+ return;
+ }
+
+ /* Find a specific error cause to send */
+ switch (dest_result) {
+ case SIP_GET_DEST_EXTEN_NOT_FOUND:
+ case SIP_GET_DEST_EXTEN_MATCHMORE:
+ transmit_response(p, "404 Not Found", req);
+ break;
+ case SIP_GET_DEST_EXTEN_FOUND:
+ default:
+ /* We should have sent the message already! */
+ ast_assert(0);
+ transmit_response(p, "500 Internal Server Error", req);
+ break;
+ }
sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
+ ast_msg_destroy(msg);
}
/*! \brief CLI Command to show calls within limits set by call_limit */
Modified: team/group/ari-greedy-atxfer/include/asterisk/json.h
URL: http://svnview.digium.com/svn/asterisk/team/group/ari-greedy-atxfer/include/asterisk/json.h?view=diff&rev=420096&r1=420095&r2=420096
==============================================================================
--- team/group/ari-greedy-atxfer/include/asterisk/json.h (original)
+++ team/group/ari-greedy-atxfer/include/asterisk/json.h Tue Aug 5 15:26:40 2014
@@ -1010,6 +1010,27 @@
*/
struct ast_json *ast_json_party_id(struct ast_party_id *party);
+/*!
+ * \brief Convert a \c ast_json list of key/value pair tuples into a \c ast_variable list
+ * \since 12.5.0
+ *
+ * \param json_variables The JSON blob containing the variable
+ * \param variables An out reference to the variables to populate.
+ * The pointer to the variables should be NULL when calling this.
+ *
+ * \code
+ * struct ast_json *json_variables = ast_json_pack("[ { s: s } ]", "foo", "bar");
+ * struct ast_variable *variables = NULL;
+ * int res;
+ *
+ * res = ast_json_to_ast_variables(json_variables, &variables);
+ * \endcode
+ *
+ * \retval 0 success
+ * \retval -1 error
+ */
+int ast_json_to_ast_variables(struct ast_json *json_variables, struct ast_variable **variables);
+
/*!@}*/
#endif /* _ASTERISK_JSON_H */
Modified: team/group/ari-greedy-atxfer/include/asterisk/manager.h
URL: http://svnview.digium.com/svn/asterisk/team/group/ari-greedy-atxfer/include/asterisk/manager.h?view=diff&rev=420096&r1=420095&r2=420096
==============================================================================
--- team/group/ari-greedy-atxfer/include/asterisk/manager.h (original)
+++ team/group/ari-greedy-atxfer/include/asterisk/manager.h Tue Aug 5 15:26:40 2014
@@ -94,8 +94,16 @@
/*! \brief Export manager structures */
#define AST_MAX_MANHEADERS 128
-/*! \brief Manager Helper Function */
-typedef int (*manager_hook_t)(int, const char *, char *);
+/*! \brief Manager Helper Function
+ *
+ * \param category The class authorization category of the event
+ * \param event The name of the event being raised
+ * \param body The body of the event
+ *
+ * \retval 0 Success
+ * \retval non-zero Error
+ */
+typedef int (*manager_hook_t)(int category, const char *event, char *body);
struct manager_custom_hook {
/*! Identifier */
Modified: team/group/ari-greedy-atxfer/include/asterisk/message.h
URL: http://svnview.digium.com/svn/asterisk/team/group/ari-greedy-atxfer/include/asterisk/message.h?view=diff&rev=420096&r1=420095&r2=420096
==============================================================================
--- team/group/ari-greedy-atxfer/include/asterisk/message.h (original)
+++ team/group/ari-greedy-atxfer/include/asterisk/message.h Tue Aug 5 15:26:40 2014
@@ -25,8 +25,9 @@
*
* The purpose of this API is to provide support for text messages that
* are not session based. The messages are passed into the Asterisk core
- * to be routed through the dialplan and potentially sent back out through
- * a message technology that has been registered through this API.
+ * to be routed through the dialplan or another interface and potentially
+ * sent back out through a message technology that has been registered
+ * through this API.
*/
#ifndef __AST_MESSAGE_H__
@@ -91,6 +92,64 @@
int ast_msg_tech_unregister(const struct ast_msg_tech *tech);
/*!
+ * \brief An external processor of received messages
+ * \since 12.5.0
+ */
+struct ast_msg_handler {
+ /*!
+ * \brief Name of the message handler
+ */
+ const char *name;
+
+ /*!
+ * \brief The function callback that will handle the message
+ *
+ * \param msg The message to handle
+ *
+ * \retval 0 The handler processed the message successfull
+ * \retval non-zero The handler passed or could not process the message
+ */
+ int (* const handle_msg)(struct ast_msg *msg);
+
+ /*!
+ * \brief Return whether or not the message has a valid destination
+ *
+ * A message may be delivered to the dialplan and/or other locations,
+ * depending on whether or not other handlers have been registered. This
+ * function is called by the message core to determine if any handler can
+ * process a message.
+ *
+ * \param msg The message to inspect
+ *
+ * \retval 0 The message does not have a valid destination
+ * \retval 1 The message has a valid destination
+ */
+ int (* const has_destination)(const struct ast_msg *msg);
+};
+
+/*!
+ * \brief Register a \c ast_msg_handler
+ * \since 12.5.0
+ *
+ * \param handler The handler to register
+ *
+ * \retval 0 Success
+ * \retval non-zero Error
+ */
+int ast_msg_handler_register(const struct ast_msg_handler *handler);
+
+/*!
+ * \brief Unregister a \c ast_msg_handler
+ * \since 12.5.0
+ *
+ * \param handler The handler to unregister
+ *
+ * \retval 0 Success
+ * \retval non-zero Error
+ */
+int ast_msg_handler_unregister(const struct ast_msg_handler *handler);
+
+/*!
* \brief Allocate a message.
*
* Allocate a message for the purposes of passing it into the Asterisk core
@@ -162,7 +221,29 @@
*/
int __attribute__((format(printf, 2, 3)))
ast_msg_set_exten(struct ast_msg *msg, const char *fmt, ...);
-
+
+/*!
+ * \brief Set the technology associated with this message
+ *
+ * \since 12.5.0
+ *
+ * \retval 0 success
+ * \retval -1 failure
+ */
+int __attribute__((format(printf, 2, 3)))
+ ast_msg_set_tech(struct ast_msg *msg, const char *fmt, ...);
+
+/*!
+ * \brief Set the technology's endpoint associated with this message
+ *
+ * \since 12.5.0
+ *
+ * \retval 0 success
+ * \retval -1 failure
+ */
+int __attribute__((format(printf, 2, 3)))
+ ast_msg_set_endpoint(struct ast_msg *msg, const char *fmt, ...);
+
/*!
* \brief Set a variable on the message going to the dialplan.
* \note Setting a variable that already exists overwrites the existing variable value
@@ -207,6 +288,66 @@
* \return The body of the messsage, encoded in UTF-8.
*/
const char *ast_msg_get_body(const struct ast_msg *msg);
+
+/*!
+ * \brief Retrieve the source of this message
+ *
+ * \since 12.5.0
+ *
+ * \param msg The message to get the soure from
+ *
+ * \retval The source of the message
+ * \retval NULL or empty string if the message has no source
+ */
+const char *ast_msg_get_from(const struct ast_msg *msg);
+
+/*!
+ * \brief Retrieve the destination of this message
+ *
+ * \since 12.5.0
+ *
+ * \param msg The message to get the destination from
+ *
+ * \retval The destination of the message
+ * \retval NULL or empty string if the message has no destination
+ */
+const char *ast_msg_get_to(const struct ast_msg *msg);
+
+/*!
+ * \brief Retrieve the technology associated with this message
+ *
+ * \since 12.5.0
+ *
+ * \param msg The message to get the technology from
+ *
+ * \retval The technology of the message
+ * \retval NULL or empty string if the message has no associated technology
+ */
+const char *ast_msg_get_tech(const struct ast_msg *msg);
+
+/*!
+ * \brief Retrieve the endpoint associated with this message
+ *
+ * \since 12.5.0
+ *
+ * \param msg The message to get the endpoint from
+ *
+ * \retval The endpoint associated with the message
+ * \retval NULL or empty string if the message has no associated endpoint
+ */
+const char *ast_msg_get_endpoint(const struct ast_msg *msg);
+
+/*!
+ * \brief Determine if a particular message has a destination via some handler
+ *
+ * \since 12.5.0
+ *
+ * \param msg The message to check
+ *
+ * \retval 0 if the message has no handler that can find a destination
+ * \retval 1 if the message has a handler that can find a destination
+ */
+int ast_msg_has_destination(const struct ast_msg *msg);
/*!
* \brief Queue a message for routing through the dialplan.
Modified: team/group/ari-greedy-atxfer/include/asterisk/vector.h
URL: http://svnview.digium.com/svn/asterisk/team/group/ari-greedy-atxfer/include/asterisk/vector.h?view=diff&rev=420096&r1=420095&r2=420096
==============================================================================
--- team/group/ari-greedy-atxfer/include/asterisk/vector.h (original)
+++ team/group/ari-greedy-atxfer/include/asterisk/vector.h Tue Aug 5 15:26:40 2014
@@ -61,7 +61,7 @@
#define AST_VECTOR_INIT(vec, size) ({ \
size_t __size = (size); \
size_t alloc_size = __size * sizeof(*((vec)->elems)); \
- (vec)->elems = alloc_size ? ast_malloc(alloc_size) : NULL; \
+ (vec)->elems = alloc_size ? ast_calloc(1, alloc_size) : NULL; \
(vec)->current = 0; \
if ((vec)->elems) { \
(vec)->max = __size; \
@@ -116,6 +116,48 @@
})
/*!
+ * \brief Insert an element at a specific position in a vector, growing the vector if needed.
+ *
+ * \param vec Vector to insert into.
+ * \param idx Position to insert at.
+ * \param elem Element to insert.
+ *
+ * \return 0 on success.
+ * \return Non-zero on failure.
+ *
+ * \warning This macro will overwrite anything already present at the position provided.
+ *
+ * \warning Use of this macro with the expectation that the element will remain at the provided
+ * index means you can not use the UNORDERED assortment of macros. These macros alter the ordering
+ * of the vector itself.
+ */
+#define AST_VECTOR_INSERT(vec, idx, elem) ({ \
+ int res = 0; \
+ do { \
+ if (((idx) + 1) > (vec)->max) { \
+ size_t new_max = ((idx) + 1) * 2; \
+ typeof((vec)->elems) new_elems = ast_calloc(1, \
+ new_max * sizeof(*new_elems)); \
+ if (new_elems) { \
+ memcpy(new_elems, (vec)->elems, \
+ (vec)->current * sizeof(*new_elems)); \
+ ast_free((vec)->elems); \
+ (vec)->elems = new_elems; \
+ (vec)->max = new_max; \
+ } else { \
+ res = -1; \
+ break; \
+ } \
+ } \
+ (vec)->elems[(idx)] = (elem); \
+ if (((idx) + 1) > (vec)->current) { \
+ (vec)->current = (idx) + 1; \
+ } \
+ } while(0); \
+ res; \
+})
+
+/*!
* \brief Remove an element from a vector by index.
*
* Note that elements in the vector may be reordered, so that the remove can
Modified: team/group/ari-greedy-atxfer/main/json.c
URL: http://svnview.digium.com/svn/asterisk/team/group/ari-greedy-atxfer/main/json.c?view=diff&rev=420096&r1=420095&r2=420096
==============================================================================
--- team/group/ari-greedy-atxfer/main/json.c (original)
+++ team/group/ari-greedy-atxfer/main/json.c Tue Aug 5 15:26:40 2014
@@ -881,3 +881,33 @@
return ast_json_ref(json_party_id);
}
+
+int ast_json_to_ast_variables(struct ast_json *json_variables, struct ast_variable **variables)
+{
+ struct ast_json_iter *it_json_var;
+
+ *variables = NULL;
+
+ for (it_json_var = ast_json_object_iter(json_variables); it_json_var;
+ it_json_var = ast_json_object_iter_next(json_variables, it_json_var)) {
+ struct ast_variable *new_var;
+ const char *key = ast_json_object_iter_key(it_json_var);
+
+ if (ast_strlen_zero(key)) {
+ continue;
+ }
+
+ new_var = ast_variable_new(key,
+ ast_json_string_get(ast_json_object_iter_value(it_json_var)),
+ "");
+ if (!new_var) {
+ ast_variables_destroy(*variables);
+ *variables = NULL;
+ return -1;
+ }
+
+ ast_variable_list_append(variables, new_var);
+ }
+
+ return 0;
+}
Modified: team/group/ari-greedy-atxfer/main/message.c
URL: http://svnview.digium.com/svn/asterisk/team/group/ari-greedy-atxfer/main/message.c?view=diff&rev=420096&r1=420095&r2=420096
==============================================================================
--- team/group/ari-greedy-atxfer/main/message.c (original)
+++ team/group/ari-greedy-atxfer/main/message.c Tue Aug 5 15:26:40 2014
@@ -39,6 +39,7 @@
#include "asterisk/manager.h"
#include "asterisk/strings.h"
#include "asterisk/astobj2.h"
+#include "asterisk/vector.h"
#include "asterisk/app.h"
#include "asterisk/taskprocessor.h"
#include "asterisk/message.h"
@@ -201,37 +202,46 @@
AST_STRING_FIELD(name);
AST_STRING_FIELD(value);
);
- unsigned int send:1; /* Whether to send out on outbound messages */
+ unsigned int send; /* Whether to send out on outbound messages */
};
AST_LIST_HEAD_NOLOCK(outhead, msg_data);
/*!
* \brief A message.
- *
- * \todo Consider whether stringfields would be an appropriate optimization here.
*/
struct ast_msg {
- struct ast_str *to;
- struct ast_str *from;
- struct ast_str *body;
- struct ast_str *context;
- struct ast_str *exten;
+ AST_DECLARE_STRING_FIELDS(
+ /*! Where the message is going */
+ AST_STRING_FIELD(to);
+ /*! Where we "say" the message came from */
+ AST_STRING_FIELD(from);
+ /*! The text to send */
+ AST_STRING_FIELD(body);
+ /*! The dialplan context for the message */
+ AST_STRING_FIELD(context);
+ /*! The dialplan extension for the message */
+ AST_STRING_FIELD(exten);
+ /*! An endpoint associated with this message */
+ AST_STRING_FIELD(endpoint);
+ /*! The technology of the endpoint associated with this message */
+ AST_STRING_FIELD(tech);
+ );
+ /*! Technology/dialplan specific variables associated with the message */
struct ao2_container *vars;
};
-struct ast_msg_tech_holder {
- const struct ast_msg_tech *tech;
- /*!
- * \brief A rwlock for this object
- *
- * a read/write lock must be used to protect the wrapper instead
- * of the ao2 lock. A rdlock must be held to read tech_holder->tech.
- */
- ast_rwlock_t tech_lock;
-};
-
-static struct ao2_container *msg_techs;
+/*! \brief Lock for \c msg_techs vector */
+static ast_rwlock_t msg_techs_lock;
+
+/*! \brief Vector of message technologies */
+AST_VECTOR(, const struct ast_msg_tech *) msg_techs;
+
+/*! \brief Lock for \c msg_handlers vector */
+static ast_rwlock_t msg_handlers_lock;
+
+/*! \brief Vector of received message handlers */
+AST_VECTOR(, const struct ast_msg_handler *) msg_handlers;
static struct ast_taskprocessor *msg_q_tp;
@@ -387,21 +397,7 @@
{
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;
-
+ ast_string_field_free_memory(msg);
ao2_ref(msg->vars, -1);
}
@@ -413,27 +409,7 @@
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))) {
+ if (ast_string_field_init(msg, 128)) {
ao2_ref(msg, -1);
return NULL;
}
@@ -442,8 +418,7 @@
ao2_ref(msg, -1);
return NULL;
}
-
- ast_str_set(&msg->context, 0, "default");
+ ast_string_field_set(msg, context, "default");
return msg;
}
@@ -457,73 +432,109 @@
struct ast_msg *ast_msg_destroy(struct ast_msg *msg)
{
ao2_ref(msg, -1);
-
return NULL;
}
int ast_msg_set_to(struct ast_msg *msg, const char *fmt, ...)
{
va_list ap;
- int res;
va_start(ap, fmt);
- res = ast_str_set_va(&msg->to, 0, fmt, ap);
+ ast_string_field_build_va(msg, to, fmt, ap);
va_end(ap);
- return res < 0 ? -1 : 0;
+ return 0;
}
int ast_msg_set_from(struct ast_msg *msg, const char *fmt, ...)
{
va_list ap;
- int res;
va_start(ap, fmt);
- res = ast_str_set_va(&msg->from, 0, fmt, ap);
+ ast_string_field_build_va(msg, from, fmt, ap);
va_end(ap);
- return res < 0 ? -1 : 0;
+ return 0;
}
int ast_msg_set_body(struct ast_msg *msg, const char *fmt, ...)
{
va_list ap;
- int res;
va_start(ap, fmt);
- res = ast_str_set_va(&msg->body, 0, fmt, ap);
+ ast_string_field_build_va(msg, body, fmt, ap);
va_end(ap);
- return res < 0 ? -1 : 0;
+ return 0;
}
int ast_msg_set_context(struct ast_msg *msg, const char *fmt, ...)
{
va_list ap;
- int res;
va_start(ap, fmt);
- res = ast_str_set_va(&msg->context, 0, fmt, ap);
+ ast_string_field_build_va(msg, context, fmt, ap);
va_end(ap);
- return res < 0 ? -1 : 0;
+ return 0;
}
int ast_msg_set_exten(struct ast_msg *msg, const char *fmt, ...)
{
va_list ap;
- int res;
va_start(ap, fmt);
- res = ast_str_set_va(&msg->exten, 0, fmt, ap);
+ ast_string_field_build_va(msg, exten, fmt, ap);
va_end(ap);
- return res < 0 ? -1 : 0;
+ return 0;
+}
+
+int ast_msg_set_tech(struct ast_msg *msg, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ ast_string_field_build_va(msg, tech, fmt, ap);
+ va_end(ap);
+
+ return 0;
+}
+
+int ast_msg_set_endpoint(struct ast_msg *msg, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ ast_string_field_build_va(msg, endpoint, fmt, ap);
+ va_end(ap);
+
+ return 0;
}
const char *ast_msg_get_body(const struct ast_msg *msg)
{
- return ast_str_buffer(msg->body);
+ return msg->body;
+}
+
+const char *ast_msg_get_from(const struct ast_msg *msg)
+{
+ return msg->from;
+}
+
+const char *ast_msg_get_to(const struct ast_msg *msg)
+{
+ return msg->to;
+}
+
+const char *ast_msg_get_tech(const struct ast_msg *msg)
+{
+ return msg->tech;
+}
+
+const char *ast_msg_get_endpoint(const struct ast_msg *msg)
+{
+ return msg->endpoint;
}
static struct msg_data *msg_data_alloc(void)
@@ -713,7 +724,7 @@
{
struct ast_pbx_args pbx_args;
- ast_explicit_goto(chan, ast_str_buffer(msg->context), AS_OR(msg->exten, "s"), 1);
+ ast_explicit_goto(chan, msg->context, S_OR(msg->exten, "s"), 1);
memset(&pbx_args, 0, sizeof(pbx_args));
pbx_args.no_hangup_chan = 1,
@@ -787,18 +798,9 @@
AST_THREADSTORAGE_CUSTOM(msg_q_chan, NULL, destroy_msg_q_chan);
-/*!
- * \internal
- * \brief Message queue task processor callback
- *
- * \retval 0 success
- * \retval -1 failure
- *
- * \note Even though this returns a value, the taskprocessor code ignores the value.
- */
-static int msg_q_cb(void *data)
-{
- struct ast_msg *msg = data;
+/*! \internal \brief Handle a message bound for the dialplan */
+static int dialplan_handle_msg_cb(struct ast_msg *msg)
+{
struct ast_channel **chan_p, *chan;
struct ast_datastore *ds;
@@ -824,15 +826,90 @@
msg_route(chan, msg);
chan_cleanup(chan);
+ return 0;
+}
+
+/*! \internal \brief Determine if a message has a destination in the dialplan */
+static int dialplan_has_destination_cb(const struct ast_msg *msg)
+{
+ if (ast_strlen_zero(msg->context)) {
+ return 0;
+ }
+
+ return ast_exists_extension(NULL, msg->context, S_OR(msg->exten, "s"), 1, NULL);
+}
+
+static struct ast_msg_handler dialplan_msg_handler = {
+ .name = "dialplan",
+ .handle_msg = dialplan_handle_msg_cb,
+ .has_destination = dialplan_has_destination_cb,
+};
+
+/*!
+ * \internal
+ * \brief Message queue task processor callback
+ *
+ * \retval 0 success
+ * \retval non-zero failure
+ *
+ * \note Even though this returns a value, the taskprocessor code ignores the value.
+ */
+static int msg_q_cb(void *data)
+{
+ struct ast_msg *msg = data;
+ int res = 1;
+ int i;
+
+ ast_rwlock_rdlock(&msg_handlers_lock);
+ for (i = 0; i < AST_VECTOR_SIZE(&msg_handlers); i++) {
+ const struct ast_msg_handler *handler = AST_VECTOR_GET(&msg_handlers, i);
+
+ if (!handler->has_destination(msg)) {
+ ast_debug(5, "Handler %s doesn't want message, moving on\n", handler->name);
+ continue;
+ }
+
+ ast_debug(5, "Dispatching message to %s handler", handler->name);
+ res &= handler->handle_msg(msg);
+ }
+ ast_rwlock_unlock(&msg_handlers_lock);
+
+ if (res != 0) {
+ ast_log(LOG_WARNING, "No handler processed message from %s to %s\n",
+ S_OR(msg->from, "<unknown>"), S_OR(msg->to, "<unknown>"));
+ }
+
ao2_ref(msg, -1);
- return 0;
+ return res;
+}
+
+int ast_msg_has_destination(const struct ast_msg *msg)
+{
+ int i;
+ int result = 0;
+
+ ast_rwlock_rdlock(&msg_handlers_lock);
+ for (i = 0; i < AST_VECTOR_SIZE(&msg_handlers); i++) {
+ const struct ast_msg_handler *handler = AST_VECTOR_GET(&msg_handlers, i);
+
+ ast_debug(5, "Seeing if %s can handle message\n", handler->name);
+ if (handler->has_destination(msg)) {
+ ast_debug(5, "%s can handle message\n", handler->name);
+ result = 1;
+ break;
+ }
+ }
+ ast_rwlock_unlock(&msg_handlers_lock);
+
+ return result;
}
int ast_msg_queue(struct ast_msg *msg)
{
int res;
-
+ ast_log(LOG_ERROR, "@@@@@ to: %s from: %s exten: %s context: %s\n",
+ msg->to, msg->from, msg->exten, msg->context);
res = ast_taskprocessor_push(msg_q_tp, msg_q_cb, msg);
if (res == -1) {
ao2_ref(msg, -1);
@@ -899,11 +976,11 @@
ao2_lock(msg);
if (!strcasecmp(data, "to")) {
- ast_copy_string(buf, ast_str_buffer(msg->to), len);
+ ast_copy_string(buf, msg->to, len);
} else if (!strcasecmp(data, "from")) {
- ast_copy_string(buf, ast_str_buffer(msg->from), len);
+ ast_copy_string(buf, msg->from, len);
} else if (!strcasecmp(data, "body")) {
- ast_copy_string(buf, ast_msg_get_body(msg), len);
+ ast_copy_string(buf, msg->body, len);
} else {
ast_log(LOG_WARNING, "Invalid argument to MESSAGE(): '%s'\n", data);
}
@@ -1041,57 +1118,57 @@
return 0;
}
-static int msg_tech_hash(const void *obj, const int flags)
-{
- 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;
-}
-
-static int msg_tech_cmp(void *obj, void *arg, int flags)
-{
- 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 struct ast_msg_tech_holder *msg_find_by_tech(const struct ast_msg_tech *msg_tech, int ao2_flags)
-{
- 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)
-{
- struct ast_msg_tech tmp_msg_tech = {
- .name = tech_name,
- };
- return msg_find_by_tech(&tmp_msg_tech, ao2_flags);
+
+/*!
+ * \internal \brief Find a \c ast_msg_tech by its technology name
+ *
+ * \param tech_name The name of the message technology
+ *
+ * \note \c msg_techs should be locked via \c msg_techs_lock prior to
+ * calling this function
+ *
+ * \retval NULL if no \c ast_msg_tech has been registered
+ * \retval \c ast_msg_tech if registered
+ */
+static const struct ast_msg_tech *msg_find_by_tech_name(const char *tech_name)
+{
+ const struct ast_msg_tech *current;
+ int i;
+
+ for (i = 0; i < AST_VECTOR_SIZE(&msg_techs); i++) {
+ current = AST_VECTOR_GET(&msg_techs, i);
+ if (!strcmp(current->name, tech_name)) {
+ return current;
+ }
+ }
+
+ return NULL;
+}
+
+/*!
+ * \internal \brief Find a \c ast_msg_handler by its technology name
+ *
+ * \param tech_name The name of the message technology
+ *
+ * \note \c msg_handlers should be locked via \c msg_handlers_lock
+ * prior to calling this function
+ *
+ * \retval NULL if no \c ast_msg_handler has been registered
+ * \retval \c ast_msg_handler if registered
+ */
+static const struct ast_msg_handler *msg_handler_find_by_tech_name(const char *tech_name)
+{
+ const struct ast_msg_handler *current;
+ int i;
+
+ for (i = 0; i < AST_VECTOR_SIZE(&msg_handlers); i++) {
+ current = AST_VECTOR_GET(&msg_handlers, i);
+ if (!strcmp(current->name, tech_name)) {
+ return current;
+ }
+ }
+
+ return NULL;
}
/*!
@@ -1103,7 +1180,7 @@
struct ast_datastore *ds;
struct ast_msg *msg;
char *tech_name;
- struct ast_msg_tech_holder *tech_holder = NULL;
+ const struct ast_msg_tech *msg_tech;
char *parse;
int res = -1;
AST_DECLARE_APP_ARGS(args,
@@ -1142,9 +1219,10 @@
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_rwlock_rdlock(&msg_techs_lock);
+ msg_tech = msg_find_by_tech_name(tech_name);
+
+ if (!msg_tech) {
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;
@@ -1156,22 +1234,13 @@
* 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);
+ res = msg_tech->msg_send(msg, S_OR(args.to, ""), S_OR(args.from, ""));
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;
- }
-
+ ast_rwlock_unlock(&msg_techs_lock);
ao2_ref(msg, -1);
return 0;
@@ -1187,7 +1256,7 @@
char *tech_name = NULL;
struct ast_variable *vars = NULL;
struct ast_variable *data = NULL;
- struct ast_msg_tech_holder *tech_holder = NULL;
+ const struct ast_msg_tech *msg_tech;
struct ast_msg *msg;
int res = -1;
@@ -1204,15 +1273,16 @@
tech_name = ast_strdupa(to);
tech_name = strsep(&tech_name, ":");
- tech_holder = msg_find_by_tech_name(tech_name, OBJ_POINTER);
-
- if (!tech_holder) {
+ ast_rwlock_rdlock(&msg_techs_lock);
+ msg_tech = msg_find_by_tech_name(tech_name);
+ if (!msg_tech) {
+ ast_rwlock_unlock(&msg_techs_lock);
astman_send_error(s, m, "Message technology not found.");
- return -1;
+ return 0;
}
if (!(msg = ast_msg_alloc())) {
- ao2_ref(tech_holder, -1);
+ ast_rwlock_unlock(&msg_techs_lock);
astman_send_error(s, m, "Internal failure\n");
return -1;
}
@@ -1224,14 +1294,11 @@
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);
+ res = msg_tech->msg_send(msg, S_OR(to, ""), S_OR(from, ""));
+
+ ast_rwlock_unlock(&msg_techs_lock);
ast_variables_destroy(vars);
- ao2_ref(tech_holder, -1);
ao2_ref(msg, -1);
if (res) {
@@ -1245,7 +1312,7 @@
int ast_msg_send(struct ast_msg *msg, const char *to, const char *from)
{
char *tech_name = NULL;
- struct ast_msg_tech_holder *tech_holder = NULL;
+ const struct ast_msg_tech *msg_tech;
int res = -1;
if (ast_strlen_zero(to)) {
@@ -1256,20 +1323,19 @@
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);
+ ast_rwlock_rdlock(&msg_techs_lock);
+ msg_tech = msg_find_by_tech_name(tech_name);
+
+ if (!msg_tech) {
+ ast_log(LOG_ERROR, "Unknown message tech: %s\n", tech_name);
+ ast_rwlock_unlock(&msg_techs_lock);
+ return -1;
+ }
+
+ res = msg_tech->msg_send(msg, S_OR(to, ""), S_OR(from, ""));
+
+ ast_rwlock_unlock(&msg_techs_lock);
+
ao2_ref(msg, -1);
return res;
@@ -1277,52 +1343,111 @@
int ast_msg_tech_register(const struct ast_msg_tech *tech)
{
- struct ast_msg_tech_holder *tech_holder;
-
- if ((tech_holder = msg_find_by_tech(tech, OBJ_POINTER))) {
- ao2_ref(tech_holder, -1);
+ const struct ast_msg_tech *match;
+
+ ast_rwlock_wrlock(&msg_techs_lock);
+
+ match = msg_find_by_tech_name(tech->name);
+ if (match) {
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;
+ tech->name);
+ ast_rwlock_unlock(&msg_techs_lock);
+ return -1;
+ }
+
+ AST_VECTOR_APPEND(&msg_techs, tech);
+ ast_verb(3, "Message technology '%s' registered.\n", tech->name);
+
+ ast_rwlock_unlock(&msg_techs_lock);
+
+ return 0;
+}
+
+/*!
+ * \brief Comparison callback for \c ast_msg_tech vector removal
+ *
+ * \param vec_elem The element in the vector being compared
+ * \param srch The element being looked up
+ *
+ * \retval non-zero The items are equal
+ * \retval 0 The items are not equal
+ */
+static int msg_tech_cmp(const struct ast_msg_tech *vec_elem, const struct ast_msg_tech *srch)
+{
+ return !strcmp(vec_elem->name, srch->name);
}
int ast_msg_tech_unregister(const struct ast_msg_tech *tech)
{
- struct ast_msg_tech_holder *tech_holder;
-
- tech_holder = msg_find_by_tech(tech, OBJ_POINTER | OBJ_UNLINK);
-
- if (!tech_holder) {
+ int match;
+
+ ast_rwlock_wrlock(&msg_techs_lock);
+ match = AST_VECTOR_REMOVE_CMP_UNORDERED(&msg_techs, tech, msg_tech_cmp,
+ AST_VECTOR_ELEM_CLEANUP_NOOP);
+ ast_rwlock_unlock(&msg_techs_lock);
+
+ if (match) {
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);
-
+ ast_verb(2, "Message technology '%s' unregistered.\n", tech->name);
+
+ return 0;
+}
+
+int ast_msg_handler_register(const struct ast_msg_handler *handler)
+{
+ const struct ast_msg_handler *match;
+
+ ast_rwlock_wrlock(&msg_handlers_lock);
+
+ match = msg_handler_find_by_tech_name(handler->name);
+ if (match) {
+ ast_log(LOG_ERROR, "Message handler already registered for '%s'\n",
+ handler->name);
+ ast_rwlock_unlock(&msg_handlers_lock);
+ return -1;
+ }
+
+ AST_VECTOR_APPEND(&msg_handlers, handler);
+ ast_verb(2, "Message handler '%s' registered.\n", handler->name);
+
+ ast_rwlock_unlock(&msg_handlers_lock);
+
+ return 0;
+
+}
+
+/*!
+ * \brief Comparison callback for \c ast_msg_handler vector removal
+ *
+ * \param vec_elem The element in the vector being compared
+ * \param srch The element being looked up
+ *
+ * \retval non-zero The items are equal
+ * \retval 0 The items are not equal
+ */
+static int msg_handler_cmp(const struct ast_msg_handler *vec_elem, const struct ast_msg_handler *srch)
+{
+ return !strcmp(vec_elem->name, srch->name);
+}
+
+int ast_msg_handler_unregister(const struct ast_msg_handler *handler)
+{
+ int match;
+
+ ast_rwlock_wrlock(&msg_handlers_lock);
+ match = AST_VECTOR_REMOVE_CMP_UNORDERED(&msg_handlers, handler, msg_handler_cmp,
+ AST_VECTOR_ELEM_CLEANUP_NOOP);
+ ast_rwlock_unlock(&msg_handlers_lock);
+
+ if (match) {
+ ast_log(LOG_ERROR, "No '%s' message handler found.\n", handler->name);
+ return -1;
+ }
+
+ ast_verb(3, "Message handler '%s' unregistered.\n", handler->name);
return 0;
}
@@ -1343,15 +1468,18 @@
*/
static void message_shutdown(void)
{
+ ast_msg_handler_unregister(&dialplan_msg_handler);
+
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;
- }
+ AST_VECTOR_FREE(&msg_techs);
+ ast_rwlock_destroy(&msg_techs_lock);
+
+ AST_VECTOR_FREE(&msg_handlers);
+ ast_rwlock_destroy(&msg_handlers_lock);
}
/*
@@ -1373,12 +1501,19 @@
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);
+ ast_rwlock_init(&msg_techs_lock);
+ if (AST_VECTOR_INIT(&msg_techs, 8)) {
+ return -1;
+ }
+
+ ast_rwlock_init(&msg_handlers_lock);
+ if (AST_VECTOR_INIT(&msg_handlers, 4)) {
+ return -1;
+ }
+
+ res = ast_msg_handler_register(&dialplan_msg_handler);
+
+ 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);
Modified: team/group/ari-greedy-atxfer/res/ari/ari_model_validators.c
URL: http://svnview.digium.com/svn/asterisk/team/group/ari-greedy-atxfer/res/ari/ari_model_validators.c?view=diff&rev=420096&r1=420095&r2=420096
==============================================================================
--- team/group/ari-greedy-atxfer/res/ari/ari_model_validators.c (original)
+++ team/group/ari-greedy-atxfer/res/ari/ari_model_validators.c Tue Aug 5 15:26:40 2014
@@ -588,6 +588,140 @@
return ast_ari_validate_endpoint;
}
+int ast_ari_validate_text_message(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_body = 0;
+ int has_from = 0;
+ int has_to = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
[... 1492 lines stripped ...]
More information about the svn-commits
mailing list