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: 394980 $")
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 (!strcasecmp(data, "audionativeformat"))
00342
00343
00344 ast_copy_string(buf, ast_getformatname(chan->nativeformats & AST_FORMAT_AUDIO_MASK), len);
00345 else if (!strcasecmp(data, "videonativeformat"))
00346
00347
00348 ast_copy_string(buf, ast_getformatname(chan->nativeformats & AST_FORMAT_VIDEO_MASK), len);
00349 else if (!strcasecmp(data, "audioreadformat"))
00350 ast_copy_string(buf, ast_getformatname(chan->readformat), len);
00351 else if (!strcasecmp(data, "audiowriteformat"))
00352 ast_copy_string(buf, ast_getformatname(chan->writeformat), len);
00353 #ifdef CHANNEL_TRACE
00354 else if (!strcasecmp(data, "trace")) {
00355 ast_channel_lock(chan);
00356 ast_copy_string(buf, ast_channel_trace_is_enabled(chan) ? "1" : "0", len);
00357 ast_channel_unlock(chan);
00358 }
00359 #endif
00360 else if (!strcasecmp(data, "tonezone") && chan->zone)
00361 locked_copy_string(chan, buf, chan->zone->country, len);
00362 else if (!strcasecmp(data, "language"))
00363 locked_copy_string(chan, buf, chan->language, len);
00364 else if (!strcasecmp(data, "musicclass"))
00365 locked_copy_string(chan, buf, chan->musicclass, len);
00366 else if (!strcasecmp(data, "name")) {
00367 locked_copy_string(chan, buf, chan->name, len);
00368 } else if (!strcasecmp(data, "parkinglot"))
00369 locked_copy_string(chan, buf, chan->parkinglot, len);
00370 else if (!strcasecmp(data, "state"))
00371 locked_copy_string(chan, buf, ast_state2str(chan->_state), len);
00372 else if (!strcasecmp(data, "channeltype"))
00373 locked_copy_string(chan, buf, chan->tech->type, len);
00374 else if (!strcasecmp(data, "accountcode"))
00375 locked_copy_string(chan, buf, chan->accountcode, len);
00376 else if (!strcasecmp(data, "checkhangup")) {
00377 ast_channel_lock(chan);
00378 ast_copy_string(buf, ast_check_hangup(chan) ? "1" : "0", len);
00379 ast_channel_unlock(chan);
00380 } else if (!strcasecmp(data, "peeraccount"))
00381 locked_copy_string(chan, buf, chan->peeraccount, len);
00382 else if (!strcasecmp(data, "hangupsource"))
00383 locked_copy_string(chan, buf, chan->hangupsource, len);
00384 else if (!strcasecmp(data, "appname") && chan->appl)
00385 locked_copy_string(chan, buf, chan->appl, len);
00386 else if (!strcasecmp(data, "appdata") && chan->data)
00387 locked_copy_string(chan, buf, chan->data, len);
00388 else if (!strcasecmp(data, "exten") && chan->data)
00389 locked_copy_string(chan, buf, chan->exten, len);
00390 else if (!strcasecmp(data, "context") && chan->data)
00391 locked_copy_string(chan, buf, chan->context, len);
00392 else if (!strcasecmp(data, "userfield") && chan->data)
00393 locked_copy_string(chan, buf, chan->userfield, len);
00394 else if (!strcasecmp(data, "channame") && chan->data)
00395 locked_copy_string(chan, buf, chan->name, len);
00396 else if (!strcasecmp(data, "linkedid")) {
00397 ast_channel_lock(chan);
00398 if (ast_strlen_zero(chan->linkedid)) {
00399
00400 ast_copy_string(buf, chan->uniqueid, len);
00401 }
00402 else {
00403 ast_copy_string(buf, chan->linkedid, len);
00404 }
00405 ast_channel_unlock(chan);
00406 } else if (!strcasecmp(data, "peer")) {
00407 struct ast_channel *p;
00408 ast_channel_lock(chan);
00409 p = ast_bridged_channel(chan);
00410 if (p || chan->tech || chan->cdr)
00411 ast_copy_string(buf, (p ? p->name : ""), len);
00412 else {
00413
00414
00415 const char *pname = pbx_builtin_getvar_helper(chan, "BRIDGEPEER");
00416 if (!ast_strlen_zero(pname))
00417 ast_copy_string(buf, pname, len);
00418 else
00419 buf[0] = 0;
00420 }
00421 ast_channel_unlock(chan);
00422 } else if (!strcasecmp(data, "uniqueid")) {
00423 locked_copy_string(chan, buf, chan->uniqueid, len);
00424 } else if (!strcasecmp(data, "transfercapability"))
00425 locked_copy_string(chan, buf, transfercapability_table[chan->transfercapability & 0x1f], len);
00426 else if (!strcasecmp(data, "callgroup")) {
00427 char groupbuf[256];
00428 locked_copy_string(chan, buf, ast_print_group(groupbuf, sizeof(groupbuf), chan->callgroup), len);
00429 } else if (!strcasecmp(data, "amaflags")) {
00430 char amabuf[256];
00431 snprintf(amabuf,sizeof(amabuf), "%d", chan->amaflags);
00432 locked_copy_string(chan, buf, amabuf, len);
00433 } else if (!strncasecmp(data, "secure_bridge_", 14)) {
00434 struct ast_datastore *ds;
00435 ast_channel_lock(chan);
00436 if ((ds = ast_channel_datastore_find(chan, &secure_call_info, NULL))) {
00437 struct ast_secure_call_store *encrypt = ds->data;
00438 if (!strcasecmp(data, "secure_bridge_signaling")) {
00439 snprintf(buf, len, "%s", encrypt->signaling ? "1" : "");
00440 } else if (!strcasecmp(data, "secure_bridge_media")) {
00441 snprintf(buf, len, "%s", encrypt->media ? "1" : "");
00442 }
00443 }
00444 ast_channel_unlock(chan);
00445 } else if (!chan->tech || !chan->tech->func_channel_read || chan->tech->func_channel_read(chan, function, data, buf, len)) {
00446 ast_log(LOG_WARNING, "Unknown or unavailable item requested: '%s'\n", data);
00447 ret = -1;
00448 }
00449
00450 return ret;
00451 }
00452
00453 static int func_channel_write_real(struct ast_channel *chan, const char *function,
00454 char *data, const char *value)
00455 {
00456 int ret = 0;
00457 signed char gainset;
00458
00459 if (!strcasecmp(data, "language"))
00460 locked_string_field_set(chan, language, value);
00461 else if (!strcasecmp(data, "parkinglot"))
00462 locked_string_field_set(chan, parkinglot, value);
00463 else if (!strcasecmp(data, "musicclass"))
00464 locked_string_field_set(chan, musicclass, value);
00465 else if (!strcasecmp(data, "accountcode"))
00466 locked_string_field_set(chan, accountcode, value);
00467 else if (!strcasecmp(data, "userfield"))
00468 locked_string_field_set(chan, userfield, value);
00469 else if (!strcasecmp(data, "amaflags")) {
00470 ast_channel_lock(chan);
00471 if(isdigit(*value)) {
00472 sscanf(value, "%30d", &chan->amaflags);
00473 } else if (!strcasecmp(value,"OMIT")){
00474 chan->amaflags = 1;
00475 } else if (!strcasecmp(value,"BILLING")){
00476 chan->amaflags = 2;
00477 } else if (!strcasecmp(value,"DOCUMENTATION")){
00478 chan->amaflags = 3;
00479 }
00480 ast_channel_unlock(chan);
00481 } else if (!strcasecmp(data, "peeraccount"))
00482 locked_string_field_set(chan, peeraccount, value);
00483 else if (!strcasecmp(data, "hangupsource"))
00484
00485 ast_set_hangupsource(chan, value, 0);
00486 #ifdef CHANNEL_TRACE
00487 else if (!strcasecmp(data, "trace")) {
00488 ast_channel_lock(chan);
00489 if (ast_true(value))
00490 ret = ast_channel_trace_enable(chan);
00491 else if (ast_false(value))
00492 ret = ast_channel_trace_disable(chan);
00493 else {
00494 ret = -1;
00495 ast_log(LOG_WARNING, "Invalid value for CHANNEL(trace).\n");
00496 }
00497 ast_channel_unlock(chan);
00498 }
00499 #endif
00500 else if (!strcasecmp(data, "tonezone")) {
00501 struct ast_tone_zone *new_zone;
00502 if (!(new_zone = ast_get_indication_zone(value))) {
00503 ast_log(LOG_ERROR, "Unknown country code '%s' for tonezone. Check indications.conf for available country codes.\n", value);
00504 ret = -1;
00505 } else {
00506 ast_channel_lock(chan);
00507 if (chan->zone) {
00508 chan->zone = ast_tone_zone_unref(chan->zone);
00509 }
00510 chan->zone = ast_tone_zone_ref(new_zone);
00511 ast_channel_unlock(chan);
00512 new_zone = ast_tone_zone_unref(new_zone);
00513 }
00514 } else if (!strcasecmp(data, "callgroup"))
00515 chan->callgroup = ast_get_group(value);
00516 else if (!strcasecmp(data, "txgain")) {
00517 sscanf(value, "%4hhd", &gainset);
00518 ast_channel_setoption(chan, AST_OPTION_TXGAIN, &gainset, sizeof(gainset), 0);
00519 } else if (!strcasecmp(data, "rxgain")) {
00520 sscanf(value, "%4hhd", &gainset);
00521 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &gainset, sizeof(gainset), 0);
00522 } else if (!strcasecmp(data, "transfercapability")) {
00523 unsigned short i;
00524 for (i = 0; i < 0x20; i++) {
00525 if (!strcasecmp(transfercapability_table[i], value) && strcmp(value, "UNK")) {
00526 chan->transfercapability = i;
00527 break;
00528 }
00529 }
00530 } else if (!strncasecmp(data, "secure_bridge_", 14)) {
00531 struct ast_datastore *ds;
00532 struct ast_secure_call_store *store;
00533
00534 if (!chan || !value) {
00535 return -1;
00536 }
00537
00538 ast_channel_lock(chan);
00539 if (!(ds = ast_channel_datastore_find(chan, &secure_call_info, NULL))) {
00540 if (!(ds = ast_datastore_alloc(&secure_call_info, NULL))) {
00541 ast_channel_unlock(chan);
00542 return -1;
00543 }
00544 if (!(store = ast_calloc(1, sizeof(*store)))) {
00545 ast_channel_unlock(chan);
00546 ast_free(ds);
00547 return -1;
00548 }
00549 ds->data = store;
00550 ast_channel_datastore_add(chan, ds);
00551 } else {
00552 store = ds->data;
00553 }
00554 ast_channel_unlock(chan);
00555
00556 if (!strcasecmp(data, "secure_bridge_signaling")) {
00557 store->signaling = ast_true(value) ? 1 : 0;
00558 } else if (!strcasecmp(data, "secure_bridge_media")) {
00559 store->media = ast_true(value) ? 1 : 0;
00560 }
00561 } else if (!chan->tech->func_channel_write
00562 || chan->tech->func_channel_write(chan, function, data, value)) {
00563 ast_log(LOG_WARNING, "Unknown or unavailable item requested: '%s'\n",
00564 data);
00565 ret = -1;
00566 }
00567
00568 return ret;
00569 }
00570
00571 static int func_channel_write(struct ast_channel *chan, const char *function, char *data, const char *value)
00572 {
00573 int res;
00574 ast_chan_write_info_t write_info = {
00575 .version = AST_CHAN_WRITE_INFO_T_VERSION,
00576 .write_fn = func_channel_write_real,
00577 .chan = chan,
00578 .function = function,
00579 .data = data,
00580 .value = value,
00581 };
00582
00583 res = func_channel_write_real(chan, function, data, value);
00584 ast_channel_setoption(chan, AST_OPTION_CHANNEL_WRITE, &write_info, sizeof(write_info), 0);
00585
00586 return res;
00587 }
00588
00589 static struct ast_custom_function channel_function = {
00590 .name = "CHANNEL",
00591 .read = func_channel_read,
00592 .write = func_channel_write,
00593 };
00594
00595 static int func_channels_read(struct ast_channel *chan, const char *function, char *data, char *buf, size_t maxlen)
00596 {
00597 struct ast_channel *c = NULL;
00598 regex_t re;
00599 int res;
00600 size_t buflen = 0;
00601 struct ast_channel_iterator *iter;
00602
00603 buf[0] = '\0';
00604
00605 if (!ast_strlen_zero(data)) {
00606 if ((res = regcomp(&re, data, REG_EXTENDED | REG_ICASE | REG_NOSUB))) {
00607 regerror(res, &re, buf, maxlen);
00608 ast_log(LOG_WARNING, "Error compiling regular expression for %s(%s): %s\n", function, data, buf);
00609 return -1;
00610 }
00611 }
00612
00613 if (!(iter = ast_channel_iterator_all_new())) {
00614 if (!ast_strlen_zero(data)) {
00615 regfree(&re);
00616 }
00617 return -1;
00618 }
00619
00620 while ((c = ast_channel_iterator_next(iter))) {
00621 ast_channel_lock(c);
00622 if (ast_strlen_zero(data) || regexec(&re, c->name, 0, NULL, 0) == 0) {
00623 size_t namelen = strlen(c->name);
00624 if (buflen + namelen + (ast_strlen_zero(buf) ? 0 : 1) + 1 < maxlen) {
00625 if (!ast_strlen_zero(buf)) {
00626 strcat(buf, " ");
00627 buflen++;
00628 }
00629 strcat(buf, c->name);
00630 buflen += namelen;
00631 } else {
00632 ast_log(LOG_WARNING, "Number of channels exceeds the available buffer space. Output will be truncated!\n");
00633 }
00634 }
00635 ast_channel_unlock(c);
00636 c = ast_channel_unref(c);
00637 }
00638
00639 ast_channel_iterator_destroy(iter);
00640
00641 if (!ast_strlen_zero(data)) {
00642 regfree(&re);
00643 }
00644
00645 return 0;
00646 }
00647
00648 static struct ast_custom_function channels_function = {
00649 .name = "CHANNELS",
00650 .read = func_channels_read,
00651 };
00652
00653 static int func_mchan_read(struct ast_channel *chan, const char *function,
00654 char *data, struct ast_str **buf, ssize_t len)
00655 {
00656 struct ast_channel *mchan = ast_channel_get_by_name(chan->linkedid);
00657 char *template = ast_alloca(4 + strlen(data));
00658 sprintf(template, "${%s}", data);
00659 ast_str_substitute_variables(buf, len, mchan ? mchan : chan, template);
00660 if (mchan) {
00661 ast_channel_unref(mchan);
00662 }
00663 return 0;
00664 }
00665
00666 static int func_mchan_write(struct ast_channel *chan, const char *function,
00667 char *data, const char *value)
00668 {
00669 struct ast_channel *mchan = ast_channel_get_by_name(chan->linkedid);
00670 pbx_builtin_setvar_helper(mchan ? mchan : chan, data, value);
00671 if (mchan) {
00672 ast_channel_unref(mchan);
00673 }
00674 return 0;
00675 }
00676
00677 static struct ast_custom_function mchan_function = {
00678 .name = "MASTER_CHANNEL",
00679 .read2 = func_mchan_read,
00680 .write = func_mchan_write,
00681 };
00682
00683 static int unload_module(void)
00684 {
00685 int res = 0;
00686
00687 res |= ast_custom_function_unregister(&channel_function);
00688 res |= ast_custom_function_unregister(&channels_function);
00689 res |= ast_custom_function_unregister(&mchan_function);
00690
00691 return res;
00692 }
00693
00694 static int load_module(void)
00695 {
00696 int res = 0;
00697
00698 res |= ast_custom_function_register(&channel_function);
00699 res |= ast_custom_function_register(&channels_function);
00700 res |= ast_custom_function_register(&mchan_function);
00701
00702 return res;
00703 }
00704
00705 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Channel information dialplan functions");