Add proper call forwarding (all and busy) support for chan_skinny.
Note: NoAnswer support is currently not implemented, as it would take a significant amount of work to figure out how to do correctly. Closes issue #11310, patches, testing, and support by DEA, mvanbaak, and myself. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@98776 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
parent
673d610b53
commit
524aed3768
|
@ -371,6 +371,18 @@ struct call_info_message {
|
||||||
uint32_t space[3];
|
uint32_t space[3];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define FORWARD_STAT_MESSAGE 0x0090
|
||||||
|
struct forward_stat_message {
|
||||||
|
uint32_t activeforward;
|
||||||
|
uint32_t lineNumber;
|
||||||
|
uint32_t fwdall;
|
||||||
|
char fwdallnum[24];
|
||||||
|
uint32_t fwdbusy;
|
||||||
|
char fwdbusynum[24];
|
||||||
|
uint32_t fwdnoanswer;
|
||||||
|
char fwdnoanswernum[24];
|
||||||
|
};
|
||||||
|
|
||||||
#define SPEED_DIAL_STAT_RES_MESSAGE 0x0091
|
#define SPEED_DIAL_STAT_RES_MESSAGE 0x0091
|
||||||
struct speed_dial_stat_res_message {
|
struct speed_dial_stat_res_message {
|
||||||
uint32_t speedDialNumber;
|
uint32_t speedDialNumber;
|
||||||
|
@ -422,6 +434,7 @@ struct button_definition_template {
|
||||||
#define STIMULUS_LINE 0x09
|
#define STIMULUS_LINE 0x09
|
||||||
#define STIMULUS_VOICEMAIL 0x0F
|
#define STIMULUS_VOICEMAIL 0x0F
|
||||||
#define STIMULUS_AUTOANSWER 0x11
|
#define STIMULUS_AUTOANSWER 0x11
|
||||||
|
#define STIMULUS_DND 0x3F
|
||||||
#define STIMULUS_CONFERENCE 0x7D
|
#define STIMULUS_CONFERENCE 0x7D
|
||||||
#define STIMULUS_CALLPARK 0x7E
|
#define STIMULUS_CALLPARK 0x7E
|
||||||
#define STIMULUS_CALLPICKUP 0x7F
|
#define STIMULUS_CALLPICKUP 0x7F
|
||||||
|
@ -439,6 +452,7 @@ struct button_definition_template {
|
||||||
#define BT_LINE STIMULUS_LINE
|
#define BT_LINE STIMULUS_LINE
|
||||||
#define BT_VOICEMAIL STIMULUS_VOICEMAIL
|
#define BT_VOICEMAIL STIMULUS_VOICEMAIL
|
||||||
#define BT_AUTOANSWER STIMULUS_AUTOANSWER
|
#define BT_AUTOANSWER STIMULUS_AUTOANSWER
|
||||||
|
#define BT_DND STIMULUS_DND
|
||||||
#define BT_CONFERENCE STIMULUS_CONFERENCE
|
#define BT_CONFERENCE STIMULUS_CONFERENCE
|
||||||
#define BT_CALLPARK STIMULUS_CALLPARK
|
#define BT_CALLPARK STIMULUS_CALLPARK
|
||||||
#define BT_CALLPICKUP STIMULUS_CALLPICKUP
|
#define BT_CALLPICKUP STIMULUS_CALLPICKUP
|
||||||
|
@ -551,6 +565,8 @@ struct soft_key_template_definition {
|
||||||
#define SOFTKEY_MEETME 0x10
|
#define SOFTKEY_MEETME 0x10
|
||||||
#define SOFTKEY_PICKUP 0x11
|
#define SOFTKEY_PICKUP 0x11
|
||||||
#define SOFTKEY_GPICKUP 0x12
|
#define SOFTKEY_GPICKUP 0x12
|
||||||
|
#define SOFTKEY_DND 0x13
|
||||||
|
#define SOFTKEY_IDIVERT 0x14
|
||||||
|
|
||||||
struct soft_key_template_definition soft_key_template_default[] = {
|
struct soft_key_template_definition soft_key_template_default[] = {
|
||||||
{ "\200\001", SOFTKEY_REDIAL },
|
{ "\200\001", SOFTKEY_REDIAL },
|
||||||
|
@ -571,6 +587,8 @@ struct soft_key_template_definition soft_key_template_default[] = {
|
||||||
{ "\200\020", SOFTKEY_MEETME },
|
{ "\200\020", SOFTKEY_MEETME },
|
||||||
{ "\200\021", SOFTKEY_PICKUP },
|
{ "\200\021", SOFTKEY_PICKUP },
|
||||||
{ "\200\022", SOFTKEY_GPICKUP },
|
{ "\200\022", SOFTKEY_GPICKUP },
|
||||||
|
{ "\200\077", SOFTKEY_DND },
|
||||||
|
{ "\200\120", SOFTKEY_IDIVERT },
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Localized message "codes" (in octal)
|
/* Localized message "codes" (in octal)
|
||||||
|
@ -718,6 +736,7 @@ static const uint8_t soft_key_default_onhook[] = {
|
||||||
SOFTKEY_NEWCALL,
|
SOFTKEY_NEWCALL,
|
||||||
SOFTKEY_CFWDALL,
|
SOFTKEY_CFWDALL,
|
||||||
SOFTKEY_CFWDBUSY,
|
SOFTKEY_CFWDBUSY,
|
||||||
|
SOFTKEY_DND,
|
||||||
SOFTKEY_GPICKUP,
|
SOFTKEY_GPICKUP,
|
||||||
SOFTKEY_CONFRN,
|
SOFTKEY_CONFRN,
|
||||||
};
|
};
|
||||||
|
@ -911,6 +930,7 @@ union skinny_data {
|
||||||
struct dialed_number_message dialednumber;
|
struct dialed_number_message dialednumber;
|
||||||
struct soft_key_event_message softkeyeventmessage;
|
struct soft_key_event_message softkeyeventmessage;
|
||||||
struct enbloc_call_message enbloccallmessage;
|
struct enbloc_call_message enbloccallmessage;
|
||||||
|
struct forward_stat_message forwardstat;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* packet composition */
|
/* packet composition */
|
||||||
|
@ -1037,6 +1057,10 @@ static int canreinvite = 0;
|
||||||
#define SKINNY_RING_OUTSIDE 3
|
#define SKINNY_RING_OUTSIDE 3
|
||||||
#define SKINNY_RING_FEATURE 4
|
#define SKINNY_RING_FEATURE 4
|
||||||
|
|
||||||
|
#define SKINNY_CFWD_ALL (1 << 0)
|
||||||
|
#define SKINNY_CFWD_BUSY (1 << 1)
|
||||||
|
#define SKINNY_CFWD_NOANSWER (1 << 2)
|
||||||
|
|
||||||
#define TYPE_TRUNK 1
|
#define TYPE_TRUNK 1
|
||||||
#define TYPE_LINE 2
|
#define TYPE_LINE 2
|
||||||
|
|
||||||
|
@ -1121,7 +1145,10 @@ struct skinny_line {
|
||||||
char cid_num[AST_MAX_EXTENSION]; /* Caller*ID */
|
char cid_num[AST_MAX_EXTENSION]; /* Caller*ID */
|
||||||
char cid_name[AST_MAX_EXTENSION]; /* Caller*ID */
|
char cid_name[AST_MAX_EXTENSION]; /* Caller*ID */
|
||||||
char lastcallerid[AST_MAX_EXTENSION]; /* Last Caller*ID */
|
char lastcallerid[AST_MAX_EXTENSION]; /* Last Caller*ID */
|
||||||
char call_forward[AST_MAX_EXTENSION];
|
int cfwdtype;
|
||||||
|
char call_forward_all[AST_MAX_EXTENSION];
|
||||||
|
char call_forward_busy[AST_MAX_EXTENSION];
|
||||||
|
char call_forward_noanswer[AST_MAX_EXTENSION];
|
||||||
char mailbox[AST_MAX_EXTENSION];
|
char mailbox[AST_MAX_EXTENSION];
|
||||||
char vmexten[AST_MAX_EXTENSION];
|
char vmexten[AST_MAX_EXTENSION];
|
||||||
char regexten[AST_MAX_EXTENSION]; /* Extension for auto-extensions */
|
char regexten[AST_MAX_EXTENSION]; /* Extension for auto-extensions */
|
||||||
|
@ -1137,6 +1164,7 @@ struct skinny_line {
|
||||||
int threewaycalling;
|
int threewaycalling;
|
||||||
int mwiblink;
|
int mwiblink;
|
||||||
int cancallforward;
|
int cancallforward;
|
||||||
|
int getforward;
|
||||||
int callreturn;
|
int callreturn;
|
||||||
int dnd; /* How does this affect callwait? Do we just deny a skinny_request if we're dnd? */
|
int dnd; /* How does this affect callwait? Do we just deny a skinny_request if we're dnd? */
|
||||||
int hascallerid;
|
int hascallerid;
|
||||||
|
@ -1585,6 +1613,41 @@ static int codec_ast2skinny(int astcodec)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int set_callforwards(struct skinny_line *l, const char *cfwd, int cfwdtype)
|
||||||
|
{
|
||||||
|
if (!l)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!ast_strlen_zero(cfwd)) {
|
||||||
|
if (cfwdtype & SKINNY_CFWD_ALL) {
|
||||||
|
l->cfwdtype |= SKINNY_CFWD_ALL;
|
||||||
|
ast_copy_string(l->call_forward_all, cfwd, sizeof(l->call_forward_all));
|
||||||
|
}
|
||||||
|
if (cfwdtype & SKINNY_CFWD_BUSY) {
|
||||||
|
l->cfwdtype |= SKINNY_CFWD_BUSY;
|
||||||
|
ast_copy_string(l->call_forward_busy, cfwd, sizeof(l->call_forward_busy));
|
||||||
|
}
|
||||||
|
if (cfwdtype & SKINNY_CFWD_NOANSWER) {
|
||||||
|
l->cfwdtype |= SKINNY_CFWD_NOANSWER;
|
||||||
|
ast_copy_string(l->call_forward_noanswer, cfwd, sizeof(l->call_forward_noanswer));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (cfwdtype & SKINNY_CFWD_ALL) {
|
||||||
|
l->cfwdtype &= ~SKINNY_CFWD_ALL;
|
||||||
|
memset(l->call_forward_all, 0, sizeof(l->call_forward_all));
|
||||||
|
}
|
||||||
|
if (cfwdtype & SKINNY_CFWD_BUSY) {
|
||||||
|
l->cfwdtype &= ~SKINNY_CFWD_BUSY;
|
||||||
|
memset(l->call_forward_busy, 0, sizeof(l->call_forward_busy));
|
||||||
|
}
|
||||||
|
if (cfwdtype & SKINNY_CFWD_NOANSWER) {
|
||||||
|
l->cfwdtype &= ~SKINNY_CFWD_NOANSWER;
|
||||||
|
memset(l->call_forward_noanswer, 0, sizeof(l->call_forward_noanswer));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return l->cfwdtype;
|
||||||
|
}
|
||||||
|
|
||||||
static void cleanup_stale_contexts(char *new, char *old)
|
static void cleanup_stale_contexts(char *new, char *old)
|
||||||
{
|
{
|
||||||
char *oldcontext, *newcontext, *stalecontext, *stringp, newlist[AST_MAX_CONTEXT];
|
char *oldcontext, *newcontext, *stalecontext, *stringp, newlist[AST_MAX_CONTEXT];
|
||||||
|
@ -2045,6 +2108,51 @@ static void transmit_callstate(struct skinnysession *s, int instance, int state,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void transmit_cfwdstate(struct skinnysession *s, struct skinny_line *l)
|
||||||
|
{
|
||||||
|
struct skinny_req *req;
|
||||||
|
int anyon = 0;
|
||||||
|
|
||||||
|
if (!(req = req_alloc(sizeof(struct forward_stat_message), FORWARD_STAT_MESSAGE)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (l->cfwdtype & SKINNY_CFWD_ALL) {
|
||||||
|
if (!ast_strlen_zero(l->call_forward_all)) {
|
||||||
|
ast_copy_string(req->data.forwardstat.fwdallnum, l->call_forward_all, sizeof(req->data.forwardstat.fwdallnum));
|
||||||
|
req->data.forwardstat.fwdall = htolel(1);
|
||||||
|
anyon++;
|
||||||
|
} else {
|
||||||
|
req->data.forwardstat.fwdall = htolel(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (l->cfwdtype & SKINNY_CFWD_BUSY) {
|
||||||
|
if (!ast_strlen_zero(l->call_forward_busy)) {
|
||||||
|
ast_copy_string(req->data.forwardstat.fwdbusynum, l->call_forward_busy, sizeof(req->data.forwardstat.fwdbusynum));
|
||||||
|
req->data.forwardstat.fwdbusy = htolel(1);
|
||||||
|
anyon++;
|
||||||
|
} else {
|
||||||
|
req->data.forwardstat.fwdbusy = htolel(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (l->cfwdtype & SKINNY_CFWD_NOANSWER) {
|
||||||
|
if (!ast_strlen_zero(l->call_forward_noanswer)) {
|
||||||
|
ast_copy_string(req->data.forwardstat.fwdnoanswernum, l->call_forward_noanswer, sizeof(req->data.forwardstat.fwdnoanswernum));
|
||||||
|
req->data.forwardstat.fwdnoanswer = htolel(1);
|
||||||
|
anyon++;
|
||||||
|
} else {
|
||||||
|
req->data.forwardstat.fwdnoanswer = htolel(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
req->data.forwardstat.lineNumber = htolel(l->instance);
|
||||||
|
if (anyon)
|
||||||
|
req->data.forwardstat.activeforward = htolel(7);
|
||||||
|
else
|
||||||
|
req->data.forwardstat.activeforward = htolel(0);
|
||||||
|
|
||||||
|
transmit_response(s, req);
|
||||||
|
}
|
||||||
|
|
||||||
static int skinny_extensionstate_cb(char *context, char *exten, int state, void *data)
|
static int skinny_extensionstate_cb(char *context, char *exten, int state, void *data)
|
||||||
{
|
{
|
||||||
struct skinny_speeddial *sd = data;
|
struct skinny_speeddial *sd = data;
|
||||||
|
@ -2665,7 +2773,9 @@ static char *handle_skinny_show_line(struct ast_cli_entry *e, int cmd, struct as
|
||||||
ast_cli(a->fd, "CallerId Number: %s\n", S_OR(l->cid_num, "<not set>"));
|
ast_cli(a->fd, "CallerId Number: %s\n", S_OR(l->cid_num, "<not set>"));
|
||||||
ast_cli(a->fd, "CallerId Name: %s\n", S_OR(l->cid_name, "<not set>"));
|
ast_cli(a->fd, "CallerId Name: %s\n", S_OR(l->cid_name, "<not set>"));
|
||||||
ast_cli(a->fd, "Hide CallerId: %s\n", (l->hidecallerid ? "Yes" : "No"));
|
ast_cli(a->fd, "Hide CallerId: %s\n", (l->hidecallerid ? "Yes" : "No"));
|
||||||
ast_cli(a->fd, "CallForward: %s\n", S_OR(l->call_forward, "<not set>"));
|
ast_cli(a->fd, "CFwdAll: %s\n", S_COR((l->cfwdtype & SKINNY_CFWD_ALL), l->call_forward_all, "<not set>"));
|
||||||
|
ast_cli(a->fd, "CFwdBusy: %s\n", S_COR((l->cfwdtype & SKINNY_CFWD_BUSY), l->call_forward_busy, "<not set>"));
|
||||||
|
ast_cli(a->fd, "CFwdNoAnswer: %s\n", S_COR((l->cfwdtype & SKINNY_CFWD_NOANSWER), l->call_forward_noanswer, "<not set>"));
|
||||||
ast_cli(a->fd, "VoicemailBox: %s\n", S_OR(l->mailbox, "<not set>"));
|
ast_cli(a->fd, "VoicemailBox: %s\n", S_OR(l->mailbox, "<not set>"));
|
||||||
ast_cli(a->fd, "VoicemailNumber: %s\n", S_OR(l->vmexten, "<not set>"));
|
ast_cli(a->fd, "VoicemailNumber: %s\n", S_OR(l->vmexten, "<not set>"));
|
||||||
ast_cli(a->fd, "MWIblink: %d\n", l->mwiblink);
|
ast_cli(a->fd, "MWIblink: %d\n", l->mwiblink);
|
||||||
|
@ -2923,6 +3033,8 @@ static struct skinny_device *build_device(const char *cat, struct ast_variable *
|
||||||
l->pickupgroup = cur_pickupgroup;
|
l->pickupgroup = cur_pickupgroup;
|
||||||
l->callreturn = callreturn;
|
l->callreturn = callreturn;
|
||||||
l->cancallforward = cancallforward;
|
l->cancallforward = cancallforward;
|
||||||
|
l->getforward = 0;
|
||||||
|
set_callforwards(l, NULL, 0);
|
||||||
l->callwaiting = callwaiting;
|
l->callwaiting = callwaiting;
|
||||||
l->transfer = transfer;
|
l->transfer = transfer;
|
||||||
l->threewaycalling = threewaycalling;
|
l->threewaycalling = threewaycalling;
|
||||||
|
@ -3035,7 +3147,6 @@ static void *skinny_ss(void *data)
|
||||||
int len = 0;
|
int len = 0;
|
||||||
int timeout = firstdigittimeout;
|
int timeout = firstdigittimeout;
|
||||||
int res = 0;
|
int res = 0;
|
||||||
int getforward=0;
|
|
||||||
int loop_pause = 100;
|
int loop_pause = 100;
|
||||||
|
|
||||||
ast_verb(3, "Starting simple switch on '%s@%s'\n", l->name, d->name);
|
ast_verb(3, "Starting simple switch on '%s@%s'\n", l->name, d->name);
|
||||||
|
@ -3062,22 +3173,26 @@ static void *skinny_ss(void *data)
|
||||||
}
|
}
|
||||||
if (ast_exists_extension(c, c->context, d->exten, 1, l->cid_num)) {
|
if (ast_exists_extension(c, c->context, d->exten, 1, l->cid_num)) {
|
||||||
if (!res || !ast_matchmore_extension(c, c->context, d->exten, 1, l->cid_num)) {
|
if (!res || !ast_matchmore_extension(c, c->context, d->exten, 1, l->cid_num)) {
|
||||||
if (getforward) {
|
if (l->getforward) {
|
||||||
/* Record this as the forwarding extension */
|
/* Record this as the forwarding extension */
|
||||||
ast_copy_string(l->call_forward, d->exten, sizeof(l->call_forward));
|
set_callforwards(l, d->exten, l->getforward);
|
||||||
ast_verb(3, "Setting call forward to '%s' on channel %s\n",
|
ast_verb(3, "Setting call forward (%d) to '%s' on channel %s\n",
|
||||||
l->call_forward, c->name);
|
l->cfwdtype, d->exten, c->name);
|
||||||
transmit_tone(s, SKINNY_DIALTONE, l->instance, sub->callid);
|
transmit_tone(s, SKINNY_DIALTONE, l->instance, sub->callid);
|
||||||
if (res) {
|
transmit_lamp_indication(s, STIMULUS_FORWARDALL, 1, SKINNY_LAMP_ON);
|
||||||
break;
|
transmit_displaynotify(s, "CFwd enabled", 10);
|
||||||
}
|
transmit_cfwdstate(s, l);
|
||||||
ast_safe_sleep(c, 500);
|
ast_safe_sleep(c, 500);
|
||||||
ast_indicate(c, -1);
|
ast_indicate(c, -1);
|
||||||
ast_safe_sleep(c, 1000);
|
ast_safe_sleep(c, 1000);
|
||||||
memset(d->exten, 0, sizeof(d->exten));
|
memset(d->exten, 0, sizeof(d->exten));
|
||||||
transmit_tone(s, SKINNY_DIALTONE, l->instance, sub->callid);
|
|
||||||
len = 0;
|
len = 0;
|
||||||
getforward = 0;
|
l->getforward = 0;
|
||||||
|
if (sub->owner && sub->owner->_state != AST_STATE_UP) {
|
||||||
|
ast_indicate(c, -1);
|
||||||
|
ast_hangup(c);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
} else {
|
} else {
|
||||||
ast_copy_string(c->exten, d->exten, sizeof(c->exten));
|
ast_copy_string(c->exten, d->exten, sizeof(c->exten));
|
||||||
ast_copy_string(l->lastnumberdialed, d->exten, sizeof(l->lastnumberdialed));
|
ast_copy_string(l->lastnumberdialed, d->exten, sizeof(l->lastnumberdialed));
|
||||||
|
@ -3368,6 +3483,35 @@ static int skinny_senddigit_end(struct ast_channel *ast, char digit, unsigned in
|
||||||
return -1; /* Stop inband indications */
|
return -1; /* Stop inband indications */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int get_devicestate(struct skinny_line *l)
|
||||||
|
{
|
||||||
|
struct skinny_subchannel *sub;
|
||||||
|
int res = AST_DEVICE_UNKNOWN;
|
||||||
|
|
||||||
|
if (!l)
|
||||||
|
res = AST_DEVICE_INVALID;
|
||||||
|
else if (!l->parent)
|
||||||
|
res = AST_DEVICE_UNAVAILABLE;
|
||||||
|
else if (l->dnd)
|
||||||
|
res = AST_DEVICE_BUSY;
|
||||||
|
else {
|
||||||
|
if (l->hookstate == SKINNY_ONHOOK) {
|
||||||
|
res = AST_DEVICE_NOT_INUSE;
|
||||||
|
} else {
|
||||||
|
res = AST_DEVICE_INUSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (sub = l->sub; sub; sub = sub->next) {
|
||||||
|
if (sub->onhold) {
|
||||||
|
res = AST_DEVICE_ONHOLD;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
static char *control2str(int ind) {
|
static char *control2str(int ind) {
|
||||||
char *tmp;
|
char *tmp;
|
||||||
|
|
||||||
|
@ -3554,7 +3698,16 @@ static struct ast_channel *skinny_new(struct skinny_line *l, int state)
|
||||||
ast_module_ref(ast_module_info->self);
|
ast_module_ref(ast_module_info->self);
|
||||||
tmp->callgroup = l->callgroup;
|
tmp->callgroup = l->callgroup;
|
||||||
tmp->pickupgroup = l->pickupgroup;
|
tmp->pickupgroup = l->pickupgroup;
|
||||||
ast_string_field_set(tmp, call_forward, l->call_forward);
|
|
||||||
|
/* XXX Need to figure out how to handle CFwdNoAnswer */
|
||||||
|
if (l->cfwdtype & SKINNY_CFWD_ALL) {
|
||||||
|
ast_string_field_set(tmp, call_forward, l->call_forward_all);
|
||||||
|
} else if (l->cfwdtype & SKINNY_CFWD_BUSY) {
|
||||||
|
if (get_devicestate(l) != AST_DEVICE_NOT_INUSE) {
|
||||||
|
ast_string_field_set(tmp, call_forward, l->call_forward_busy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ast_copy_string(tmp->context, l->context, sizeof(tmp->context));
|
ast_copy_string(tmp->context, l->context, sizeof(tmp->context));
|
||||||
ast_copy_string(tmp->exten, l->exten, sizeof(tmp->exten));
|
ast_copy_string(tmp->exten, l->exten, sizeof(tmp->exten));
|
||||||
|
|
||||||
|
@ -3707,6 +3860,45 @@ static int handle_register_message(struct skinny_req *req, struct skinnysession
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int handle_callforward_button(struct skinny_subchannel *sub, int cfwdtype)
|
||||||
|
{
|
||||||
|
struct skinny_line *l = sub->parent;
|
||||||
|
struct skinny_device *d = l->parent;
|
||||||
|
struct skinnysession *s = d->session;
|
||||||
|
struct ast_channel *c = sub->owner;
|
||||||
|
pthread_t t;
|
||||||
|
|
||||||
|
if (l->hookstate == SKINNY_ONHOOK) {
|
||||||
|
l->hookstate = SKINNY_OFFHOOK;
|
||||||
|
transmit_speaker_mode(s, SKINNY_SPEAKERON);
|
||||||
|
transmit_callstate(s, l->instance, SKINNY_OFFHOOK, sub->callid);
|
||||||
|
}
|
||||||
|
if (skinnydebug)
|
||||||
|
ast_verbose("Attempting to Clear display on Skinny %s@%s\n", l->name, d->name);
|
||||||
|
transmit_displaymessage(s, NULL, l->instance, sub->callid); /* clear display */
|
||||||
|
|
||||||
|
if (l->cfwdtype & cfwdtype) {
|
||||||
|
set_callforwards(l, NULL, cfwdtype);
|
||||||
|
ast_safe_sleep(c, 500);
|
||||||
|
transmit_speaker_mode(s, SKINNY_SPEAKEROFF);
|
||||||
|
transmit_callstate(s, l->instance, SKINNY_ONHOOK, sub->callid);
|
||||||
|
transmit_displaynotify(s, "CFwd disabled", 10);
|
||||||
|
if (sub->owner && sub->owner->_state != AST_STATE_UP) {
|
||||||
|
ast_indicate(c, -1);
|
||||||
|
ast_hangup(c);
|
||||||
|
}
|
||||||
|
transmit_cfwdstate(s, l);
|
||||||
|
} else {
|
||||||
|
l->getforward = cfwdtype;
|
||||||
|
transmit_tone(s, SKINNY_DIALTONE, l->instance, sub->callid);
|
||||||
|
transmit_selectsoftkeys(s, l->instance, sub->callid, KEYDEF_RINGOUT);
|
||||||
|
if (ast_pthread_create(&t, NULL, skinny_ss, c)) {
|
||||||
|
ast_log(LOG_WARNING, "Unable to create switch thread: %s\n", strerror(errno));
|
||||||
|
ast_hangup(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
static int handle_ip_port_message(struct skinny_req *req, struct skinnysession *s)
|
static int handle_ip_port_message(struct skinny_req *req, struct skinnysession *s)
|
||||||
{
|
{
|
||||||
/* no response necessary */
|
/* no response necessary */
|
||||||
|
@ -3974,32 +4166,75 @@ static int handle_stimulus_message(struct skinny_req *req, struct skinnysession
|
||||||
ast_verbose("Received Stimulus: Park Call(%d/%d)\n", instance, callreference);
|
ast_verbose("Received Stimulus: Park Call(%d/%d)\n", instance, callreference);
|
||||||
/* XXX Park the call */
|
/* XXX Park the call */
|
||||||
break;
|
break;
|
||||||
case STIMULUS_FORWARDALL:
|
case STIMULUS_DND:
|
||||||
if (skinnydebug)
|
if (skinnydebug)
|
||||||
ast_verbose("Received Stimulus: Forward All(%d/%d)\n", instance, callreference);
|
ast_verbose("Received Stimulus: DND (%d/%d)\n", instance, callreference);
|
||||||
/* Why is DND under FORWARDALL? */
|
|
||||||
/* Because it's the same thing. */
|
|
||||||
|
|
||||||
/* Do not disturb */
|
/* Do not disturb */
|
||||||
if (l->dnd != 0){
|
if (l->dnd != 0){
|
||||||
ast_verb(3, "Disabling DND on %s@%s\n", l->name, d->name);
|
ast_verb(3, "Disabling DND on %s@%s\n", l->name, d->name);
|
||||||
l->dnd = 0;
|
l->dnd = 0;
|
||||||
transmit_lamp_indication(s, STIMULUS_FORWARDALL, 1, SKINNY_LAMP_ON);
|
transmit_lamp_indication(s, STIMULUS_DND, 1, SKINNY_LAMP_ON);
|
||||||
transmit_displaynotify(s, "DnD disabled", 10);
|
transmit_displaynotify(s, "DnD disabled", 10);
|
||||||
} else {
|
} else {
|
||||||
ast_verb(3, "Enabling DND on %s@%s\n", l->name, d->name);
|
ast_verb(3, "Enabling DND on %s@%s\n", l->name, d->name);
|
||||||
l->dnd = 1;
|
l->dnd = 1;
|
||||||
transmit_lamp_indication(s, STIMULUS_FORWARDALL, 1, SKINNY_LAMP_OFF);
|
transmit_lamp_indication(s, STIMULUS_DND, 1, SKINNY_LAMP_OFF);
|
||||||
transmit_displaynotify(s, "DnD enabled", 10);
|
transmit_displaynotify(s, "DnD enabled", 10);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case STIMULUS_FORWARDALL:
|
||||||
|
if (skinnydebug)
|
||||||
|
ast_verbose("Received Stimulus: Forward All(%d/%d)\n", instance, callreference);
|
||||||
|
|
||||||
|
if (!sub || !sub->owner) {
|
||||||
|
c = skinny_new(l, AST_STATE_DOWN);
|
||||||
|
} 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_ALL);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case STIMULUS_FORWARDBUSY:
|
case STIMULUS_FORWARDBUSY:
|
||||||
if (skinnydebug)
|
if (skinnydebug)
|
||||||
ast_verbose("Received Stimulus: Forward Busy (%d/%d)\n", instance, callreference);
|
ast_verbose("Received Stimulus: Forward Busy (%d/%d)\n", instance, callreference);
|
||||||
|
|
||||||
|
if (!sub || !sub->owner) {
|
||||||
|
c = skinny_new(l, AST_STATE_DOWN);
|
||||||
|
} 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_BUSY);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case STIMULUS_FORWARDNOANSWER:
|
case STIMULUS_FORWARDNOANSWER:
|
||||||
if (skinnydebug)
|
if (skinnydebug)
|
||||||
ast_verbose("Received Stimulus: Forward No Answer (%d/%d)\n", instance, callreference);
|
ast_verbose("Received Stimulus: Forward No Answer (%d/%d)\n", instance, callreference);
|
||||||
|
|
||||||
|
#if 0 /* Not sure how to handle this yet */
|
||||||
|
if (!sub || !sub->owner) {
|
||||||
|
c = skinny_new(l, AST_STATE_DOWN);
|
||||||
|
} 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
|
||||||
break;
|
break;
|
||||||
case STIMULUS_DISPLAY:
|
case STIMULUS_DISPLAY:
|
||||||
/* Not sure what this is */
|
/* Not sure what this is */
|
||||||
|
@ -4796,30 +5031,75 @@ static int handle_soft_key_event_message(struct skinny_req *req, struct skinnyse
|
||||||
ast_verbose("Received Softkey Event: Transfer(%d/%d)\n", instance, callreference);
|
ast_verbose("Received Softkey Event: Transfer(%d/%d)\n", instance, callreference);
|
||||||
/* XXX figure out how to transfer */
|
/* XXX figure out how to transfer */
|
||||||
break;
|
break;
|
||||||
case SOFTKEY_CFWDALL:
|
case SOFTKEY_DND:
|
||||||
if (skinnydebug)
|
if (skinnydebug)
|
||||||
ast_verbose("Received Softkey Event: Forward All(%d/%d)\n", instance, callreference);
|
ast_verbose("Received Softkey Event: DND(%d/%d)\n", instance, callreference);
|
||||||
|
|
||||||
/* Do not disturb */
|
/* Do not disturb */
|
||||||
if (l->dnd != 0){
|
if (l->dnd != 0){
|
||||||
ast_verb(3, "Disabling DND on %s@%s\n", l->name, d->name);
|
ast_verb(3, "Disabling DND on %s@%s\n", l->name, d->name);
|
||||||
l->dnd = 0;
|
l->dnd = 0;
|
||||||
transmit_lamp_indication(s, STIMULUS_FORWARDALL, 1, SKINNY_LAMP_ON);
|
transmit_lamp_indication(s, STIMULUS_DND, 1, SKINNY_LAMP_ON);
|
||||||
transmit_displaynotify(s, "DnD disabled", 10);
|
transmit_displaynotify(s, "DnD disabled", 10);
|
||||||
} else {
|
} else {
|
||||||
ast_verb(3, "Enabling DND on %s@%s\n", l->name, d->name);
|
ast_verb(3, "Enabling DND on %s@%s\n", l->name, d->name);
|
||||||
l->dnd = 1;
|
l->dnd = 1;
|
||||||
transmit_lamp_indication(s, STIMULUS_FORWARDALL, 1, SKINNY_LAMP_OFF);
|
transmit_lamp_indication(s, STIMULUS_DND, 1, SKINNY_LAMP_OFF);
|
||||||
transmit_displaynotify(s, "DnD enabled", 10);
|
transmit_displaynotify(s, "DnD enabled", 10);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case SOFTKEY_CFWDALL:
|
||||||
|
if (skinnydebug)
|
||||||
|
ast_verbose("Received Softkey Event: Forward All(%d/%d)\n", instance, callreference);
|
||||||
|
|
||||||
|
if (!sub || !sub->owner) {
|
||||||
|
c = skinny_new(l, AST_STATE_DOWN);
|
||||||
|
} 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_ALL);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case SOFTKEY_CFWDBUSY:
|
case SOFTKEY_CFWDBUSY:
|
||||||
if (skinnydebug)
|
if (skinnydebug)
|
||||||
ast_verbose("Received Softkey Event: Forward Busy (%d/%d)\n", instance, callreference);
|
ast_verbose("Received Softkey Event: Forward Busy (%d/%d)\n", instance, callreference);
|
||||||
|
|
||||||
|
if (!sub || !sub->owner) {
|
||||||
|
c = skinny_new(l, AST_STATE_DOWN);
|
||||||
|
} 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_BUSY);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case SOFTKEY_CFWDNOANSWER:
|
case SOFTKEY_CFWDNOANSWER:
|
||||||
if (skinnydebug)
|
if (skinnydebug)
|
||||||
ast_verbose("Received Softkey Event: Forward No Answer (%d/%d)\n", instance, callreference);
|
ast_verbose("Received Softkey Event: Forward No Answer (%d/%d)\n", instance, callreference);
|
||||||
|
|
||||||
|
#if 0 /* Not sure how to handle this yet */
|
||||||
|
if (!sub || !sub->owner) {
|
||||||
|
c = skinny_new(l, AST_STATE_DOWN);
|
||||||
|
} 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
|
||||||
break;
|
break;
|
||||||
case SOFTKEY_BKSPC:
|
case SOFTKEY_BKSPC:
|
||||||
if (skinnydebug)
|
if (skinnydebug)
|
||||||
|
@ -5391,6 +5671,18 @@ static int restart_monitor(void)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int skinny_devicestate(void *data)
|
||||||
|
{
|
||||||
|
struct skinny_line *l;
|
||||||
|
char *tmp;
|
||||||
|
|
||||||
|
tmp = ast_strdupa(data);
|
||||||
|
|
||||||
|
l = find_line_by_name(tmp);
|
||||||
|
|
||||||
|
return get_devicestate(l);
|
||||||
|
}
|
||||||
|
|
||||||
static struct ast_channel *skinny_request(const char *type, int format, void *data, int *cause)
|
static struct ast_channel *skinny_request(const char *type, int format, void *data, int *cause)
|
||||||
{
|
{
|
||||||
int oldformat;
|
int oldformat;
|
||||||
|
@ -5426,41 +5718,6 @@ static struct ast_channel *skinny_request(const char *type, int format, void *da
|
||||||
return tmpc;
|
return tmpc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int skinny_devicestate(void *data)
|
|
||||||
{
|
|
||||||
struct skinny_line *l;
|
|
||||||
struct skinny_subchannel *sub;
|
|
||||||
char *tmp;
|
|
||||||
int res = AST_DEVICE_UNKNOWN;
|
|
||||||
|
|
||||||
tmp = ast_strdupa(data);
|
|
||||||
|
|
||||||
l = find_line_by_name(tmp);
|
|
||||||
|
|
||||||
if (!l)
|
|
||||||
res = AST_DEVICE_INVALID;
|
|
||||||
else if (!l->parent)
|
|
||||||
res = AST_DEVICE_UNAVAILABLE;
|
|
||||||
else if (l->dnd)
|
|
||||||
res = AST_DEVICE_BUSY;
|
|
||||||
else {
|
|
||||||
if (l->hookstate == SKINNY_ONHOOK) {
|
|
||||||
res = AST_DEVICE_NOT_INUSE;
|
|
||||||
} else {
|
|
||||||
res = AST_DEVICE_INUSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (sub = l->sub; sub; sub = sub->next) {
|
|
||||||
if (sub->onhold) {
|
|
||||||
res = AST_DEVICE_ONHOLD;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int reload_config(void)
|
static int reload_config(void)
|
||||||
{
|
{
|
||||||
int on = 1;
|
int on = 1;
|
||||||
|
|
Loading…
Reference in New Issue