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