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: 250732 $")
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, "%4hhd", &gainset);
00147 ast_channel_setoption(chan, AST_OPTION_TXGAIN, &gainset, sizeof(gainset), 0);
00148 } else if (!strcasecmp(data, "rxgain")) {
00149 sscanf(value, "%4hhd", &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 transfercapability ISDN transfer capability (one of SPEECH, DIGITAL,\n"
00187 " RESTRICTED_DIGITAL, 3K1AUDIO, DIGITAL_W_TONES, or VIDEO).\n"
00188 "R/W txgain set txgain level on channel drivers that support it\n"
00189 "R/O videonativeformat format used natively for video\n"
00190 #ifdef CHANNEL_TRACE
00191 "R/W trace whether or not context tracing is enabled\n"
00192 #endif
00193 "\n"
00194 "chan_sip provides the following additional options:\n"
00195 "R/O peerip Get the IP address of the peer\n"
00196 "R/O recvip Get the source IP address of the peer\n"
00197 "R/O from Get the URI from the From: header\n"
00198 "R/O uri Get the URI from the Contact: header\n"
00199 "R/O useragent Get the useragent\n"
00200 "R/O peername Get the name of the peer\n"
00201 "R/O t38passthrough 1 if T38 is offered or enabled in this channel, otherwise 0\n"
00202 "R/O rtpqos Get QOS information about the RTP stream\n"
00203 " This option takes two additional arguments:\n"
00204 " Argument 1:\n"
00205 " audio Get data about the audio stream\n"
00206 " video Get data about the video stream\n"
00207 " text Get data about the text stream\n"
00208 " Argument 2:\n"
00209 " local_ssrc Local SSRC (stream ID)\n"
00210 " local_lostpackets Local lost packets\n"
00211 " local_jitter Local calculated jitter\n"
00212 " local_maxjitter Local calculated jitter (maximum)\n"
00213 " local_minjitter Local calculated jitter (minimum)\n"
00214 " local_normdevjitter Local calculated jitter (normal deviation)\n"
00215 " local_stdevjitter Local calculated jitter (standard deviation)\n"
00216 " local_count Number of received packets\n"
00217 " remote_ssrc Remote SSRC (stream ID)\n"
00218 " remote_lostpackets Remote lost packets\n"
00219 " remote_jitter Remote reported jitter\n"
00220 " remote_maxjitter Remote calculated jitter (maximum)\n"
00221 " remote_minjitter Remote calculated jitter (minimum)\n"
00222 " remote_normdevjitter Remote calculated jitter (normal deviation)\n"
00223 " remote_stdevjitter Remote calculated jitter (standard deviation)\n"
00224 " remote_count Number of transmitted packets\n"
00225 " rtt Round trip time\n"
00226 " maxrtt Round trip time (maximum)\n"
00227 " minrtt Round trip time (minimum)\n"
00228 " normdevrtt Round trip time (normal deviation)\n"
00229 " stdevrtt Round trip time (standard deviation)\n"
00230 " all All statistics (in a form suited to logging, but not for parsing)\n"
00231 "R/O rtpdest Get remote RTP destination information\n"
00232 " This option takes one additional argument:\n"
00233 " Argument 1:\n"
00234 " audio Get audio destination\n"
00235 " video Get video destination\n"
00236 " text Get text destination\n"
00237 "\n"
00238 "chan_iax2 provides the following additional options:\n"
00239 "R/O peerip Get the peer's ip address\n"
00240 "R/O peername Get the peer's username\n"
00241 "\n"
00242 "Additional items may be available from the channel driver providing\n"
00243 "the channel; see its documentation for details.\n"
00244 "\n"
00245 "Any item requested that is not available on the current channel will\n"
00246 "return an empty string.\n",
00247 .read = func_channel_read,
00248 .write = func_channel_write,
00249 };
00250
00251 static int func_channels_read(struct ast_channel *chan, const char *function, char *data, char *buf, size_t maxlen)
00252 {
00253 struct ast_channel *c = NULL;
00254 regex_t re;
00255 int res;
00256 size_t buflen = 0;
00257
00258 buf[0] = '\0';
00259
00260 if (!ast_strlen_zero(data)) {
00261 if ((res = regcomp(&re, data, REG_EXTENDED | REG_ICASE | REG_NOSUB))) {
00262 regerror(res, &re, buf, maxlen);
00263 ast_log(LOG_WARNING, "Error compiling regular expression for %s(%s): %s\n", function, data, buf);
00264 return -1;
00265 }
00266 }
00267
00268 for (c = ast_channel_walk_locked(NULL); c; ast_channel_unlock(c), c = ast_channel_walk_locked(c)) {
00269 if (ast_strlen_zero(data) || regexec(&re, c->name, 0, NULL, 0) == 0) {
00270 size_t namelen = strlen(c->name);
00271 if (buflen + namelen + (ast_strlen_zero(buf) ? 0 : 1) + 1 < maxlen) {
00272 if (!ast_strlen_zero(buf)) {
00273 strcat(buf, " ");
00274 buflen++;
00275 }
00276 strcat(buf, c->name);
00277 buflen += namelen;
00278 } else {
00279 ast_log(LOG_WARNING, "Number of channels exceeds the available buffer space. Output will be truncated!\n");
00280 }
00281 }
00282 }
00283
00284 if (!ast_strlen_zero(data)) {
00285 regfree(&re);
00286 }
00287
00288 return 0;
00289 }
00290
00291 static struct ast_custom_function channels_function = {
00292 .name = "CHANNELS",
00293 .synopsis = "Gets the list of channels, optionally filtering by a regular expression.",
00294 .syntax = "CHANNEL([regular expression])",
00295 .desc =
00296 "Gets the list of channels, optionally filtering by a regular expression. If\n"
00297 "no argument is provided, all known channels are returned. The regular\n"
00298 "expression must correspond to the POSIX.2 specification, as shown in\n"
00299 "regex(7). The list returned will be space-delimited.\n",
00300 .read = func_channels_read,
00301 };
00302
00303 static int unload_module(void)
00304 {
00305 int res = 0;
00306
00307 res |= ast_custom_function_unregister(&channel_function);
00308 res |= ast_custom_function_unregister(&channels_function);
00309
00310 return res;
00311 }
00312
00313 static int load_module(void)
00314 {
00315 int res = 0;
00316
00317 res |= ast_custom_function_register(&channel_function);
00318 res |= ast_custom_function_register(&channels_function);
00319
00320 return res;
00321 }
00322
00323 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Channel information dialplan functions");