Asterisk - The Open Source Telephony Project GIT-master-7e7a603
main/message.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2010, Digium, Inc.
5 *
6 * Russell Bryant <russell@digium.com>
7 *
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.
13 *
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.
17 */
18
19/*! \file
20 *
21 * \brief Out-of-call text message support
22 *
23 * \author Russell Bryant <russell@digium.com>
24 */
25
26/*** MODULEINFO
27 <support_level>core</support_level>
28 ***/
29
30#include "asterisk.h"
31
32#include "asterisk/_private.h"
33
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"
43#include "asterisk/message.h"
44
45/*** DOCUMENTATION
46 <function name="MESSAGE" language="en_US">
47 <synopsis>
48 Create a message or read fields from a message.
49 </synopsis>
50 <syntax argsep="/">
51 <parameter name="argument" required="true">
52 <para>Field of the message to get or set.</para>
53 <enumlist>
54 <enum name="to">
55 <para>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>
58 <para>
59 </para>
60 <para>For an ourgoing message, this will set the To header in the
61 outgoing SIP message. This may be overridden by the "to" parameter
62 of MessageSend.
63 </para>
64 </enum>
65 <enum name="from">
66 <para>When processing an
67 incoming message, this will be set to the source of the message.</para>
68 <para>
69 </para>
70 <para>For an ourgoing message, this will set the From header in the
71 outgoing SIP message. This may be overridden by the "from" parameter
72 of MessageSend.
73 </para>
74 </enum>
75 <enum name="custom_data">
76 <para>Write-only. Mark or unmark all message headers for an outgoing
77 message. The following values can be set:</para>
78 <enumlist>
79 <enum name="mark_all_outbound">
80 <para>Mark all headers for an outgoing message.</para>
81 </enum>
82 <enum name="clear_all_outbound">
83 <para>Unmark all headers for an outgoing message.</para>
84 </enum>
85 </enumlist>
86 </enum>
87 <enum name="body">
88 <para>Read/Write. The message body. When processing an incoming
89 message, this includes the body of the message that Asterisk
90 received. When MessageSend() is executed, the contents of this
91 field are used as the body of the outgoing message. The body
92 will always be UTF-8.</para>
93 </enum>
94 </enumlist>
95 </parameter>
96 </syntax>
97 <description>
98 <para>This function will read from or write a value to a text message.
99 It is used both to read the data out of an incoming message, as well as
100 modify or create a message that will be sent outbound.</para>
101 </description>
102 <see-also>
103 <ref type="application">MessageSend</ref>
104 </see-also>
105 </function>
106 <function name="MESSAGE_DATA" language="en_US">
107 <synopsis>
108 Read or write custom data attached to a message.
109 </synopsis>
110 <syntax argsep="/">
111 <parameter name="argument" required="true">
112 <para>Field of the message to get or set.</para>
113 </parameter>
114 </syntax>
115 <description>
116 <para>This function will read from or write a value to a text message.
117 It is used both to read the data out of an incoming message, as well as
118 modify a message that will be sent outbound.</para>
119 <note>
120 <para>If you want to set an outbound message to carry data in the
121 current message, do
122 Set(MESSAGE_DATA(<replaceable>key</replaceable>)=${MESSAGE_DATA(<replaceable>key</replaceable>)}).</para>
123 </note>
124 </description>
125 <see-also>
126 <ref type="application">MessageSend</ref>
127 </see-also>
128 </function>
129 <application name="MessageSend" language="en_US">
130 <synopsis>
131 Send a text message.
132 </synopsis>
133 <syntax>
134 <parameter name="destination" required="true">
135 <para>A To URI for the message.</para>
136 <xi:include xpointer="xpointer(/docs/info[@name='MessageDestinationInfo'])" />
137 </parameter>
138 <parameter name="from" required="false">
139 <para>A From URI for the message if needed for the
140 message technology being used to send this message. This can be a
141 SIP(S) URI, such as <literal>Alice &lt;sip:alice@atlanta.com&gt;</literal>,
142 or a string in the format <literal>alice@atlanta.com</literal>.
143 This will override a <literal>from</literal>
144 specified using the MESSAGE dialplan function or the <literal>from</literal>
145 that may have been on an incoming message.
146 </para>
147 <xi:include xpointer="xpointer(/docs/info[@name='MessageFromInfo'])" />
148 </parameter>
149 <parameter name="to" required="false">
150 <para>A To URI for the message if needed for the
151 message technology being used to send this message. This can be a
152 SIP(S) URI, such as <literal>Alice &lt;sip:alice@atlanta.com&gt;</literal>,
153 or a string in the format <literal>alice@atlanta.com</literal>.
154 This will override a <literal>to</literal>
155 specified using the MESSAGE dialplan function or the <literal>to</literal>
156 that may have been on an incoming message.
157 </para>
158 <xi:include xpointer="xpointer(/docs/info[@name='MessageToInfo'])" />
159 </parameter>
160 </syntax>
161 <description>
162 <para>Send a text message. The body of the message that will be
163 sent is what is currently set to <literal>MESSAGE(body)</literal>.
164 This may he come from an incoming message.
165 The technology chosen for sending the message is determined
166 based on a prefix to the <literal>destination</literal> parameter.</para>
167 <para>This application sets the following channel variables:</para>
168 <variablelist>
169 <variable name="MESSAGE_SEND_STATUS">
170 <para>This is the message delivery status returned by this application.</para>
171 <value name="INVALID_PROTOCOL">
172 No handler for the technology part of the URI was found.
173 </value>
174 <value name="INVALID_URI">
175 The protocol handler reported that the URI was not valid.
176 </value>
177 <value name="SUCCESS">
178 Successfully passed on to the protocol handler, but delivery has not necessarily been guaranteed.
179 </value>
180 <value name="FAILURE">
181 The protocol handler reported that it was unabled to deliver the message for some reason.
182 </value>
183 </variable>
184 </variablelist>
185 </description>
186 </application>
187 <manager name="MessageSend" language="en_US">
188 <synopsis>
189 Send an out of call message to an endpoint.
190 </synopsis>
191 <syntax>
192 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
193 <parameter name="Destination" required="false">
194 <para>A To URI for the message. If Destination is provided, the To
195 parameter can also be supplied and may alter the message based on
196 the specified message technology.</para>
197 <para>For backwards compatibility, if Destination is not provided,
198 the To parameter must be provided and will be used as the message
199 destination.</para>
200 <xi:include xpointer="xpointer(/docs/info[@name='MessageDestinationInfo'])" />
201 </parameter>
202 <parameter name="To" required="false">
203 <para>A To URI for the message if needed for the
204 message technology being used to send this message. This can be a
205 SIP(S) URI, such as <literal>Alice &lt;sip:alice@atlanta.com&gt;</literal>,
206 or a string in the format <literal>alice@atlanta.com</literal>.</para>
207 <para>This parameter is required if the Destination parameter is not
208 provided.</para>
209 <xi:include xpointer="xpointer(/docs/info[@name='MessageToInfo'])" />
210 </parameter>
211 <parameter name="From">
212 <para>A From URI for the message if needed for the
213 message technology being used to send this message.</para>
214 <xi:include xpointer="xpointer(/docs/info[@name='MessageFromInfo'])" />
215 </parameter>
216 <parameter name="Body">
217 <para>The message body text. This must not contain any newlines as that
218 conflicts with the AMI protocol.</para>
219 </parameter>
220 <parameter name="Base64Body">
221 <para>Text bodies requiring the use of newlines have to be base64 encoded
222 in this field. Base64Body will be decoded before being sent out.
223 Base64Body takes precedence over Body.</para>
224 </parameter>
225 <parameter name="Variable">
226 <para>Message variable to set, multiple Variable: headers are
227 allowed. The header value is a comma separated list of
228 name=value pairs.</para>
229 </parameter>
230 </syntax>
231 </manager>
232 ***/
233
234struct msg_data {
238 );
239 unsigned int send; /* Whether to send out on outbound messages */
240};
241
243
244/*!
245 * \brief A message.
246 */
247struct ast_msg {
249 /*! Where the message is going */
251 /*! Where we "say" the message came from */
253 /*! The text to send */
255 /*! The dialplan context for the message */
257 /*! The dialplan extension for the message */
259 /*! An endpoint associated with this message */
261 /*! The technology of the endpoint associated with this message */
263 );
264 /*! Technology/dialplan specific variables associated with the message */
266};
267
268/*! \brief Lock for \c msg_techs vector */
270
271/*! \brief Vector of message technologies */
273
274/*! \brief Lock for \c msg_handlers vector */
276
277/*! \brief Vector of received message handlers */
279
281
282static const char app_msg_send[] = "MessageSend";
283
284static void msg_ds_destroy(void *data);
285
286static const struct ast_datastore_info msg_datastore = {
287 .type = "message",
288 .destroy = msg_ds_destroy,
289};
290
291static int msg_func_read(struct ast_channel *chan, const char *function,
292 char *data, char *buf, size_t len);
293static int msg_func_write(struct ast_channel *chan, const char *function,
294 char *data, const char *value);
295
297 .name = "MESSAGE",
298 .read = msg_func_read,
299 .write = msg_func_write,
300};
301
302static int msg_data_func_read(struct ast_channel *chan, const char *function,
303 char *data, char *buf, size_t len);
304static int msg_data_func_write(struct ast_channel *chan, const char *function,
305 char *data, const char *value);
306
308 .name = "MESSAGE_DATA",
309 .read = msg_data_func_read,
310 .write = msg_data_func_write,
311};
312
313static struct ast_frame *chan_msg_read(struct ast_channel *chan);
314static int chan_msg_write(struct ast_channel *chan, struct ast_frame *fr);
315static int chan_msg_indicate(struct ast_channel *chan, int condition,
316 const void *data, size_t datalen);
317static int chan_msg_send_digit_begin(struct ast_channel *chan, char digit);
318static int chan_msg_send_digit_end(struct ast_channel *chan, char digit,
319 unsigned int duration);
320
321/*!
322 * \internal
323 * \brief A bare minimum channel technology
324 *
325 * This will not be registered as we never want anything to try
326 * to create Message channels other than internally in this file.
327 */
329 .type = "Message",
330 .description = "Internal Text Message Processing",
331 .read = chan_msg_read,
332 .write = chan_msg_write,
333 .indicate = chan_msg_indicate,
334 .send_digit_begin = chan_msg_send_digit_begin,
335 .send_digit_end = chan_msg_send_digit_end,
336};
337
338/*!
339 * \internal
340 * \brief ast_channel_tech read callback
341 *
342 * This should never be called. However, we say that about chan_iax2's
343 * read callback, too, and it seems to randomly get called for some
344 * reason. If it does, a simple NULL frame will suffice.
345 */
346static struct ast_frame *chan_msg_read(struct ast_channel *chan)
347{
348 return &ast_null_frame;
349}
350
351/*!
352 * \internal
353 * \brief ast_channel_tech write callback
354 *
355 * Throw all frames away. We don't care about any of them.
356 */
357static int chan_msg_write(struct ast_channel *chan, struct ast_frame *fr)
358{
359 return 0;
360}
361
362/*!
363 * \internal
364 * \brief ast_channel_tech indicate callback
365 *
366 * The indicate callback is here just so it can return success.
367 * We don't want any callers of ast_indicate() to think something
368 * has failed. We also don't want ast_indicate() itself to try
369 * to generate inband tones since we didn't tell it that we took
370 * care of it ourselves.
371 */
372static int chan_msg_indicate(struct ast_channel *chan, int condition,
373 const void *data, size_t datalen)
374{
375 return 0;
376}
377
378/*!
379 * \internal
380 * \brief ast_channel_tech send_digit_begin callback
381 *
382 * This is here so that just in case a digit comes at a message channel
383 * that the Asterisk core doesn't waste any time trying to generate
384 * inband DTMF in audio. It's a waste of resources.
385 */
386static int chan_msg_send_digit_begin(struct ast_channel *chan, char digit)
387{
388 return 0;
389}
390
391/*!
392 * \internal
393 * \brief ast_channel_tech send_digit_end callback
394 *
395 * This is here so that just in case a digit comes at a message channel
396 * that the Asterisk core doesn't waste any time trying to generate
397 * inband DTMF in audio. It's a waste of resources.
398 */
399static int chan_msg_send_digit_end(struct ast_channel *chan, char digit,
400 unsigned int duration)
401{
402 return 0;
403}
404
405static void msg_ds_destroy(void *data)
406{
407 struct ast_msg *msg = data;
408
409 ao2_ref(msg, -1);
410}
411
412static int msg_data_cmp_fn(void *obj, void *arg, int flags)
413{
414 const struct msg_data *one = obj, *two = arg;
415 return !strcasecmp(one->name, two->name) ? CMP_MATCH | CMP_STOP : 0;
416}
417
418static void msg_data_destructor(void *obj)
419{
420 struct msg_data *data = obj;
422}
423
424static void msg_destructor(void *obj)
425{
426 struct ast_msg *msg = obj;
427
429 ao2_cleanup(msg->vars);
430}
431
433{
434 struct ast_msg *msg;
435
436 if (!(msg = ao2_alloc(sizeof(*msg), msg_destructor))) {
437 return NULL;
438 }
439
440 if (ast_string_field_init(msg, 128)) {
441 ao2_ref(msg, -1);
442 return NULL;
443 }
444
447 if (!msg->vars) {
448 ao2_ref(msg, -1);
449 return NULL;
450 }
451 ast_string_field_set(msg, context, "default");
452
453 return msg;
454}
455
456struct ast_msg *ast_msg_ref(struct ast_msg *msg)
457{
458 ao2_ref(msg, 1);
459 return msg;
460}
461
462struct ast_msg *ast_msg_destroy(struct ast_msg *msg)
463{
464 ao2_ref(msg, -1);
465 return NULL;
466}
467
468int ast_msg_set_to(struct ast_msg *msg, const char *fmt, ...)
469{
470 va_list ap;
471
472 va_start(ap, fmt);
473 ast_string_field_build_va(msg, to, fmt, ap);
474 va_end(ap);
475
476 return 0;
477}
478
479int ast_msg_set_from(struct ast_msg *msg, const char *fmt, ...)
480{
481 va_list ap;
482
483 va_start(ap, fmt);
484 ast_string_field_build_va(msg, from, fmt, ap);
485 va_end(ap);
486
487 return 0;
488}
489
490int ast_msg_set_body(struct ast_msg *msg, const char *fmt, ...)
491{
492 va_list ap;
493
494 va_start(ap, fmt);
495 ast_string_field_build_va(msg, body, fmt, ap);
496 va_end(ap);
497
498 return 0;
499}
500
501int ast_msg_set_context(struct ast_msg *msg, const char *fmt, ...)
502{
503 va_list ap;
504
505 va_start(ap, fmt);
506 ast_string_field_build_va(msg, context, fmt, ap);
507 va_end(ap);
508
509 return 0;
510}
511
512int ast_msg_set_exten(struct ast_msg *msg, const char *fmt, ...)
513{
514 va_list ap;
515
516 va_start(ap, fmt);
517 ast_string_field_build_va(msg, exten, fmt, ap);
518 va_end(ap);
519
520 return 0;
521}
522
523int ast_msg_set_tech(struct ast_msg *msg, const char *fmt, ...)
524{
525 va_list ap;
526
527 va_start(ap, fmt);
528 ast_string_field_build_va(msg, tech, fmt, ap);
529 va_end(ap);
530
531 return 0;
532}
533
534int ast_msg_set_endpoint(struct ast_msg *msg, const char *fmt, ...)
535{
536 va_list ap;
537
538 va_start(ap, fmt);
539 ast_string_field_build_va(msg, endpoint, fmt, ap);
540 va_end(ap);
541
542 return 0;
543}
544
545const char *ast_msg_get_body(const struct ast_msg *msg)
546{
547 return msg->body;
548}
549
550const char *ast_msg_get_from(const struct ast_msg *msg)
551{
552 return msg->from;
553}
554
555const char *ast_msg_get_to(const struct ast_msg *msg)
556{
557 return msg->to;
558}
559
560const char *ast_msg_get_tech(const struct ast_msg *msg)
561{
562 return msg->tech;
563}
564
565const char *ast_msg_get_endpoint(const struct ast_msg *msg)
566{
567 return msg->endpoint;
568}
569
570static struct msg_data *msg_data_alloc(void)
571{
572 struct msg_data *data;
573
574 if (!(data = ao2_alloc(sizeof(*data), msg_data_destructor))) {
575 return NULL;
576 }
577
578 if (ast_string_field_init(data, 32)) {
579 ao2_ref(data, -1);
580 return NULL;
581 }
582
583 return data;
584}
585
586static struct msg_data *msg_data_find(struct ao2_container *vars, const char *name)
587{
588 struct msg_data tmp = {
589 .name = name,
590 };
591 return ao2_find(vars, &tmp, OBJ_POINTER);
592}
593
594static int msg_set_var_full(struct ast_msg *msg, const char *name, const char *value, unsigned int outbound)
595{
596 struct msg_data *data;
597
598 if (!(data = msg_data_find(msg->vars, name))) {
599 if (ast_strlen_zero(value)) {
600 return 0;
601 }
602 if (!(data = msg_data_alloc())) {
603 return -1;
604 };
605
608 data->send = outbound;
609 ao2_link(msg->vars, data);
610 } else {
611 if (ast_strlen_zero(value)) {
612 ao2_unlink(msg->vars, data);
613 } else {
615 data->send = outbound;
616 }
617 }
618
619 ao2_ref(data, -1);
620
621 return 0;
622}
623
624int ast_msg_set_var_outbound(struct ast_msg *msg, const char *name, const char *value)
625{
626 return msg_set_var_full(msg, name, value, 1);
627}
628
629int ast_msg_set_var(struct ast_msg *msg, const char *name, const char *value)
630{
631 return msg_set_var_full(msg, name, value, 0);
632}
633
634const char *ast_msg_get_var(struct ast_msg *msg, const char *name)
635{
636 struct msg_data *data;
637 const char *val = NULL;
638
639 if (!(data = msg_data_find(msg->vars, name))) {
640 return NULL;
641 }
642
643 /* Yep, this definitely looks like val would be a dangling pointer
644 * after the ref count is decremented. As long as the message structure
645 * is used in a thread safe manner, this will not be the case though.
646 * The ast_msg holds a reference to this object in the msg->vars container. */
647 val = data->value;
648 ao2_ref(data, -1);
649
650 return val;
651}
652
656};
657
659{
661
662 iter = ast_calloc(1, sizeof(*iter));
663 if (!iter) {
664 return NULL;
665 }
666
667 iter->iter = ao2_iterator_init(msg->vars, 0);
668
669 return iter;
670}
671
672static int ast_msg_var_iterator_get_next(const struct ast_msg *msg,
673 struct ast_msg_var_iterator *iter, const char **name, const char **value,
674 unsigned int send)
675{
676 struct msg_data *data;
677
678 if (!iter) {
679 return 0;
680 }
681
682 /* Skip any that we're told to */
683 while ((data = ao2_iterator_next(&iter->iter)) && (data->send != send)) {
684 ao2_ref(data, -1);
685 }
686
687 if (!data) {
688 return 0;
689 }
690
691 if (data->send == send) {
692 *name = data->name;
693 *value = data->value;
694 }
695
696 /* Leave the refcount to be cleaned up by the caller with
697 * ast_msg_var_unref_current after they finish with the pointers to the data */
698 iter->current_used = data;
699
700 return 1;
701}
702
703int ast_msg_var_iterator_next(const struct ast_msg *msg, struct ast_msg_var_iterator *iter, const char **name, const char **value)
704{
705 return ast_msg_var_iterator_get_next(msg, iter, name, value, 1);
706}
707
709 struct ast_msg_var_iterator *iter, const char **name, const char **value)
710{
711 return ast_msg_var_iterator_get_next(msg, iter, name, value, 0);
712}
713
715{
717 iter->current_used = NULL;
718}
719
721{
722 if (iter) {
725 ast_free(iter);
726 }
727}
728
729static struct ast_channel *create_msg_q_chan(void)
730{
731 struct ast_channel *chan;
732 struct ast_datastore *ds;
733
735 NULL, NULL, NULL,
736 NULL, NULL, NULL, NULL, 0,
737 "%s", "Message/ast_msg_queue");
738
739 if (!chan) {
740 return NULL;
741 }
742
745 }
746
748 ast_channel_unlock(chan);
749 ast_channel_unlink(chan);
750
751 if (!(ds = ast_datastore_alloc(&msg_datastore, NULL))) {
752 ast_hangup(chan);
753 return NULL;
754 }
755
756 ast_channel_lock(chan);
758 ast_channel_unlock(chan);
759
760 return chan;
761}
762
763/*!
764 * \internal
765 * \brief Run the dialplan for message processing
766 *
767 * \pre The message has already been set up on the msg datastore
768 * on this channel.
769 */
770static void msg_route(struct ast_channel *chan, struct ast_msg *msg)
771{
772 struct ast_pbx_args pbx_args;
773
774 ast_explicit_goto(chan, msg->context, S_OR(msg->exten, "s"), 1);
775
776 memset(&pbx_args, 0, sizeof(pbx_args));
777 pbx_args.no_hangup_chan = 1,
778 ast_pbx_run_args(chan, &pbx_args);
779}
780
781/*!
782 * \internal
783 * \brief Clean up ast_channel after each message
784 *
785 * Reset various bits of state after routing each message so the same ast_channel
786 * can just be reused.
787 */
788static void chan_cleanup(struct ast_channel *chan)
789{
790 struct ast_datastore *msg_ds, *ds;
791 struct varshead *headp;
792 struct ast_var_t *vardata;
793 struct ast_frame *cur;
794
795 ast_channel_lock(chan);
796
797 /*
798 * Remove the msg datastore. Free its data but keep around the datastore
799 * object and just reuse it.
800 */
801 if ((msg_ds = ast_channel_datastore_find(chan, &msg_datastore, NULL)) && msg_ds->data) {
802 ast_channel_datastore_remove(chan, msg_ds);
803 ao2_ref(msg_ds->data, -1);
804 msg_ds->data = NULL;
805 }
806
807 /*
808 * Destroy all other datastores.
809 */
810 while ((ds = AST_LIST_REMOVE_HEAD(ast_channel_datastores(chan), entry))) {
812 }
813
814 /*
815 * Destroy all channel variables.
816 */
817 headp = ast_channel_varshead(chan);
818 while ((vardata = AST_LIST_REMOVE_HEAD(headp, entries))) {
819 ast_var_delete(vardata);
820 }
821
822 /*
823 * Remove frames from read queue
824 */
825 while ((cur = AST_LIST_REMOVE_HEAD(ast_channel_readq(chan), frame_list))) {
826 ast_frfree(cur);
827 }
828
829 /*
830 * Restore msg datastore.
831 */
832 if (msg_ds) {
833 ast_channel_datastore_add(chan, msg_ds);
834 }
835
836 /*
837 * Clear softhangup flags.
838 */
840
841 /*
842 * Flush the alert pipe in case we miscounted somewhere when
843 * messing with frames on the read queue, we had to flush the
844 * read queue above, or we had an "Exceptionally long queue
845 * length" event.
846 */
848
849 ast_channel_unlock(chan);
850}
851
852static void destroy_msg_q_chan(void *data)
853{
854 struct ast_channel **chan = data;
855
856 if (!*chan) {
857 return;
858 }
859
860 ast_channel_release(*chan);
861}
862
864
865/*! \internal \brief Handle a message bound for the dialplan */
866static int dialplan_handle_msg_cb(struct ast_msg *msg)
867{
868 struct ast_channel **chan_p, *chan;
869 struct ast_datastore *ds;
870
871 if (!(chan_p = ast_threadstorage_get(&msg_q_chan, sizeof(struct ast_channel *)))) {
872 return -1;
873 }
874 if (!*chan_p) {
875 if (!(*chan_p = create_msg_q_chan())) {
876 return -1;
877 }
878 }
879 chan = *chan_p;
880
881 ast_channel_lock(chan);
882 if (!(ds = ast_channel_datastore_find(chan, &msg_datastore, NULL))) {
883 ast_channel_unlock(chan);
884 return -1;
885 }
886 ao2_ref(msg, +1);
887 ds->data = msg;
888 ast_channel_unlock(chan);
889
890 msg_route(chan, msg);
891 chan_cleanup(chan);
892
893 return 0;
894}
895
896/*! \internal \brief Determine if a message has a destination in the dialplan */
897static int dialplan_has_destination_cb(const struct ast_msg *msg)
898{
899 if (ast_strlen_zero(msg->context)) {
900 return 0;
901 }
902
903 return ast_exists_extension(NULL, msg->context, S_OR(msg->exten, "s"), 1, NULL);
904}
905
907 .name = "dialplan",
908 .handle_msg = dialplan_handle_msg_cb,
909 .has_destination = dialplan_has_destination_cb,
910};
911
912/*!
913 * \internal
914 * \brief Message queue task processor callback
915 *
916 * \retval 0 success
917 * \retval non-zero failure
918 *
919 * \note Even though this returns a value, the taskprocessor code ignores the value.
920 */
921static int msg_q_cb(void *data)
922{
923 struct ast_msg *msg = data;
924 int res = 1;
925 int i;
926
928 for (i = 0; i < AST_VECTOR_SIZE(&msg_handlers); i++) {
930
931 if (!handler->has_destination(msg)) {
932 ast_debug(5, "Handler %s doesn't want message, moving on\n", handler->name);
933 continue;
934 }
935
936 ast_debug(5, "Dispatching message to %s handler\n", handler->name);
937 res &= handler->handle_msg(msg);
938 }
940
941 if (res != 0) {
942 ast_log(LOG_WARNING, "No handler processed message from %s to %s\n",
943 S_OR(msg->from, "<unknown>"), S_OR(msg->to, "<unknown>"));
944 }
945
946 ao2_ref(msg, -1);
947
948 return res;
949}
950
951int ast_msg_has_destination(const struct ast_msg *msg)
952{
953 int i;
954 int result = 0;
955
957 for (i = 0; i < AST_VECTOR_SIZE(&msg_handlers); i++) {
959
960 ast_debug(5, "Seeing if %s can handle message\n", handler->name);
961 if (handler->has_destination(msg)) {
962 ast_debug(5, "%s can handle message\n", handler->name);
963 result = 1;
964 break;
965 }
966 }
968
969 return result;
970}
971
972int ast_msg_queue(struct ast_msg *msg)
973{
974 int res;
976 if (res == -1) {
977 ao2_ref(msg, -1);
978 }
979
980 return res;
981}
982
983/*!
984 * \internal
985 * \brief Find or create a message datastore on a channel
986 *
987 * \pre chan is locked
988 *
989 * \param chan the relevant channel
990 *
991 * \return the channel's message datastore
992 * \retval NULL on error
993 */
995{
996 struct ast_datastore *ds;
997
998 if ((ds = ast_channel_datastore_find(chan, &msg_datastore, NULL))) {
999 return ds;
1000 }
1001
1002 if (!(ds = ast_datastore_alloc(&msg_datastore, NULL))) {
1003 return NULL;
1004 }
1005
1006 if (!(ds->data = ast_msg_alloc())) {
1008 return NULL;
1009 }
1010
1011 ast_channel_datastore_add(chan, ds);
1012
1013 return ds;
1014}
1015
1016static int msg_func_read(struct ast_channel *chan, const char *function,
1017 char *data, char *buf, size_t len)
1018{
1019 struct ast_datastore *ds;
1020 struct ast_msg *msg;
1021
1022 if (!chan) {
1023 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", function);
1024 return -1;
1025 }
1026
1027 ast_channel_lock(chan);
1028
1029 if (!(ds = ast_channel_datastore_find(chan, &msg_datastore, NULL))) {
1030 ast_channel_unlock(chan);
1031 ast_log(LOG_ERROR, "No MESSAGE data found on the channel to read.\n");
1032 return -1;
1033 }
1034
1035 msg = ds->data;
1036 ao2_ref(msg, +1);
1037 ast_channel_unlock(chan);
1038
1039 ao2_lock(msg);
1040
1041 if (!strcasecmp(data, "to")) {
1042 ast_copy_string(buf, msg->to, len);
1043 } else if (!strcasecmp(data, "from")) {
1044 ast_copy_string(buf, msg->from, len);
1045 } else if (!strcasecmp(data, "body")) {
1046 ast_copy_string(buf, msg->body, len);
1047 } else {
1048 ast_log(LOG_WARNING, "Invalid argument to MESSAGE(): '%s'\n", data);
1049 }
1050
1051 ao2_unlock(msg);
1052 ao2_ref(msg, -1);
1053
1054 return 0;
1055}
1056
1057static int msg_func_write(struct ast_channel *chan, const char *function,
1058 char *data, const char *value)
1059{
1060 struct ast_datastore *ds;
1061 struct ast_msg *msg;
1062
1063 if (!chan) {
1064 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", function);
1065 return -1;
1066 }
1067
1068 ast_channel_lock(chan);
1069
1070 if (!(ds = msg_datastore_find_or_create(chan))) {
1071 ast_channel_unlock(chan);
1072 return -1;
1073 }
1074
1075 msg = ds->data;
1076 ao2_ref(msg, +1);
1077 ast_channel_unlock(chan);
1078
1079 ao2_lock(msg);
1080
1081 if (!strcasecmp(data, "to")) {
1082 ast_msg_set_to(msg, "%s", value);
1083 } else if (!strcasecmp(data, "from")) {
1084 ast_msg_set_from(msg, "%s", value);
1085 } else if (!strcasecmp(data, "body")) {
1086 ast_msg_set_body(msg, "%s", value);
1087 } else if (!strcasecmp(data, "custom_data")) {
1088 int outbound = -1;
1089 if (!strcasecmp(value, "mark_all_outbound")) {
1090 outbound = 1;
1091 } else if (!strcasecmp(value, "clear_all_outbound")) {
1092 outbound = 0;
1093 } else {
1094 ast_log(LOG_WARNING, "'%s' is not a valid value for custom_data\n", value);
1095 }
1096
1097 if (outbound != -1) {
1098 struct msg_data *hdr_data;
1099 struct ao2_iterator iter = ao2_iterator_init(msg->vars, 0);
1100
1101 while ((hdr_data = ao2_iterator_next(&iter))) {
1102 hdr_data->send = outbound;
1103 ao2_ref(hdr_data, -1);
1104 }
1105 ao2_iterator_destroy(&iter);
1106 }
1107 } else {
1108 ast_log(LOG_WARNING, "'%s' is not a valid write argument.\n", data);
1109 }
1110
1111 ao2_unlock(msg);
1112 ao2_ref(msg, -1);
1113
1114 return 0;
1115}
1116
1117static int msg_data_func_read(struct ast_channel *chan, const char *function,
1118 char *data, char *buf, size_t len)
1119{
1120 struct ast_datastore *ds;
1121 struct ast_msg *msg;
1122 const char *val;
1123
1124 if (!chan) {
1125 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", function);
1126 return -1;
1127 }
1128
1129 ast_channel_lock(chan);
1130
1131 if (!(ds = ast_channel_datastore_find(chan, &msg_datastore, NULL))) {
1132 ast_channel_unlock(chan);
1133 ast_log(LOG_ERROR, "No MESSAGE data found on the channel to read.\n");
1134 return -1;
1135 }
1136
1137 msg = ds->data;
1138 ao2_ref(msg, +1);
1139 ast_channel_unlock(chan);
1140
1141 ao2_lock(msg);
1142
1143 if ((val = ast_msg_get_var(msg, data))) {
1145 }
1146
1147 ao2_unlock(msg);
1148 ao2_ref(msg, -1);
1149
1150 return 0;
1151}
1152
1153static int msg_data_func_write(struct ast_channel *chan, const char *function,
1154 char *data, const char *value)
1155{
1156 struct ast_datastore *ds;
1157 struct ast_msg *msg;
1158
1159 if (!chan) {
1160 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", function);
1161 return -1;
1162 }
1163
1164 ast_channel_lock(chan);
1165
1166 if (!(ds = msg_datastore_find_or_create(chan))) {
1167 ast_channel_unlock(chan);
1168 return -1;
1169 }
1170
1171 msg = ds->data;
1172 ao2_ref(msg, +1);
1173 ast_channel_unlock(chan);
1174
1175 ao2_lock(msg);
1176
1177 ast_msg_set_var_outbound(msg, data, value);
1178
1179 ao2_unlock(msg);
1180 ao2_ref(msg, -1);
1181
1182 return 0;
1183}
1184
1185/*!
1186 * \internal \brief Find a \c ast_msg_tech by its technology name
1187 *
1188 * \param tech_name The name of the message technology
1189 *
1190 * \note \c msg_techs should be locked via \c msg_techs_lock prior to
1191 * calling this function
1192 *
1193 * \retval NULL if no \ref ast_msg_tech has been registered
1194 * \return \ref ast_msg_tech if registered
1195 */
1196static const struct ast_msg_tech *msg_find_by_tech_name(const char *tech_name)
1197{
1198 const struct ast_msg_tech *current;
1199 int i;
1200
1201 for (i = 0; i < AST_VECTOR_SIZE(&msg_techs); i++) {
1203 if (!strcmp(current->name, tech_name)) {
1204 return current;
1205 }
1206 }
1207
1208 return NULL;
1209}
1210
1211/*!
1212 * \internal \brief Find a \c ast_msg_handler by its technology name
1213 *
1214 * \param tech_name The name of the message technology
1215 *
1216 * \note \c msg_handlers should be locked via \c msg_handlers_lock
1217 * prior to calling this function
1218 *
1219 * \retval NULL if no \ref ast_msg_handler has been registered
1220 * \return \ref ast_msg_handler if registered
1221 */
1222static const struct ast_msg_handler *msg_handler_find_by_tech_name(const char *tech_name)
1223{
1224 const struct ast_msg_handler *current;
1225 int i;
1226
1227 for (i = 0; i < AST_VECTOR_SIZE(&msg_handlers); i++) {
1229 if (!strcmp(current->name, tech_name)) {
1230 return current;
1231 }
1232 }
1233
1234 return NULL;
1235}
1236
1237/*!
1238 * \internal
1239 * \brief MessageSend() application
1240 */
1241static int msg_send_exec(struct ast_channel *chan, const char *data)
1242{
1243 struct ast_datastore *ds;
1244 struct ast_msg *msg;
1245 char *tech_name;
1246 const struct ast_msg_tech *msg_tech;
1247 char *parse;
1248 int res = -1;
1250 AST_APP_ARG(destination);
1251 AST_APP_ARG(from);
1252 AST_APP_ARG(to);
1253 );
1254
1255 if (ast_strlen_zero(data)) {
1256 ast_log(LOG_WARNING, "An argument is required to MessageSend()\n");
1257 pbx_builtin_setvar_helper(chan, "MESSAGE_SEND_STATUS", "INVALID_URI");
1258 return 0;
1259 }
1260
1261 parse = ast_strdupa(data);
1263
1264 if (ast_strlen_zero(args.destination)) {
1265 ast_log(LOG_WARNING, "A 'to' URI is required for MessageSend()\n");
1266 pbx_builtin_setvar_helper(chan, "MESSAGE_SEND_STATUS", "INVALID_URI");
1267 return 0;
1268 }
1269
1270 ast_channel_lock(chan);
1271
1272 if (!(ds = ast_channel_datastore_find(chan, &msg_datastore, NULL))) {
1273 ast_channel_unlock(chan);
1274 ast_log(LOG_WARNING, "No message data found on channel to send.\n");
1275 pbx_builtin_setvar_helper(chan, "MESSAGE_SEND_STATUS", "FAILURE");
1276 return 0;
1277 }
1278
1279 msg = ds->data;
1280 ao2_ref(msg, +1);
1281 ast_channel_unlock(chan);
1282
1283 tech_name = ast_strdupa(args.destination);
1284 tech_name = strsep(&tech_name, ":");
1285
1287 msg_tech = msg_find_by_tech_name(tech_name);
1288
1289 if (!msg_tech) {
1290 ast_log(LOG_WARNING, "No message technology '%s' found.\n", tech_name);
1291 pbx_builtin_setvar_helper(chan, "MESSAGE_SEND_STATUS", "INVALID_PROTOCOL");
1292 goto exit_cleanup;
1293 }
1294
1295 /*
1296 * If there was a "to" in the call to MessageSend,
1297 * replace the to already in the channel datastore.
1298 */
1299 if (!ast_strlen_zero(args.to)) {
1300 ast_string_field_set(msg, to, args.to);
1301 }
1302
1303 /*
1304 * The message lock is held here to safely allow the technology
1305 * implementation to access the message fields without worrying
1306 * that they could change.
1307 */
1308 ao2_lock(msg);
1309 res = msg_tech->msg_send(msg, S_OR(args.destination, ""), S_OR(args.from, ""));
1310 ao2_unlock(msg);
1311
1312 pbx_builtin_setvar_helper(chan, "MESSAGE_SEND_STATUS", res ? "FAILURE" : "SUCCESS");
1313
1314exit_cleanup:
1316 ao2_ref(msg, -1);
1317
1318 return 0;
1319}
1320
1321static int action_messagesend(struct mansession *s, const struct message *m)
1322{
1323 const char *destination = astman_get_header(m, "Destination");
1324 const char *to = astman_get_header(m, "To");
1325 const char *from = astman_get_header(m, "From");
1326 const char *body = astman_get_header(m, "Body");
1327 const char *base64body = astman_get_header(m, "Base64Body");
1328 const char *to_override = NULL;
1329 char base64decoded[1301] = { 0, };
1330 char *tech_name = NULL;
1331 struct ast_variable *vars = NULL;
1332 struct ast_variable *data = NULL;
1333 const struct ast_msg_tech *msg_tech;
1334 struct ast_msg *msg;
1335 int res = -1;
1336
1337 if (!ast_strlen_zero(destination)) {
1338 if (!ast_strlen_zero(to)) {
1339 to_override = to;
1340 }
1341 to = destination;
1342 } else {
1343 if (ast_strlen_zero(to)) {
1344 astman_send_error(s, m, "No 'To' address specified.");
1345 return 0;
1346 }
1347 }
1348
1349 if (!ast_strlen_zero(base64body)) {
1350 ast_base64decode((unsigned char *) base64decoded, base64body, sizeof(base64decoded) - 1);
1351 body = base64decoded;
1352 }
1353
1354 tech_name = ast_strdupa(to);
1355 tech_name = strsep(&tech_name, ":");
1356
1358 msg_tech = msg_find_by_tech_name(tech_name);
1359 if (!msg_tech) {
1361 astman_send_error(s, m, "Message technology not found.");
1362 return 0;
1363 }
1364
1365 if (!(msg = ast_msg_alloc())) {
1367 astman_send_error(s, m, "Internal failure\n");
1368 return 0;
1369 }
1370
1372 for (vars = data; vars; vars = vars->next) {
1373 ast_msg_set_var_outbound(msg, vars->name, vars->value);
1374 }
1375
1376 ast_msg_set_body(msg, "%s", body);
1377
1378 if (to_override) {
1379 ast_string_field_set(msg, to, to_override);
1380 }
1381
1382 res = msg_tech->msg_send(msg, S_OR(to, ""), S_OR(from, ""));
1383
1385
1387 ao2_ref(msg, -1);
1388
1389 if (res) {
1390 astman_send_error(s, m, "Message failed to send.");
1391 } else {
1392 astman_send_ack(s, m, "Message successfully sent");
1393 }
1394 return 0;
1395}
1396
1397int ast_msg_send(struct ast_msg *msg, const char *to, const char *from)
1398{
1399 char *tech_name = NULL;
1400 const struct ast_msg_tech *msg_tech;
1401 int res = -1;
1402
1403 if (ast_strlen_zero(to)) {
1404 ao2_ref(msg, -1);
1405 return -1;
1406 }
1407
1408 tech_name = ast_strdupa(to);
1409 tech_name = strsep(&tech_name, ":");
1410
1412 msg_tech = msg_find_by_tech_name(tech_name);
1413
1414 if (!msg_tech) {
1415 ast_log(LOG_ERROR, "Unknown message tech: %s\n", tech_name);
1417 return -1;
1418 }
1419
1420 res = msg_tech->msg_send(msg, S_OR(to, ""), S_OR(from, ""));
1421
1423
1424 ao2_ref(msg, -1);
1425
1426 return res;
1427}
1428
1429/*!
1430 * \brief Structure used to transport a message through the frame core
1431 * \since 13.22.0
1432 * \since 15.5.0
1433 */
1435 /*! The length of this structure plus the actual length of the allocated buffer */
1436 size_t length;
1438 /*! These are indices into the buffer where teh attribute starts */
1440 /*! The buffer containing the NULL separated attributes */
1441 char buf[0];
1442};
1443
1444#define ATTRIBUTE_UNSET -1
1445
1447 struct ast_msg_data_attribute attributes[], size_t count)
1448{
1449 struct ast_msg_data *msg;
1450 size_t len = sizeof(*msg);
1451 size_t i;
1452 size_t current_offset = 0;
1453 enum ast_msg_data_attribute_type attr_type;
1454
1455 if (!attributes) {
1456 ast_assert(attributes != NULL);
1457 return NULL;
1458 }
1459
1460 if (!count) {
1461 ast_assert(count > 0);
1462 return NULL;
1463 }
1464
1465 /* Calculate the length required for the buffer */
1466 for (i=0; i < count; i++) {
1467 if (!attributes[i].value) {
1468 ast_assert(attributes[i].value != NULL);
1469 return NULL;
1470 }
1471 len += (strlen(attributes[i].value) + 1);
1472 }
1473
1474 msg = ast_calloc(1, len);
1475 if (!msg) {
1476 return NULL;
1477 }
1478 msg->source = source;
1479 msg->length = len;
1480
1481 /* Mark all of the attributes as unset */
1482 for (attr_type = 0; attr_type < __AST_MSG_DATA_ATTR_LAST; attr_type++) {
1483 msg->attribute_value_offsets[attr_type] = ATTRIBUTE_UNSET;
1484 }
1485
1486 /* Set the ones we have and increment the offset */
1487 for (i=0; i < count; i++) {
1488 len = (strlen(attributes[i].value) + 1);
1489 ast_copy_string(msg->buf + current_offset, attributes[i].value, len); /* Safe */
1490 msg->attribute_value_offsets[attributes[i].type] = current_offset;
1491 current_offset += len;
1492 }
1493
1494 return msg;
1495}
1496
1498 const char *to, const char *from, const char *content_type, const char *body)
1499{
1500 struct ast_msg_data_attribute attrs[] =
1501 {
1502 {
1504 .value = (char *)S_OR(to, ""),
1505 },
1506 {
1507 .type = AST_MSG_DATA_ATTR_FROM,
1508 .value = (char *)S_OR(from, ""),
1509 },
1510 {
1512 .value = (char *)S_OR(content_type, ""),
1513 },
1514 {
1515 .type = AST_MSG_DATA_ATTR_BODY,
1516 .value = (char *)S_OR(body, ""),
1517 },
1518 };
1519
1520 return ast_msg_data_alloc(source_type, attrs, ARRAY_LEN(attrs));
1521}
1522
1524{
1525 struct ast_msg_data *dest;
1526
1527 if (!msg) {
1528 ast_assert(msg != NULL);
1529 return NULL;
1530 }
1531
1532 dest = ast_malloc(msg->length);
1533 if (!dest) {
1534 return NULL;
1535 }
1536 memcpy(dest, msg, msg->length);
1537
1538 return dest;
1539}
1540
1542{
1543 if (!msg) {
1544 ast_assert(msg != NULL);
1545 return 0;
1546 }
1547
1548 return msg->length;
1549}
1550
1552{
1553 if (!msg) {
1554 ast_assert(msg != NULL);
1556 }
1557
1558 return msg->source;
1559}
1560
1562 enum ast_msg_data_attribute_type attribute_type)
1563{
1564 if (!msg) {
1565 ast_assert(msg != NULL);
1566 return "";
1567 }
1568
1569 if (msg->attribute_value_offsets[attribute_type] > ATTRIBUTE_UNSET) {
1570 return msg->buf + msg->attribute_value_offsets[attribute_type];
1571 }
1572
1573 return "";
1574}
1575
1576int ast_msg_data_queue_frame(struct ast_channel *channel, struct ast_msg_data *msg)
1577{
1578 struct ast_frame f;
1579
1580 if (!channel) {
1581 ast_assert(channel != NULL);
1582 return -1;
1583 }
1584
1585 if (!msg) {
1586 ast_assert(msg != NULL);
1587 return -1;
1588 }
1589
1590 memset(&f, 0, sizeof(f));
1592 f.data.ptr = msg;
1593 f.datalen = msg->length;
1594 return ast_queue_frame(channel, &f);
1595}
1596
1598{
1599 const struct ast_msg_tech *match;
1600
1602
1604 if (match) {
1605 ast_log(LOG_ERROR, "Message technology already registered for '%s'\n",
1606 tech->name);
1608 return -1;
1609 }
1610
1611 if (AST_VECTOR_APPEND(&msg_techs, tech)) {
1612 ast_log(LOG_ERROR, "Failed to register message technology for '%s'\n",
1613 tech->name);
1615 return -1;
1616 }
1617 ast_verb(5, "Message technology '%s' registered.\n", tech->name);
1618
1620
1621 return 0;
1622}
1623
1624/*!
1625 * \brief Comparison callback for \c ast_msg_tech vector removal
1626 *
1627 * \param vec_elem The element in the vector being compared
1628 * \param srch The element being looked up
1629 *
1630 * \retval non-zero The items are equal
1631 * \retval 0 The items are not equal
1632 */
1633static int msg_tech_cmp(const struct ast_msg_tech *vec_elem, const struct ast_msg_tech *srch)
1634{
1635 return !strcmp(vec_elem->name, srch->name);
1636}
1637
1639{
1640 int match;
1641
1646
1647 if (match) {
1648 ast_log(LOG_ERROR, "No '%s' message technology found.\n", tech->name);
1649 return -1;
1650 }
1651
1652 ast_verb(5, "Message technology '%s' unregistered.\n", tech->name);
1653
1654 return 0;
1655}
1656
1658{
1659 const struct ast_msg_handler *match;
1660
1662
1664 if (match) {
1665 ast_log(LOG_ERROR, "Message handler already registered for '%s'\n",
1666 handler->name);
1668 return -1;
1669 }
1670
1672 ast_log(LOG_ERROR, "Failed to register message handler for '%s'\n",
1673 handler->name);
1675 return -1;
1676 }
1677 ast_verb(5, "Message handler '%s' registered.\n", handler->name);
1678
1680
1681 return 0;
1682
1683}
1684
1685/*!
1686 * \brief Comparison callback for \c ast_msg_handler vector removal
1687 *
1688 * \param vec_elem The element in the vector being compared
1689 * \param srch The element being looked up
1690 *
1691 * \retval non-zero The items are equal
1692 * \retval 0 The items are not equal
1693 */
1694static int msg_handler_cmp(const struct ast_msg_handler *vec_elem, const struct ast_msg_handler *srch)
1695{
1696 return !strcmp(vec_elem->name, srch->name);
1697}
1698
1700{
1701 int match;
1702
1707
1708 if (match) {
1709 ast_log(LOG_ERROR, "No '%s' message handler found.\n", handler->name);
1710 return -1;
1711 }
1712
1713 ast_verb(5, "Message handler '%s' unregistered.\n", handler->name);
1714 return 0;
1715}
1716
1718{
1719 if (msg_q_tp) {
1721 }
1722}
1723
1724/*!
1725 * \internal
1726 * \brief Clean up other resources on Asterisk shutdown
1727 *
1728 * \note This does not include the msg_q_tp object, which must be disposed
1729 * of prior to Asterisk checking for channel destruction in its shutdown
1730 * sequence. The atexit handlers are executed after this occurs.
1731 */
1732static void message_shutdown(void)
1733{
1735
1739 ast_manager_unregister("MessageSend");
1740
1743
1746}
1747
1748/*!
1749 * \internal
1750 * \brief Initialize stuff during Asterisk startup.
1751 *
1752 * Cleanup isn't a big deal in this function. If we return non-zero,
1753 * Asterisk is going to exit.
1754 *
1755 * \retval 0 success
1756 * \retval non-zero failure
1757 */
1759{
1760 int res;
1761
1763 if (!msg_q_tp) {
1764 return -1;
1765 }
1766
1768 if (AST_VECTOR_INIT(&msg_techs, 8)) {
1769 return -1;
1770 }
1771
1773 if (AST_VECTOR_INIT(&msg_handlers, 4)) {
1774 return -1;
1775 }
1776
1778
1783
1785
1786 return res;
1787}
Prototypes for public functions only of internal interest,.
char digit
Asterisk main include file. File version handling, generic pbx functions.
int ast_register_cleanup(void(*func)(void))
Register a function to be executed before Asterisk gracefully exits.
Definition: clicompat.c:19
#define ast_free(a)
Definition: astmm.h:180
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:191
#define ast_log
Definition: astobj2.c:42
#define ao2_iterator_next(iter)
Definition: astobj2.h:1911
#define ao2_link(container, obj)
Add an object to a container.
Definition: astobj2.h:1532
@ CMP_MATCH
Definition: astobj2.h:1027
@ CMP_STOP
Definition: astobj2.h:1028
#define OBJ_POINTER
Definition: astobj2.h:1150
@ AO2_ALLOC_OPT_LOCK_MUTEX
Definition: astobj2.h:363
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_unlink(container, obj)
Remove an object from a container.
Definition: astobj2.h:1578
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1736
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ao2_unlock(a)
Definition: astobj2.h:729
#define ao2_lock(a)
Definition: astobj2.h:717
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a list container.
Definition: astobj2.h:1327
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:409
static int tmp()
Definition: bt_open.c:389
static PGresult * result
Definition: cel_pgsql.c:84
static int match(struct ast_sockaddr *addr, unsigned short callno, unsigned short dcallno, const struct chan_iax2_pvt *cur, int check_dcallno)
Definition: chan_iax2.c:2362
@ AST_CHAN_TP_INTERNAL
Channels with this particular technology are an implementation detail of Asterisk and should generall...
Definition: channel.h:971
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2385
int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore)
Remove a datastore from a channel.
Definition: channel.c:2394
void ast_channel_clear_softhangup(struct ast_channel *chan, int flag)
Clear a set of softhangup flags from a channel.
Definition: channel.c:2432
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2541
struct varshead * ast_channel_varshead(struct ast_channel *chan)
#define ast_channel_alloc(needqueue, state, cid_num, cid_name, acctcode, exten, context, assignedids, requestor, amaflag,...)
Create a channel structure.
Definition: channel.h:1258
void ast_channel_unlink(struct ast_channel *chan)
Remove a channel from the global channels container.
Definition: channel.c:10529
#define ast_channel_lock(chan)
Definition: channel.h:2922
int ast_queue_frame(struct ast_channel *chan, struct ast_frame *f)
Queue one or more frames to a channel's frame queue.
Definition: channel.c:1139
ast_alert_status_t ast_channel_internal_alert_flush(struct ast_channel *chan)
struct ast_channel * ast_channel_release(struct ast_channel *chan)
Unlink and release reference to a channel.
Definition: channel.c:1584
struct ast_readq_list * ast_channel_readq(struct ast_channel *chan)
@ AST_SOFTHANGUP_ALL
All softhangup flags.
Definition: channel.h:1161
void ast_channel_tech_set(struct ast_channel *chan, const struct ast_channel_tech *value)
struct ast_datastore_list * ast_channel_datastores(struct ast_channel *chan)
#define ast_channel_unlock(chan)
Definition: channel.h:2923
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
Definition: channel.c:2399
@ AST_STATE_UP
Definition: channelstate.h:42
void ast_var_delete(struct ast_var_t *var)
Definition: extconf.c:2471
Asterisk datastore objects.
#define ast_datastore_alloc(info, uid)
Definition: datastore.h:85
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition: datastore.c:68
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static const char name[]
Definition: format_mp3.c:68
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:3381
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:3413
struct ast_variable * astman_get_variables_order(const struct message *m, enum variable_orders order)
Get a linked list of the Variable: headers with order specified.
Definition: manager.c:3133
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition: manager.c:3042
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition: manager.c:8041
const char * ast_msg_data_get_attribute(struct ast_msg_data *msg, enum ast_msg_data_attribute_type attribute_type)
Get attribute from ast_msg_data.
enum ast_msg_data_source_type ast_msg_data_get_source_type(struct ast_msg_data *msg)
Get "source type" from ast_msg_data.
ast_msg_data_attribute_type
Definition: message.h:454
struct ast_msg_data * ast_msg_data_alloc(enum ast_msg_data_source_type source, struct ast_msg_data_attribute attributes[], size_t count)
Allocates an ast_msg_data structure.
ast_msg_data_source_type
Definition: message.h:446
struct ast_msg_data * ast_msg_data_alloc2(enum ast_msg_data_source_type source_type, const char *to, const char *from, const char *content_type, const char *body)
Allocates an ast_msg_data structure.
struct ast_msg_data * ast_msg_data_dup(struct ast_msg_data *msg)
Clone an ast_msg_data structure.
int ast_msg_data_queue_frame(struct ast_channel *channel, struct ast_msg_data *msg)
Queue an AST_FRAME_TEXT_DATA frame containing an ast_msg_data structure.
size_t ast_msg_data_get_length(struct ast_msg_data *msg)
Get length of the structure.
@ AST_MSG_DATA_ATTR_BODY
Definition: message.h:458
@ AST_MSG_DATA_ATTR_TO
Definition: message.h:455
@ AST_MSG_DATA_ATTR_FROM
Definition: message.h:456
@ __AST_MSG_DATA_ATTR_LAST
Definition: message.h:459
@ AST_MSG_DATA_ATTR_CONTENT_TYPE
Definition: message.h:457
@ AST_MSG_DATA_SOURCE_TYPE_UNKNOWN
Definition: message.h:447
Application convenience functions, designed to give consistent look and feel to Asterisk apps.
#define AST_APP_ARG(name)
Define an application argument.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
char * strsep(char **str, const char *delims)
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1262
#define ast_frfree(fr)
@ AST_FRAME_TEXT_DATA
struct ast_frame ast_null_frame
Definition: main/frame.c:79
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define ast_verb(level,...)
#define LOG_WARNING
#define AST_LIST_HEAD_NOLOCK(name, type)
Defines a structure to be used to hold a list of specified type (with no lock).
Definition: linkedlists.h:225
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
#define ast_rwlock_wrlock(a)
Definition: lock.h:236
#define ast_rwlock_rdlock(a)
Definition: lock.h:235
#define ast_rwlock_init(rwlock)
wrapper for rwlock with tracking enabled
Definition: lock.h:224
#define ast_rwlock_destroy(rwlock)
Definition: lock.h:233
#define ast_rwlock_unlock(a)
Definition: lock.h:234
int ast_msg_set_from(struct ast_msg *msg, const char *fmt,...)
Set the 'from' URI of a message.
Definition: main/message.c:479
static void msg_destructor(void *obj)
Definition: main/message.c:424
static void chan_cleanup(struct ast_channel *chan)
Definition: main/message.c:788
static int msg_handler_cmp(const struct ast_msg_handler *vec_elem, const struct ast_msg_handler *srch)
Comparison callback for ast_msg_handler vector removal.
static int msg_set_var_full(struct ast_msg *msg, const char *name, const char *value, unsigned int outbound)
Definition: main/message.c:594
int ast_msg_send(struct ast_msg *msg, const char *to, const char *from)
Send a msg directly to an endpoint.
const char * ast_msg_get_var(struct ast_msg *msg, const char *name)
Get the specified variable on the message.
Definition: main/message.c:634
void ast_msg_shutdown(void)
static int msg_q_cb(void *data)
Definition: main/message.c:921
static int msg_data_cmp_fn(void *obj, void *arg, int flags)
Definition: main/message.c:412
size_t current
Definition: main/message.c:272
static int chan_msg_send_digit_begin(struct ast_channel *chan, char digit)
Definition: main/message.c:386
static const char app_msg_send[]
Definition: main/message.c:282
static ast_rwlock_t msg_techs_lock
Lock for msg_techs vector.
Definition: main/message.c:269
int ast_msg_handler_unregister(const struct ast_msg_handler *handler)
Unregister a ast_msg_handler.
const char * ast_msg_get_from(const struct ast_msg *msg)
Retrieve the source of this message.
Definition: main/message.c:550
static int chan_msg_write(struct ast_channel *chan, struct ast_frame *fr)
Definition: main/message.c:357
static const struct ast_datastore_info msg_datastore
Definition: main/message.c:286
static struct ast_msg_handler dialplan_msg_handler
Definition: main/message.c:906
void ast_msg_var_iterator_destroy(struct ast_msg_var_iterator *iter)
Destroy a message variable iterator.
Definition: main/message.c:720
struct ast_msg * ast_msg_destroy(struct ast_msg *msg)
Destroy an ast_msg.
Definition: main/message.c:462
struct @373 msg_techs
Vector of message technologies.
static int msg_data_func_read(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len)
static struct ast_custom_function msg_function
Definition: main/message.c:296
int ast_msg_set_endpoint(struct ast_msg *msg, const char *fmt,...)
Set the technology's endpoint associated with this message.
Definition: main/message.c:534
static int ast_msg_var_iterator_get_next(const struct ast_msg *msg, struct ast_msg_var_iterator *iter, const char **name, const char **value, unsigned int send)
Definition: main/message.c:672
static struct msg_data * msg_data_alloc(void)
Definition: main/message.c:570
int ast_msg_var_iterator_next(const struct ast_msg *msg, struct ast_msg_var_iterator *iter, const char **name, const char **value)
Get the next variable name and value that is set for sending outbound.
Definition: main/message.c:703
const char * ast_msg_get_endpoint(const struct ast_msg *msg)
Retrieve the endpoint associated with this message.
Definition: main/message.c:565
int ast_msg_init(void)
static struct ast_frame * chan_msg_read(struct ast_channel *chan)
Definition: main/message.c:346
int ast_msg_set_exten(struct ast_msg *msg, const char *fmt,...)
Set the dialplan extension for this message.
Definition: main/message.c:512
int ast_msg_set_tech(struct ast_msg *msg, const char *fmt,...)
Set the technology associated with this message.
Definition: main/message.c:523
int ast_msg_has_destination(const struct ast_msg *msg)
Determine if a particular message has a destination via some handler.
Definition: main/message.c:951
static int chan_msg_indicate(struct ast_channel *chan, int condition, const void *data, size_t datalen)
Definition: main/message.c:372
static struct ast_channel * create_msg_q_chan(void)
Definition: main/message.c:729
static const struct ast_msg_handler * msg_handler_find_by_tech_name(const char *tech_name)
static int msg_func_write(struct ast_channel *chan, const char *function, char *data, const char *value)
struct ast_msg * ast_msg_alloc(void)
Allocate a message.
Definition: main/message.c:432
static int msg_func_read(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len)
static int msg_tech_cmp(const struct ast_msg_tech *vec_elem, const struct ast_msg_tech *srch)
Comparison callback for ast_msg_tech vector removal.
static int chan_msg_send_digit_end(struct ast_channel *chan, char digit, unsigned int duration)
Definition: main/message.c:399
static struct ast_taskprocessor * msg_q_tp
Definition: main/message.c:280
int ast_msg_tech_unregister(const struct ast_msg_tech *tech)
Unregister a message technology.
static void msg_ds_destroy(void *data)
Definition: main/message.c:405
static struct ast_threadstorage msg_q_chan
Definition: main/message.c:863
int ast_msg_set_var(struct ast_msg *msg, const char *name, const char *value)
Set a variable on the message going to the dialplan.
Definition: main/message.c:629
static void msg_data_destructor(void *obj)
Definition: main/message.c:418
const char * ast_msg_get_to(const struct ast_msg *msg)
Retrieve the destination of this message.
Definition: main/message.c:555
static void message_shutdown(void)
const char * ast_msg_get_tech(const struct ast_msg *msg)
Retrieve the technology associated with this message.
Definition: main/message.c:560
int ast_msg_tech_register(const struct ast_msg_tech *tech)
Register a message technology.
const char * ast_msg_get_body(const struct ast_msg *msg)
Get the body of a message.
Definition: main/message.c:545
int ast_msg_handler_register(const struct ast_msg_handler *handler)
Register a ast_msg_handler.
int ast_msg_set_context(struct ast_msg *msg, const char *fmt,...)
Set the dialplan context for this message.
Definition: main/message.c:501
static int msg_send_exec(struct ast_channel *chan, const char *data)
static struct msg_data * msg_data_find(struct ao2_container *vars, const char *name)
Definition: main/message.c:586
int ast_msg_set_body(struct ast_msg *msg, const char *fmt,...)
Set the 'body' text of a message (in UTF-8)
Definition: main/message.c:490
static const struct ast_msg_tech * msg_find_by_tech_name(const char *tech_name)
static int msg_data_func_write(struct ast_channel *chan, const char *function, char *data, const char *value)
static void msg_route(struct ast_channel *chan, struct ast_msg *msg)
Definition: main/message.c:770
static ast_rwlock_t msg_handlers_lock
Lock for msg_handlers vector.
Definition: main/message.c:275
int ast_msg_var_iterator_next_received(const struct ast_msg *msg, struct ast_msg_var_iterator *iter, const char **name, const char **value)
Get the next variable name and value that was set on a received message.
Definition: main/message.c:708
struct @374 msg_handlers
Vector of received message handlers.
int ast_msg_set_to(struct ast_msg *msg, const char *fmt,...)
Set the 'to' URI of a message.
Definition: main/message.c:468
void ast_msg_var_unref_current(struct ast_msg_var_iterator *iter)
Unref a message var from inside an iterator loop.
Definition: main/message.c:714
static int action_messagesend(struct mansession *s, const struct message *m)
struct ast_msg_var_iterator * ast_msg_var_iterator_init(const struct ast_msg *msg)
Create a new message variable iterator.
Definition: main/message.c:658
int ast_msg_set_var_outbound(struct ast_msg *msg, const char *name, const char *value)
Set a variable on the message being sent to a message tech directly.
Definition: main/message.c:624
int ast_msg_queue(struct ast_msg *msg)
Queue a message for routing through the dialplan.
Definition: main/message.c:972
static int dialplan_handle_msg_cb(struct ast_msg *msg)
Definition: main/message.c:866
static int dialplan_has_destination_cb(const struct ast_msg *msg)
Definition: main/message.c:897
#define ATTRIBUTE_UNSET
static void destroy_msg_q_chan(void *data)
Definition: main/message.c:852
static struct ast_custom_function msg_data_function
Definition: main/message.c:307
struct ast_msg * ast_msg_ref(struct ast_msg *msg)
Bump a msg's ref count.
Definition: main/message.c:456
static struct ast_datastore * msg_datastore_find_or_create(struct ast_channel *chan)
Definition: main/message.c:994
static struct ast_channel_tech msg_chan_tech_hack
Definition: main/message.c:328
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
#define ast_manager_register_xml_core(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition: manager.h:202
@ ORDER_NATURAL
Definition: manager.h:288
#define EVENT_FLAG_MESSAGE
Definition: manager.h:95
Out-of-call text message support.
Asterisk module definitions.
int ast_register_application2(const char *app, int(*execute)(struct ast_channel *, const char *), const char *synopsis, const char *description, void *mod)
Register an application.
Definition: pbx_app.c:103
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392
#define ast_opt_hide_messaging_ami_events
Definition: options.h:137
Core PBX routines and definitions.
enum ast_pbx_result ast_pbx_run_args(struct ast_channel *c, struct ast_pbx_args *args)
Execute the PBX in the current thread.
Definition: pbx.c:4735
int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Determine whether an extension exists.
Definition: pbx.c:4175
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name.
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
int ast_explicit_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
Definition: pbx.c:6945
int __ast_custom_function_register(struct ast_custom_function *acf, struct ast_module *mod)
Register a custom function.
static const struct ast_msg_tech msg_tech
#define NULL
Definition: resample.c:96
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
Definition: stringfields.h:341
#define AST_STRING_FIELD(name)
Declare a string field.
Definition: stringfields.h:303
#define ast_string_field_build_va(x, field, fmt, args)
Set a field to a complex (built) value.
Definition: stringfields.h:591
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:521
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:359
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374
String manipulation functions.
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition: strings.h:80
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
Generic container type.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1821
Structure to describe a channel "technology", ie a channel driver See for examples:
Definition: channel.h:628
const char *const type
Definition: channel.h:629
Main Channel structure associated with a channel.
const char * data
Data structure associated with a custom dialplan function.
Definition: pbx.h:118
const char * name
Definition: pbx.h:119
Structure for a data store type.
Definition: datastore.h:31
const char * type
Definition: datastore.h:32
Structure for a data store object.
Definition: datastore.h:64
void * data
Definition: datastore.h:66
Data structure associated with a single frame of data.
union ast_frame::@226 data
enum ast_frame_type frametype
enum ast_msg_data_attribute_type type
Definition: message.h:463
Structure used to transport a message through the frame core.
enum ast_msg_data_source_type source
int attribute_value_offsets[__AST_MSG_DATA_ATTR_LAST]
An external processor of received messages.
Definition: message.h:98
const char * name
Name of the message handler.
Definition: message.h:102
A message technology.
Definition: message.h:52
int(*const msg_send)(const struct ast_msg *msg, const char *to, const char *from)
Send a message.
Definition: message.h:75
const char *const name
Name of this message technology.
Definition: message.h:61
struct msg_data * current_used
Definition: main/message.c:655
struct ao2_iterator iter
Definition: main/message.c:654
A message.
Definition: main/message.c:247
struct ao2_container * vars
Definition: main/message.c:265
const ast_string_field tech
Definition: main/message.c:263
const ast_string_field context
Definition: main/message.c:263
const ast_string_field from
Definition: main/message.c:263
const ast_string_field endpoint
Definition: main/message.c:263
const ast_string_field to
Definition: main/message.c:263
const ast_string_field exten
Definition: main/message.c:263
const ast_string_field body
Definition: main/message.c:263
Options for ast_pbx_run()
Definition: pbx.h:407
unsigned int no_hangup_chan
Definition: pbx.h:414
Structure for rwlock and tracking information.
Definition: lock.h:157
A ast_taskprocessor structure is a singleton by name.
Definition: taskprocessor.c:69
Structure for variables, used for configurations and for channel variables.
Definition: search.h:40
In case you didn't read that giant block of text above the mansession_session struct,...
Definition: manager.c:1777
struct ast_msg * msg
unsigned int send
Definition: main/message.c:239
const ast_string_field value
Definition: main/message.c:238
const ast_string_field name
Definition: main/message.c:238
Definition: ast_expr2.c:325
int value
Definition: syslog.c:37
An API for managing task processing threads that can be shared across modules.
struct ast_taskprocessor * ast_taskprocessor_get(const char *name, enum ast_tps_options create)
Get a reference to a taskprocessor with the specified name and create the taskprocessor if necessary.
void * ast_taskprocessor_unreference(struct ast_taskprocessor *tps)
Unreference the specified taskprocessor and its reference count will decrement.
@ TPS_REF_DEFAULT
return a reference to a taskprocessor, create one if it does not exist
Definition: taskprocessor.h:76
int ast_taskprocessor_push(struct ast_taskprocessor *tps, int(*task_exe)(void *datap), void *datap) attribute_warn_unused_result
Push a task into the specified taskprocessor queue and signal the taskprocessor thread.
static void handler(const char *name, int response_code, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
Definition: test_ari.c:59
const char * args
#define AST_THREADSTORAGE_CUSTOM(a, b, c)
Define a thread storage variable, with custom initialization and cleanup.
void * ast_threadstorage_get(struct ast_threadstorage *ts, size_t init_size)
Retrieve thread storage.
int ast_base64decode(unsigned char *dst, const char *src, int max)
Decode data from base64.
Definition: utils.c:296
#define ast_assert(a)
Definition: utils.h:739
#define ARRAY_LEN(a)
Definition: utils.h:666
Vector container support.
#define AST_VECTOR_ELEM_CLEANUP_NOOP(elem)
Vector element cleanup that does nothing.
Definition: vector.h:571
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:609
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition: vector.h:174
#define AST_VECTOR_REMOVE_CMP_UNORDERED(vec, value, cmp, cleanup)
Remove an element from a vector that matches the given comparison.
Definition: vector.h:488
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition: vector.h:256
#define AST_VECTOR(name, type)
Define a vector structure.
Definition: vector.h:44
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:680