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
00027
00028
00029
00030
00031 #include "asterisk.h"
00032
00033 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 411313 $")
00034
00035 #include <regex.h>
00036 #include <ctype.h>
00037
00038 #include "asterisk/module.h"
00039 #include "asterisk/channel.h"
00040 #include "asterisk/pbx.h"
00041 #include "asterisk/utils.h"
00042 #include "asterisk/app.h"
00043 #include "asterisk/indications.h"
00044 #include "asterisk/stringfields.h"
00045 #include "asterisk/global_datastores.h"
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
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317 #define locked_copy_string(chan, dest, source, len) \
00318 do { \
00319 ast_channel_lock(chan); \
00320 ast_copy_string(dest, source, len); \
00321 ast_channel_unlock(chan); \
00322 } while (0)
00323 #define locked_string_field_set(chan, field, source) \
00324 do { \
00325 ast_channel_lock(chan); \
00326 ast_string_field_set(chan, field, source); \
00327 ast_channel_unlock(chan); \
00328 } while (0)
00329
00330 static const char * const transfercapability_table[0x20] = {
00331 "SPEECH", "UNK", "UNK", "UNK", "UNK", "UNK", "UNK", "UNK",
00332 "DIGITAL", "RESTRICTED_DIGITAL", "UNK", "UNK", "UNK", "UNK", "UNK", "UNK",
00333 "3K1AUDIO", "DIGITAL_W_TONES", "UNK", "UNK", "UNK", "UNK", "UNK", "UNK",
00334 "VIDEO", "UNK", "UNK", "UNK", "UNK", "UNK", "UNK", "UNK", };
00335
00336 static int func_channel_read(struct ast_channel *chan, const char *function,
00337 char *data, char *buf, size_t len)
00338 {
00339 int ret = 0;
00340
00341 if (!chan) {
00342 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", function);
00343 return -1;
00344 }
00345
00346 if (!strcasecmp(data, "audionativeformat"))
00347
00348
00349 ast_copy_string(buf, ast_getformatname(chan->nativeformats & AST_FORMAT_AUDIO_MASK), len);
00350 else if (!strcasecmp(data, "videonativeformat"))
00351
00352
00353 ast_copy_string(buf, ast_getformatname(chan->nativeformats & AST_FORMAT_VIDEO_MASK), len);
00354 else if (!strcasecmp(data, "audioreadformat"))
00355 ast_copy_string(buf, ast_getformatname(chan->readformat), len);
00356 else if (!strcasecmp(data, "audiowriteformat"))
00357 ast_copy_string(buf, ast_getformatname(chan->writeformat), len);
00358 #ifdef CHANNEL_TRACE
00359 else if (!strcasecmp(data, "trace")) {
00360 ast_channel_lock(chan);
00361 ast_copy_string(buf, ast_channel_trace_is_enabled(chan) ? "1" : "0", len);
00362 ast_channel_unlock(chan);
00363 }
00364 #endif
00365 else if (!strcasecmp(data, "tonezone") && chan->zone)
00366 locked_copy_string(chan, buf, chan->zone->country, len);
00367 else if (!strcasecmp(data, "language"))
00368 locked_copy_string(chan, buf, chan->language, len);
00369 else if (!strcasecmp(data, "musicclass"))
00370 locked_copy_string(chan, buf, chan->musicclass, len);
00371 else if (!strcasecmp(data, "name")) {
00372 locked_copy_string(chan, buf, chan->name, len);
00373 } else if (!strcasecmp(data, "parkinglot"))
00374 locked_copy_string(chan, buf, chan->parkinglot, len);
00375 else if (!strcasecmp(data, "state"))
00376 locked_copy_string(chan, buf, ast_state2str(chan->_state), len);
00377 else if (!strcasecmp(data, "channeltype"))
00378 locked_copy_string(chan, buf, chan->tech->type, len);
00379 else if (!strcasecmp(data, "accountcode"))
00380 locked_copy_string(chan, buf, chan->accountcode, len);
00381 else if (!strcasecmp(data, "checkhangup")) {
00382 ast_channel_lock(chan);
00383 ast_copy_string(buf, ast_check_hangup(chan) ? "1" : "0", len);
00384 ast_channel_unlock(chan);
00385 } else if (!strcasecmp(data, "peeraccount"))
00386 locked_copy_string(chan, buf, chan->peeraccount, len);
00387 else if (!strcasecmp(data, "hangupsource"))
00388 locked_copy_string(chan, buf, chan->hangupsource, len);
00389 else if (!strcasecmp(data, "appname") && chan->appl)
00390 locked_copy_string(chan, buf, chan->appl, len);
00391 else if (!strcasecmp(data, "appdata") && chan->data)
00392 locked_copy_string(chan, buf, chan->data, len);
00393 else if (!strcasecmp(data, "exten") && chan->data)
00394 locked_copy_string(chan, buf, chan->exten, len);
00395 else if (!strcasecmp(data, "context") && chan->data)
00396 locked_copy_string(chan, buf, chan->context, len);
00397 else if (!strcasecmp(data, "userfield") && chan->data)
00398 locked_copy_string(chan, buf, chan->userfield, len);
00399 else if (!strcasecmp(data, "channame") && chan->data)
00400 locked_copy_string(chan, buf, chan->name, len);
00401 else if (!strcasecmp(data, "linkedid")) {
00402 ast_channel_lock(chan);
00403 if (ast_strlen_zero(chan->linkedid)) {
00404
00405 ast_copy_string(buf, chan->uniqueid, len);
00406 }
00407 else {
00408 ast_copy_string(buf, chan->linkedid, len);
00409 }
00410 ast_channel_unlock(chan);
00411 } else if (!strcasecmp(data, "peer")) {
00412 struct ast_channel *p;
00413 ast_channel_lock(chan);
00414 p = ast_bridged_channel(chan);
00415 if (p || chan->tech || chan->cdr)
00416 ast_copy_string(buf, (p ? p->name : ""), len);
00417 else {
00418
00419
00420 const char *pname = pbx_builtin_getvar_helper(chan, "BRIDGEPEER");
00421 if (!ast_strlen_zero(pname))
00422 ast_copy_string(buf, pname, len);
00423 else
00424 buf[0] = 0;
00425 }
00426 ast_channel_unlock(chan);
00427 } else if (!strcasecmp(data, "uniqueid")) {
00428 locked_copy_string(chan, buf, chan->uniqueid, len);
00429 } else if (!strcasecmp(data, "transfercapability"))
00430 locked_copy_string(chan, buf, transfercapability_table[chan->transfercapability & 0x1f], len);
00431 else if (!strcasecmp(data, "callgroup")) {
00432 char groupbuf[256];
00433 locked_copy_string(chan, buf, ast_print_group(groupbuf, sizeof(groupbuf), chan->callgroup), len);
00434 } else if (!strcasecmp(data, "amaflags")) {
00435 char amabuf[256];
00436 snprintf(amabuf,sizeof(amabuf), "%d", chan->amaflags);
00437 locked_copy_string(chan, buf, amabuf, len);
00438 } else if (!strncasecmp(data, "secure_bridge_", 14)) {
00439 struct ast_datastore *ds;
00440 ast_channel_lock(chan);
00441 if ((ds = ast_channel_datastore_find(chan, &secure_call_info, NULL))) {
00442 struct ast_secure_call_store *encrypt = ds->data;
00443 if (!strcasecmp(data, "secure_bridge_signaling")) {
00444 snprintf(buf, len, "%s", encrypt->signaling ? "1" : "");
00445 } else if (!strcasecmp(data, "secure_bridge_media")) {
00446 snprintf(buf, len, "%s", encrypt->media ? "1" : "");
00447 }
00448 }
00449 ast_channel_unlock(chan);
00450 } else if (!chan->tech || !chan->tech->func_channel_read || chan->tech->func_channel_read(chan, function, data, buf, len)) {
00451 ast_log(LOG_WARNING, "Unknown or unavailable item requested: '%s'\n", data);
00452 ret = -1;
00453 }
00454
00455 return ret;
00456 }
00457
00458 static int func_channel_write_real(struct ast_channel *chan, const char *function,
00459 char *data, const char *value)
00460 {
00461 int ret = 0;
00462 signed char gainset;
00463
00464 if (!strcasecmp(data, "language"))
00465 locked_string_field_set(chan, language, value);
00466 else if (!strcasecmp(data, "parkinglot"))
00467 locked_string_field_set(chan, parkinglot, value);
00468 else if (!strcasecmp(data, "musicclass"))
00469 locked_string_field_set(chan, musicclass, value);
00470 else if (!strcasecmp(data, "accountcode"))
00471 locked_string_field_set(chan, accountcode, value);
00472 else if (!strcasecmp(data, "userfield"))
00473 locked_string_field_set(chan, userfield, value);
00474 else if (!strcasecmp(data, "amaflags")) {
00475 ast_channel_lock(chan);
00476 if(isdigit(*value)) {
00477 sscanf(value, "%30d", &chan->amaflags);
00478 } else if (!strcasecmp(value,"OMIT")){
00479 chan->amaflags = 1;
00480 } else if (!strcasecmp(value,"BILLING")){
00481 chan->amaflags = 2;
00482 } else if (!strcasecmp(value,"DOCUMENTATION")){
00483 chan->amaflags = 3;
00484 }
00485 ast_channel_unlock(chan);
00486 } else if (!strcasecmp(data, "peeraccount"))
00487 locked_string_field_set(chan, peeraccount, value);
00488 else if (!strcasecmp(data, "hangupsource"))
00489
00490 ast_set_hangupsource(chan, value, 0);
00491 #ifdef CHANNEL_TRACE
00492 else if (!strcasecmp(data, "trace")) {
00493 ast_channel_lock(chan);
00494 if (ast_true(value))
00495 ret = ast_channel_trace_enable(chan);
00496 else if (ast_false(value))
00497 ret = ast_channel_trace_disable(chan);
00498 else {
00499 ret = -1;
00500 ast_log(LOG_WARNING, "Invalid value for CHANNEL(trace).\n");
00501 }
00502 ast_channel_unlock(chan);
00503 }
00504 #endif
00505 else if (!strcasecmp(data, "tonezone")) {
00506 struct ast_tone_zone *new_zone;
00507 if (!(new_zone = ast_get_indication_zone(value))) {
00508 ast_log(LOG_ERROR, "Unknown country code '%s' for tonezone. Check indications.conf for available country codes.\n", value);
00509 ret = -1;
00510 } else {
00511 ast_channel_lock(chan);
00512 if (chan->zone) {
00513 chan->zone = ast_tone_zone_unref(chan->zone);
00514 }
00515 chan->zone = ast_tone_zone_ref(new_zone);
00516 ast_channel_unlock(chan);
00517 new_zone = ast_tone_zone_unref(new_zone);
00518 }
00519 } else if (!strcasecmp(data, "callgroup"))
00520 chan->callgroup = ast_get_group(value);
00521 else if (!strcasecmp(data, "txgain")) {
00522 sscanf(value, "%4hhd", &gainset);
00523 ast_channel_setoption(chan, AST_OPTION_TXGAIN, &gainset, sizeof(gainset), 0);
00524 } else if (!strcasecmp(data, "rxgain")) {
00525 sscanf(value, "%4hhd", &gainset);
00526 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &gainset, sizeof(gainset), 0);
00527 } else if (!strcasecmp(data, "transfercapability")) {
00528 unsigned short i;
00529 for (i = 0; i < 0x20; i++) {
00530 if (!strcasecmp(transfercapability_table[i], value) && strcmp(value, "UNK")) {
00531 chan->transfercapability = i;
00532 break;
00533 }
00534 }
00535 } else if (!strncasecmp(data, "secure_bridge_", 14)) {
00536 struct ast_datastore *ds;
00537 struct ast_secure_call_store *store;
00538
00539 if (!chan || !value) {
00540 return -1;
00541 }
00542
00543 ast_channel_lock(chan);
00544 if (!(ds = ast_channel_datastore_find(chan, &secure_call_info, NULL))) {
00545 if (!(ds = ast_datastore_alloc(&secure_call_info, NULL))) {
00546 ast_channel_unlock(chan);
00547 return -1;
00548 }
00549 if (!(store = ast_calloc(1, sizeof(*store)))) {
00550 ast_channel_unlock(chan);
00551 ast_free(ds);
00552 return -1;
00553 }
00554 ds->data = store;
00555 ast_channel_datastore_add(chan, ds);
00556 } else {
00557 store = ds->data;
00558 }
00559 ast_channel_unlock(chan);
00560
00561 if (!strcasecmp(data, "secure_bridge_signaling")) {
00562 store->signaling = ast_true(value) ? 1 : 0;
00563 } else if (!strcasecmp(data, "secure_bridge_media")) {
00564 store->media = ast_true(value) ? 1 : 0;
00565 }
00566 } else if (!chan->tech->func_channel_write
00567 || chan->tech->func_channel_write(chan, function, data, value)) {
00568 ast_log(LOG_WARNING, "Unknown or unavailable item requested: '%s'\n",
00569 data);
00570 ret = -1;
00571 }
00572
00573 return ret;
00574 }
00575
00576 static int func_channel_write(struct ast_channel *chan, const char *function, char *data, const char *value)
00577 {
00578 int res;
00579 ast_chan_write_info_t write_info = {
00580 .version = AST_CHAN_WRITE_INFO_T_VERSION,
00581 .write_fn = func_channel_write_real,
00582 .chan = chan,
00583 .function = function,
00584 .data = data,
00585 .value = value,
00586 };
00587
00588 if (!chan) {
00589 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", function);
00590 return -1;
00591 }
00592
00593 res = func_channel_write_real(chan, function, data, value);
00594 ast_channel_setoption(chan, AST_OPTION_CHANNEL_WRITE, &write_info, sizeof(write_info), 0);
00595
00596 return res;
00597 }
00598
00599 static struct ast_custom_function channel_function = {
00600 .name = "CHANNEL",
00601 .read = func_channel_read,
00602 .write = func_channel_write,
00603 };
00604
00605 static int func_channels_read(struct ast_channel *chan, const char *function, char *data, char *buf, size_t maxlen)
00606 {
00607 struct ast_channel *c = NULL;
00608 regex_t re;
00609 int res;
00610 size_t buflen = 0;
00611 struct ast_channel_iterator *iter;
00612
00613 buf[0] = '\0';
00614
00615 if (!ast_strlen_zero(data)) {
00616 if ((res = regcomp(&re, data, REG_EXTENDED | REG_ICASE | REG_NOSUB))) {
00617 regerror(res, &re, buf, maxlen);
00618 ast_log(LOG_WARNING, "Error compiling regular expression for %s(%s): %s\n", function, data, buf);
00619 return -1;
00620 }
00621 }
00622
00623 if (!(iter = ast_channel_iterator_all_new())) {
00624 if (!ast_strlen_zero(data)) {
00625 regfree(&re);
00626 }
00627 return -1;
00628 }
00629
00630 while ((c = ast_channel_iterator_next(iter))) {
00631 ast_channel_lock(c);
00632 if (ast_strlen_zero(data) || regexec(&re, c->name, 0, NULL, 0) == 0) {
00633 size_t namelen = strlen(c->name);
00634 if (buflen + namelen + (ast_strlen_zero(buf) ? 0 : 1) + 1 < maxlen) {
00635 if (!ast_strlen_zero(buf)) {
00636 strcat(buf, " ");
00637 buflen++;
00638 }
00639 strcat(buf, c->name);
00640 buflen += namelen;
00641 } else {
00642 ast_log(LOG_WARNING, "Number of channels exceeds the available buffer space. Output will be truncated!\n");
00643 }
00644 }
00645 ast_channel_unlock(c);
00646 c = ast_channel_unref(c);
00647 }
00648
00649 ast_channel_iterator_destroy(iter);
00650
00651 if (!ast_strlen_zero(data)) {
00652 regfree(&re);
00653 }
00654
00655 return 0;
00656 }
00657
00658 static struct ast_custom_function channels_function = {
00659 .name = "CHANNELS",
00660 .read = func_channels_read,
00661 };
00662
00663 static int func_mchan_read(struct ast_channel *chan, const char *function,
00664 char *data, struct ast_str **buf, ssize_t len)
00665 {
00666 struct ast_channel *mchan;
00667 char *template = ast_alloca(4 + strlen(data));
00668
00669 if (!chan) {
00670 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", function);
00671 return -1;
00672 }
00673
00674 mchan = ast_channel_get_by_name(chan->linkedid);
00675 sprintf(template, "${%s}", data);
00676 ast_str_substitute_variables(buf, len, mchan ? mchan : chan, template);
00677 if (mchan) {
00678 ast_channel_unref(mchan);
00679 }
00680 return 0;
00681 }
00682
00683 static int func_mchan_write(struct ast_channel *chan, const char *function,
00684 char *data, const char *value)
00685 {
00686 struct ast_channel *mchan;
00687
00688 if (!chan) {
00689 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", function);
00690 return -1;
00691 }
00692
00693 mchan = ast_channel_get_by_name(chan->linkedid);
00694 pbx_builtin_setvar_helper(mchan ? mchan : chan, data, value);
00695 if (mchan) {
00696 ast_channel_unref(mchan);
00697 }
00698 return 0;
00699 }
00700
00701 static struct ast_custom_function mchan_function = {
00702 .name = "MASTER_CHANNEL",
00703 .read2 = func_mchan_read,
00704 .write = func_mchan_write,
00705 };
00706
00707 static int unload_module(void)
00708 {
00709 int res = 0;
00710
00711 res |= ast_custom_function_unregister(&channel_function);
00712 res |= ast_custom_function_unregister(&channels_function);
00713 res |= ast_custom_function_unregister(&mchan_function);
00714
00715 return res;
00716 }
00717
00718 static int load_module(void)
00719 {
00720 int res = 0;
00721
00722 res |= ast_custom_function_register(&channel_function);
00723 res |= ast_custom_function_register(&channels_function);
00724 res |= ast_custom_function_register(&mchan_function);
00725
00726 return res;
00727 }
00728
00729 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Channel information dialplan functions");