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