Multiple revisions 420089-420090,420097
[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         ast_log(LOG_ERROR, "@@@@@ to: %s from: %s exten: %s context: %s\n",
912                 msg->to, msg->from, msg->exten, msg->context);
913         res = ast_taskprocessor_push(msg_q_tp, msg_q_cb, msg);
914         if (res == -1) {
915                 ao2_ref(msg, -1);
916         }
917
918         return res;
919 }
920
921 /*!
922  * \internal
923  * \brief Find or create a message datastore on a channel
924  *
925  * \pre chan is locked
926  *
927  * \param chan the relevant channel
928  *
929  * \return the channel's message datastore, or NULL on error
930  */
931 static struct ast_datastore *msg_datastore_find_or_create(struct ast_channel *chan)
932 {
933         struct ast_datastore *ds;
934
935         if ((ds = ast_channel_datastore_find(chan, &msg_datastore, NULL))) {
936                 return ds;
937         }
938
939         if (!(ds = ast_datastore_alloc(&msg_datastore, NULL))) {
940                 return NULL;
941         }
942
943         if (!(ds->data = ast_msg_alloc())) {
944                 ast_datastore_free(ds);
945                 return NULL;
946         }
947
948         ast_channel_datastore_add(chan, ds);
949
950         return ds;
951 }
952
953 static int msg_func_read(struct ast_channel *chan, const char *function,
954                 char *data, char *buf, size_t len)
955 {
956         struct ast_datastore *ds;
957         struct ast_msg *msg;
958
959         if (!chan) {
960                 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", function);
961                 return -1;
962         }
963
964         ast_channel_lock(chan);
965
966         if (!(ds = ast_channel_datastore_find(chan, &msg_datastore, NULL))) {
967                 ast_channel_unlock(chan);
968                 ast_log(LOG_ERROR, "No MESSAGE data found on the channel to read.\n");
969                 return -1;
970         }
971
972         msg = ds->data;
973         ao2_ref(msg, +1);
974         ast_channel_unlock(chan);
975
976         ao2_lock(msg);
977
978         if (!strcasecmp(data, "to")) {
979                 ast_copy_string(buf, msg->to, len);
980         } else if (!strcasecmp(data, "from")) {
981                 ast_copy_string(buf, msg->from, len);
982         } else if (!strcasecmp(data, "body")) {
983                 ast_copy_string(buf, msg->body, len);
984         } else {
985                 ast_log(LOG_WARNING, "Invalid argument to MESSAGE(): '%s'\n", data);
986         }
987
988         ao2_unlock(msg);
989         ao2_ref(msg, -1);
990
991         return 0;
992 }
993
994 static int msg_func_write(struct ast_channel *chan, const char *function,
995                 char *data, const char *value)
996 {
997         struct ast_datastore *ds;
998         struct ast_msg *msg;
999
1000         if (!chan) {
1001                 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", function);
1002                 return -1;
1003         }
1004
1005         ast_channel_lock(chan);
1006
1007         if (!(ds = msg_datastore_find_or_create(chan))) {
1008                 ast_channel_unlock(chan);
1009                 return -1;
1010         }
1011
1012         msg = ds->data;
1013         ao2_ref(msg, +1);
1014         ast_channel_unlock(chan);
1015
1016         ao2_lock(msg);
1017
1018         if (!strcasecmp(data, "to")) {
1019                 ast_msg_set_to(msg, "%s", value);
1020         } else if (!strcasecmp(data, "from")) {
1021                 ast_msg_set_from(msg, "%s", value);
1022         } else if (!strcasecmp(data, "body")) {
1023                 ast_msg_set_body(msg, "%s", value);
1024         } else if (!strcasecmp(data, "custom_data")) {
1025                 int outbound = -1;
1026                 if (!strcasecmp(value, "mark_all_outbound")) {
1027                         outbound = 1;
1028                 } else if (!strcasecmp(value, "clear_all_outbound")) {
1029                         outbound = 0;
1030                 } else {
1031                         ast_log(LOG_WARNING, "'%s' is not a valid value for custom_data\n", value);
1032                 }
1033
1034                 if (outbound != -1) {
1035                         struct msg_data *hdr_data;
1036                         struct ao2_iterator iter = ao2_iterator_init(msg->vars, 0);
1037
1038                         while ((hdr_data = ao2_iterator_next(&iter))) {
1039                                 hdr_data->send = outbound;
1040                                 ao2_ref(hdr_data, -1);
1041                         }
1042                         ao2_iterator_destroy(&iter);
1043                 }
1044         } else {
1045                 ast_log(LOG_WARNING, "'%s' is not a valid write argument.\n", data);
1046         }
1047
1048         ao2_unlock(msg);
1049         ao2_ref(msg, -1);
1050
1051         return 0;
1052 }
1053
1054 static int msg_data_func_read(struct ast_channel *chan, const char *function,
1055                 char *data, char *buf, size_t len)
1056 {
1057         struct ast_datastore *ds;
1058         struct ast_msg *msg;
1059         const char *val;
1060
1061         if (!chan) {
1062                 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", function);
1063                 return -1;
1064         }
1065
1066         ast_channel_lock(chan);
1067
1068         if (!(ds = ast_channel_datastore_find(chan, &msg_datastore, NULL))) {
1069                 ast_channel_unlock(chan);
1070                 ast_log(LOG_ERROR, "No MESSAGE data found on the channel to read.\n");
1071                 return -1;
1072         }
1073
1074         msg = ds->data;
1075         ao2_ref(msg, +1);
1076         ast_channel_unlock(chan);
1077
1078         ao2_lock(msg);
1079
1080         if ((val = ast_msg_get_var(msg, data))) {
1081                 ast_copy_string(buf, val, len);
1082         }
1083
1084         ao2_unlock(msg);
1085         ao2_ref(msg, -1);
1086
1087         return 0;
1088 }
1089
1090 static int msg_data_func_write(struct ast_channel *chan, const char *function,
1091                 char *data, const char *value)
1092 {
1093         struct ast_datastore *ds;
1094         struct ast_msg *msg;
1095
1096         if (!chan) {
1097                 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", function);
1098                 return -1;
1099         }
1100
1101         ast_channel_lock(chan);
1102
1103         if (!(ds = msg_datastore_find_or_create(chan))) {
1104                 ast_channel_unlock(chan);
1105                 return -1;
1106         }
1107
1108         msg = ds->data;
1109         ao2_ref(msg, +1);
1110         ast_channel_unlock(chan);
1111
1112         ao2_lock(msg);
1113
1114         ast_msg_set_var_outbound(msg, data, value);
1115
1116         ao2_unlock(msg);
1117         ao2_ref(msg, -1);
1118
1119         return 0;
1120 }
1121
1122 /*!
1123  * \internal \brief Find a \c ast_msg_tech by its technology name
1124  *
1125  * \param tech_name The name of the message technology
1126  *
1127  * \note \c msg_techs should be locked via \c msg_techs_lock prior to
1128  *       calling this function
1129  *
1130  * \retval NULL if no \c ast_msg_tech has been registered
1131  * \retval \c ast_msg_tech if registered
1132  */
1133 static const struct ast_msg_tech *msg_find_by_tech_name(const char *tech_name)
1134 {
1135         const struct ast_msg_tech *current;
1136         int i;
1137
1138         for (i = 0; i < AST_VECTOR_SIZE(&msg_techs); i++) {
1139                 current = AST_VECTOR_GET(&msg_techs, i);
1140                 if (!strcmp(current->name, tech_name)) {
1141                         return current;
1142                 }
1143         }
1144
1145         return NULL;
1146 }
1147
1148 /*!
1149  * \internal \brief Find a \c ast_msg_handler by its technology name
1150  *
1151  * \param tech_name The name of the message technology
1152  *
1153  * \note \c msg_handlers should be locked via \c msg_handlers_lock
1154  *       prior to calling this function
1155  *
1156  * \retval NULL if no \c ast_msg_handler has been registered
1157  * \retval \c ast_msg_handler if registered
1158  */
1159 static const struct ast_msg_handler *msg_handler_find_by_tech_name(const char *tech_name)
1160 {
1161         const struct ast_msg_handler *current;
1162         int i;
1163
1164         for (i = 0; i < AST_VECTOR_SIZE(&msg_handlers); i++) {
1165                 current = AST_VECTOR_GET(&msg_handlers, i);
1166                 if (!strcmp(current->name, tech_name)) {
1167                         return current;
1168                 }
1169         }
1170
1171         return NULL;
1172 }
1173
1174 /*!
1175  * \internal
1176  * \brief MessageSend() application
1177  */
1178 static int msg_send_exec(struct ast_channel *chan, const char *data)
1179 {
1180         struct ast_datastore *ds;
1181         struct ast_msg *msg;
1182         char *tech_name;
1183         const struct ast_msg_tech *msg_tech;
1184         char *parse;
1185         int res = -1;
1186         AST_DECLARE_APP_ARGS(args,
1187                 AST_APP_ARG(to);
1188                 AST_APP_ARG(from);
1189         );
1190
1191         if (ast_strlen_zero(data)) {
1192                 ast_log(LOG_WARNING, "An argument is required to MessageSend()\n");
1193                 pbx_builtin_setvar_helper(chan, "MESSAGE_SEND_STATUS", "INVALID_URI");
1194                 return 0;
1195         }
1196
1197         parse = ast_strdupa(data);
1198         AST_STANDARD_APP_ARGS(args, parse);
1199
1200         if (ast_strlen_zero(args.to)) {
1201                 ast_log(LOG_WARNING, "A 'to' URI is required for MessageSend()\n");
1202                 pbx_builtin_setvar_helper(chan, "MESSAGE_SEND_STATUS", "INVALID_URI");
1203                 return 0;
1204         }
1205
1206         ast_channel_lock(chan);
1207
1208         if (!(ds = ast_channel_datastore_find(chan, &msg_datastore, NULL))) {
1209                 ast_channel_unlock(chan);
1210                 ast_log(LOG_WARNING, "No message data found on channel to send.\n");
1211                 pbx_builtin_setvar_helper(chan, "MESSAGE_SEND_STATUS", "FAILURE");
1212                 return 0;
1213         }
1214
1215         msg = ds->data;
1216         ao2_ref(msg, +1);
1217         ast_channel_unlock(chan);
1218
1219         tech_name = ast_strdupa(args.to);
1220         tech_name = strsep(&tech_name, ":");
1221
1222         ast_rwlock_rdlock(&msg_techs_lock);
1223         msg_tech = msg_find_by_tech_name(tech_name);
1224
1225         if (!msg_tech) {
1226                 ast_log(LOG_WARNING, "No message technology '%s' found.\n", tech_name);
1227                 pbx_builtin_setvar_helper(chan, "MESSAGE_SEND_STATUS", "INVALID_PROTOCOL");
1228                 goto exit_cleanup;
1229         }
1230
1231         /*
1232          * The message lock is held here to safely allow the technology
1233          * implementation to access the message fields without worrying
1234          * that they could change.
1235          */
1236         ao2_lock(msg);
1237         res = msg_tech->msg_send(msg, S_OR(args.to, ""), S_OR(args.from, ""));
1238         ao2_unlock(msg);
1239
1240         pbx_builtin_setvar_helper(chan, "MESSAGE_SEND_STATUS", res ? "FAILURE" : "SUCCESS");
1241
1242 exit_cleanup:
1243         ast_rwlock_unlock(&msg_techs_lock);
1244         ao2_ref(msg, -1);
1245
1246         return 0;
1247 }
1248
1249 static int action_messagesend(struct mansession *s, const struct message *m)
1250 {
1251         const char *to = ast_strdupa(astman_get_header(m, "To"));
1252         const char *from = astman_get_header(m, "From");
1253         const char *body = astman_get_header(m, "Body");
1254         const char *base64body = astman_get_header(m, "Base64Body");
1255         char base64decoded[1301] = { 0, };
1256         char *tech_name = NULL;
1257         struct ast_variable *vars = NULL;
1258         struct ast_variable *data = NULL;
1259         const struct ast_msg_tech *msg_tech;
1260         struct ast_msg *msg;
1261         int res = -1;
1262
1263         if (ast_strlen_zero(to)) {
1264                 astman_send_error(s, m, "No 'To' address specified.");
1265                 return -1;
1266         }
1267
1268         if (!ast_strlen_zero(base64body)) {
1269                 ast_base64decode((unsigned char *) base64decoded, base64body, sizeof(base64decoded) - 1);
1270                 body = base64decoded;
1271         }
1272
1273         tech_name = ast_strdupa(to);
1274         tech_name = strsep(&tech_name, ":");
1275
1276         ast_rwlock_rdlock(&msg_techs_lock);
1277         msg_tech = msg_find_by_tech_name(tech_name);
1278         if (!msg_tech) {
1279                 ast_rwlock_unlock(&msg_techs_lock);
1280                 astman_send_error(s, m, "Message technology not found.");
1281                 return 0;
1282         }
1283
1284         if (!(msg = ast_msg_alloc())) {
1285                 ast_rwlock_unlock(&msg_techs_lock);
1286                 astman_send_error(s, m, "Internal failure\n");
1287                 return -1;
1288         }
1289
1290         data = astman_get_variables_order(m, ORDER_NATURAL);
1291         for (vars = data; vars; vars = vars->next) {
1292                 ast_msg_set_var_outbound(msg, vars->name, vars->value);
1293         }
1294
1295         ast_msg_set_body(msg, "%s", body);
1296
1297         res = msg_tech->msg_send(msg, S_OR(to, ""), S_OR(from, ""));
1298
1299         ast_rwlock_unlock(&msg_techs_lock);
1300
1301         ast_variables_destroy(vars);
1302         ao2_ref(msg, -1);
1303
1304         if (res) {
1305                 astman_send_error(s, m, "Message failed to send.");
1306         } else {
1307                 astman_send_ack(s, m, "Message successfully sent");
1308         }
1309         return res;
1310 }
1311
1312 int ast_msg_send(struct ast_msg *msg, const char *to, const char *from)
1313 {
1314         char *tech_name = NULL;
1315         const struct ast_msg_tech *msg_tech;
1316         int res = -1;
1317
1318         if (ast_strlen_zero(to)) {
1319                 ao2_ref(msg, -1);
1320                 return -1;
1321         }
1322
1323         tech_name = ast_strdupa(to);
1324         tech_name = strsep(&tech_name, ":");
1325
1326         ast_rwlock_rdlock(&msg_techs_lock);
1327         msg_tech = msg_find_by_tech_name(tech_name);
1328
1329         if (!msg_tech) {
1330                 ast_log(LOG_ERROR, "Unknown message tech: %s\n", tech_name);
1331                 ast_rwlock_unlock(&msg_techs_lock);
1332                 return -1;
1333         }
1334
1335         res = msg_tech->msg_send(msg, S_OR(to, ""), S_OR(from, ""));
1336
1337         ast_rwlock_unlock(&msg_techs_lock);
1338
1339         ao2_ref(msg, -1);
1340
1341         return res;
1342 }
1343
1344 int ast_msg_tech_register(const struct ast_msg_tech *tech)
1345 {
1346         const struct ast_msg_tech *match;
1347
1348         ast_rwlock_wrlock(&msg_techs_lock);
1349
1350         match = msg_find_by_tech_name(tech->name);
1351         if (match) {
1352                 ast_log(LOG_ERROR, "Message technology already registered for '%s'\n",
1353                         tech->name);
1354                 ast_rwlock_unlock(&msg_techs_lock);
1355                 return -1;
1356         }
1357
1358         AST_VECTOR_APPEND(&msg_techs, tech);
1359         ast_verb(3, "Message technology '%s' registered.\n", tech->name);
1360
1361         ast_rwlock_unlock(&msg_techs_lock);
1362
1363         return 0;
1364 }
1365
1366 /*!
1367  * \brief Comparison callback for \c ast_msg_tech vector removal
1368  *
1369  * \param vec_elem The element in the vector being compared
1370  * \param srch The element being looked up
1371  *
1372  * \retval non-zero The items are equal
1373  * \retval 0 The items are not equal
1374  */
1375 static int msg_tech_cmp(const struct ast_msg_tech *vec_elem, const struct ast_msg_tech *srch)
1376 {
1377         return !strcmp(vec_elem->name, srch->name);
1378 }
1379
1380 int ast_msg_tech_unregister(const struct ast_msg_tech *tech)
1381 {
1382         int match;
1383
1384         ast_rwlock_wrlock(&msg_techs_lock);
1385         match = AST_VECTOR_REMOVE_CMP_UNORDERED(&msg_techs, tech, msg_tech_cmp,
1386                                                 AST_VECTOR_ELEM_CLEANUP_NOOP);
1387         ast_rwlock_unlock(&msg_techs_lock);
1388
1389         if (match) {
1390                 ast_log(LOG_ERROR, "No '%s' message technology found.\n", tech->name);
1391                 return -1;
1392         }
1393
1394         ast_verb(2, "Message technology '%s' unregistered.\n", tech->name);
1395
1396         return 0;
1397 }
1398
1399 int ast_msg_handler_register(const struct ast_msg_handler *handler)
1400 {
1401         const struct ast_msg_handler *match;
1402
1403         ast_rwlock_wrlock(&msg_handlers_lock);
1404
1405         match = msg_handler_find_by_tech_name(handler->name);
1406         if (match) {
1407                 ast_log(LOG_ERROR, "Message handler already registered for '%s'\n",
1408                         handler->name);
1409                 ast_rwlock_unlock(&msg_handlers_lock);
1410                 return -1;
1411         }
1412
1413         AST_VECTOR_APPEND(&msg_handlers, handler);
1414         ast_verb(2, "Message handler '%s' registered.\n", handler->name);
1415
1416         ast_rwlock_unlock(&msg_handlers_lock);
1417
1418         return 0;
1419
1420 }
1421
1422 /*!
1423  * \brief Comparison callback for \c ast_msg_handler vector removal
1424  *
1425  * \param vec_elem The element in the vector being compared
1426  * \param srch The element being looked up
1427  *
1428  * \retval non-zero The items are equal
1429  * \retval 0 The items are not equal
1430  */
1431 static int msg_handler_cmp(const struct ast_msg_handler *vec_elem, const struct ast_msg_handler *srch)
1432 {
1433         return !strcmp(vec_elem->name, srch->name);
1434 }
1435
1436 int ast_msg_handler_unregister(const struct ast_msg_handler *handler)
1437 {
1438         int match;
1439
1440         ast_rwlock_wrlock(&msg_handlers_lock);
1441         match = AST_VECTOR_REMOVE_CMP_UNORDERED(&msg_handlers, handler, msg_handler_cmp,
1442                                                 AST_VECTOR_ELEM_CLEANUP_NOOP);
1443         ast_rwlock_unlock(&msg_handlers_lock);
1444
1445         if (match) {
1446                 ast_log(LOG_ERROR, "No '%s' message handler found.\n", handler->name);
1447                 return -1;
1448         }
1449
1450         ast_verb(3, "Message handler '%s' unregistered.\n", handler->name);
1451         return 0;
1452 }
1453
1454 void ast_msg_shutdown(void)
1455 {
1456         if (msg_q_tp) {
1457                 msg_q_tp = ast_taskprocessor_unreference(msg_q_tp);
1458         }
1459 }
1460
1461 /*!
1462  * \internal
1463  * \brief Clean up other resources on Asterisk shutdown
1464  *
1465  * \note This does not include the msg_q_tp object, which must be disposed
1466  * of prior to Asterisk checking for channel destruction in its shutdown
1467  * sequence.  The atexit handlers are executed after this occurs.
1468  */
1469 static void message_shutdown(void)
1470 {
1471         ast_msg_handler_unregister(&dialplan_msg_handler);
1472
1473         ast_custom_function_unregister(&msg_function);
1474         ast_custom_function_unregister(&msg_data_function);
1475         ast_unregister_application(app_msg_send);
1476         ast_manager_unregister("MessageSend");
1477
1478         AST_VECTOR_FREE(&msg_techs);
1479         ast_rwlock_destroy(&msg_techs_lock);
1480
1481         AST_VECTOR_FREE(&msg_handlers);
1482         ast_rwlock_destroy(&msg_handlers_lock);
1483 }
1484
1485 /*
1486  * \internal
1487  * \brief Initialize stuff during Asterisk startup.
1488  *
1489  * Cleanup isn't a big deal in this function.  If we return non-zero,
1490  * Asterisk is going to exit.
1491  *
1492  * \retval 0 success
1493  * \retval non-zero failure
1494  */
1495 int ast_msg_init(void)
1496 {
1497         int res;
1498
1499         msg_q_tp = ast_taskprocessor_get("ast_msg_queue", TPS_REF_DEFAULT);
1500         if (!msg_q_tp) {
1501                 return -1;
1502         }
1503
1504         ast_rwlock_init(&msg_techs_lock);
1505         if (AST_VECTOR_INIT(&msg_techs, 8)) {
1506                 return -1;
1507         }
1508
1509         ast_rwlock_init(&msg_handlers_lock);
1510         if (AST_VECTOR_INIT(&msg_handlers, 4)) {
1511                 return -1;
1512         }
1513
1514         res = ast_msg_handler_register(&dialplan_msg_handler);
1515
1516         res |= __ast_custom_function_register(&msg_function, NULL);
1517         res |= __ast_custom_function_register(&msg_data_function, NULL);
1518         res |= ast_register_application2(app_msg_send, msg_send_exec, NULL, NULL, NULL);
1519         res |= ast_manager_register_xml_core("MessageSend", EVENT_FLAG_MESSAGE, action_messagesend);
1520
1521         ast_register_atexit(message_shutdown);
1522
1523         return res;
1524 }