[asterisk-commits] mmichelson: branch group/ari-greedy-atxfer r420096 - in /team/group/ari-greed...

SVN commits to the Asterisk project asterisk-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 asterisk-commits mailing list