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