</example>
</description>
</function>
+ <function name="DAHDI_CHANNEL" language="en_US">
+ <synopsis>
+ Set or get a property of a DAHDI channel.
+ </synopsis>
+ <syntax>
+ <parameter name="property" required="true">
+ <para>The property to set or get.</para>
+ <enumlist>
+ <enum name="owner">
+ <para>R/O The name of the active channel on this DAHDI device.</para>
+ </enum>
+ <enum name="callwait">
+ <para>R/O The name of the call waiting channel on this DAHDI device.</para>
+ </enum>
+ <enum name="threeway">
+ <para>R/O The name of the three-way channel on this DAHDI device.</para>
+ </enum>
+ <enum name="polarity">
+ <para>R/W The polarity of the channel (0 or 1, idle or reverse can also be used for setting).</para>
+ <para>Only valid on FXO-signalled channels.</para>
+ </enum>
+ <enum name="dnd">
+ <para>R/W Whether Do Not Disturb is active.</para>
+ <para>Only valid on FXO-signalled channels.</para>
+ </enum>
+ <enum name="callforward">
+ <para>R/W The call forwarding target number.</para>
+ <para>Only valid on FXO-signalled channels.</para>
+ </enum>
+ <enum name="lastexten">
+ <para>R/W The last number dialed.</para>
+ <para>Only valid on FXO-signalled channels.</para>
+ </enum>
+ </enumlist>
+ </parameter>
+ <parameter name="channel" required="false">
+ <para>The DAHDI channel number.</para>
+ <para>If not specified, the DAHDI channel number of the current channel
+ will be used (in which case it must be a DAHDI channel).</para>
+ </parameter>
+ </syntax>
+ <description>
+ <para>The DAHDI_CHANNEL function can be used to set or get properties of DAHDI channels
+ that are not specific to Asterisk channels.</para>
+ <para>This function may also be called from non-DAHDI channels.</para>
+ <example title="Set reverse polarity on current DAHDI channel">
+ same => n,Set(DAHDI_CHANNEL(polarity)=1)
+ same => n,NoOp(${DAHDI_CHANNEL(polarity)})
+ </example>
+ <example title="Set call forwarding target for channel 1">
+ same => n,Set(DAHDI_CHANNEL(callforwardnumber,1)=5552368)
+ same => n,NoOp(Calls now forwarding to ${DAHDI_CHANNEL(callforwardnumber,1)})
+ </example>
+ </description>
+ </function>
<info name="CHANNEL" language="en_US" tech="DAHDI">
<enumlist>
<enum name="dahdi_channel">
}
}
-/*! \brief Return DAHDI pivot if channel is FXO signalled */
-static struct dahdi_pvt *fxo_pvt(struct ast_channel *chan)
-{
- int res;
- struct dahdi_params dahdip;
- struct dahdi_pvt *pvt = NULL;
-
- if (strcasecmp(ast_channel_tech(chan)->type, "DAHDI")) {
- ast_log(LOG_WARNING, "%s is not a DAHDI channel\n", ast_channel_name(chan));
- return NULL;
- }
-
- memset(&dahdip, 0, sizeof(dahdip));
- res = ioctl(ast_channel_fd(chan, 0), DAHDI_GET_PARAMS, &dahdip);
-
- if (res) {
- ast_log(LOG_WARNING, "Unable to get parameters of %s: %s\n", ast_channel_name(chan), strerror(errno));
- return NULL;
- }
- if (!(dahdip.sigtype & __DAHDI_SIG_FXO)) {
- ast_log(LOG_WARNING, "%s is not FXO signalled\n", ast_channel_name(chan));
- return NULL;
- }
-
- pvt = ast_channel_tech_pvt(chan);
- if (!dahdi_analog_lib_handles(pvt->sig, 0, 0)) {
- ast_log(LOG_WARNING, "Channel signalling is not analog");
- return NULL;
- }
-
- return pvt;
-}
-
-static int polarity_read(struct ast_channel *chan, const char *cmd, char *data, char *buffer, size_t buflen)
-{
- struct dahdi_pvt *pvt;
-
- pvt = fxo_pvt(chan);
- if (!pvt) {
- return -1;
- }
-
- snprintf(buffer, buflen, "%d", pvt->polarity);
-
- return 0;
-}
-
-static int polarity_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
-{
- struct dahdi_pvt *pvt;
- int polarity;
-
- pvt = fxo_pvt(chan);
- if (!pvt) {
- return -1;
- }
-
- if (!strcasecmp(value, "idle")) {
- polarity = POLARITY_IDLE;
- } else if (!strcasecmp(value, "reverse")) {
- polarity = POLARITY_REV;
- } else {
- polarity = atoi(value);
- }
-
- if (polarity != POLARITY_IDLE && polarity != POLARITY_REV) {
- ast_log(LOG_WARNING, "Invalid polarity: '%s'\n", value);
- return -1;
- }
-
- my_set_polarity(pvt, polarity);
- return 0;
-}
-
-static struct ast_custom_function polarity_function = {
- .name = "POLARITY",
- .write = polarity_write,
- .read = polarity_read,
-};
-
static int my_start(void *pvt)
{
struct dahdi_pvt *p = pvt;
return find_channel(chan_num);
}
+static int print_subchannel(struct dahdi_pvt *p, int subchan, char *buffer, size_t len)
+{
+ if (!p->subs[subchan].owner) {
+ return -1;
+ }
+ ast_channel_lock(p->subs[subchan].owner);
+ snprintf(buffer, len, "%s", ast_channel_name(p->subs[subchan].owner));
+ ast_channel_unlock(p->subs[subchan].owner);
+ return 0;
+}
+
+#define REQUIRE_FXO_SIG() \
+ if (!(dahdip->sigtype & __DAHDI_SIG_FXO)) { \
+ ast_log(LOG_WARNING, "DAHDI channel %d is not FXO signalled\n", p->channel); \
+ return -1; \
+ }
+
+static int dahdichan_read_property(struct dahdi_pvt *p, struct dahdi_params *dahdip, const char *property, char *buffer, size_t len)
+{
+ struct analog_pvt *analog_p = p->sig_pvt;
+
+ /* R/O properties */
+ if (!strcasecmp(property, "owner")) {
+ return print_subchannel(p, SUB_REAL, buffer, len);
+ } else if (!strcasecmp(property, "callwait")) {
+ return print_subchannel(p, SUB_CALLWAIT, buffer, len);
+ } else if (!strcasecmp(property, "threeway")) {
+ return print_subchannel(p, SUB_THREEWAY, buffer, len);
+ /* R/W properties */
+ } else if (!strcasecmp(property, "polarity")) {
+ REQUIRE_FXO_SIG();
+ snprintf(buffer, len, "%d", p->polarity);
+ } else if (!strcasecmp(property, "dnd")) {
+ REQUIRE_FXO_SIG();
+ snprintf(buffer, len, "%d", analog_p->dnd);
+ } else if (!strcasecmp(property, "callforward")) {
+ REQUIRE_FXO_SIG();
+ snprintf(buffer, len, "%s", analog_p->call_forward);
+ } else if (!strcasecmp(property, "lastexten")) {
+ REQUIRE_FXO_SIG();
+ snprintf(buffer, len, "%s", analog_p->lastexten);
+ } else {
+ ast_log(LOG_ERROR, "Unknown DAHDI_CHANNEL property '%s'\n", property);
+ return -1;
+ }
+ return 0;
+}
+
+static int dahdichan_write_property(struct dahdi_pvt *p, struct dahdi_params *dahdip, const char *property, const char *value)
+{
+ struct analog_pvt *analog_p = p->sig_pvt;
+
+ /* We don't need to check ast_strlen_zero(value) because it's obviously not NULL.
+ * It may even be okay for it to be an empty string, but that's a per-setting thing. */
+
+ /* R/O properties */
+ if (!strcasecmp(property, "owner") || !strcasecmp(property, "callwait") || !strcasecmp(property, "threeway")) {
+ ast_log(LOG_ERROR, "DAHDI subchannel names are R/O\n");
+ return -1;
+ /* R/W properties */
+ } else if (!strcasecmp(property, "polarity")) {
+ int polarity = atoi(value);
+ REQUIRE_FXO_SIG();
+ if (polarity != POLARITY_IDLE && polarity != POLARITY_REV) {
+ ast_log(LOG_ERROR, "Invalid polarity: '%s'\n", value);
+ return -1;
+ }
+ my_set_polarity(p, polarity);
+ } else if (!strcasecmp(property, "dnd")) {
+ int dnd = atoi(value);
+ REQUIRE_FXO_SIG();
+ analog_dnd(analog_p, dnd ? 1 : 0);
+ } else if (!strcasecmp(property, "callforward")) {
+ REQUIRE_FXO_SIG();
+ if (strlen(value) >= sizeof(analog_p->call_forward) - 1) {
+ ast_log(LOG_ERROR, "Provided call forwarding target '%s' is too long\n", value);
+ }
+ ast_copy_string(analog_p->call_forward, value, sizeof(analog_p->call_forward)); /* Could be empty to clear value */
+ } else if (!strcasecmp(property, "lastexten")) {
+ REQUIRE_FXO_SIG();
+ if (strlen(value) >= sizeof(analog_p->lastexten) - 1) {
+ ast_log(LOG_ERROR, "Provided lastexten target '%s' is too long\n", value);
+ }
+ ast_copy_string(analog_p->lastexten, value, sizeof(analog_p->lastexten)); /* Could be empty to clear value */
+ } else {
+ ast_log(LOG_ERROR, "Unknown DAHDI_CHANNEL property '%s'\n", property);
+ return -1;
+ }
+ return 0;
+}
+#undef REQUIRE_FXO_SIG
+
+static int dahdichan_helper(struct ast_channel *chan, char *data, const char *value, char *buffer, size_t buflen)
+{
+ char *parse;
+ struct dahdi_pvt *pvt;
+ struct dahdi_params dahdip;
+ int res;
+ AST_DECLARE_APP_ARGS(args,
+ AST_APP_ARG(property);
+ AST_APP_ARG(dahdichan);
+ );
+
+ parse = ast_strdupa(data);
+ AST_STANDARD_APP_ARGS(args, parse);
+
+ if (buflen > 0) {
+ *buffer = '\0';
+ }
+
+ if (!ast_strlen_zero(args.dahdichan)) {
+ /* DAHDI channel number explicitly provided, find it. */
+ int channo = atoi(args.dahdichan);
+ pvt = find_channel(channo);
+ if (!pvt) {
+ ast_log(LOG_ERROR, "DAHDI channel %d does not exist\n", channo);
+ return -1;
+ }
+ } else {
+ /* No channel specified explicitly, so implicitly use the current channel, in which case it must be a DAHDI channel. */
+ if (!chan || !ast_channel_tech(chan) || strcasecmp(ast_channel_tech(chan)->type, "DAHDI")) {
+ ast_log(LOG_WARNING, "%s is not a DAHDI channel, and no DAHDI channel specified\n", ast_channel_name(chan));
+ return -1;
+ }
+ pvt = ast_channel_tech_pvt(chan);
+ }
+
+ memset(&dahdip, 0, sizeof(dahdip));
+ if (ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &dahdip)) {
+ ast_log(LOG_WARNING, "Unable to get parameters of DAHDI channel %d: %s\n", pvt->channel, strerror(errno));
+ return -1;
+ }
+
+ /* We have the channel private to use. */
+ ast_mutex_lock(&pvt->lock);
+ if (value) {
+ res = dahdichan_write_property(pvt, &dahdip, args.property, value);
+ } else {
+ res = dahdichan_read_property(pvt, &dahdip, args.property, buffer, buflen);
+ }
+ ast_mutex_unlock(&pvt->lock);
+ return res;
+}
+
+static int dahdichan_read(struct ast_channel *chan, const char *cmd, char *data, char *buffer, size_t buflen)
+{
+ return dahdichan_helper(chan, data, NULL, buffer, buflen);
+}
+
+static int dahdichan_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
+{
+ return dahdichan_helper(chan, data, value, NULL, 0);
+}
+
+static struct ast_custom_function dahdichan_function = {
+ .name = "DAHDI_CHANNEL",
+ .write = dahdichan_write,
+ .read = dahdichan_read,
+};
+
+/*! \todo The standalone POLARITY function can and should be deprecated/removed, since its functionality is now part of DAHDI_CHANNEL. */
+
+static int polarity_read(struct ast_channel *chan, const char *cmd, char *data, char *buffer, size_t buflen)
+{
+ struct dahdi_params dahdip;
+ struct dahdi_pvt *pvt = ast_channel_tech_pvt(chan);
+ if (strcasecmp(ast_channel_tech(chan)->type, "DAHDI")) {
+ ast_log(LOG_WARNING, "%s is not a DAHDI channel\n", ast_channel_name(chan));
+ return -1;
+ }
+ memset(&dahdip, 0, sizeof(dahdip));
+ if (ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &dahdip)) {
+ ast_log(LOG_WARNING, "Unable to get parameters of DAHDI channel %d: %s\n", pvt->subs[SUB_REAL].dfd, strerror(errno));
+ return -1;
+ }
+ return dahdichan_read_property(ast_channel_tech_pvt(chan), &dahdip, "polarity", buffer, buflen);
+}
+
+static int polarity_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
+{
+ struct dahdi_params dahdip;
+ struct dahdi_pvt *pvt = ast_channel_tech_pvt(chan);
+ if (strcasecmp(ast_channel_tech(chan)->type, "DAHDI")) {
+ ast_log(LOG_WARNING, "%s is not a DAHDI channel\n", ast_channel_name(chan));
+ return -1;
+ }
+ memset(&dahdip, 0, sizeof(dahdip));
+ if (ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &dahdip)) {
+ ast_log(LOG_WARNING, "Unable to get parameters of DAHDI channel %d: %s\n", pvt->subs[SUB_REAL].dfd, strerror(errno));
+ return -1;
+ }
+ return dahdichan_write_property(ast_channel_tech_pvt(chan), &dahdip, "polarity", value);
+}
+
+static struct ast_custom_function polarity_function = {
+ .name = "POLARITY",
+ .write = polarity_write,
+ .read = polarity_read,
+};
+
static int action_dahdidndon(struct mansession *s, const struct message *m)
{
struct dahdi_pvt *p;
ast_unregister_application(dahdi_accept_r2_call_app);
#endif
+ ast_custom_function_unregister(&dahdichan_function);
ast_custom_function_unregister(&polarity_function);
ast_cli_unregister_multiple(dahdi_cli, ARRAY_LEN(dahdi_cli));
ast_register_application_xml(dahdi_accept_r2_call_app, dahdi_accept_r2_call_exec);
#endif
+ ast_custom_function_register(&dahdichan_function);
ast_custom_function_register(&polarity_function);
ast_cli_register_multiple(dahdi_cli, ARRAY_LEN(dahdi_cli));