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