2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 2010, Digium, Inc.
6 * Russell Bryant <russell@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
21 * \brief Out-of-call text message support
23 * \author Russell Bryant <russell@digium.com>
27 <support_level>core</support_level>
32 #include "asterisk/_private.h"
34 #include "asterisk/module.h"
35 #include "asterisk/datastore.h"
36 #include "asterisk/pbx.h"
37 #include "asterisk/manager.h"
38 #include "asterisk/strings.h"
39 #include "asterisk/astobj2.h"
40 #include "asterisk/vector.h"
41 #include "asterisk/app.h"
42 #include "asterisk/taskprocessor.h"
43 #include "asterisk/message.h"
46 <function name="MESSAGE" language="en_US">
48 Create a message or read fields from a message.
51 <parameter name="argument" required="true">
52 <para>Field of the message to get or set.</para>
55 <para>Read-only. The destination of the message. When processing an
56 incoming message, this will be set to the destination listed as
57 the recipient of the message that was received by Asterisk.</para>
60 <para>Read-only. The source of the message. When processing an
61 incoming message, this will be set to the source of the message.</para>
63 <enum name="custom_data">
64 <para>Write-only. Mark or unmark all message headers for an outgoing
65 message. The following values can be set:</para>
67 <enum name="mark_all_outbound">
68 <para>Mark all headers for an outgoing message.</para>
70 <enum name="clear_all_outbound">
71 <para>Unmark all headers for an outgoing message.</para>
76 <para>Read/Write. The message body. When processing an incoming
77 message, this includes the body of the message that Asterisk
78 received. When MessageSend() is executed, the contents of this
79 field are used as the body of the outgoing message. The body
80 will always be UTF-8.</para>
86 <para>This function will read from or write a value to a text message.
87 It is used both to read the data out of an incoming message, as well as
88 modify or create a message that will be sent outbound.</para>
91 <ref type="application">MessageSend</ref>
94 <function name="MESSAGE_DATA" language="en_US">
96 Read or write custom data attached to a message.
99 <parameter name="argument" required="true">
100 <para>Field of the message to get or set.</para>
104 <para>This function will read from or write a value to a text message.
105 It is used both to read the data out of an incoming message, as well as
106 modify a message that will be sent outbound.</para>
108 <para>If you want to set an outbound message to carry data in the
110 Set(MESSAGE_DATA(<replaceable>key</replaceable>)=${MESSAGE_DATA(<replaceable>key</replaceable>)}).</para>
114 <ref type="application">MessageSend</ref>
117 <application name="MessageSend" language="en_US">
122 <parameter name="to" required="true">
123 <para>A To URI for the message.</para>
124 <xi:include xpointer="xpointer(/docs/info[@name='MessageToInfo'])" />
126 <parameter name="from" required="false">
127 <para>A From URI for the message if needed for the
128 message technology being used to send this message.</para>
129 <xi:include xpointer="xpointer(/docs/info[@name='MessageFromInfo'])" />
133 <para>Send a text message. The body of the message that will be
134 sent is what is currently set to <literal>MESSAGE(body)</literal>.
135 The technology chosen for sending the message is determined
136 based on a prefix to the <literal>to</literal> parameter.</para>
137 <para>This application sets the following channel variables:</para>
139 <variable name="MESSAGE_SEND_STATUS">
140 <para>This is the message delivery status returned by this application.</para>
141 <value name="INVALID_PROTOCOL">
142 No handler for the technology part of the URI was found.
144 <value name="INVALID_URI">
145 The protocol handler reported that the URI was not valid.
147 <value name="SUCCESS">
148 Successfully passed on to the protocol handler, but delivery has not necessarily been guaranteed.
150 <value name="FAILURE">
151 The protocol handler reported that it was unabled to deliver the message for some reason.
157 <manager name="MessageSend" language="en_US">
159 Send an out of call message to an endpoint.
162 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
163 <parameter name="To" required="true">
164 <para>The URI the message is to be sent to.</para>
165 <xi:include xpointer="xpointer(/docs/info[@name='MessageToInfo'])" />
167 <parameter name="From">
168 <para>A From URI for the message if needed for the
169 message technology being used to send this message.</para>
170 <xi:include xpointer="xpointer(/docs/info[@name='MessageFromInfo'])" />
172 <parameter name="Body">
173 <para>The message body text. This must not contain any newlines as that
174 conflicts with the AMI protocol.</para>
176 <parameter name="Base64Body">
177 <para>Text bodies requiring the use of newlines have to be base64 encoded
178 in this field. Base64Body will be decoded before being sent out.
179 Base64Body takes precedence over Body.</para>
181 <parameter name="Variable">
182 <para>Message variable to set, multiple Variable: headers are
183 allowed. The header value is a comma separated list of
184 name=value pairs.</para>
191 AST_DECLARE_STRING_FIELDS(
192 AST_STRING_FIELD(name);
193 AST_STRING_FIELD(value);
195 unsigned int send; /* Whether to send out on outbound messages */
198 AST_LIST_HEAD_NOLOCK(outhead, msg_data);
204 AST_DECLARE_STRING_FIELDS(
205 /*! Where the message is going */
206 AST_STRING_FIELD(to);
207 /*! Where we "say" the message came from */
208 AST_STRING_FIELD(from);
209 /*! The text to send */
210 AST_STRING_FIELD(body);
211 /*! The dialplan context for the message */
212 AST_STRING_FIELD(context);
213 /*! The dialplan extension for the message */
214 AST_STRING_FIELD(exten);
215 /*! An endpoint associated with this message */
216 AST_STRING_FIELD(endpoint);
217 /*! The technology of the endpoint associated with this message */
218 AST_STRING_FIELD(tech);
220 /*! Technology/dialplan specific variables associated with the message */
221 struct ao2_container *vars;
224 /*! \brief Lock for \c msg_techs vector */
225 static ast_rwlock_t msg_techs_lock;
227 /*! \brief Vector of message technologies */
228 AST_VECTOR(, const struct ast_msg_tech *) msg_techs;
230 /*! \brief Lock for \c msg_handlers vector */
231 static ast_rwlock_t msg_handlers_lock;
233 /*! \brief Vector of received message handlers */
234 AST_VECTOR(, const struct ast_msg_handler *) msg_handlers;
236 static struct ast_taskprocessor *msg_q_tp;
238 static const char app_msg_send[] = "MessageSend";
240 static void msg_ds_destroy(void *data);
242 static const struct ast_datastore_info msg_datastore = {
244 .destroy = msg_ds_destroy,
247 static int msg_func_read(struct ast_channel *chan, const char *function,
248 char *data, char *buf, size_t len);
249 static int msg_func_write(struct ast_channel *chan, const char *function,
250 char *data, const char *value);
252 static struct ast_custom_function msg_function = {
254 .read = msg_func_read,
255 .write = msg_func_write,
258 static int msg_data_func_read(struct ast_channel *chan, const char *function,
259 char *data, char *buf, size_t len);
260 static int msg_data_func_write(struct ast_channel *chan, const char *function,
261 char *data, const char *value);
263 static struct ast_custom_function msg_data_function = {
264 .name = "MESSAGE_DATA",
265 .read = msg_data_func_read,
266 .write = msg_data_func_write,
269 static struct ast_frame *chan_msg_read(struct ast_channel *chan);
270 static int chan_msg_write(struct ast_channel *chan, struct ast_frame *fr);
271 static int chan_msg_indicate(struct ast_channel *chan, int condition,
272 const void *data, size_t datalen);
273 static int chan_msg_send_digit_begin(struct ast_channel *chan, char digit);
274 static int chan_msg_send_digit_end(struct ast_channel *chan, char digit,
275 unsigned int duration);
279 * \brief A bare minimum channel technology
281 * This will not be registered as we never want anything to try
282 * to create Message channels other than internally in this file.
284 static const struct ast_channel_tech msg_chan_tech_hack = {
286 .description = "Internal Text Message Processing",
287 .read = chan_msg_read,
288 .write = chan_msg_write,
289 .indicate = chan_msg_indicate,
290 .send_digit_begin = chan_msg_send_digit_begin,
291 .send_digit_end = chan_msg_send_digit_end,
296 * \brief ast_channel_tech read callback
298 * This should never be called. However, we say that about chan_iax2's
299 * read callback, too, and it seems to randomly get called for some
300 * reason. If it does, a simple NULL frame will suffice.
302 static struct ast_frame *chan_msg_read(struct ast_channel *chan)
304 return &ast_null_frame;
309 * \brief ast_channel_tech write callback
311 * Throw all frames away. We don't care about any of them.
313 static int chan_msg_write(struct ast_channel *chan, struct ast_frame *fr)
320 * \brief ast_channel_tech indicate callback
322 * The indicate callback is here just so it can return success.
323 * We don't want any callers of ast_indicate() to think something
324 * has failed. We also don't want ast_indicate() itself to try
325 * to generate inband tones since we didn't tell it that we took
326 * care of it ourselves.
328 static int chan_msg_indicate(struct ast_channel *chan, int condition,
329 const void *data, size_t datalen)
336 * \brief ast_channel_tech send_digit_begin callback
338 * This is here so that just in case a digit comes at a message channel
339 * that the Asterisk core doesn't waste any time trying to generate
340 * inband DTMF in audio. It's a waste of resources.
342 static int chan_msg_send_digit_begin(struct ast_channel *chan, char digit)
349 * \brief ast_channel_tech send_digit_end callback
351 * This is here so that just in case a digit comes at a message channel
352 * that the Asterisk core doesn't waste any time trying to generate
353 * inband DTMF in audio. It's a waste of resources.
355 static int chan_msg_send_digit_end(struct ast_channel *chan, char digit,
356 unsigned int duration)
361 static void msg_ds_destroy(void *data)
363 struct ast_msg *msg = data;
368 static int msg_data_hash_fn(const void *obj, const int flags)
370 const struct msg_data *data = obj;
371 return ast_str_case_hash(data->name);
374 static int msg_data_cmp_fn(void *obj, void *arg, int flags)
376 const struct msg_data *one = obj, *two = arg;
377 return !strcasecmp(one->name, two->name) ? CMP_MATCH | CMP_STOP : 0;
380 static void msg_data_destructor(void *obj)
382 struct msg_data *data = obj;
383 ast_string_field_free_memory(data);
386 static void msg_destructor(void *obj)
388 struct ast_msg *msg = obj;
390 ast_string_field_free_memory(msg);
391 ao2_cleanup(msg->vars);
394 struct ast_msg *ast_msg_alloc(void)
398 if (!(msg = ao2_alloc(sizeof(*msg), msg_destructor))) {
402 if (ast_string_field_init(msg, 128)) {
407 if (!(msg->vars = ao2_container_alloc(1, msg_data_hash_fn, msg_data_cmp_fn))) {
411 ast_string_field_set(msg, context, "default");
416 struct ast_msg *ast_msg_ref(struct ast_msg *msg)
422 struct ast_msg *ast_msg_destroy(struct ast_msg *msg)
428 int ast_msg_set_to(struct ast_msg *msg, const char *fmt, ...)
433 ast_string_field_build_va(msg, to, fmt, ap);
439 int ast_msg_set_from(struct ast_msg *msg, const char *fmt, ...)
444 ast_string_field_build_va(msg, from, fmt, ap);
450 int ast_msg_set_body(struct ast_msg *msg, const char *fmt, ...)
455 ast_string_field_build_va(msg, body, fmt, ap);
461 int ast_msg_set_context(struct ast_msg *msg, const char *fmt, ...)
466 ast_string_field_build_va(msg, context, fmt, ap);
472 int ast_msg_set_exten(struct ast_msg *msg, const char *fmt, ...)
477 ast_string_field_build_va(msg, exten, fmt, ap);
483 int ast_msg_set_tech(struct ast_msg *msg, const char *fmt, ...)
488 ast_string_field_build_va(msg, tech, fmt, ap);
494 int ast_msg_set_endpoint(struct ast_msg *msg, const char *fmt, ...)
499 ast_string_field_build_va(msg, endpoint, fmt, ap);
505 const char *ast_msg_get_body(const struct ast_msg *msg)
510 const char *ast_msg_get_from(const struct ast_msg *msg)
515 const char *ast_msg_get_to(const struct ast_msg *msg)
520 const char *ast_msg_get_tech(const struct ast_msg *msg)
525 const char *ast_msg_get_endpoint(const struct ast_msg *msg)
527 return msg->endpoint;
530 static struct msg_data *msg_data_alloc(void)
532 struct msg_data *data;
534 if (!(data = ao2_alloc(sizeof(*data), msg_data_destructor))) {
538 if (ast_string_field_init(data, 32)) {
546 static struct msg_data *msg_data_find(struct ao2_container *vars, const char *name)
548 struct msg_data tmp = {
551 return ao2_find(vars, &tmp, OBJ_POINTER);
554 static int msg_set_var_full(struct ast_msg *msg, const char *name, const char *value, unsigned int outbound)
556 struct msg_data *data;
558 if (!(data = msg_data_find(msg->vars, name))) {
559 if (ast_strlen_zero(value)) {
562 if (!(data = msg_data_alloc())) {
566 ast_string_field_set(data, name, name);
567 ast_string_field_set(data, value, value);
568 data->send = outbound;
569 ao2_link(msg->vars, data);
571 if (ast_strlen_zero(value)) {
572 ao2_unlink(msg->vars, data);
574 ast_string_field_set(data, value, value);
575 data->send = outbound;
584 int ast_msg_set_var_outbound(struct ast_msg *msg, const char *name, const char *value)
586 return msg_set_var_full(msg, name, value, 1);
589 int ast_msg_set_var(struct ast_msg *msg, const char *name, const char *value)
591 return msg_set_var_full(msg, name, value, 0);
594 const char *ast_msg_get_var(struct ast_msg *msg, const char *name)
596 struct msg_data *data;
597 const char *val = NULL;
599 if (!(data = msg_data_find(msg->vars, name))) {
603 /* Yep, this definitely looks like val would be a dangling pointer
604 * after the ref count is decremented. As long as the message structure
605 * is used in a thread safe manner, this will not be the case though.
606 * The ast_msg holds a reference to this object in the msg->vars container. */
613 struct ast_msg_var_iterator {
614 struct ao2_iterator iter;
615 struct msg_data *current_used;
618 struct ast_msg_var_iterator *ast_msg_var_iterator_init(const struct ast_msg *msg)
620 struct ast_msg_var_iterator *iter;
622 iter = ast_calloc(1, sizeof(*iter));
627 iter->iter = ao2_iterator_init(msg->vars, 0);
632 int ast_msg_var_iterator_next(const struct ast_msg *msg, struct ast_msg_var_iterator *iter, const char **name, const char **value)
634 struct msg_data *data;
640 /* Skip any that aren't marked for sending out */
641 while ((data = ao2_iterator_next(&iter->iter)) && !data->send) {
651 *value = data->value;
654 /* Leave the refcount to be cleaned up by the caller with
655 * ast_msg_var_unref_current after they finish with the pointers to the data */
656 iter->current_used = data;
661 void ast_msg_var_unref_current(struct ast_msg_var_iterator *iter)
663 ao2_cleanup(iter->current_used);
664 iter->current_used = NULL;
667 void ast_msg_var_iterator_destroy(struct ast_msg_var_iterator *iter)
670 ao2_iterator_destroy(&iter->iter);
671 ast_msg_var_unref_current(iter);
676 static struct ast_channel *create_msg_q_chan(void)
678 struct ast_channel *chan;
679 struct ast_datastore *ds;
681 chan = ast_channel_alloc(1, AST_STATE_UP,
683 NULL, NULL, NULL, NULL, 0,
684 "%s", "Message/ast_msg_queue");
690 ast_channel_tech_set(chan, &msg_chan_tech_hack);
691 ast_channel_unlock(chan);
692 ast_channel_unlink(chan);
694 if (!(ds = ast_datastore_alloc(&msg_datastore, NULL))) {
699 ast_channel_lock(chan);
700 ast_channel_datastore_add(chan, ds);
701 ast_channel_unlock(chan);
708 * \brief Run the dialplan for message processing
710 * \pre The message has already been set up on the msg datastore
713 static void msg_route(struct ast_channel *chan, struct ast_msg *msg)
715 struct ast_pbx_args pbx_args;
717 ast_explicit_goto(chan, msg->context, S_OR(msg->exten, "s"), 1);
719 memset(&pbx_args, 0, sizeof(pbx_args));
720 pbx_args.no_hangup_chan = 1,
721 ast_pbx_run_args(chan, &pbx_args);
726 * \brief Clean up ast_channel after each message
728 * Reset various bits of state after routing each message so the same ast_channel
729 * can just be reused.
731 static void chan_cleanup(struct ast_channel *chan)
733 struct ast_datastore *msg_ds, *ds;
734 struct varshead *headp;
735 struct ast_var_t *vardata;
736 struct ast_frame *cur;
738 ast_channel_lock(chan);
741 * Remove the msg datastore. Free its data but keep around the datastore
742 * object and just reuse it.
744 if ((msg_ds = ast_channel_datastore_find(chan, &msg_datastore, NULL)) && msg_ds->data) {
745 ast_channel_datastore_remove(chan, msg_ds);
746 ao2_ref(msg_ds->data, -1);
751 * Destroy all other datastores.
753 while ((ds = AST_LIST_REMOVE_HEAD(ast_channel_datastores(chan), entry))) {
754 ast_datastore_free(ds);
758 * Destroy all channel variables.
760 headp = ast_channel_varshead(chan);
761 while ((vardata = AST_LIST_REMOVE_HEAD(headp, entries))) {
762 ast_var_delete(vardata);
766 * Remove frames from read queue
768 while ((cur = AST_LIST_REMOVE_HEAD(ast_channel_readq(chan), frame_list))) {
773 * Restore msg datastore.
776 ast_channel_datastore_add(chan, msg_ds);
779 * Clear softhangup flags.
781 ast_channel_clear_softhangup(chan, AST_SOFTHANGUP_ALL);
783 ast_channel_unlock(chan);
786 static void destroy_msg_q_chan(void *data)
788 struct ast_channel **chan = data;
794 ast_channel_release(*chan);
797 AST_THREADSTORAGE_CUSTOM(msg_q_chan, NULL, destroy_msg_q_chan);
799 /*! \internal \brief Handle a message bound for the dialplan */
800 static int dialplan_handle_msg_cb(struct ast_msg *msg)
802 struct ast_channel **chan_p, *chan;
803 struct ast_datastore *ds;
805 if (!(chan_p = ast_threadstorage_get(&msg_q_chan, sizeof(struct ast_channel *)))) {
809 if (!(*chan_p = create_msg_q_chan())) {
815 ast_channel_lock(chan);
816 if (!(ds = ast_channel_datastore_find(chan, &msg_datastore, NULL))) {
817 ast_channel_unlock(chan);
822 ast_channel_unlock(chan);
824 msg_route(chan, msg);
830 /*! \internal \brief Determine if a message has a destination in the dialplan */
831 static int dialplan_has_destination_cb(const struct ast_msg *msg)
833 if (ast_strlen_zero(msg->context)) {
837 return ast_exists_extension(NULL, msg->context, S_OR(msg->exten, "s"), 1, NULL);
840 static struct ast_msg_handler dialplan_msg_handler = {
842 .handle_msg = dialplan_handle_msg_cb,
843 .has_destination = dialplan_has_destination_cb,
848 * \brief Message queue task processor callback
851 * \retval non-zero failure
853 * \note Even though this returns a value, the taskprocessor code ignores the value.
855 static int msg_q_cb(void *data)
857 struct ast_msg *msg = data;
861 ast_rwlock_rdlock(&msg_handlers_lock);
862 for (i = 0; i < AST_VECTOR_SIZE(&msg_handlers); i++) {
863 const struct ast_msg_handler *handler = AST_VECTOR_GET(&msg_handlers, i);
865 if (!handler->has_destination(msg)) {
866 ast_debug(5, "Handler %s doesn't want message, moving on\n", handler->name);
870 ast_debug(5, "Dispatching message to %s handler\n", handler->name);
871 res &= handler->handle_msg(msg);
873 ast_rwlock_unlock(&msg_handlers_lock);
876 ast_log(LOG_WARNING, "No handler processed message from %s to %s\n",
877 S_OR(msg->from, "<unknown>"), S_OR(msg->to, "<unknown>"));
885 int ast_msg_has_destination(const struct ast_msg *msg)
890 ast_rwlock_rdlock(&msg_handlers_lock);
891 for (i = 0; i < AST_VECTOR_SIZE(&msg_handlers); i++) {
892 const struct ast_msg_handler *handler = AST_VECTOR_GET(&msg_handlers, i);
894 ast_debug(5, "Seeing if %s can handle message\n", handler->name);
895 if (handler->has_destination(msg)) {
896 ast_debug(5, "%s can handle message\n", handler->name);
901 ast_rwlock_unlock(&msg_handlers_lock);
906 int ast_msg_queue(struct ast_msg *msg)
909 res = ast_taskprocessor_push(msg_q_tp, msg_q_cb, msg);
919 * \brief Find or create a message datastore on a channel
921 * \pre chan is locked
923 * \param chan the relevant channel
925 * \return the channel's message datastore, or NULL on error
927 static struct ast_datastore *msg_datastore_find_or_create(struct ast_channel *chan)
929 struct ast_datastore *ds;
931 if ((ds = ast_channel_datastore_find(chan, &msg_datastore, NULL))) {
935 if (!(ds = ast_datastore_alloc(&msg_datastore, NULL))) {
939 if (!(ds->data = ast_msg_alloc())) {
940 ast_datastore_free(ds);
944 ast_channel_datastore_add(chan, ds);
949 static int msg_func_read(struct ast_channel *chan, const char *function,
950 char *data, char *buf, size_t len)
952 struct ast_datastore *ds;
956 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", function);
960 ast_channel_lock(chan);
962 if (!(ds = ast_channel_datastore_find(chan, &msg_datastore, NULL))) {
963 ast_channel_unlock(chan);
964 ast_log(LOG_ERROR, "No MESSAGE data found on the channel to read.\n");
970 ast_channel_unlock(chan);
974 if (!strcasecmp(data, "to")) {
975 ast_copy_string(buf, msg->to, len);
976 } else if (!strcasecmp(data, "from")) {
977 ast_copy_string(buf, msg->from, len);
978 } else if (!strcasecmp(data, "body")) {
979 ast_copy_string(buf, msg->body, len);
981 ast_log(LOG_WARNING, "Invalid argument to MESSAGE(): '%s'\n", data);
990 static int msg_func_write(struct ast_channel *chan, const char *function,
991 char *data, const char *value)
993 struct ast_datastore *ds;
997 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", function);
1001 ast_channel_lock(chan);
1003 if (!(ds = msg_datastore_find_or_create(chan))) {
1004 ast_channel_unlock(chan);
1010 ast_channel_unlock(chan);
1014 if (!strcasecmp(data, "to")) {
1015 ast_msg_set_to(msg, "%s", value);
1016 } else if (!strcasecmp(data, "from")) {
1017 ast_msg_set_from(msg, "%s", value);
1018 } else if (!strcasecmp(data, "body")) {
1019 ast_msg_set_body(msg, "%s", value);
1020 } else if (!strcasecmp(data, "custom_data")) {
1022 if (!strcasecmp(value, "mark_all_outbound")) {
1024 } else if (!strcasecmp(value, "clear_all_outbound")) {
1027 ast_log(LOG_WARNING, "'%s' is not a valid value for custom_data\n", value);
1030 if (outbound != -1) {
1031 struct msg_data *hdr_data;
1032 struct ao2_iterator iter = ao2_iterator_init(msg->vars, 0);
1034 while ((hdr_data = ao2_iterator_next(&iter))) {
1035 hdr_data->send = outbound;
1036 ao2_ref(hdr_data, -1);
1038 ao2_iterator_destroy(&iter);
1041 ast_log(LOG_WARNING, "'%s' is not a valid write argument.\n", data);
1050 static int msg_data_func_read(struct ast_channel *chan, const char *function,
1051 char *data, char *buf, size_t len)
1053 struct ast_datastore *ds;
1054 struct ast_msg *msg;
1058 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", function);
1062 ast_channel_lock(chan);
1064 if (!(ds = ast_channel_datastore_find(chan, &msg_datastore, NULL))) {
1065 ast_channel_unlock(chan);
1066 ast_log(LOG_ERROR, "No MESSAGE data found on the channel to read.\n");
1072 ast_channel_unlock(chan);
1076 if ((val = ast_msg_get_var(msg, data))) {
1077 ast_copy_string(buf, val, len);
1086 static int msg_data_func_write(struct ast_channel *chan, const char *function,
1087 char *data, const char *value)
1089 struct ast_datastore *ds;
1090 struct ast_msg *msg;
1093 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", function);
1097 ast_channel_lock(chan);
1099 if (!(ds = msg_datastore_find_or_create(chan))) {
1100 ast_channel_unlock(chan);
1106 ast_channel_unlock(chan);
1110 ast_msg_set_var_outbound(msg, data, value);
1119 * \internal \brief Find a \c ast_msg_tech by its technology name
1121 * \param tech_name The name of the message technology
1123 * \note \c msg_techs should be locked via \c msg_techs_lock prior to
1124 * calling this function
1126 * \retval NULL if no \c ast_msg_tech has been registered
1127 * \retval \c ast_msg_tech if registered
1129 static const struct ast_msg_tech *msg_find_by_tech_name(const char *tech_name)
1131 const struct ast_msg_tech *current;
1134 for (i = 0; i < AST_VECTOR_SIZE(&msg_techs); i++) {
1135 current = AST_VECTOR_GET(&msg_techs, i);
1136 if (!strcmp(current->name, tech_name)) {
1145 * \internal \brief Find a \c ast_msg_handler by its technology name
1147 * \param tech_name The name of the message technology
1149 * \note \c msg_handlers should be locked via \c msg_handlers_lock
1150 * prior to calling this function
1152 * \retval NULL if no \c ast_msg_handler has been registered
1153 * \retval \c ast_msg_handler if registered
1155 static const struct ast_msg_handler *msg_handler_find_by_tech_name(const char *tech_name)
1157 const struct ast_msg_handler *current;
1160 for (i = 0; i < AST_VECTOR_SIZE(&msg_handlers); i++) {
1161 current = AST_VECTOR_GET(&msg_handlers, i);
1162 if (!strcmp(current->name, tech_name)) {
1172 * \brief MessageSend() application
1174 static int msg_send_exec(struct ast_channel *chan, const char *data)
1176 struct ast_datastore *ds;
1177 struct ast_msg *msg;
1179 const struct ast_msg_tech *msg_tech;
1182 AST_DECLARE_APP_ARGS(args,
1187 if (ast_strlen_zero(data)) {
1188 ast_log(LOG_WARNING, "An argument is required to MessageSend()\n");
1189 pbx_builtin_setvar_helper(chan, "MESSAGE_SEND_STATUS", "INVALID_URI");
1193 parse = ast_strdupa(data);
1194 AST_STANDARD_APP_ARGS(args, parse);
1196 if (ast_strlen_zero(args.to)) {
1197 ast_log(LOG_WARNING, "A 'to' URI is required for MessageSend()\n");
1198 pbx_builtin_setvar_helper(chan, "MESSAGE_SEND_STATUS", "INVALID_URI");
1202 ast_channel_lock(chan);
1204 if (!(ds = ast_channel_datastore_find(chan, &msg_datastore, NULL))) {
1205 ast_channel_unlock(chan);
1206 ast_log(LOG_WARNING, "No message data found on channel to send.\n");
1207 pbx_builtin_setvar_helper(chan, "MESSAGE_SEND_STATUS", "FAILURE");
1213 ast_channel_unlock(chan);
1215 tech_name = ast_strdupa(args.to);
1216 tech_name = strsep(&tech_name, ":");
1218 ast_rwlock_rdlock(&msg_techs_lock);
1219 msg_tech = msg_find_by_tech_name(tech_name);
1222 ast_log(LOG_WARNING, "No message technology '%s' found.\n", tech_name);
1223 pbx_builtin_setvar_helper(chan, "MESSAGE_SEND_STATUS", "INVALID_PROTOCOL");
1228 * The message lock is held here to safely allow the technology
1229 * implementation to access the message fields without worrying
1230 * that they could change.
1233 res = msg_tech->msg_send(msg, S_OR(args.to, ""), S_OR(args.from, ""));
1236 pbx_builtin_setvar_helper(chan, "MESSAGE_SEND_STATUS", res ? "FAILURE" : "SUCCESS");
1239 ast_rwlock_unlock(&msg_techs_lock);
1245 static int action_messagesend(struct mansession *s, const struct message *m)
1247 const char *to = ast_strdupa(astman_get_header(m, "To"));
1248 const char *from = astman_get_header(m, "From");
1249 const char *body = astman_get_header(m, "Body");
1250 const char *base64body = astman_get_header(m, "Base64Body");
1251 char base64decoded[1301] = { 0, };
1252 char *tech_name = NULL;
1253 struct ast_variable *vars = NULL;
1254 struct ast_variable *data = NULL;
1255 const struct ast_msg_tech *msg_tech;
1256 struct ast_msg *msg;
1259 if (ast_strlen_zero(to)) {
1260 astman_send_error(s, m, "No 'To' address specified.");
1264 if (!ast_strlen_zero(base64body)) {
1265 ast_base64decode((unsigned char *) base64decoded, base64body, sizeof(base64decoded) - 1);
1266 body = base64decoded;
1269 tech_name = ast_strdupa(to);
1270 tech_name = strsep(&tech_name, ":");
1272 ast_rwlock_rdlock(&msg_techs_lock);
1273 msg_tech = msg_find_by_tech_name(tech_name);
1275 ast_rwlock_unlock(&msg_techs_lock);
1276 astman_send_error(s, m, "Message technology not found.");
1280 if (!(msg = ast_msg_alloc())) {
1281 ast_rwlock_unlock(&msg_techs_lock);
1282 astman_send_error(s, m, "Internal failure\n");
1286 data = astman_get_variables_order(m, ORDER_NATURAL);
1287 for (vars = data; vars; vars = vars->next) {
1288 ast_msg_set_var_outbound(msg, vars->name, vars->value);
1291 ast_msg_set_body(msg, "%s", body);
1293 res = msg_tech->msg_send(msg, S_OR(to, ""), S_OR(from, ""));
1295 ast_rwlock_unlock(&msg_techs_lock);
1297 ast_variables_destroy(vars);
1301 astman_send_error(s, m, "Message failed to send.");
1303 astman_send_ack(s, m, "Message successfully sent");
1308 int ast_msg_send(struct ast_msg *msg, const char *to, const char *from)
1310 char *tech_name = NULL;
1311 const struct ast_msg_tech *msg_tech;
1314 if (ast_strlen_zero(to)) {
1319 tech_name = ast_strdupa(to);
1320 tech_name = strsep(&tech_name, ":");
1322 ast_rwlock_rdlock(&msg_techs_lock);
1323 msg_tech = msg_find_by_tech_name(tech_name);
1326 ast_log(LOG_ERROR, "Unknown message tech: %s\n", tech_name);
1327 ast_rwlock_unlock(&msg_techs_lock);
1331 res = msg_tech->msg_send(msg, S_OR(to, ""), S_OR(from, ""));
1333 ast_rwlock_unlock(&msg_techs_lock);
1340 int ast_msg_tech_register(const struct ast_msg_tech *tech)
1342 const struct ast_msg_tech *match;
1344 ast_rwlock_wrlock(&msg_techs_lock);
1346 match = msg_find_by_tech_name(tech->name);
1348 ast_log(LOG_ERROR, "Message technology already registered for '%s'\n",
1350 ast_rwlock_unlock(&msg_techs_lock);
1354 AST_VECTOR_APPEND(&msg_techs, tech);
1355 ast_verb(3, "Message technology '%s' registered.\n", tech->name);
1357 ast_rwlock_unlock(&msg_techs_lock);
1363 * \brief Comparison callback for \c ast_msg_tech vector removal
1365 * \param vec_elem The element in the vector being compared
1366 * \param srch The element being looked up
1368 * \retval non-zero The items are equal
1369 * \retval 0 The items are not equal
1371 static int msg_tech_cmp(const struct ast_msg_tech *vec_elem, const struct ast_msg_tech *srch)
1373 return !strcmp(vec_elem->name, srch->name);
1376 int ast_msg_tech_unregister(const struct ast_msg_tech *tech)
1380 ast_rwlock_wrlock(&msg_techs_lock);
1381 match = AST_VECTOR_REMOVE_CMP_UNORDERED(&msg_techs, tech, msg_tech_cmp,
1382 AST_VECTOR_ELEM_CLEANUP_NOOP);
1383 ast_rwlock_unlock(&msg_techs_lock);
1386 ast_log(LOG_ERROR, "No '%s' message technology found.\n", tech->name);
1390 ast_verb(2, "Message technology '%s' unregistered.\n", tech->name);
1395 int ast_msg_handler_register(const struct ast_msg_handler *handler)
1397 const struct ast_msg_handler *match;
1399 ast_rwlock_wrlock(&msg_handlers_lock);
1401 match = msg_handler_find_by_tech_name(handler->name);
1403 ast_log(LOG_ERROR, "Message handler already registered for '%s'\n",
1405 ast_rwlock_unlock(&msg_handlers_lock);
1409 AST_VECTOR_APPEND(&msg_handlers, handler);
1410 ast_verb(2, "Message handler '%s' registered.\n", handler->name);
1412 ast_rwlock_unlock(&msg_handlers_lock);
1419 * \brief Comparison callback for \c ast_msg_handler vector removal
1421 * \param vec_elem The element in the vector being compared
1422 * \param srch The element being looked up
1424 * \retval non-zero The items are equal
1425 * \retval 0 The items are not equal
1427 static int msg_handler_cmp(const struct ast_msg_handler *vec_elem, const struct ast_msg_handler *srch)
1429 return !strcmp(vec_elem->name, srch->name);
1432 int ast_msg_handler_unregister(const struct ast_msg_handler *handler)
1436 ast_rwlock_wrlock(&msg_handlers_lock);
1437 match = AST_VECTOR_REMOVE_CMP_UNORDERED(&msg_handlers, handler, msg_handler_cmp,
1438 AST_VECTOR_ELEM_CLEANUP_NOOP);
1439 ast_rwlock_unlock(&msg_handlers_lock);
1442 ast_log(LOG_ERROR, "No '%s' message handler found.\n", handler->name);
1446 ast_verb(3, "Message handler '%s' unregistered.\n", handler->name);
1450 void ast_msg_shutdown(void)
1453 msg_q_tp = ast_taskprocessor_unreference(msg_q_tp);
1459 * \brief Clean up other resources on Asterisk shutdown
1461 * \note This does not include the msg_q_tp object, which must be disposed
1462 * of prior to Asterisk checking for channel destruction in its shutdown
1463 * sequence. The atexit handlers are executed after this occurs.
1465 static void message_shutdown(void)
1467 ast_msg_handler_unregister(&dialplan_msg_handler);
1469 ast_custom_function_unregister(&msg_function);
1470 ast_custom_function_unregister(&msg_data_function);
1471 ast_unregister_application(app_msg_send);
1472 ast_manager_unregister("MessageSend");
1474 AST_VECTOR_FREE(&msg_techs);
1475 ast_rwlock_destroy(&msg_techs_lock);
1477 AST_VECTOR_FREE(&msg_handlers);
1478 ast_rwlock_destroy(&msg_handlers_lock);
1483 * \brief Initialize stuff during Asterisk startup.
1485 * Cleanup isn't a big deal in this function. If we return non-zero,
1486 * Asterisk is going to exit.
1489 * \retval non-zero failure
1491 int ast_msg_init(void)
1495 msg_q_tp = ast_taskprocessor_get("ast_msg_queue", TPS_REF_DEFAULT);
1500 ast_rwlock_init(&msg_techs_lock);
1501 if (AST_VECTOR_INIT(&msg_techs, 8)) {
1505 ast_rwlock_init(&msg_handlers_lock);
1506 if (AST_VECTOR_INIT(&msg_handlers, 4)) {
1510 res = ast_msg_handler_register(&dialplan_msg_handler);
1512 res |= __ast_custom_function_register(&msg_function, NULL);
1513 res |= __ast_custom_function_register(&msg_data_function, NULL);
1514 res |= ast_register_application2(app_msg_send, msg_send_exec, NULL, NULL, NULL);
1515 res |= ast_manager_register_xml_core("MessageSend", EVENT_FLAG_MESSAGE, action_messagesend);
1517 ast_register_cleanup(message_shutdown);