summaryrefslogtreecommitdiff
path: root/channels
diff options
context:
space:
mode:
authorDamien Wedhorn <voip@facts.com.au>2013-05-18 23:20:53 +0000
committerDamien Wedhorn <voip@facts.com.au>2013-05-18 23:20:53 +0000
commit01d6e8dbc99d4ca16977cf48bd65e364850fb07d (patch)
tree279908bb15b05f032c7cc199ecd4d7aeeb1867af /channels
parent7316abeb8f4864bbaa0f26a557055d1af8d3a455 (diff)
Add call forward no answer to skinny and cleanup general callfwd handling.
CallforwardNoAnswer uses a sched to determine when to forward the call. Defaults to 20secs but configurable in skinny.conf. Adds dialType to each subchannel structure to be used to differentiate between normal dials that result in a call being placed (default) and other uses for the skinny_dialer (such as cfwd digit collection). Restructured all cfwd handling to use this new arrangement. (closes issue ASTERISK-21292) Reported by: wedhorn Tested by: myself Patches: skinny-callfwdnoans03.diff uploaded by wedhorn (license 5019) git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@389097 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'channels')
-rw-r--r--channels/chan_skinny.c229
1 files changed, 88 insertions, 141 deletions
diff --git a/channels/chan_skinny.c b/channels/chan_skinny.c
index bf2871e7f..f5b7dfff3 100644
--- a/channels/chan_skinny.c
+++ b/channels/chan_skinny.c
@@ -919,6 +919,7 @@ static const uint8_t soft_key_default_onhook[] = {
SOFTKEY_NEWCALL,
SOFTKEY_CFWDALL,
SOFTKEY_CFWDBUSY,
+ SOFTKEY_CFWDNOANSWER,
SOFTKEY_DND,
SOFTKEY_GPICKUP,
/*SOFTKEY_CONFRN,*/
@@ -931,6 +932,7 @@ static const uint8_t soft_key_default_connected[] = {
SOFTKEY_PARK,
SOFTKEY_CFWDALL,
SOFTKEY_CFWDBUSY,
+ SOFTKEY_CFWDNOANSWER,
};
static const uint8_t soft_key_default_onhold[] = {
@@ -951,6 +953,7 @@ static const uint8_t soft_key_default_offhook[] = {
SOFTKEY_ENDCALL,
SOFTKEY_CFWDALL,
SOFTKEY_CFWDBUSY,
+ SOFTKEY_CFWDNOANSWER,
SOFTKEY_GPICKUP,
};
@@ -961,6 +964,7 @@ static const uint8_t soft_key_default_connwithtrans[] = {
SOFTKEY_PARK,
SOFTKEY_CFWDALL,
SOFTKEY_CFWDBUSY,
+ SOFTKEY_CFWDNOANSWER,
};
static const uint8_t soft_key_default_dadfd[] = {
@@ -1361,6 +1365,9 @@ static int matchdigittimeout = 3000;
#define SUBSTATE_PROGRESS 12
#define SUBSTATE_DIALING 101
+#define DIALTYPE_NORMAL 1<<0
+#define DIALTYPE_CFWD 1<<1
+
struct skinny_subchannel {
ast_mutex_t lock;
struct ast_channel *owner;
@@ -1382,6 +1389,9 @@ struct skinny_subchannel {
int aa_beep;
int aa_mute;
int dialer_sched;
+ int cfwd_sched;
+ int dialType;
+ int getforward;
char *origtonum;
char *origtoname;
@@ -1424,7 +1434,7 @@ struct skinny_subchannel {
int threewaycalling; \
int mwiblink; \
int cancallforward; \
- int getforward; \
+ int callfwdtimeout; \
int dnd; \
int hidecallerid; \
int amaflags; \
@@ -1467,7 +1477,7 @@ static struct skinny_line_options{
.instance = 0,
.directmedia = 0,
.nat = 0,
- .getforward = 0,
+ .callfwdtimeout = 20000,
.prune = 0,
};
static struct skinny_line_options *default_line = &default_line_struct;
@@ -2257,7 +2267,7 @@ static int skinny_register(struct skinny_req *req, struct skinnysession *s)
l->prefs = d->prefs; */
l->instance = instance;
l->newmsgs = ast_app_has_voicemail(l->mailbox, NULL);
- set_callforwards(l, NULL, 0);
+ set_callforwards(l, NULL, SKINNY_CFWD_ALL|SKINNY_CFWD_BUSY|SKINNY_CFWD_NOANSWER);
manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: Skinny\r\nPeer: Skinny/%s@%s\r\nPeerStatus: Registered\r\n", l->name, d->name);
register_exten(l);
/* initialize MWI on line and device */
@@ -4464,6 +4474,7 @@ static char *_skinny_show_line(int type, int fd, struct mansession *s, const str
ast_cli(fd, "CFwdAll: %s\n", S_COR((l->cfwdtype & SKINNY_CFWD_ALL), l->call_forward_all, "<not set>"));
ast_cli(fd, "CFwdBusy: %s\n", S_COR((l->cfwdtype & SKINNY_CFWD_BUSY), l->call_forward_busy, "<not set>"));
ast_cli(fd, "CFwdNoAnswer: %s\n", S_COR((l->cfwdtype & SKINNY_CFWD_NOANSWER), l->call_forward_noanswer, "<not set>"));
+ ast_cli(fd, "CFwdTimeout: %dms\n", l->callfwdtimeout);
ast_cli(fd, "VoicemailBox: %s\n", S_OR(l->mailbox, "<not set>"));
ast_cli(fd, "VoicemailNumber: %s\n", S_OR(l->vmexten, "<not set>"));
ast_cli(fd, "MWIblink: %d\n", l->mwiblink);
@@ -4882,6 +4893,17 @@ static int skinny_autoanswer_cb(const void *data)
return 0;
}
+static int skinny_cfwd_cb(const void *data)
+{
+ struct skinny_subchannel *sub = (struct skinny_subchannel *)data;
+ struct skinny_line *l = sub->line;
+ sub->cfwd_sched = 0;
+ SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %d - CFWDNOANS to %s.\n", sub->callid, l->call_forward_noanswer);
+ ast_channel_call_forward_set(sub->owner, l->call_forward_noanswer);
+ ast_queue_control(sub->owner, AST_CONTROL_REDIRECTING);
+ return 0;
+}
+
static int skinny_call(struct ast_channel *ast, const char *dest, int timeout)
{
int res = 0;
@@ -5380,6 +5402,9 @@ static struct ast_channel *skinny_new(struct skinny_line *l, struct skinny_subli
sub->calldirection = direction;
sub->aa_sched = 0;
sub->dialer_sched = 0;
+ sub->cfwd_sched = 0;
+ sub->dialType = DIALTYPE_NORMAL;
+ sub->getforward = 0;
if (subline) {
sub->subline = subline;
@@ -5429,13 +5454,15 @@ static struct ast_channel *skinny_new(struct skinny_line *l, struct skinny_subli
ast_channel_named_callgroups_set(tmp, l->named_callgroups);
ast_channel_named_pickupgroups_set(tmp, l->named_pickupgroups);
- /* XXX Need to figure out how to handle CFwdNoAnswer */
if (l->cfwdtype & SKINNY_CFWD_ALL) {
+ SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %d - CFWDALL to %s.\n", sub->callid, l->call_forward_all);
ast_channel_call_forward_set(tmp, l->call_forward_all);
- } else if (l->cfwdtype & SKINNY_CFWD_BUSY) {
- if (get_devicestate(l) != AST_DEVICE_NOT_INUSE) {
- ast_channel_call_forward_set(tmp, l->call_forward_busy);
- }
+ } else if ((l->cfwdtype & SKINNY_CFWD_BUSY) && (get_devicestate(l) != AST_DEVICE_NOT_INUSE)) {
+ SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %d - CFWDBUSY to %s.\n", sub->callid, l->call_forward_busy);
+ ast_channel_call_forward_set(tmp, l->call_forward_busy);
+ } else if (l->cfwdtype & SKINNY_CFWD_NOANSWER) {
+ SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %d - CFWDNOANS Scheduling for %d seconds.\n", sub->callid, l->callfwdtimeout/1000);
+ sub->cfwd_sched = skinny_sched_add(l->callfwdtimeout, skinny_cfwd_cb, sub);
}
if (subline) {
@@ -5535,6 +5562,19 @@ static void setsubstate(struct skinny_subchannel *sub, int state)
sub->aa_mute = 0;
}
+ if (sub->cfwd_sched) {
+ if (state == SUBSTATE_CONNECTED) {
+ if (skinny_sched_del(sub->cfwd_sched, sub)) {
+ SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %d - trying to change state from %s to %s, but already forwarded because no answer.\n",
+ sub->callid, substate2str(sub->substate), substate2str(actualstate));
+ return;
+ }
+ sub->cfwd_sched = 0;
+ } else if (state == SUBSTATE_ONHOOK) {
+ skinny_sched_del(sub->cfwd_sched, sub);
+ }
+ }
+
if ((state == SUBSTATE_RINGIN) && ((d->hookstate == SKINNY_OFFHOOK) || (AST_LIST_NEXT(AST_LIST_FIRST(&l->sub), list)))) {
actualstate = SUBSTATE_CALLWAIT;
}
@@ -5665,8 +5705,6 @@ static void setsubstate(struct skinny_subchannel *sub, int state)
sub->callid, substate2str(sub->substate), substate2str(actualstate));
if (actualstate == sub->substate) {
- send_callinfo(sub);
- transmit_callstate(d, l->instance, sub->callid, SKINNY_HOLD);
return;
}
@@ -6001,26 +6039,19 @@ static void activatesub(struct skinny_subchannel *sub, int state)
static void dialandactivatesub(struct skinny_subchannel *sub, char exten[AST_MAX_EXTENSION])
{
- if (sub->line->getforward) {
- struct skinny_line *l = sub->line;
- struct skinny_device *d = l->device;
-
- // FIXME: needs some love and remove sleeps
- SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %d - Set callforward to %s\n", sub->callid, exten);
- set_callforwards(l, sub->exten, l->getforward);
- transmit_start_tone(d, SKINNY_DIALTONE, l->instance, sub->callid);
- transmit_lamp_indication(d, STIMULUS_FORWARDALL, 1, SKINNY_LAMP_ON);
- transmit_displaynotify(d, "CFwd enabled", 10);
- transmit_cfwdstate(d, l);
- ast_safe_sleep(sub->owner, 500);
- ast_indicate(sub->owner, -1);
- ast_safe_sleep(sub->owner, 1000);
- l->getforward = 0;
- dumpsub(sub, 0);
- } else {
+ struct skinny_line *l = sub->line;
+ struct skinny_device *d = l->device;
+
+ if (sub->dialType == DIALTYPE_NORMAL) {
SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %d - Dial %s and Activate\n", sub->callid, exten);
ast_copy_string(sub->exten, exten, sizeof(sub->exten));
activatesub(sub, SUBSTATE_DIALING);
+ } else if (sub->dialType == DIALTYPE_CFWD) {
+ SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %d - Set callforward(%d) to %s\n", sub->callid, sub->getforward, exten);
+ set_callforwards(l, sub->exten, sub->getforward);
+ dumpsub(sub, 1);
+ transmit_cfwdstate(d, l);
+ transmit_displaynotify(d, "CFwd enabled", 10);
}
}
@@ -6099,48 +6130,38 @@ static int handle_transfer_button(struct skinny_subchannel *sub)
return 0;
}
-static int handle_callforward_button(struct skinny_subchannel *sub, int cfwdtype)
+static void handle_callforward_button(struct skinny_line *l, struct skinny_subchannel *sub, int cfwdtype)
{
- struct skinny_line *l = sub->line;
struct skinny_device *d = l->device;
- struct ast_channel *c = sub->owner;
+ struct ast_channel *c;
if (!d->session) {
ast_log(LOG_WARNING, "Device for line %s is not registered.\n", l->name);
- return 0;
- }
-
- if (d->hookstate == SKINNY_ONHOOK) {
- d->hookstate = SKINNY_OFFHOOK;
- transmit_speaker_mode(d, SKINNY_SPEAKERON);
- transmit_callstate(d, l->instance, sub->callid, SKINNY_OFFHOOK);
- transmit_activatecallplane(d, l);
+ return;
}
- transmit_clear_display_message(d, l->instance, sub->callid);
- if (l->cfwdtype & cfwdtype) {
+ if (!sub && (l->cfwdtype & cfwdtype)) {
set_callforwards(l, NULL, cfwdtype);
- ast_safe_sleep(c, 500);
- transmit_speaker_mode(d, SKINNY_SPEAKEROFF);
- transmit_closereceivechannel(d, sub);
- transmit_stopmediatransmission(d, sub);
- transmit_speaker_mode(d, SKINNY_SPEAKEROFF);
- transmit_clearpromptmessage(d, l->instance, sub->callid);
- transmit_callstate(d, l->instance, sub->callid, SKINNY_ONHOOK);
- transmit_selectsoftkeys(d, 0, 0, KEYDEF_ONHOOK, KEYMASK_ALL);
- transmit_activatecallplane(d, l);
- transmit_displaynotify(d, "CFwd disabled", 10);
- if (sub->owner && ast_channel_state(sub->owner) != AST_STATE_UP) {
- ast_indicate(c, -1);
- ast_hangup(c);
+ if (sub) {
+ dumpsub(sub, 1);
}
transmit_cfwdstate(d, l);
+ transmit_displaynotify(d, "CFwd disabled", 10);
} else {
- l->getforward = cfwdtype;
- setsubstate(sub, SUBSTATE_OFFHOOK);
+ if (!sub || !sub->owner) {
+ if (!(c = skinny_new(l, NULL, AST_STATE_DOWN, NULL, SKINNY_OUTGOING))) {
+ ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
+ return;
+ }
+ sub = ast_channel_tech_pvt(c);
+ l->activesub = sub;
+ setsubstate(sub, SUBSTATE_OFFHOOK);
+ }
+ sub->getforward |= cfwdtype;
+ sub->dialType = DIALTYPE_CFWD;
}
- return 0;
}
+
static int handle_ip_port_message(struct skinny_req *req, struct skinnysession *s)
{
/* no response necessary */
@@ -6400,55 +6421,17 @@ static int handle_stimulus_message(struct skinny_req *req, struct skinnysession
case STIMULUS_FORWARDALL:
SKINNY_DEBUG(DEBUG_PACKET, 3, "Received STIMULUS_FORWARDALL from %s, inst %d, callref %d\n",
d->name, instance, callreference);
-
- if (!sub || !sub->owner) {
- c = skinny_new(l, NULL, AST_STATE_DOWN, NULL, SKINNY_OUTGOING);
- } else {
- c = sub->owner;
- }
-
- if (!c) {
- ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
- } else {
- sub = ast_channel_tech_pvt(c);
- handle_callforward_button(sub, SKINNY_CFWD_ALL);
- }
+ handle_callforward_button(l, sub, SKINNY_CFWD_ALL);
break;
case STIMULUS_FORWARDBUSY:
SKINNY_DEBUG(DEBUG_PACKET, 3, "Received STIMULUS_FORWARDBUSY from %s, inst %d, callref %d\n",
d->name, instance, callreference);
-
- if (!sub || !sub->owner) {
- c = skinny_new(l, NULL, AST_STATE_DOWN, NULL, SKINNY_OUTGOING);
- } else {
- c = sub->owner;
- }
-
- if (!c) {
- ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
- } else {
- sub = ast_channel_tech_pvt(c);
- handle_callforward_button(sub, SKINNY_CFWD_BUSY);
- }
+ handle_callforward_button(l, sub, SKINNY_CFWD_BUSY);
break;
case STIMULUS_FORWARDNOANSWER:
SKINNY_DEBUG(DEBUG_PACKET, 3, "Received STIMULUS_FORWARDNOANSWER from %s, inst %d, callref %d\n",
d->name, instance, callreference);
-
-#if 0 /* Not sure how to handle this yet */
- if (!sub || !sub->owner) {
- c = skinny_new(l, NULL, AST_STATE_DOWN, NULL, SKINNY_OUTGOING);
- } else {
- c = sub->owner;
- }
-
- if (!c) {
- ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
- } else {
- sub = c->tech_pvt;
- handle_callforward_button(sub, SKINNY_CFWD_NOANSWER);
- }
-#endif
+ handle_callforward_button(l, sub, SKINNY_CFWD_NOANSWER);
break;
case STIMULUS_DISPLAY:
/* Not sure what this is */
@@ -7037,58 +7020,17 @@ static int handle_soft_key_event_message(struct skinny_req *req, struct skinnyse
case SOFTKEY_CFWDALL:
SKINNY_DEBUG(DEBUG_PACKET, 3, "Received SOFTKEY_CFWDALL from %s, inst %d, callref %d\n",
d->name, instance, callreference);
-
- if (!sub || !sub->owner) {
- c = skinny_new(l, NULL, AST_STATE_DOWN, NULL, SKINNY_OUTGOING);
- } else {
- c = sub->owner;
- }
-
- if (!c) {
- ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
- } else {
- sub = ast_channel_tech_pvt(c);
- l->activesub = sub;
- handle_callforward_button(sub, SKINNY_CFWD_ALL);
- }
+ handle_callforward_button(l, sub, SKINNY_CFWD_ALL);
break;
case SOFTKEY_CFWDBUSY:
SKINNY_DEBUG(DEBUG_PACKET, 3, "Received SOFTKEY_CFWDBUSY from %s, inst %d, callref %d\n",
d->name, instance, callreference);
-
- if (!sub || !sub->owner) {
- c = skinny_new(l, NULL, AST_STATE_DOWN, NULL, SKINNY_OUTGOING);
- } else {
- c = sub->owner;
- }
-
- if (!c) {
- ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
- } else {
- sub = ast_channel_tech_pvt(c);
- l->activesub = sub;
- handle_callforward_button(sub, SKINNY_CFWD_BUSY);
- }
+ handle_callforward_button(l, sub, SKINNY_CFWD_BUSY);
break;
case SOFTKEY_CFWDNOANSWER:
SKINNY_DEBUG(DEBUG_PACKET, 3, "Received SOFTKEY_CFWDNOANSWER from %s, inst %d, callref %d\n",
d->name, instance, callreference);
-
-#if 0 /* Not sure how to handle this yet */
- if (!sub || !sub->owner) {
- c = skinny_new(l, NULL, AST_STATE_DOWN, NULL, SKINNY_OUTGOING);
- } else {
- c = sub->owner;
- }
-
- if (!c) {
- ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
- } else {
- sub = c->tech_pvt;
- l->activesub = sub;
- handle_callforward_button(sub, SKINNY_CFWD_NOANSWER);
- }
-#endif
+ handle_callforward_button(l, sub, SKINNY_CFWD_NOANSWER);
break;
case SOFTKEY_BKSPC:
SKINNY_DEBUG(DEBUG_PACKET, 3, "Received SOFTKEY_BKSPC from %s, inst %d, callref %d\n",
@@ -7950,6 +7892,11 @@ static void config_parse_variables(int type, void *item, struct ast_variable *vp
CLINE_OPTS->cancallforward = ast_true(v->value);
continue;
}
+ } else if (!strcasecmp(v->name, "callfwdtimeout")) {
+ if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
+ CLINE_OPTS->callfwdtimeout = atoi(v->value);
+ continue;
+ }
} else if (!strcasecmp(v->name, "mailbox")) {
if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
ast_copy_string(CLINE_OPTS->mailbox, v->value, sizeof(CLINE_OPTS->mailbox));