Asterisk - The Open Source Telephony Project  GIT-master-8beac82
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"
42 #include "asterisk/taskprocessor.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 
234 struct msg_data {
238  );
239  unsigned int send; /* Whether to send out on outbound messages */
240 };
241 
243 
244 /*!
245  * \brief A message.
246  */
247 struct ast_msg {
249  /*! Where the message is going */
250  AST_STRING_FIELD(to);
251  /*! Where we "say" the message came from */
253  /*! The text to send */
254  AST_STRING_FIELD(body);
255  /*! The dialplan context for the message */
257  /*! The dialplan extension for the message */
259  /*! An endpoint associated with this message */
260  AST_STRING_FIELD(endpoint);
261  /*! The technology of the endpoint associated with this message */
262  AST_STRING_FIELD(tech);
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 */
272 AST_VECTOR(, const struct ast_msg_tech *) msg_techs;
273 
274 /*! \brief Lock for \c msg_handlers vector */
275 static ast_rwlock_t msg_handlers_lock;
276 
277 /*! \brief Vector of received message handlers */
278 AST_VECTOR(, const struct ast_msg_handler *) msg_handlers;
279 
280 static struct ast_taskprocessor *msg_q_tp;
281 
282 static const char app_msg_send[] = "MessageSend";
283 
284 static void msg_ds_destroy(void *data);
285 
286 static const struct ast_datastore_info msg_datastore = {
287  .type = "message",
288  .destroy = msg_ds_destroy,
289 };
290 
291 static int msg_func_read(struct ast_channel *chan, const char *function,
292  char *data, char *buf, size_t len);
293 static 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 
302 static int msg_data_func_read(struct ast_channel *chan, const char *function,
303  char *data, char *buf, size_t len);
304 static 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 
313 static struct ast_frame *chan_msg_read(struct ast_channel *chan);
314 static int chan_msg_write(struct ast_channel *chan, struct ast_frame *fr);
315 static int chan_msg_indicate(struct ast_channel *chan, int condition,
316  const void *data, size_t datalen);
317 static int chan_msg_send_digit_begin(struct ast_channel *chan, char digit);
318 static 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  */
346 static 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  */
357 static 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  */
372 static 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  */
386 static 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  */
399 static int chan_msg_send_digit_end(struct ast_channel *chan, char digit,
400  unsigned int duration)
401 {
402  return 0;
403 }
404 
405 static void msg_ds_destroy(void *data)
406 {
407  struct ast_msg *msg = data;
408 
409  ao2_ref(msg, -1);
410 }
411 
412 static 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 
418 static void msg_data_destructor(void *obj)
419 {
420  struct msg_data *data = obj;
422 }
423 
424 static void msg_destructor(void *obj)
425 {
426  struct ast_msg *msg = obj;
427 
429  ao2_cleanup(msg->vars);
430 }
431 
432 struct ast_msg *ast_msg_alloc(void)
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 
456 struct ast_msg *ast_msg_ref(struct ast_msg *msg)
457 {
458  ao2_ref(msg, 1);
459  return msg;
460 }
461 
463 {
464  ao2_ref(msg, -1);
465  return NULL;
466 }
467 
468 int 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 
479 int 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 
490 int 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 
501 int 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 
512 int 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 
523 int 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 
534 int 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 
545 const char *ast_msg_get_body(const struct ast_msg *msg)
546 {
547  return msg->body;
548 }
549 
550 const char *ast_msg_get_from(const struct ast_msg *msg)
551 {
552  return msg->from;
553 }
554 
555 const char *ast_msg_get_to(const struct ast_msg *msg)
556 {
557  return msg->to;
558 }
559 
560 const char *ast_msg_get_tech(const struct ast_msg *msg)
561 {
562  return msg->tech;
563 }
564 
565 const char *ast_msg_get_endpoint(const struct ast_msg *msg)
566 {
567  return msg->endpoint;
568 }
569 
570 static 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 
586 static 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 
594 static 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 
606  ast_string_field_set(data, name, name);
607  ast_string_field_set(data, value, value);
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 {
614  ast_string_field_set(data, value, value);
615  data->send = outbound;
616  }
617  }
618 
619  ao2_ref(data, -1);
620 
621  return 0;
622 }
623 
624 int 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 
629 int 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 
634 const 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 
654  struct ao2_iterator iter;
656 };
657 
659 {
660  struct ast_msg_var_iterator *iter;
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 
672 static 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 
703 int 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 {
716  ao2_cleanup(iter->current_used);
717  iter->current_used = NULL;
718 }
719 
721 {
722  if (iter) {
723  ao2_iterator_destroy(&iter->iter);
725  ast_free(iter);
726  }
727 }
728 
729 static 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 
744  msg_chan_tech_hack.properties |= AST_CHAN_TP_INTERNAL;
745  }
746 
747  ast_channel_tech_set(chan, &msg_chan_tech_hack);
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);
757  ast_channel_datastore_add(chan, ds);
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  */
770 static 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  */
788 static 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))) {
811  ast_datastore_free(ds);
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 
852 static 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 */
866 static 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 */
897 static 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  */
921 static int msg_q_cb(void *data)
922 {
923  struct ast_msg *msg = data;
924  int res = 1;
925  int i;
926 
927  ast_rwlock_rdlock(&msg_handlers_lock);
928  for (i = 0; i < AST_VECTOR_SIZE(&msg_handlers); i++) {
929  const struct ast_msg_handler *handler = AST_VECTOR_GET(&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  }
939  ast_rwlock_unlock(&msg_handlers_lock);
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 
952 {
953  int i;
954  int result = 0;
955 
956  ast_rwlock_rdlock(&msg_handlers_lock);
957  for (i = 0; i < AST_VECTOR_SIZE(&msg_handlers); i++) {
958  const struct ast_msg_handler *handler = AST_VECTOR_GET(&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  }
967  ast_rwlock_unlock(&msg_handlers_lock);
968 
969  return result;
970 }
971 
973 {
974  int res;
975  res = ast_taskprocessor_push(msg_q_tp, msg_q_cb, msg);
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, or NULL on error
992  */
994 {
995  struct ast_datastore *ds;
996 
997  if ((ds = ast_channel_datastore_find(chan, &msg_datastore, NULL))) {
998  return ds;
999  }
1000 
1001  if (!(ds = ast_datastore_alloc(&msg_datastore, NULL))) {
1002  return NULL;
1003  }
1004 
1005  if (!(ds->data = ast_msg_alloc())) {
1006  ast_datastore_free(ds);
1007  return NULL;
1008  }
1009 
1010  ast_channel_datastore_add(chan, ds);
1011 
1012  return ds;
1013 }
1014 
1015 static int msg_func_read(struct ast_channel *chan, const char *function,
1016  char *data, char *buf, size_t len)
1017 {
1018  struct ast_datastore *ds;
1019  struct ast_msg *msg;
1020 
1021  if (!chan) {
1022  ast_log(LOG_WARNING, "No channel was provided to %s function.\n", function);
1023  return -1;
1024  }
1025 
1026  ast_channel_lock(chan);
1027 
1028  if (!(ds = ast_channel_datastore_find(chan, &msg_datastore, NULL))) {
1029  ast_channel_unlock(chan);
1030  ast_log(LOG_ERROR, "No MESSAGE data found on the channel to read.\n");
1031  return -1;
1032  }
1033 
1034  msg = ds->data;
1035  ao2_ref(msg, +1);
1036  ast_channel_unlock(chan);
1037 
1038  ao2_lock(msg);
1039 
1040  if (!strcasecmp(data, "to")) {
1041  ast_copy_string(buf, msg->to, len);
1042  } else if (!strcasecmp(data, "from")) {
1043  ast_copy_string(buf, msg->from, len);
1044  } else if (!strcasecmp(data, "body")) {
1045  ast_copy_string(buf, msg->body, len);
1046  } else {
1047  ast_log(LOG_WARNING, "Invalid argument to MESSAGE(): '%s'\n", data);
1048  }
1049 
1050  ao2_unlock(msg);
1051  ao2_ref(msg, -1);
1052 
1053  return 0;
1054 }
1055 
1056 static int msg_func_write(struct ast_channel *chan, const char *function,
1057  char *data, const char *value)
1058 {
1059  struct ast_datastore *ds;
1060  struct ast_msg *msg;
1061 
1062  if (!chan) {
1063  ast_log(LOG_WARNING, "No channel was provided to %s function.\n", function);
1064  return -1;
1065  }
1066 
1067  ast_channel_lock(chan);
1068 
1069  if (!(ds = msg_datastore_find_or_create(chan))) {
1070  ast_channel_unlock(chan);
1071  return -1;
1072  }
1073 
1074  msg = ds->data;
1075  ao2_ref(msg, +1);
1076  ast_channel_unlock(chan);
1077 
1078  ao2_lock(msg);
1079 
1080  if (!strcasecmp(data, "to")) {
1081  ast_msg_set_to(msg, "%s", value);
1082  } else if (!strcasecmp(data, "from")) {
1083  ast_msg_set_from(msg, "%s", value);
1084  } else if (!strcasecmp(data, "body")) {
1085  ast_msg_set_body(msg, "%s", value);
1086  } else if (!strcasecmp(data, "custom_data")) {
1087  int outbound = -1;
1088  if (!strcasecmp(value, "mark_all_outbound")) {
1089  outbound = 1;
1090  } else if (!strcasecmp(value, "clear_all_outbound")) {
1091  outbound = 0;
1092  } else {
1093  ast_log(LOG_WARNING, "'%s' is not a valid value for custom_data\n", value);
1094  }
1095 
1096  if (outbound != -1) {
1097  struct msg_data *hdr_data;
1098  struct ao2_iterator iter = ao2_iterator_init(msg->vars, 0);
1099 
1100  while ((hdr_data = ao2_iterator_next(&iter))) {
1101  hdr_data->send = outbound;
1102  ao2_ref(hdr_data, -1);
1103  }
1104  ao2_iterator_destroy(&iter);
1105  }
1106  } else {
1107  ast_log(LOG_WARNING, "'%s' is not a valid write argument.\n", data);
1108  }
1109 
1110  ao2_unlock(msg);
1111  ao2_ref(msg, -1);
1112 
1113  return 0;
1114 }
1115 
1116 static int msg_data_func_read(struct ast_channel *chan, const char *function,
1117  char *data, char *buf, size_t len)
1118 {
1119  struct ast_datastore *ds;
1120  struct ast_msg *msg;
1121  const char *val;
1122 
1123  if (!chan) {
1124  ast_log(LOG_WARNING, "No channel was provided to %s function.\n", function);
1125  return -1;
1126  }
1127 
1128  ast_channel_lock(chan);
1129 
1130  if (!(ds = ast_channel_datastore_find(chan, &msg_datastore, NULL))) {
1131  ast_channel_unlock(chan);
1132  ast_log(LOG_ERROR, "No MESSAGE data found on the channel to read.\n");
1133  return -1;
1134  }
1135 
1136  msg = ds->data;
1137  ao2_ref(msg, +1);
1138  ast_channel_unlock(chan);
1139 
1140  ao2_lock(msg);
1141 
1142  if ((val = ast_msg_get_var(msg, data))) {
1143  ast_copy_string(buf, val, len);
1144  }
1145 
1146  ao2_unlock(msg);
1147  ao2_ref(msg, -1);
1148 
1149  return 0;
1150 }
1151 
1152 static int msg_data_func_write(struct ast_channel *chan, const char *function,
1153  char *data, const char *value)
1154 {
1155  struct ast_datastore *ds;
1156  struct ast_msg *msg;
1157 
1158  if (!chan) {
1159  ast_log(LOG_WARNING, "No channel was provided to %s function.\n", function);
1160  return -1;
1161  }
1162 
1163  ast_channel_lock(chan);
1164 
1165  if (!(ds = msg_datastore_find_or_create(chan))) {
1166  ast_channel_unlock(chan);
1167  return -1;
1168  }
1169 
1170  msg = ds->data;
1171  ao2_ref(msg, +1);
1172  ast_channel_unlock(chan);
1173 
1174  ao2_lock(msg);
1175 
1176  ast_msg_set_var_outbound(msg, data, value);
1177 
1178  ao2_unlock(msg);
1179  ao2_ref(msg, -1);
1180 
1181  return 0;
1182 }
1183 
1184 /*!
1185  * \internal \brief Find a \c ast_msg_tech by its technology name
1186  *
1187  * \param tech_name The name of the message technology
1188  *
1189  * \note \c msg_techs should be locked via \c msg_techs_lock prior to
1190  * calling this function
1191  *
1192  * \retval NULL if no \c ast_msg_tech has been registered
1193  * \retval \c ast_msg_tech if registered
1194  */
1195 static const struct ast_msg_tech *msg_find_by_tech_name(const char *tech_name)
1196 {
1197  const struct ast_msg_tech *current;
1198  int i;
1199 
1200  for (i = 0; i < AST_VECTOR_SIZE(&msg_techs); i++) {
1201  current = AST_VECTOR_GET(&msg_techs, i);
1202  if (!strcmp(current->name, tech_name)) {
1203  return current;
1204  }
1205  }
1206 
1207  return NULL;
1208 }
1209 
1210 /*!
1211  * \internal \brief Find a \c ast_msg_handler by its technology name
1212  *
1213  * \param tech_name The name of the message technology
1214  *
1215  * \note \c msg_handlers should be locked via \c msg_handlers_lock
1216  * prior to calling this function
1217  *
1218  * \retval NULL if no \c ast_msg_handler has been registered
1219  * \retval \c ast_msg_handler if registered
1220  */
1221 static const struct ast_msg_handler *msg_handler_find_by_tech_name(const char *tech_name)
1222 {
1223  const struct ast_msg_handler *current;
1224  int i;
1225 
1226  for (i = 0; i < AST_VECTOR_SIZE(&msg_handlers); i++) {
1227  current = AST_VECTOR_GET(&msg_handlers, i);
1228  if (!strcmp(current->name, tech_name)) {
1229  return current;
1230  }
1231  }
1232 
1233  return NULL;
1234 }
1235 
1236 /*!
1237  * \internal
1238  * \brief MessageSend() application
1239  */
1240 static int msg_send_exec(struct ast_channel *chan, const char *data)
1241 {
1242  struct ast_datastore *ds;
1243  struct ast_msg *msg;
1244  char *tech_name;
1245  const struct ast_msg_tech *msg_tech;
1246  char *parse;
1247  int res = -1;
1250  AST_APP_ARG(from);
1251  AST_APP_ARG(to);
1252  );
1253 
1254  if (ast_strlen_zero(data)) {
1255  ast_log(LOG_WARNING, "An argument is required to MessageSend()\n");
1256  pbx_builtin_setvar_helper(chan, "MESSAGE_SEND_STATUS", "INVALID_URI");
1257  return 0;
1258  }
1259 
1260  parse = ast_strdupa(data);
1261  AST_STANDARD_APP_ARGS(args, parse);
1262 
1263  if (ast_strlen_zero(args.destination)) {
1264  ast_log(LOG_WARNING, "A 'to' URI is required for MessageSend()\n");
1265  pbx_builtin_setvar_helper(chan, "MESSAGE_SEND_STATUS", "INVALID_URI");
1266  return 0;
1267  }
1268 
1269  ast_channel_lock(chan);
1270 
1271  if (!(ds = ast_channel_datastore_find(chan, &msg_datastore, NULL))) {
1272  ast_channel_unlock(chan);
1273  ast_log(LOG_WARNING, "No message data found on channel to send.\n");
1274  pbx_builtin_setvar_helper(chan, "MESSAGE_SEND_STATUS", "FAILURE");
1275  return 0;
1276  }
1277 
1278  msg = ds->data;
1279  ao2_ref(msg, +1);
1280  ast_channel_unlock(chan);
1281 
1282  tech_name = ast_strdupa(args.destination);
1283  tech_name = strsep(&tech_name, ":");
1284 
1285  ast_rwlock_rdlock(&msg_techs_lock);
1286  msg_tech = msg_find_by_tech_name(tech_name);
1287 
1288  if (!msg_tech) {
1289  ast_log(LOG_WARNING, "No message technology '%s' found.\n", tech_name);
1290  pbx_builtin_setvar_helper(chan, "MESSAGE_SEND_STATUS", "INVALID_PROTOCOL");
1291  goto exit_cleanup;
1292  }
1293 
1294  /*
1295  * If there was a "to" in the call to MessageSend,
1296  * replace the to already in the channel datastore.
1297  */
1298  if (!ast_strlen_zero(args.to)) {
1299  ast_string_field_set(msg, to, args.to);
1300  }
1301 
1302  /*
1303  * The message lock is held here to safely allow the technology
1304  * implementation to access the message fields without worrying
1305  * that they could change.
1306  */
1307  ao2_lock(msg);
1308  res = msg_tech->msg_send(msg, S_OR(args.destination, ""), S_OR(args.from, ""));
1309  ao2_unlock(msg);
1310 
1311  pbx_builtin_setvar_helper(chan, "MESSAGE_SEND_STATUS", res ? "FAILURE" : "SUCCESS");
1312 
1313 exit_cleanup:
1314  ast_rwlock_unlock(&msg_techs_lock);
1315  ao2_ref(msg, -1);
1316 
1317  return 0;
1318 }
1319 
1320 static int action_messagesend(struct mansession *s, const struct message *m)
1321 {
1322  const char *destination = astman_get_header(m, "Destination");
1323  const char *to = astman_get_header(m, "To");
1324  const char *from = astman_get_header(m, "From");
1325  const char *body = astman_get_header(m, "Body");
1326  const char *base64body = astman_get_header(m, "Base64Body");
1327  const char *to_override = NULL;
1328  char base64decoded[1301] = { 0, };
1329  char *tech_name = NULL;
1330  struct ast_variable *vars = NULL;
1331  struct ast_variable *data = NULL;
1332  const struct ast_msg_tech *msg_tech;
1333  struct ast_msg *msg;
1334  int res = -1;
1335 
1336  if (!ast_strlen_zero(destination)) {
1337  if (!ast_strlen_zero(to)) {
1338  to_override = to;
1339  }
1340  to = destination;
1341  } else {
1342  if (ast_strlen_zero(to)) {
1343  astman_send_error(s, m, "No 'To' address specified.");
1344  return 0;
1345  }
1346  }
1347 
1348  if (!ast_strlen_zero(base64body)) {
1349  ast_base64decode((unsigned char *) base64decoded, base64body, sizeof(base64decoded) - 1);
1350  body = base64decoded;
1351  }
1352 
1353  tech_name = ast_strdupa(to);
1354  tech_name = strsep(&tech_name, ":");
1355 
1356  ast_rwlock_rdlock(&msg_techs_lock);
1357  msg_tech = msg_find_by_tech_name(tech_name);
1358  if (!msg_tech) {
1359  ast_rwlock_unlock(&msg_techs_lock);
1360  astman_send_error(s, m, "Message technology not found.");
1361  return 0;
1362  }
1363 
1364  if (!(msg = ast_msg_alloc())) {
1365  ast_rwlock_unlock(&msg_techs_lock);
1366  astman_send_error(s, m, "Internal failure\n");
1367  return 0;
1368  }
1369 
1371  for (vars = data; vars; vars = vars->next) {
1372  ast_msg_set_var_outbound(msg, vars->name, vars->value);
1373  }
1374 
1375  ast_msg_set_body(msg, "%s", body);
1376 
1377  if (to_override) {
1378  ast_string_field_set(msg, to, to_override);
1379  }
1380 
1381  res = msg_tech->msg_send(msg, S_OR(to, ""), S_OR(from, ""));
1382 
1383  ast_rwlock_unlock(&msg_techs_lock);
1384 
1385  ast_variables_destroy(vars);
1386  ao2_ref(msg, -1);
1387 
1388  if (res) {
1389  astman_send_error(s, m, "Message failed to send.");
1390  } else {
1391  astman_send_ack(s, m, "Message successfully sent");
1392  }
1393  return 0;
1394 }
1395 
1396 int ast_msg_send(struct ast_msg *msg, const char *to, const char *from)
1397 {
1398  char *tech_name = NULL;
1399  const struct ast_msg_tech *msg_tech;
1400  int res = -1;
1401 
1402  if (ast_strlen_zero(to)) {
1403  ao2_ref(msg, -1);
1404  return -1;
1405  }
1406 
1407  tech_name = ast_strdupa(to);
1408  tech_name = strsep(&tech_name, ":");
1409 
1410  ast_rwlock_rdlock(&msg_techs_lock);
1411  msg_tech = msg_find_by_tech_name(tech_name);
1412 
1413  if (!msg_tech) {
1414  ast_log(LOG_ERROR, "Unknown message tech: %s\n", tech_name);
1415  ast_rwlock_unlock(&msg_techs_lock);
1416  return -1;
1417  }
1418 
1419  res = msg_tech->msg_send(msg, S_OR(to, ""), S_OR(from, ""));
1420 
1421  ast_rwlock_unlock(&msg_techs_lock);
1422 
1423  ao2_ref(msg, -1);
1424 
1425  return res;
1426 }
1427 
1428 /*!
1429  * \brief Structure used to transport a message through the frame core
1430  * \since 13.22.0
1431  * \since 15.5.0
1432  */
1434  /*! The length of this structure plus the actual length of the allocated buffer */
1435  size_t length;
1437  /*! These are indices into the buffer where teh attribute starts */
1438  int attribute_value_offsets[__AST_MSG_DATA_ATTR_LAST];
1439  /*! The buffer containing the NULL separated attributes */
1440  char buf[0];
1441 };
1442 
1443 #define ATTRIBUTE_UNSET -1
1444 
1446  struct ast_msg_data_attribute attributes[], size_t count)
1447 {
1448  struct ast_msg_data *msg;
1449  size_t len = sizeof(*msg);
1450  size_t i;
1451  size_t current_offset = 0;
1452  enum ast_msg_data_attribute_type attr_type;
1453 
1454  if (!attributes) {
1455  ast_assert(attributes != NULL);
1456  return NULL;
1457  }
1458 
1459  if (!count) {
1460  ast_assert(count > 0);
1461  return NULL;
1462  }
1463 
1464  /* Calculate the length required for the buffer */
1465  for (i=0; i < count; i++) {
1466  if (!attributes[i].value) {
1467  ast_assert(attributes[i].value != NULL);
1468  return NULL;
1469  }
1470  len += (strlen(attributes[i].value) + 1);
1471  }
1472 
1473  msg = ast_calloc(1, len);
1474  if (!msg) {
1475  return NULL;
1476  }
1477  msg->source = source;
1478  msg->length = len;
1479 
1480  /* Mark all of the attributes as unset */
1481  for (attr_type = 0; attr_type < __AST_MSG_DATA_ATTR_LAST; attr_type++) {
1482  msg->attribute_value_offsets[attr_type] = ATTRIBUTE_UNSET;
1483  }
1484 
1485  /* Set the ones we have and increment the offset */
1486  for (i=0; i < count; i++) {
1487  len = (strlen(attributes[i].value) + 1);
1488  ast_copy_string(msg->buf + current_offset, attributes[i].value, len); /* Safe */
1489  msg->attribute_value_offsets[attributes[i].type] = current_offset;
1490  current_offset += len;
1491  }
1492 
1493  return msg;
1494 }
1495 
1497  const char *to, const char *from, const char *content_type, const char *body)
1498 {
1499  struct ast_msg_data_attribute attrs[] =
1500  {
1501  {
1503  .value = (char *)S_OR(to, ""),
1504  },
1505  {
1506  .type = AST_MSG_DATA_ATTR_FROM,
1507  .value = (char *)S_OR(from, ""),
1508  },
1509  {
1511  .value = (char *)S_OR(content_type, ""),
1512  },
1513  {
1514  .type = AST_MSG_DATA_ATTR_BODY,
1515  .value = (char *)S_OR(body, ""),
1516  },
1517  };
1518 
1519  return ast_msg_data_alloc(source_type, attrs, ARRAY_LEN(attrs));
1520 }
1521 
1523 {
1524  struct ast_msg_data *dest;
1525 
1526  if (!msg) {
1527  ast_assert(msg != NULL);
1528  return NULL;
1529  }
1530 
1531  dest = ast_malloc(msg->length);
1532  if (!dest) {
1533  return NULL;
1534  }
1535  memcpy(dest, msg, msg->length);
1536 
1537  return dest;
1538 }
1539 
1541 {
1542  if (!msg) {
1543  ast_assert(msg != NULL);
1544  return 0;
1545  }
1546 
1547  return msg->length;
1548 }
1549 
1551 {
1552  if (!msg) {
1553  ast_assert(msg != NULL);
1555  }
1556 
1557  return msg->source;
1558 }
1559 
1561  enum ast_msg_data_attribute_type attribute_type)
1562 {
1563  if (!msg) {
1564  ast_assert(msg != NULL);
1565  return "";
1566  }
1567 
1568  if (msg->attribute_value_offsets[attribute_type] > ATTRIBUTE_UNSET) {
1569  return msg->buf + msg->attribute_value_offsets[attribute_type];
1570  }
1571 
1572  return "";
1573 }
1574 
1576 {
1577  struct ast_frame f;
1578 
1579  if (!channel) {
1580  ast_assert(channel != NULL);
1581  return -1;
1582  }
1583 
1584  if (!msg) {
1585  ast_assert(msg != NULL);
1586  return -1;
1587  }
1588 
1589  memset(&f, 0, sizeof(f));
1591  f.data.ptr = msg;
1592  f.datalen = msg->length;
1593  return ast_queue_frame(channel, &f);
1594 }
1595 
1596 int ast_msg_tech_register(const struct ast_msg_tech *tech)
1597 {
1598  const struct ast_msg_tech *match;
1599 
1600  ast_rwlock_wrlock(&msg_techs_lock);
1601 
1602  match = msg_find_by_tech_name(tech->name);
1603  if (match) {
1604  ast_log(LOG_ERROR, "Message technology already registered for '%s'\n",
1605  tech->name);
1606  ast_rwlock_unlock(&msg_techs_lock);
1607  return -1;
1608  }
1609 
1610  if (AST_VECTOR_APPEND(&msg_techs, tech)) {
1611  ast_log(LOG_ERROR, "Failed to register message technology for '%s'\n",
1612  tech->name);
1613  ast_rwlock_unlock(&msg_techs_lock);
1614  return -1;
1615  }
1616  ast_verb(3, "Message technology '%s' registered.\n", tech->name);
1617 
1618  ast_rwlock_unlock(&msg_techs_lock);
1619 
1620  return 0;
1621 }
1622 
1623 /*!
1624  * \brief Comparison callback for \c ast_msg_tech vector removal
1625  *
1626  * \param vec_elem The element in the vector being compared
1627  * \param srch The element being looked up
1628  *
1629  * \retval non-zero The items are equal
1630  * \retval 0 The items are not equal
1631  */
1632 static int msg_tech_cmp(const struct ast_msg_tech *vec_elem, const struct ast_msg_tech *srch)
1633 {
1634  return !strcmp(vec_elem->name, srch->name);
1635 }
1636 
1637 int ast_msg_tech_unregister(const struct ast_msg_tech *tech)
1638 {
1639  int match;
1640 
1641  ast_rwlock_wrlock(&msg_techs_lock);
1642  match = AST_VECTOR_REMOVE_CMP_UNORDERED(&msg_techs, tech, msg_tech_cmp,
1644  ast_rwlock_unlock(&msg_techs_lock);
1645 
1646  if (match) {
1647  ast_log(LOG_ERROR, "No '%s' message technology found.\n", tech->name);
1648  return -1;
1649  }
1650 
1651  ast_verb(2, "Message technology '%s' unregistered.\n", tech->name);
1652 
1653  return 0;
1654 }
1655 
1657 {
1658  const struct ast_msg_handler *match;
1659 
1660  ast_rwlock_wrlock(&msg_handlers_lock);
1661 
1662  match = msg_handler_find_by_tech_name(handler->name);
1663  if (match) {
1664  ast_log(LOG_ERROR, "Message handler already registered for '%s'\n",
1665  handler->name);
1666  ast_rwlock_unlock(&msg_handlers_lock);
1667  return -1;
1668  }
1669 
1670  if (AST_VECTOR_APPEND(&msg_handlers, handler)) {
1671  ast_log(LOG_ERROR, "Failed to register message handler for '%s'\n",
1672  handler->name);
1673  ast_rwlock_unlock(&msg_handlers_lock);
1674  return -1;
1675  }
1676  ast_verb(2, "Message handler '%s' registered.\n", handler->name);
1677 
1678  ast_rwlock_unlock(&msg_handlers_lock);
1679 
1680  return 0;
1681 
1682 }
1683 
1684 /*!
1685  * \brief Comparison callback for \c ast_msg_handler vector removal
1686  *
1687  * \param vec_elem The element in the vector being compared
1688  * \param srch The element being looked up
1689  *
1690  * \retval non-zero The items are equal
1691  * \retval 0 The items are not equal
1692  */
1693 static int msg_handler_cmp(const struct ast_msg_handler *vec_elem, const struct ast_msg_handler *srch)
1694 {
1695  return !strcmp(vec_elem->name, srch->name);
1696 }
1697 
1699 {
1700  int match;
1701 
1702  ast_rwlock_wrlock(&msg_handlers_lock);
1703  match = AST_VECTOR_REMOVE_CMP_UNORDERED(&msg_handlers, handler, msg_handler_cmp,
1705  ast_rwlock_unlock(&msg_handlers_lock);
1706 
1707  if (match) {
1708  ast_log(LOG_ERROR, "No '%s' message handler found.\n", handler->name);
1709  return -1;
1710  }
1711 
1712  ast_verb(3, "Message handler '%s' unregistered.\n", handler->name);
1713  return 0;
1714 }
1715 
1717 {
1718  if (msg_q_tp) {
1719  msg_q_tp = ast_taskprocessor_unreference(msg_q_tp);
1720  }
1721 }
1722 
1723 /*!
1724  * \internal
1725  * \brief Clean up other resources on Asterisk shutdown
1726  *
1727  * \note This does not include the msg_q_tp object, which must be disposed
1728  * of prior to Asterisk checking for channel destruction in its shutdown
1729  * sequence. The atexit handlers are executed after this occurs.
1730  */
1731 static void message_shutdown(void)
1732 {
1733  ast_msg_handler_unregister(&dialplan_msg_handler);
1734 
1735  ast_custom_function_unregister(&msg_function);
1736  ast_custom_function_unregister(&msg_data_function);
1737  ast_unregister_application(app_msg_send);
1738  ast_manager_unregister("MessageSend");
1739 
1740  AST_VECTOR_FREE(&msg_techs);
1741  ast_rwlock_destroy(&msg_techs_lock);
1742 
1743  AST_VECTOR_FREE(&msg_handlers);
1744  ast_rwlock_destroy(&msg_handlers_lock);
1745 }
1746 
1747 /*
1748  * \internal
1749  * \brief Initialize stuff during Asterisk startup.
1750  *
1751  * Cleanup isn't a big deal in this function. If we return non-zero,
1752  * Asterisk is going to exit.
1753  *
1754  * \retval 0 success
1755  * \retval non-zero failure
1756  */
1757 int ast_msg_init(void)
1758 {
1759  int res;
1760 
1761  msg_q_tp = ast_taskprocessor_get("ast_msg_queue", TPS_REF_DEFAULT);
1762  if (!msg_q_tp) {
1763  return -1;
1764  }
1765 
1766  ast_rwlock_init(&msg_techs_lock);
1767  if (AST_VECTOR_INIT(&msg_techs, 8)) {
1768  return -1;
1769  }
1770 
1771  ast_rwlock_init(&msg_handlers_lock);
1772  if (AST_VECTOR_INIT(&msg_handlers, 4)) {
1773  return -1;
1774  }
1775 
1776  res = ast_msg_handler_register(&dialplan_msg_handler);
1777 
1778  res |= __ast_custom_function_register(&msg_function, NULL);
1779  res |= __ast_custom_function_register(&msg_data_function, NULL);
1780  res |= ast_register_application2(app_msg_send, msg_send_exec, NULL, NULL, NULL);
1782 
1784 
1785  return res;
1786 }
const char * name
Definition: pbx.h:119
size_t ast_msg_data_get_length(struct ast_msg_data *msg)
Get length of the structure.
Definition: message.c:1540
const char * type
Definition: datastore.h:32
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition: vector.h:174
struct ast_variable * next
All softhangup flags.
Definition: channel.h:1162
AST_VECTOR(const struct ast_msg_tech *)
Vector of message technologies.
Definition: message.c:272
Options for ast_pbx_run()
Definition: pbx.h:391
char digit
#define ast_rwlock_rdlock(a)
Definition: lock.h:233
#define ast_channel_lock(chan)
Definition: channel.h:2913
static char exten[AST_MAX_EXTENSION]
Definition: chan_alsa.c:122
Main Channel structure associated with a channel.
static int dialplan_has_destination_cb(const struct ast_msg *msg)
Definition: message.c:897
const char *const type
Definition: channel.h:630
Asterisk main include file. File version handling, generic pbx functions.
int ast_msg_set_context(struct ast_msg *msg, const char *fmt,...)
Set the dialplan context for this message.
Definition: message.c:501
enum ast_msg_data_source_type ast_msg_data_get_source_type(struct ast_msg_data *msg)
Get "source type" from ast_msg_data.
Definition: message.c:1550
void ast_msg_shutdown(void)
Definition: message.c:1716
static struct ast_channel_tech msg_chan_tech_hack
Definition: message.c:328
void * ast_threadstorage_get(struct ast_threadstorage *ts, size_t init_size)
Retrieve thread storage.
int(*const handle_msg)(struct ast_msg *msg)
The function callback that will handle the message.
Definition: message.h:112
struct ao2_iterator iter
Definition: message.c:654
String manipulation functions.
enum ast_msg_data_attribute_type type
Definition: message.h:463
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: message.c:708
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1263
Definition: ast_expr2.c:325
struct ast_msg_data * ast_msg_data_dup(struct ast_msg_data *msg)
Clone an ast_msg_data structure.
Definition: message.c:1522
#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
static void msg_route(struct ast_channel *chan, struct ast_msg *msg)
Definition: message.c:770
static int msg_data_cmp_fn(void *obj, void *arg, int flags)
Definition: message.c:412
#define ast_rwlock_destroy(rwlock)
Definition: lock.h:231
An external processor of received messages.
Definition: message.h:98
struct ast_msg * ast_msg_alloc(void)
Allocate a message.
Definition: message.c:432
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define OBJ_POINTER
Definition: astobj2.h:1154
struct ast_channel * ast_channel_release(struct ast_channel *chan)
Unlink and release reference to a channel.
Definition: channel.c:1580
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
#define LOG_WARNING
Definition: logger.h:274
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...
static void msg_data_destructor(void *obj)
Definition: message.c:418
const char * ast_msg_get_body(const struct ast_msg *msg)
Get the body of a message.
Definition: message.c:545
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Definition: astobj2.h:1335
const ast_string_field to
Definition: message.c:263
int ast_msg_handler_register(const struct ast_msg_handler *handler)
Register a ast_msg_handler.
Definition: message.c:1656
Structure for variables, used for configurations and for channel variables.
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition: vector.h:256
static struct ast_threadstorage msg_q_chan
Definition: message.c:863
return a reference to a taskprocessor, create one if it does not exist
Definition: taskprocessor.h:75
const char *const name
Name of this message technology.
Definition: message.h:61
Structure for a data store type.
Definition: datastore.h:31
Structure used to transport a message through the frame core.
Definition: message.c:1433
int ast_msg_handler_unregister(const struct ast_msg_handler *handler)
Unregister a ast_msg_handler.
Definition: message.c:1698
static void destroy_msg_q_chan(void *data)
Definition: message.c:852
static void message_shutdown(void)
Definition: message.c:1731
unsigned int send
Definition: message.c:239
static const struct ast_msg_tech * msg_find_by_tech_name(const char *tech_name)
Definition: message.c:1195
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
const ast_string_field endpoint
Definition: message.c:263
static struct msg_data * msg_data_alloc(void)
Definition: message.c:570
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
Definition: stringfields.h:337
int ast_explicit_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
Definition: pbx.c:6987
#define ast_assert(a)
Definition: utils.h:710
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:3191
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.
Definition: message.c:1445
#define ao2_unlock(a)
Definition: astobj2.h:730
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:2316
static const struct ast_msg_tech msg_tech
Structure for a data store object.
Definition: datastore.h:68
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:2400
const char * ast_msg_get_var(struct ast_msg *msg, const char *name)
Get the specified variable on the message.
Definition: message.c:634
struct varshead * ast_channel_varshead(struct ast_channel *chan)
const char * args
static struct ast_custom_function msg_function
Definition: message.c:296
#define NULL
Definition: resample.c:96
const char * data
int(*const has_destination)(const struct ast_msg *msg)
Return whether or not the message has a valid destination.
Definition: message.h:127
#define ast_manager_register_xml_core(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition: manager.h:197
Out-of-call text message support.
struct ast_msg * msg
#define ast_rwlock_unlock(a)
Definition: lock.h:232
static int msg_data_func_read(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len)
Definition: message.c:1116
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392
void ast_msg_var_unref_current(struct ast_msg_var_iterator *iter)
Unref a message var from inside an iterator loop.
Definition: message.c:714
static struct ast_custom_function msg_data_function
Definition: message.c:307
#define ast_verb(level,...)
Definition: logger.h:463
struct ast_msg * ast_msg_ref(struct ast_msg *msg)
Bump a msg&#39;s ref count.
Definition: message.c:456
const char * ast_msg_get_endpoint(const struct ast_msg *msg)
Retrieve the endpoint associated with this message.
Definition: message.c:565
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition: datastore.c:68
const ast_string_field exten
Definition: message.c:263
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: message.c:703
static int msg_data_func_write(struct ast_channel *chan, const char *function, char *data, const char *value)
Definition: message.c:1152
const char * astman_get_header(const struct message *m, char *var)
Get header from mananger transaction.
Definition: manager.c:2820
void ast_channel_tech_set(struct ast_channel *chan, const struct ast_channel_tech *value)
static void msg_destructor(void *obj)
Definition: message.c:424
Asterisk datastore objects.
static int msg_func_write(struct ast_channel *chan, const char *function, char *data, const char *value)
Definition: message.c:1056
ast_alert_status_t ast_channel_internal_alert_flush(struct ast_channel *chan)
int ast_base64decode(unsigned char *dst, const char *src, int max)
Decode data from base64.
Definition: main/utils.c:294
struct ast_readq_list * ast_channel_readq(struct ast_channel *chan)
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
int ast_msg_send(struct ast_msg *msg, const char *to, const char *from)
Send a msg directly to an endpoint.
Definition: message.c:1396
#define ast_opt_hide_messaging_ami_events
Definition: options.h:137
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113
static int msg_q_cb(void *data)
Definition: message.c:921
enum ast_msg_data_source_type source
Definition: message.c:1436
struct ao2_container * vars
Definition: message.c:265
int ast_register_cleanup(void(*func)(void))
Register a function to be executed before Asterisk gracefully exits.
Definition: clicompat.c:19
void ast_channel_clear_softhangup(struct ast_channel *chan, int flag)
Clear a set of softhangup flags from a channel.
Definition: channel.c:2433
static void msg_ds_destroy(void *data)
Definition: message.c:405
#define AST_VECTOR_ELEM_CLEANUP_NOOP(elem)
Vector element cleanup that does nothing.
Definition: vector.h:573
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:353
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
Data structure associated with a custom dialplan function.
Definition: pbx.h:118
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:4739
const ast_string_field body
Definition: message.c:263
static struct msg_data * msg_data_find(struct ao2_container *vars, const char *name)
Definition: message.c:586
#define AST_STRING_FIELD(name)
Declare a string field.
Definition: stringfields.h:299
#define ao2_ref(o, delta)
Definition: astobj2.h:464
struct ast_datastore_list * ast_channel_datastores(struct ast_channel *chan)
In case you didn&#39;t read that giant block of text above the mansession_session struct, the struct mansession is named this solely to keep the API the same in Asterisk. This structure really represents data that is different from Manager action to Manager action. The mansession_session pointer contained within points to session-specific data.
Definition: manager.c:1625
union ast_frame::@250 data
static int chan_msg_write(struct ast_channel *chan, struct ast_frame *fr)
Definition: message.c:357
#define ao2_lock(a)
Definition: astobj2.h:718
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
int ast_msg_set_exten(struct ast_msg *msg, const char *fmt,...)
Set the dialplan extension for this message.
Definition: message.c:512
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:193
int ast_msg_queue(struct ast_msg *msg)
Queue a message for routing through the dialplan.
Definition: message.c:972
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:832
AST_LIST_HEAD_NOLOCK(contactliststruct, contact)
ast_msg_data_source_type
Definition: message.h:446
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:4179
static struct ast_datastore * msg_datastore_find_or_create(struct ast_channel *chan)
Definition: message.c:993
Structure to describe a channel "technology", ie a channel driver See for examples: ...
Definition: channel.h:629
#define ARRAY_LEN(a)
Definition: utils.h:639
Core PBX routines and definitions.
int ast_queue_frame(struct ast_channel *chan, struct ast_frame *f)
Queue one or more frames to a channel&#39;s frame queue.
Definition: channel.c:1135
static int msg_set_var_full(struct ast_msg *msg, const char *name, const char *value, unsigned int outbound)
Definition: message.c:594
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition: manager.c:7258
void ast_msg_var_iterator_destroy(struct ast_msg_var_iterator *iter)
Destroy a message variable iterator.
Definition: message.c:720
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
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.
Definition: message.c:1575
const ast_string_field name
Definition: message.c:238
#define LOG_ERROR
Definition: logger.h:285
struct ast_msg_var_iterator * ast_msg_var_iterator_init(const struct ast_msg *msg)
Create a new message variable iterator.
Definition: message.c:658
const char * ast_msg_get_to(const struct ast_msg *msg)
Retrieve the destination of this message.
Definition: message.c:555
int attribute_value_offsets[__AST_MSG_DATA_ATTR_LAST]
Definition: message.c:1438
#define ao2_unlink(container, obj)
Definition: astobj2.h:1598
#define ATTRIBUTE_UNSET
Definition: message.c:1443
static int dialplan_handle_msg_cb(struct ast_msg *msg)
Definition: message.c:866
int ast_msg_set_from(struct ast_msg *msg, const char *fmt,...)
Set the &#39;from&#39; URI of a message.
Definition: message.c:479
static int chan_msg_send_digit_end(struct ast_channel *chan, char digit, unsigned int duration)
Definition: message.c:399
#define ast_rwlock_init(rwlock)
wrapper for rwlock with tracking enabled
Definition: lock.h:222
void ast_var_delete(struct ast_var_t *var)
Definition: extconf.c:2473
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
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.
Definition: message.c:1560
A message technology.
Definition: message.h:52
#define ao2_iterator_next(iter)
Definition: astobj2.h:1933
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:411
int ast_msg_set_endpoint(struct ast_msg *msg, const char *fmt,...)
Set the technology&#39;s endpoint associated with this message.
Definition: message.c:534
const char * ast_msg_get_from(const struct ast_msg *msg)
Retrieve the source of this message.
Definition: message.c:550
#define ast_channel_unlock(chan)
Definition: channel.h:2914
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1844
#define ast_free(a)
Definition: astmm.h:182
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
const ast_string_field from
Definition: message.c:263
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2544
Prototypes for public functions only of internal interest,.
static int msg_send_exec(struct ast_channel *chan, const char *data)
Definition: message.c:1240
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.
Definition: message.c:1693
Vector container support.
static struct ast_msg_handler dialplan_msg_handler
Definition: message.c:906
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756
An API for managing task processing threads that can be shared across modules.
ast_msg_data_attribute_type
Definition: message.h:454
static struct ast_channel * create_msg_q_chan(void)
Definition: message.c:729
size_t length
Definition: message.c:1435
int ast_msg_tech_unregister(const struct ast_msg_tech *tech)
Unregister a message technology.
Definition: message.c:1637
static struct ast_frame * chan_msg_read(struct ast_channel *chan)
Definition: message.c:346
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: message.c:629
static int chan_msg_send_digit_begin(struct ast_channel *chan, char digit)
Definition: message.c:386
static ast_rwlock_t msg_techs_lock
Lock for msg_techs vector.
Definition: message.c:269
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...
#define AST_THREADSTORAGE_CUSTOM(a, b, c)
Define a thread storage variable, with custom initialization and cleanup.
struct ast_msg * ast_msg_destroy(struct ast_msg *msg)
Destroy an ast_msg.
Definition: message.c:462
#define ast_rwlock_wrlock(a)
Definition: lock.h:234
const char * name
Name of the message handler.
Definition: message.h:102
struct ast_frame ast_null_frame
Definition: main/frame.c:79
void * data
Definition: datastore.h:70
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:682
char * strsep(char **str, const char *delims)
A ast_taskprocessor structure is a singleton by name.
Definition: taskprocessor.c:69
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 chan_cleanup(struct ast_channel *chan)
Definition: message.c:788
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:2911
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
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.
Definition: message.c:1632
Structure for rwlock and tracking information.
Definition: lock.h:156
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:79
void * ast_taskprocessor_unreference(struct ast_taskprocessor *tps)
Unreference the specified taskprocessor and its reference count will decrement.
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.
Definition: message.c:1496
static int msg_func_read(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len)
Definition: message.c:1015
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
#define ast_frfree(fr)
static PGresult * result
Definition: cel_pgsql.c:88
int ast_msg_init(void)
Definition: message.c:1757
struct msg_data * current_used
Definition: message.c:655
const char * ast_msg_get_tech(const struct ast_msg *msg)
Retrieve the technology associated with this message.
Definition: message.c:560
Data structure associated with a single frame of data.
int __ast_custom_function_register(struct ast_custom_function *acf, struct ast_module *mod)
Register a custom function.
int ast_msg_tech_register(const struct ast_msg_tech *tech)
Register a message technology.
Definition: message.c:1596
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
char buf[0]
Definition: message.c:1440
const ast_string_field context
Definition: message.c:263
Definition: search.h:40
#define ast_datastore_alloc(info, uid)
Definition: datastore.h:89
enum ast_frame_type frametype
int(*const msg_send)(const struct ast_msg *msg, const char *to, const char *from)
Send a message.
Definition: message.h:75
Generic container type.
A message.
Definition: message.c:247
Channels with this particular technology are an implementation detail of Asterisk and should generall...
Definition: channel.h:972
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:120
int ast_msg_set_body(struct ast_msg *msg, const char *fmt,...)
Set the &#39;body&#39; text of a message (in UTF-8)
Definition: message.c:490
#define ast_channel_alloc(needqueue, state, cid_num, cid_name, acctcode, exten, context, assignedids, requestor, amaflag,...)
Create a channel structure.
Definition: channel.h:1259
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:3159
Asterisk module definitions.
unsigned int no_hangup_chan
Definition: pbx.h:398
static const struct ast_msg_handler * msg_handler_find_by_tech_name(const char *tech_name)
Definition: message.c:1221
static int chan_msg_indicate(struct ast_channel *chan, int condition, const void *data, size_t datalen)
Definition: message.c:372
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2386
int ast_msg_set_to(struct ast_msg *msg, const char *fmt,...)
Set the &#39;to&#39; URI of a message.
Definition: message.c:468
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:368
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
const ast_string_field tech
Definition: message.c:263
int ast_msg_has_destination(const struct ast_msg *msg)
Determine if a particular message has a destination via some handler.
Definition: message.c:951
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore)
Remove a datastore from a channel.
Definition: channel.c:2395
static int action_messagesend(struct mansession *s, const struct message *m)
Definition: message.c:1320
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: message.c:624
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:611
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: message.c:672
const ast_string_field value
Definition: message.c:238
void ast_channel_unlink(struct ast_channel *chan)
Remove a channel from the global channels container.
Definition: channel.c:10653
#define ast_string_field_build_va(x, field, fmt, args)
Set a field to a complex (built) value.
Definition: stringfields.h:588
#define AST_APP_ARG(name)
Define an application argument.
#define EVENT_FLAG_MESSAGE
Definition: manager.h:91
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:514
int ast_msg_set_tech(struct ast_msg *msg, const char *fmt,...)
Set the technology associated with this message.
Definition: message.c:523
#define ao2_link(container, obj)
Definition: astobj2.h:1549