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 #include "asterisk.h"
00028
00029 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 168565 $")
00030
00031 #include <regex.h>
00032
00033 #include "asterisk/module.h"
00034 #include "asterisk/channel.h"
00035 #include "asterisk/pbx.h"
00036 #include "asterisk/utils.h"
00037 #include "asterisk/app.h"
00038 #include "asterisk/indications.h"
00039 #include "asterisk/stringfields.h"
00040
00041 #define locked_copy_string(chan, dest, source, len) \
00042 do { \
00043 ast_channel_lock(chan); \
00044 ast_copy_string(dest, source, len); \
00045 ast_channel_unlock(chan); \
00046 } while (0)
00047 #define locked_string_field_set(chan, field, source) \
00048 do { \
00049 ast_channel_lock(chan); \
00050 ast_string_field_set(chan, field, source); \
00051 ast_channel_unlock(chan); \
00052 } while (0)
00053
00054 char *transfercapability_table[0x20] = {
00055 "SPEECH", "UNK", "UNK", "UNK", "UNK", "UNK", "UNK", "UNK",
00056 "DIGITAL", "RESTRICTED_DIGITAL", "UNK", "UNK", "UNK", "UNK", "UNK", "UNK",
00057 "3K1AUDIO", "DIGITAL_W_TONES", "UNK", "UNK", "UNK", "UNK", "UNK", "UNK",
00058 "VIDEO", "UNK", "UNK", "UNK", "UNK", "UNK", "UNK", "UNK", };
00059
00060 static int func_channel_read(struct ast_channel *chan, const char *function,
00061 char *data, char *buf, size_t len)
00062 {
00063 int ret = 0;
00064
00065 if (!strcasecmp(data, "audionativeformat"))
00066
00067
00068 ast_copy_string(buf, ast_getformatname(chan->nativeformats & AST_FORMAT_AUDIO_MASK), len);
00069 else if (!strcasecmp(data, "videonativeformat"))
00070
00071
00072 ast_copy_string(buf, ast_getformatname(chan->nativeformats & AST_FORMAT_VIDEO_MASK), len);
00073 else if (!strcasecmp(data, "audioreadformat"))
00074 ast_copy_string(buf, ast_getformatname(chan->readformat), len);
00075 else if (!strcasecmp(data, "audiowriteformat"))
00076 ast_copy_string(buf, ast_getformatname(chan->writeformat), len);
00077 #ifdef CHANNEL_TRACE
00078 else if (!strcasecmp(data, "trace")) {
00079 ast_channel_lock(chan);
00080 ast_copy_string(buf, ast_channel_trace_is_enabled(chan) ? "1" : "0", len);
00081 ast_channel_unlock(chan);
00082 }
00083 #endif
00084 else if (!strcasecmp(data, "tonezone") && chan->zone)
00085 locked_copy_string(chan, buf, chan->zone->country, len);
00086 else if (!strcasecmp(data, "language"))
00087 locked_copy_string(chan, buf, chan->language, len);
00088 else if (!strcasecmp(data, "musicclass"))
00089 locked_copy_string(chan, buf, chan->musicclass, len);
00090 else if (!strcasecmp(data, "parkinglot"))
00091 locked_copy_string(chan, buf, chan->parkinglot, len);
00092 else if (!strcasecmp(data, "state"))
00093 locked_copy_string(chan, buf, ast_state2str(chan->_state), len);
00094 else if (!strcasecmp(data, "channeltype"))
00095 locked_copy_string(chan, buf, chan->tech->type, len);
00096 else if (!strcasecmp(data, "transfercapability"))
00097 locked_copy_string(chan, buf, transfercapability_table[chan->transfercapability & 0x1f], len);
00098 else if (!strcasecmp(data, "callgroup")) {
00099 char groupbuf[256];
00100 locked_copy_string(chan, buf, ast_print_group(groupbuf, sizeof(groupbuf), chan->callgroup), len);
00101 } else if (!chan->tech->func_channel_read
00102 || chan->tech->func_channel_read(chan, function, data, buf, len)) {
00103 ast_log(LOG_WARNING, "Unknown or unavailable item requested: '%s'\n", data);
00104 ret = -1;
00105 }
00106
00107 return ret;
00108 }
00109
00110 static int func_channel_write(struct ast_channel *chan, const char *function,
00111 char *data, const char *value)
00112 {
00113 int ret = 0;
00114 signed char gainset;
00115
00116 if (!strcasecmp(data, "language"))
00117 locked_string_field_set(chan, language, value);
00118 else if (!strcasecmp(data, "parkinglot"))
00119 locked_string_field_set(chan, parkinglot, value);
00120 else if (!strcasecmp(data, "musicclass"))
00121 locked_string_field_set(chan, musicclass, value);
00122 #ifdef CHANNEL_TRACE
00123 else if (!strcasecmp(data, "trace")) {
00124 ast_channel_lock(chan);
00125 if (ast_true(value))
00126 ret = ast_channel_trace_enable(chan);
00127 else if (ast_false(value))
00128 ret = ast_channel_trace_disable(chan);
00129 else {
00130 ret = -1;
00131 ast_log(LOG_WARNING, "Invalid value for CHANNEL(trace).");
00132 }
00133 ast_channel_unlock(chan);
00134 }
00135 #endif
00136 else if (!strcasecmp(data, "tonezone")) {
00137 struct tone_zone *new_zone;
00138 if (!(new_zone = ast_get_indication_zone(value))) {
00139 ast_log(LOG_ERROR, "Unknown country code '%s' for tonezone. Check indications.conf for available country codes.\n", value);
00140 ret = -1;
00141 } else
00142 chan->zone = new_zone;
00143 } else if (!strcasecmp(data, "callgroup"))
00144 chan->callgroup = ast_get_group(value);
00145 else if (!strcasecmp(data, "txgain")) {
00146 sscanf(value, "%hhd", &gainset);
00147 ast_channel_setoption(chan, AST_OPTION_TXGAIN, &gainset, sizeof(gainset), 0);
00148 } else if (!strcasecmp(data, "rxgain")) {
00149 sscanf(value, "%hhd", &gainset);
00150 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &gainset, sizeof(gainset), 0);
00151 } else if (!strcasecmp(data, "transfercapability")) {
00152 unsigned short i;
00153 for (i = 0; i < 0x20; i++) {
00154 if (!strcasecmp(transfercapability_table[i], value) && strcmp(value, "UNK")) {
00155 chan->transfercapability = i;
00156 break;
00157 }
00158 }
00159 } else if (!chan->tech->func_channel_write
00160 || chan->tech->func_channel_write(chan, function, data, value)) {
00161 ast_log(LOG_WARNING, "Unknown or unavailable item requested: '%s'\n",
00162 data);
00163 ret = -1;
00164 }
00165
00166 return ret;
00167 }
00168
00169 static struct ast_custom_function channel_function = {
00170 .name = "CHANNEL",
00171 .synopsis = "Gets/sets various pieces of information about the channel.",
00172 .syntax = "CHANNEL(item)",
00173 .desc = "Gets/set various pieces of information about the channel.\n"
00174 "Standard items (provided by all channel technologies) are:\n"
00175 "R/O audioreadformat format currently being read\n"
00176 "R/O audionativeformat format used natively for audio\n"
00177 "R/O audiowriteformat format currently being written\n"
00178 "R/W callgroup call groups for call pickup\n"
00179 "R/O channeltype technology used for channel\n"
00180 "R/W language language for sounds played\n"
00181 "R/W musicclass class (from musiconhold.conf) for hold music\n"
00182 "R/W parkinglot parkinglot for parking\n"
00183 "R/W rxgain set rxgain level on channel drivers that support it\n"
00184 "R/O state state for channel\n"
00185 "R/W tonezone zone for indications played\n"
00186 "R/W txgain set txgain level on channel drivers that support it\n"
00187 "R/O videonativeformat format used natively for video\n"
00188 #ifdef CHANNEL_TRACE
00189 "R/W trace whether or not context tracing is enabled\n"
00190 #endif
00191 "\n"
00192 "chan_sip provides the following additional options:\n"
00193 "R/O peerip Get the IP address of the peer\n"
00194 "R/O recvip Get the source IP address of the peer\n"
00195 "R/O from Get the URI from the From: header\n"
00196 "R/O uri Get the URI from the Contact: header\n"
00197 "R/O useragent Get the useragent\n"
00198 "R/O peername Get the name of the peer\n"
00199 "R/O t38passthrough 1 if T38 is offered or enabled in this channel, otherwise 0\n"
00200 "R/O rtpqos Get QOS information about the RTP stream\n"
00201 " This option takes two additional arguments:\n"
00202 " Argument 1:\n"
00203 " audio Get data about the audio stream\n"
00204 " video Get data about the video stream\n"
00205 " text Get data about the text stream\n"
00206 " Argument 2:\n"
00207 " local_ssrc Local SSRC (stream ID)\n"
00208 " local_lostpackets Local lost packets\n"
00209 " local_jitter Local calculated jitter\n"
00210 " local_maxjitter Local calculated jitter (maximum)\n"
00211 " local_minjitter Local calculated jitter (minimum)\n"
00212 " local_normdevjitter Local calculated jitter (normal deviation)\n"
00213 " local_stdevjitter Local calculated jitter (standard deviation)\n"
00214 " local_count Number of received packets\n"
00215 " remote_ssrc Remote SSRC (stream ID)\n"
00216 " remote_lostpackets Remote lost packets\n"
00217 " remote_jitter Remote reported jitter\n"
00218 " remote_maxjitter Remote calculated jitter (maximum)\n"
00219 " remote_minjitter Remote calculated jitter (minimum)\n"
00220 " remote_normdevjitter Remote calculated jitter (normal deviation)\n"
00221 " remote_stdevjitter Remote calculated jitter (standard deviation)\n"
00222 " remote_count Number of transmitted packets\n"
00223 " rtt Round trip time\n"
00224 " maxrtt Round trip time (maximum)\n"
00225 " minrtt Round trip time (minimum)\n"
00226 " normdevrtt Round trip time (normal deviation)\n"
00227 " stdevrtt Round trip time (standard deviation)\n"
00228 " all All statistics (in a form suited to logging, but not for parsing)\n"
00229 "R/O rtpdest Get remote RTP destination information\n"
00230 " This option takes one additional argument:\n"
00231 " Argument 1:\n"
00232 " audio Get audio destination\n"
00233 " video Get video destination\n"
00234 "\n"
00235 "chan_iax2 provides the following additional options:\n"
00236 "R/W osptoken Get or set the OSP token information for a call\n"
00237 "R/O peerip Get the peer's ip address\n"
00238 "R/O peername Get the peer's username\n"
00239 "\n"
00240 "Additional items may be available from the channel driver providing\n"
00241 "the channel; see its documentation for details.\n"
00242 "\n"
00243 "Any item requested that is not available on the current channel will\n"
00244 "return an empty string.\n",
00245 .read = func_channel_read,
00246 .write = func_channel_write,
00247 };
00248
00249 static int func_channels_read(struct ast_channel *chan, const char *function, char *data, char *buf, size_t maxlen)
00250 {
00251 struct ast_channel *c = NULL;
00252 regex_t re;
00253 int res;
00254 size_t buflen = 0;
00255
00256 buf[0] = '\0';
00257
00258 if (!ast_strlen_zero(data)) {
00259 if ((res = regcomp(&re, data, REG_EXTENDED | REG_ICASE | REG_NOSUB))) {
00260 regerror(res, &re, buf, maxlen);
00261 ast_log(LOG_WARNING, "Error compiling regular expression for %s(%s): %s\n", function, data, buf);
00262 return -1;
00263 }
00264 }
00265
00266 for (c = ast_channel_walk_locked(NULL); c; ast_channel_unlock(c), c = ast_channel_walk_locked(c)) {
00267 if (ast_strlen_zero(data) || regexec(&re, c->name, 0, NULL, 0) == 0) {
00268 size_t namelen = strlen(c->name);
00269 if (buflen + namelen + (ast_strlen_zero(buf) ? 0 : 1) + 1 < maxlen) {
00270 if (!ast_strlen_zero(buf)) {
00271 strcat(buf, " ");
00272 buflen++;
00273 }
00274 strcat(buf, c->name);
00275 buflen += namelen;
00276 } else {
00277 ast_log(LOG_WARNING, "Number of channels exceeds the available buffer space. Output will be truncated!\n");
00278 }
00279 }
00280 }
00281
00282 if (!ast_strlen_zero(data)) {
00283 regfree(&re);
00284 }
00285
00286 return 0;
00287 }
00288
00289 static struct ast_custom_function channels_function = {
00290 .name = "CHANNELS",
00291 .synopsis = "Gets the list of channels, optionally filtering by a regular expression.",
00292 .syntax = "CHANNEL([regular expression])",
00293 .desc =
00294 "Gets the list of channels, optionally filtering by a regular expression. If\n"
00295 "no argument is provided, all known channels are returned. The regular\n"
00296 "expression must correspond to the POSIX.2 specification, as shown in\n"
00297 "regex(7). The list returned will be space-delimited.\n",
00298 .read = func_channels_read,
00299 };
00300
00301 static int unload_module(void)
00302 {
00303 int res = 0;
00304
00305 res |= ast_custom_function_unregister(&channel_function);
00306 res |= ast_custom_function_unregister(&channels_function);
00307
00308 return res;
00309 }
00310
00311 static int load_module(void)
00312 {
00313 int res = 0;
00314
00315 res |= ast_custom_function_register(&channel_function);
00316 res |= ast_custom_function_register(&channels_function);
00317
00318 return res;
00319 }
00320
00321 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Channel information dialplan functions");