diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c
index a468650e36..6ab7b22441 100644
--- a/channels/chan_dahdi.c
+++ b/channels/chan_dahdi.c
@@ -220,6 +220,61 @@
+
+
+ Set or get a property of a DAHDI channel.
+
+
+
+ The property to set or get.
+
+
+ R/O The name of the active channel on this DAHDI device.
+
+
+ R/O The name of the call waiting channel on this DAHDI device.
+
+
+ R/O The name of the three-way channel on this DAHDI device.
+
+
+ R/W The polarity of the channel (0 or 1, idle or reverse can also be used for setting).
+ Only valid on FXO-signalled channels.
+
+
+ R/W Whether Do Not Disturb is active.
+ Only valid on FXO-signalled channels.
+
+
+ R/W The call forwarding target number.
+ Only valid on FXO-signalled channels.
+
+
+ R/W The last number dialed.
+ Only valid on FXO-signalled channels.
+
+
+
+
+ The DAHDI channel number.
+ If not specified, the DAHDI channel number of the current channel
+ will be used (in which case it must be a DAHDI channel).
+
+
+
+ The DAHDI_CHANNEL function can be used to set or get properties of DAHDI channels
+ that are not specific to Asterisk channels.
+ This function may also be called from non-DAHDI channels.
+
+ same => n,Set(DAHDI_CHANNEL(polarity)=1)
+ same => n,NoOp(${DAHDI_CHANNEL(polarity)})
+
+
+ same => n,Set(DAHDI_CHANNEL(callforwardnumber,1)=5552368)
+ same => n,NoOp(Calls now forwarding to ${DAHDI_CHANNEL(callforwardnumber,1)})
+
+
+
@@ -2913,86 +2968,6 @@ static void my_hangup_polarityswitch(void *pvt)
}
}
-/*! \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;
@@ -16905,6 +16880,206 @@ static struct dahdi_pvt *find_channel_from_str(const char *channel)
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;
@@ -18258,6 +18433,7 @@ static int __unload_module(void)
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));
@@ -20483,6 +20659,7 @@ static int load_module(void)
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));
diff --git a/channels/sig_analog.c b/channels/sig_analog.c
index 7eb222dba4..580115c3db 100644
--- a/channels/sig_analog.c
+++ b/channels/sig_analog.c
@@ -2452,7 +2452,9 @@ static void *__analog_ss_thread(void *data)
/* Last Number Redial */
if (!ast_strlen_zero(p->lastexten)) {
ast_verb(4, "Redialing last number dialed on channel %d\n", p->channel);
+ analog_lock_private(p);
ast_copy_string(exten, p->lastexten, sizeof(exten));
+ analog_unlock_private(p);
} else {
ast_verb(3, "Last Number Redial not possible on channel %d (no saved number)\n", p->channel);
res = analog_play_tone(p, idx, ANALOG_TONE_CONGESTION);
@@ -2465,8 +2467,10 @@ static void *__analog_ss_thread(void *data)
if (!res || !ast_matchmore_extension(chan, ast_channel_context(chan), exten, 1, p->cid_num)) {
if (getforward) {
/* Record this as the forwarding extension */
+ analog_lock_private(p);
ast_copy_string(p->call_forward, exten, sizeof(p->call_forward));
- ast_verb(3, "Setting call forward to '%s' on channel %d\n", p->call_forward, p->channel);
+ analog_unlock_private(p);
+ ast_verb(3, "Setting call forward to '%s' on channel %d\n", exten, p->channel);
res = analog_play_tone(p, idx, ANALOG_TONE_DIALRECALL);
if (res) {
break;