00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "asterisk.h"
00027
00028 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 361523 $")
00029
00030 #include "asterisk/_private.h"
00031
00032 #include "asterisk/module.h"
00033 #include "asterisk/datastore.h"
00034 #include "asterisk/pbx.h"
00035 #include "asterisk/strings.h"
00036 #include "asterisk/astobj2.h"
00037 #include "asterisk/app.h"
00038 #include "asterisk/taskprocessor.h"
00039 #include "asterisk/message.h"
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144 struct msg_data {
00145 AST_DECLARE_STRING_FIELDS(
00146 AST_STRING_FIELD(name);
00147 AST_STRING_FIELD(value);
00148 );
00149 unsigned int send:1;
00150 };
00151
00152 AST_LIST_HEAD_NOLOCK(outhead, msg_data);
00153
00154
00155
00156
00157
00158
00159 struct ast_msg {
00160 struct ast_str *to;
00161 struct ast_str *from;
00162 struct ast_str *body;
00163 struct ast_str *context;
00164 struct ast_str *exten;
00165 struct ao2_container *vars;
00166 };
00167
00168 struct ast_msg_tech_holder {
00169 const struct ast_msg_tech *tech;
00170
00171
00172
00173
00174
00175
00176 ast_rwlock_t tech_lock;
00177 };
00178
00179 static struct ao2_container *msg_techs;
00180
00181 static struct ast_taskprocessor *msg_q_tp;
00182
00183 static const char app_msg_send[] = "MessageSend";
00184
00185 static void msg_ds_destroy(void *data);
00186
00187 static const struct ast_datastore_info msg_datastore = {
00188 .type = "message",
00189 .destroy = msg_ds_destroy,
00190 };
00191
00192 static int msg_func_read(struct ast_channel *chan, const char *function,
00193 char *data, char *buf, size_t len);
00194 static int msg_func_write(struct ast_channel *chan, const char *function,
00195 char *data, const char *value);
00196
00197 static struct ast_custom_function msg_function = {
00198 .name = "MESSAGE",
00199 .read = msg_func_read,
00200 .write = msg_func_write,
00201 };
00202
00203 static int msg_data_func_read(struct ast_channel *chan, const char *function,
00204 char *data, char *buf, size_t len);
00205 static int msg_data_func_write(struct ast_channel *chan, const char *function,
00206 char *data, const char *value);
00207
00208 static struct ast_custom_function msg_data_function = {
00209 .name = "MESSAGE_DATA",
00210 .read = msg_data_func_read,
00211 .write = msg_data_func_write,
00212 };
00213
00214 static struct ast_frame *chan_msg_read(struct ast_channel *chan);
00215 static int chan_msg_write(struct ast_channel *chan, struct ast_frame *fr);
00216 static int chan_msg_indicate(struct ast_channel *chan, int condition,
00217 const void *data, size_t datalen);
00218 static int chan_msg_send_digit_begin(struct ast_channel *chan, char digit);
00219 static int chan_msg_send_digit_end(struct ast_channel *chan, char digit,
00220 unsigned int duration);
00221
00222
00223
00224
00225
00226
00227
00228
00229 static const struct ast_channel_tech msg_chan_tech_hack = {
00230 .type = "Message",
00231 .description = "Internal Text Message Processing",
00232 .read = chan_msg_read,
00233 .write = chan_msg_write,
00234 .indicate = chan_msg_indicate,
00235 .send_digit_begin = chan_msg_send_digit_begin,
00236 .send_digit_end = chan_msg_send_digit_end,
00237 };
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247 static struct ast_frame *chan_msg_read(struct ast_channel *chan)
00248 {
00249 return &ast_null_frame;
00250 }
00251
00252
00253
00254
00255
00256
00257
00258 static int chan_msg_write(struct ast_channel *chan, struct ast_frame *fr)
00259 {
00260 return 0;
00261 }
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273 static int chan_msg_indicate(struct ast_channel *chan, int condition,
00274 const void *data, size_t datalen)
00275 {
00276 return 0;
00277 }
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287 static int chan_msg_send_digit_begin(struct ast_channel *chan, char digit)
00288 {
00289 return 0;
00290 }
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300 static int chan_msg_send_digit_end(struct ast_channel *chan, char digit,
00301 unsigned int duration)
00302 {
00303 return 0;
00304 }
00305
00306 static void msg_ds_destroy(void *data)
00307 {
00308 struct ast_msg *msg = data;
00309
00310 ao2_ref(msg, -1);
00311 }
00312
00313 static int msg_data_hash_fn(const void *obj, const int flags)
00314 {
00315 const struct msg_data *data = obj;
00316 return ast_str_case_hash(data->name);
00317 }
00318
00319 static int msg_data_cmp_fn(void *obj, void *arg, int flags)
00320 {
00321 const struct msg_data *one = obj, *two = arg;
00322 return !strcasecmp(one->name, two->name) ? CMP_MATCH | CMP_STOP : 0;
00323 }
00324
00325 static void msg_data_destructor(void *obj)
00326 {
00327 struct msg_data *data = obj;
00328 ast_string_field_free_memory(data);
00329 }
00330
00331 static void msg_destructor(void *obj)
00332 {
00333 struct ast_msg *msg = obj;
00334
00335 ast_free(msg->to);
00336 msg->to = NULL;
00337
00338 ast_free(msg->from);
00339 msg->from = NULL;
00340
00341 ast_free(msg->body);
00342 msg->body = NULL;
00343
00344 ast_free(msg->context);
00345 msg->context = NULL;
00346
00347 ast_free(msg->exten);
00348 msg->exten = NULL;
00349
00350 ao2_ref(msg->vars, -1);
00351 }
00352
00353 struct ast_msg *ast_msg_alloc(void)
00354 {
00355 struct ast_msg *msg;
00356
00357 if (!(msg = ao2_alloc(sizeof(*msg), msg_destructor))) {
00358 return NULL;
00359 }
00360
00361 if (!(msg->to = ast_str_create(32))) {
00362 ao2_ref(msg, -1);
00363 return NULL;
00364 }
00365
00366 if (!(msg->from = ast_str_create(32))) {
00367 ao2_ref(msg, -1);
00368 return NULL;
00369 }
00370
00371 if (!(msg->body = ast_str_create(128))) {
00372 ao2_ref(msg, -1);
00373 return NULL;
00374 }
00375
00376 if (!(msg->context = ast_str_create(16))) {
00377 ao2_ref(msg, -1);
00378 return NULL;
00379 }
00380
00381 if (!(msg->exten = ast_str_create(16))) {
00382 ao2_ref(msg, -1);
00383 return NULL;
00384 }
00385
00386 if (!(msg->vars = ao2_container_alloc(1, msg_data_hash_fn, msg_data_cmp_fn))) {
00387 ao2_ref(msg, -1);
00388 return NULL;
00389 }
00390
00391 ast_str_set(&msg->context, 0, "default");
00392
00393 return msg;
00394 }
00395
00396 struct ast_msg *ast_msg_destroy(struct ast_msg *msg)
00397 {
00398 ao2_ref(msg, -1);
00399
00400 return NULL;
00401 }
00402
00403 int ast_msg_set_to(struct ast_msg *msg, const char *fmt, ...)
00404 {
00405 va_list ap;
00406 int res;
00407
00408 va_start(ap, fmt);
00409 res = ast_str_set_va(&msg->to, 0, fmt, ap);
00410 va_end(ap);
00411
00412 return res < 0 ? -1 : 0;
00413 }
00414
00415 int ast_msg_set_from(struct ast_msg *msg, const char *fmt, ...)
00416 {
00417 va_list ap;
00418 int res;
00419
00420 va_start(ap, fmt);
00421 res = ast_str_set_va(&msg->from, 0, fmt, ap);
00422 va_end(ap);
00423
00424 return res < 0 ? -1 : 0;
00425 }
00426
00427 int ast_msg_set_body(struct ast_msg *msg, const char *fmt, ...)
00428 {
00429 va_list ap;
00430 int res;
00431
00432 va_start(ap, fmt);
00433 res = ast_str_set_va(&msg->body, 0, fmt, ap);
00434 va_end(ap);
00435
00436 return res < 0 ? -1 : 0;
00437 }
00438
00439 int ast_msg_set_context(struct ast_msg *msg, const char *fmt, ...)
00440 {
00441 va_list ap;
00442 int res;
00443
00444 va_start(ap, fmt);
00445 res = ast_str_set_va(&msg->context, 0, fmt, ap);
00446 va_end(ap);
00447
00448 return res < 0 ? -1 : 0;
00449 }
00450
00451 int ast_msg_set_exten(struct ast_msg *msg, const char *fmt, ...)
00452 {
00453 va_list ap;
00454 int res;
00455
00456 va_start(ap, fmt);
00457 res = ast_str_set_va(&msg->exten, 0, fmt, ap);
00458 va_end(ap);
00459
00460 return res < 0 ? -1 : 0;
00461 }
00462
00463 const char *ast_msg_get_body(const struct ast_msg *msg)
00464 {
00465 return ast_str_buffer(msg->body);
00466 }
00467
00468 static struct msg_data *msg_data_alloc(void)
00469 {
00470 struct msg_data *data;
00471
00472 if (!(data = ao2_alloc(sizeof(*data), msg_data_destructor))) {
00473 return NULL;
00474 }
00475
00476 if (ast_string_field_init(data, 32)) {
00477 ao2_ref(data, -1);
00478 return NULL;
00479 }
00480
00481 return data;
00482 }
00483
00484 static struct msg_data *msg_data_find(struct ao2_container *vars, const char *name)
00485 {
00486 struct msg_data tmp = {
00487 .name = name,
00488 };
00489 return ao2_find(vars, &tmp, OBJ_POINTER);
00490 }
00491
00492 static int msg_set_var_full(struct ast_msg *msg, const char *name, const char *value, unsigned int outbound)
00493 {
00494 struct msg_data *data;
00495
00496 if (!(data = msg_data_find(msg->vars, name))) {
00497 if (ast_strlen_zero(value)) {
00498 return 0;
00499 }
00500 if (!(data = msg_data_alloc())) {
00501 return -1;
00502 };
00503
00504 ast_string_field_set(data, name, name);
00505 ast_string_field_set(data, value, value);
00506 data->send = outbound;
00507 ao2_link(msg->vars, data);
00508 } else {
00509 if (ast_strlen_zero(value)) {
00510 ao2_unlink(msg->vars, data);
00511 } else {
00512 ast_string_field_set(data, value, value);
00513 data->send = outbound;
00514 }
00515 }
00516
00517 ao2_ref(data, -1);
00518
00519 return 0;
00520 }
00521
00522 static int msg_set_var_outbound(struct ast_msg *msg, const char *name, const char *value)
00523 {
00524 return msg_set_var_full(msg, name, value, 1);
00525 }
00526
00527 int ast_msg_set_var(struct ast_msg *msg, const char *name, const char *value)
00528 {
00529 return msg_set_var_full(msg, name, value, 0);
00530 }
00531
00532 const char *ast_msg_get_var(struct ast_msg *msg, const char *name)
00533 {
00534 struct msg_data *data;
00535 const char *val = NULL;
00536
00537 if (!(data = msg_data_find(msg->vars, name))) {
00538 return NULL;
00539 }
00540
00541
00542
00543
00544
00545 val = data->value;
00546 ao2_ref(data, -1);
00547
00548 return val;
00549 }
00550
00551 struct ast_msg_var_iterator {
00552 struct ao2_iterator i;
00553 struct msg_data *current_used;
00554 };
00555
00556 struct ast_msg_var_iterator *ast_msg_var_iterator_init(const struct ast_msg *msg)
00557 {
00558 struct ast_msg_var_iterator *i;
00559 if (!(i = ast_calloc(1, sizeof(*i)))) {
00560 return NULL;
00561 }
00562
00563 i->i = ao2_iterator_init(msg->vars, 0);
00564
00565 return i;
00566 }
00567
00568 int ast_msg_var_iterator_next(const struct ast_msg *msg, struct ast_msg_var_iterator *i, const char **name, const char **value)
00569 {
00570 struct msg_data *data;
00571
00572
00573 while ((data = ao2_iterator_next(&i->i)) && !data->send) {
00574 ao2_ref(data, -1);
00575 }
00576
00577 if (!data) {
00578 return 0;
00579 }
00580
00581 if (data->send) {
00582 *name = data->name;
00583 *value = data->value;
00584 }
00585
00586
00587
00588 i->current_used = data;
00589
00590 return 1;
00591 }
00592
00593 void ast_msg_var_unref_current(struct ast_msg_var_iterator *i) {
00594 if (i->current_used) {
00595 ao2_ref(i->current_used, -1);
00596 }
00597 i->current_used = NULL;
00598 }
00599
00600 void ast_msg_var_iterator_destroy(struct ast_msg_var_iterator *i)
00601 {
00602 ao2_iterator_destroy(&i->i);
00603 ast_free(i);
00604 }
00605
00606 static struct ast_channel *create_msg_q_chan(void)
00607 {
00608 struct ast_channel *chan;
00609 struct ast_datastore *ds;
00610
00611 chan = ast_channel_alloc(1, AST_STATE_UP,
00612 NULL, NULL, NULL,
00613 NULL, NULL, NULL, 0,
00614 "%s", "Message/ast_msg_queue");
00615
00616 if (!chan) {
00617 return NULL;
00618 }
00619
00620 ast_channel_unlink(chan);
00621
00622 ast_channel_tech_set(chan, &msg_chan_tech_hack);
00623
00624 if (!(ds = ast_datastore_alloc(&msg_datastore, NULL))) {
00625 ast_hangup(chan);
00626 return NULL;
00627 }
00628
00629 ast_channel_lock(chan);
00630 ast_channel_datastore_add(chan, ds);
00631 ast_channel_unlock(chan);
00632
00633 return chan;
00634 }
00635
00636
00637
00638
00639
00640
00641
00642
00643 static void msg_route(struct ast_channel *chan, struct ast_msg *msg)
00644 {
00645 struct ast_pbx_args pbx_args;
00646
00647 ast_explicit_goto(chan, ast_str_buffer(msg->context), AS_OR(msg->exten, "s"), 1);
00648
00649 memset(&pbx_args, 0, sizeof(pbx_args));
00650 pbx_args.no_hangup_chan = 1,
00651 ast_pbx_run_args(chan, &pbx_args);
00652 }
00653
00654
00655
00656
00657
00658
00659
00660
00661 static void chan_cleanup(struct ast_channel *chan)
00662 {
00663 struct ast_datastore *msg_ds, *ds;
00664 struct varshead *headp;
00665 struct ast_var_t *vardata;
00666
00667 ast_channel_lock(chan);
00668
00669
00670
00671
00672
00673 if ((msg_ds = ast_channel_datastore_find(chan, &msg_datastore, NULL)) && msg_ds->data) {
00674 ast_channel_datastore_remove(chan, msg_ds);
00675 ao2_ref(msg_ds->data, -1);
00676 msg_ds->data = NULL;
00677 }
00678
00679
00680
00681
00682 while ((ds = AST_LIST_REMOVE_HEAD(ast_channel_datastores(chan), entry))) {
00683 ast_datastore_free(ds);
00684 }
00685
00686
00687
00688
00689 headp = ast_channel_varshead(chan);
00690 while ((vardata = AST_LIST_REMOVE_HEAD(headp, entries))) {
00691 ast_var_delete(vardata);
00692 }
00693
00694
00695
00696
00697 if (msg_ds) {
00698 ast_channel_datastore_add(chan, msg_ds);
00699 }
00700
00701 ast_channel_unlock(chan);
00702 }
00703
00704 AST_THREADSTORAGE(msg_q_chan);
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715 static int msg_q_cb(void *data)
00716 {
00717 struct ast_msg *msg = data;
00718 struct ast_channel **chan_p, *chan;
00719 struct ast_datastore *ds;
00720
00721 if (!(chan_p = ast_threadstorage_get(&msg_q_chan, sizeof(struct ast_channel *)))) {
00722 return -1;
00723 }
00724 if (!*chan_p) {
00725 if (!(*chan_p = create_msg_q_chan())) {
00726 return -1;
00727 }
00728 }
00729 chan = *chan_p;
00730
00731 ast_channel_lock(chan);
00732 if (!(ds = ast_channel_datastore_find(chan, &msg_datastore, NULL))) {
00733 ast_channel_unlock(chan);
00734 return -1;
00735 }
00736 ao2_ref(msg, +1);
00737 ds->data = msg;
00738 ast_channel_unlock(chan);
00739
00740 msg_route(chan, msg);
00741 chan_cleanup(chan);
00742
00743 ao2_ref(msg, -1);
00744
00745 return 0;
00746 }
00747
00748 int ast_msg_queue(struct ast_msg *msg)
00749 {
00750 int res;
00751
00752 res = ast_taskprocessor_push(msg_q_tp, msg_q_cb, msg);
00753 if (res == -1) {
00754 ao2_ref(msg, -1);
00755 }
00756
00757 return res;
00758 }
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770 static struct ast_datastore *msg_datastore_find_or_create(struct ast_channel *chan)
00771 {
00772 struct ast_datastore *ds;
00773
00774 if ((ds = ast_channel_datastore_find(chan, &msg_datastore, NULL))) {
00775 return ds;
00776 }
00777
00778 if (!(ds = ast_datastore_alloc(&msg_datastore, NULL))) {
00779 return NULL;
00780 }
00781
00782 if (!(ds->data = ast_msg_alloc())) {
00783 ast_datastore_free(ds);
00784 return NULL;
00785 }
00786
00787 ast_channel_datastore_add(chan, ds);
00788
00789 return ds;
00790 }
00791
00792 static int msg_func_read(struct ast_channel *chan, const char *function,
00793 char *data, char *buf, size_t len)
00794 {
00795 struct ast_datastore *ds;
00796 struct ast_msg *msg;
00797
00798 ast_channel_lock(chan);
00799
00800 if (!(ds = ast_channel_datastore_find(chan, &msg_datastore, NULL))) {
00801 ast_channel_unlock(chan);
00802 ast_log(LOG_ERROR, "No MESSAGE data found on the channel to read.\n");
00803 return -1;
00804 }
00805
00806 msg = ds->data;
00807 ao2_ref(msg, +1);
00808 ast_channel_unlock(chan);
00809
00810 ao2_lock(msg);
00811
00812 if (!strcasecmp(data, "to")) {
00813 ast_copy_string(buf, ast_str_buffer(msg->to), len);
00814 } else if (!strcasecmp(data, "from")) {
00815 ast_copy_string(buf, ast_str_buffer(msg->from), len);
00816 } else if (!strcasecmp(data, "body")) {
00817 ast_copy_string(buf, ast_msg_get_body(msg), len);
00818 } else {
00819 ast_log(LOG_WARNING, "Invalid argument to MESSAGE(): '%s'\n", data);
00820 }
00821
00822 ao2_unlock(msg);
00823 ao2_ref(msg, -1);
00824
00825 return 0;
00826 }
00827
00828 static int msg_func_write(struct ast_channel *chan, const char *function,
00829 char *data, const char *value)
00830 {
00831 struct ast_datastore *ds;
00832 struct ast_msg *msg;
00833
00834 ast_channel_lock(chan);
00835
00836 if (!(ds = msg_datastore_find_or_create(chan))) {
00837 ast_channel_unlock(chan);
00838 return -1;
00839 }
00840
00841 msg = ds->data;
00842 ao2_ref(msg, +1);
00843 ast_channel_unlock(chan);
00844
00845 ao2_lock(msg);
00846
00847 if (!strcasecmp(data, "to")) {
00848 ast_msg_set_to(msg, "%s", value);
00849 } else if (!strcasecmp(data, "from")) {
00850 ast_msg_set_from(msg, "%s", value);
00851 } else if (!strcasecmp(data, "body")) {
00852 ast_msg_set_body(msg, "%s", value);
00853 } else {
00854 ast_log(LOG_WARNING, "'%s' is not a valid write argument.\n", data);
00855 }
00856
00857 ao2_unlock(msg);
00858 ao2_ref(msg, -1);
00859
00860 return 0;
00861 }
00862
00863 static int msg_data_func_read(struct ast_channel *chan, const char *function,
00864 char *data, char *buf, size_t len)
00865 {
00866 struct ast_datastore *ds;
00867 struct ast_msg *msg;
00868 const char *val;
00869
00870 ast_channel_lock(chan);
00871
00872 if (!(ds = ast_channel_datastore_find(chan, &msg_datastore, NULL))) {
00873 ast_channel_unlock(chan);
00874 ast_log(LOG_ERROR, "No MESSAGE data found on the channel to read.\n");
00875 return -1;
00876 }
00877
00878 msg = ds->data;
00879 ao2_ref(msg, +1);
00880 ast_channel_unlock(chan);
00881
00882 ao2_lock(msg);
00883
00884 if ((val = ast_msg_get_var(msg, data))) {
00885 ast_copy_string(buf, val, len);
00886 }
00887
00888 ao2_unlock(msg);
00889 ao2_ref(msg, -1);
00890
00891 return 0;
00892 }
00893
00894 static int msg_data_func_write(struct ast_channel *chan, const char *function,
00895 char *data, const char *value)
00896 {
00897 struct ast_datastore *ds;
00898 struct ast_msg *msg;
00899
00900 ast_channel_lock(chan);
00901
00902 if (!(ds = msg_datastore_find_or_create(chan))) {
00903 ast_channel_unlock(chan);
00904 return -1;
00905 }
00906
00907 msg = ds->data;
00908 ao2_ref(msg, +1);
00909 ast_channel_unlock(chan);
00910
00911 ao2_lock(msg);
00912
00913 msg_set_var_outbound(msg, data, value);
00914
00915 ao2_unlock(msg);
00916 ao2_ref(msg, -1);
00917
00918 return 0;
00919 }
00920 static int msg_tech_hash(const void *obj, const int flags)
00921 {
00922 struct ast_msg_tech_holder *tech_holder = (struct ast_msg_tech_holder *) obj;
00923 int res = 0;
00924
00925 ast_rwlock_rdlock(&tech_holder->tech_lock);
00926 if (tech_holder->tech) {
00927 res = ast_str_case_hash(tech_holder->tech->name);
00928 }
00929 ast_rwlock_unlock(&tech_holder->tech_lock);
00930
00931 return res;
00932 }
00933
00934 static int msg_tech_cmp(void *obj, void *arg, int flags)
00935 {
00936 struct ast_msg_tech_holder *tech_holder = obj;
00937 const struct ast_msg_tech_holder *tech_holder2 = arg;
00938 int res = 1;
00939
00940 ast_rwlock_rdlock(&tech_holder->tech_lock);
00941
00942
00943
00944 if (tech_holder->tech) {
00945 res = strcasecmp(tech_holder->tech->name, tech_holder2->tech->name) ? 0 : CMP_MATCH | CMP_STOP;
00946 }
00947 ast_rwlock_unlock(&tech_holder->tech_lock);
00948
00949 return res;
00950 }
00951
00952
00953
00954
00955
00956 static int msg_send_exec(struct ast_channel *chan, const char *data)
00957 {
00958 struct ast_datastore *ds;
00959 struct ast_msg *msg;
00960 char *tech_name;
00961 struct ast_msg_tech_holder *tech_holder = NULL;
00962 char *parse;
00963 int res = -1;
00964 AST_DECLARE_APP_ARGS(args,
00965 AST_APP_ARG(to);
00966 AST_APP_ARG(from);
00967 );
00968
00969 if (ast_strlen_zero(data)) {
00970 ast_log(LOG_WARNING, "An argument is required to MessageSend()\n");
00971 pbx_builtin_setvar_helper(chan, "MESSAGE_SEND_STATUS", "INVALID_URI");
00972 return 0;
00973 }
00974
00975 parse = ast_strdupa(data);
00976 AST_STANDARD_APP_ARGS(args, parse);
00977
00978 if (ast_strlen_zero(args.to)) {
00979 ast_log(LOG_WARNING, "A 'to' URI is required for MessageSend()\n");
00980 pbx_builtin_setvar_helper(chan, "MESSAGE_SEND_STATUS", "INVALID_URI");
00981 return 0;
00982 }
00983
00984 ast_channel_lock(chan);
00985
00986 if (!(ds = ast_channel_datastore_find(chan, &msg_datastore, NULL))) {
00987 ast_channel_unlock(chan);
00988 ast_log(LOG_WARNING, "No message data found on channel to send.\n");
00989 pbx_builtin_setvar_helper(chan, "MESSAGE_SEND_STATUS", "FAILURE");
00990 return 0;
00991 }
00992
00993 msg = ds->data;
00994 ao2_ref(msg, +1);
00995 ast_channel_unlock(chan);
00996
00997 tech_name = ast_strdupa(args.to);
00998 tech_name = strsep(&tech_name, ":");
00999
01000 {
01001 struct ast_msg_tech tmp_msg_tech = {
01002 .name = tech_name,
01003 };
01004 struct ast_msg_tech_holder tmp_tech_holder = {
01005 .tech = &tmp_msg_tech,
01006 };
01007
01008 tech_holder = ao2_find(msg_techs, &tmp_tech_holder, OBJ_POINTER);
01009 }
01010
01011 if (!tech_holder) {
01012 ast_log(LOG_WARNING, "No message technology '%s' found.\n", tech_name);
01013 pbx_builtin_setvar_helper(chan, "MESSAGE_SEND_STATUS", "INVALID_PROTOCOL");
01014 goto exit_cleanup;
01015 }
01016
01017
01018
01019
01020
01021
01022 ao2_lock(msg);
01023 ast_rwlock_rdlock(&tech_holder->tech_lock);
01024 if (tech_holder->tech) {
01025 res = tech_holder->tech->msg_send(msg, S_OR(args.to, ""),
01026 S_OR(args.from, ""));
01027 }
01028 ast_rwlock_unlock(&tech_holder->tech_lock);
01029 ao2_unlock(msg);
01030
01031 pbx_builtin_setvar_helper(chan, "MESSAGE_SEND_STATUS", res ? "FAILURE" : "SUCCESS");
01032
01033 exit_cleanup:
01034 if (tech_holder) {
01035 ao2_ref(tech_holder, -1);
01036 tech_holder = NULL;
01037 }
01038
01039 ao2_ref(msg, -1);
01040
01041 return 0;
01042 }
01043
01044 int ast_msg_tech_register(const struct ast_msg_tech *tech)
01045 {
01046 struct ast_msg_tech_holder tmp_tech_holder = {
01047 .tech = tech,
01048 };
01049 struct ast_msg_tech_holder *tech_holder;
01050
01051 if ((tech_holder = ao2_find(msg_techs, &tmp_tech_holder, OBJ_POINTER))) {
01052 ao2_ref(tech_holder, -1);
01053 ast_log(LOG_ERROR, "Message technology already registered for '%s'\n",
01054 tech->name);
01055 return -1;
01056 }
01057
01058 if (!(tech_holder = ao2_alloc(sizeof(*tech_holder), NULL))) {
01059 return -1;
01060 }
01061
01062 ast_rwlock_init(&tech_holder->tech_lock);
01063 tech_holder->tech = tech;
01064
01065 ao2_link(msg_techs, tech_holder);
01066
01067 ao2_ref(tech_holder, -1);
01068 tech_holder = NULL;
01069
01070 ast_verb(3, "Message technology handler '%s' registered.\n", tech->name);
01071
01072 return 0;
01073 }
01074
01075 int ast_msg_tech_unregister(const struct ast_msg_tech *tech)
01076 {
01077 struct ast_msg_tech_holder tmp_tech_holder = {
01078 .tech = tech,
01079 };
01080 struct ast_msg_tech_holder *tech_holder;
01081
01082 tech_holder = ao2_find(msg_techs, &tmp_tech_holder, OBJ_POINTER | OBJ_UNLINK);
01083
01084 if (!tech_holder) {
01085 ast_log(LOG_ERROR, "No '%s' message technology found.\n", tech->name);
01086 return -1;
01087 }
01088
01089 ast_rwlock_wrlock(&tech_holder->tech_lock);
01090 tech_holder->tech = NULL;
01091 ast_rwlock_unlock(&tech_holder->tech_lock);
01092
01093 ao2_ref(tech_holder, -1);
01094 tech_holder = NULL;
01095
01096 ast_verb(3, "Message technology handler '%s' unregistered.\n", tech->name);
01097
01098 return 0;
01099 }
01100
01101
01102
01103
01104
01105
01106
01107
01108
01109
01110
01111 int ast_msg_init(void)
01112 {
01113 int res;
01114
01115 msg_q_tp = ast_taskprocessor_get("ast_msg_queue", TPS_REF_DEFAULT);
01116 if (!msg_q_tp) {
01117 return -1;
01118 }
01119
01120 msg_techs = ao2_container_alloc(17, msg_tech_hash, msg_tech_cmp);
01121 if (!msg_techs) {
01122 return -1;
01123 }
01124
01125 res = __ast_custom_function_register(&msg_function, NULL);
01126 res |= __ast_custom_function_register(&msg_data_function, NULL);
01127 res |= ast_register_application2(app_msg_send, msg_send_exec, NULL, NULL, NULL);
01128
01129 return res;
01130 }