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