summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Parker <jparker@digium.com>2007-02-24 02:23:43 +0000
committerJason Parker <jparker@digium.com>2007-02-24 02:23:43 +0000
commit97ab07a9e85ff5b38bdd5933299e8f25cf71d971 (patch)
tree86420597cd2dcbbe4fcd78524755e56a3eb391ad
parenta23096985b62ff53621af353dd82ce2544106b9a (diff)
Allow a Skinny device to monitor a dialplan hint (w00t!).
See skinny.conf.sample for configuration example. Note: Some devices (seen on 12SP+/30VIP) will lock up if they monitor too many hints. This seems to be a hardware limitation - there isn't anything we can do about it. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@56594 65c4cc65-6c06-0410-ace0-fbb531ad65f3
-rw-r--r--channels/chan_skinny.c219
-rw-r--r--configs/skinny.conf.sample4
2 files changed, 182 insertions, 41 deletions
diff --git a/channels/chan_skinny.c b/channels/chan_skinny.c
index c7d037959..730bf374d 100644
--- a/channels/chan_skinny.c
+++ b/channels/chan_skinny.c
@@ -409,8 +409,8 @@ struct button_definition_template {
/* Custom button types - add our own between 0xB0 and 0xCF.
This may need to be revised in the future,
if stimuluses are ever added in this range. */
-#define BT_CUST_LINESPEEDDIAL 0xB0 /* line or speeddial */
-#define BT_CUST_HINT 0xB1 /* pipe dream */
+#define BT_CUST_LINESPEEDDIAL 0xB0 /* line or speeddial with/without hint */
+#define BT_CUST_LINE 0xB1 /* line or speeddial with hint only */
struct button_template_res_message {
uint32_t buttonOffset;
@@ -830,6 +830,7 @@ static int callnums = 1;
#define SKINNY_TRANSFER 10
#define SKINNY_PARK 11
#define SKINNY_PROGRESS 12
+#define SKINNY_CALLREMOTEMULTILINE 13
#define SKINNY_INVALID 14
#define SKINNY_SILENCE 0x00
@@ -974,8 +975,12 @@ struct skinny_line {
struct skinny_speeddial {
ast_mutex_t lock;
char label[42];
+ char context[AST_MAX_CONTEXT];
char exten[AST_MAX_EXTENSION];
int instance;
+ int stateid;
+ int laststate;
+ int isHint;
struct skinny_speeddial *next;
struct skinny_device *parent;
@@ -1059,6 +1064,8 @@ static const struct ast_channel_tech skinny_tech = {
/* .bridge = ast_rtp_bridge, */
};
+static int skinny_extensionstate_cb(char *context, char* exten, int state, void *data);
+
static void *get_button_template(struct skinnysession *s, struct button_definition_template *btn)
{
struct skinny_device *d = s->device;
@@ -1070,7 +1077,7 @@ static void *get_button_template(struct skinnysession *s, struct button_definiti
case SKINNY_DEVICE_30VIP:
/* 13 rows, 2 columns */
for (i = 0; i < 4; i++)
- (btn++)->buttonDefinition = BT_LINE;
+ (btn++)->buttonDefinition = BT_CUST_LINE;
(btn++)->buttonDefinition = BT_REDIAL;
(btn++)->buttonDefinition = BT_VOICEMAIL;
(btn++)->buttonDefinition = BT_CALLPARK;
@@ -1087,16 +1094,15 @@ static void *get_button_template(struct skinnysession *s, struct button_definiti
case SKINNY_DEVICE_12:
/* 6 rows, 2 columns */
for (i = 0; i < 2; i++)
- (btn++)->buttonDefinition = BT_LINE;
- (btn++)->buttonDefinition = BT_REDIAL;
- for (i = 0; i < 3; i++)
+ (btn++)->buttonDefinition = BT_CUST_LINE;
+ for (i = 0; i < 4; i++)
(btn++)->buttonDefinition = BT_SPEEDDIAL;
(btn++)->buttonDefinition = BT_HOLD;
+ (btn++)->buttonDefinition = BT_REDIAL;
(btn++)->buttonDefinition = BT_TRANSFER;
(btn++)->buttonDefinition = BT_FORWARDALL;
(btn++)->buttonDefinition = BT_CALLPARK;
(btn++)->buttonDefinition = BT_VOICEMAIL;
- (btn++)->buttonDefinition = BT_CONFERENCE;
break;
case SKINNY_DEVICE_7910:
(btn++)->buttonDefinition = BT_LINE;
@@ -1285,12 +1291,12 @@ static struct skinny_subchannel *find_subchannel_by_reference(struct skinny_devi
return sub;
}
-static struct skinny_speeddial *find_speeddial_by_instance(struct skinny_device *d, int instance)
+static struct skinny_speeddial *find_speeddial_by_instance(struct skinny_device *d, int instance, int isHint)
{
struct skinny_speeddial *sd;
for (sd = d->speeddials; sd; sd = sd->next) {
- if (sd->instance == instance)
+ if (sd->isHint == isHint && sd->instance == instance)
break;
}
@@ -1344,10 +1350,11 @@ static int codec_ast2skinny(int astcodec)
}
}
-
static int skinny_register(struct skinny_req *req, struct skinnysession *s)
{
struct skinny_device *d;
+ struct skinny_line *l;
+ struct skinny_speeddial *sd;
struct sockaddr_in sin;
socklen_t slen;
@@ -1369,6 +1376,13 @@ static int skinny_register(struct skinny_req *req, struct skinnysession *s)
sin.sin_addr = __ourip;
}
d->ourip = sin.sin_addr;
+
+ for (sd = d->speeddials; sd; sd = sd->next) {
+ sd->stateid = ast_extension_state_add(sd->context, sd->exten, skinny_extensionstate_cb, sd);
+ }
+ for (l = d->lines; l; l = l->next) {
+ ast_device_state_changed("Skinny/%s@%s", l->name, d->name);
+ }
break;
}
}
@@ -1382,12 +1396,22 @@ static int skinny_register(struct skinny_req *req, struct skinnysession *s)
static int skinny_unregister(struct skinny_req *req, struct skinnysession *s)
{
struct skinny_device *d;
+ struct skinny_line *l;
+ struct skinny_speeddial *sd;
d = s->device;
if (d) {
d->session = NULL;
d->registered = 0;
+
+ for (sd = d->speeddials; sd; sd = sd->next) {
+ if (sd->stateid > -1)
+ ast_extension_state_del(sd->stateid, NULL);
+ }
+ for (l = d->lines; l; l = l->next) {
+ ast_device_state_changed("Skinny/%s@%s", l->name, d->name);
+ }
}
return -1; /* main loop will destroy the session */
@@ -1684,6 +1708,59 @@ static void transmit_dialednumber(struct skinnysession *s, const char *text, int
transmit_response(s, req);
}
+static int skinny_extensionstate_cb(char *context, char *exten, int state, void *data)
+{
+ struct skinny_speeddial *sd = data;
+ struct skinny_device *d = sd->parent;
+ struct skinnysession *s = d->session;
+ char hint[AST_MAX_EXTENSION];
+ int callstate = SKINNY_CALLREMOTEMULTILINE;
+ int lamp = SKINNY_LAMP_OFF;
+
+ switch (state) {
+ case AST_EXTENSION_DEACTIVATED: /* Retry after a while */
+ case AST_EXTENSION_REMOVED: /* Extension is gone */
+ ast_verbose(VERBOSE_PREFIX_2 "Extension state: Watcher for hint %s %s. Notify Device %s\n", exten, state == AST_EXTENSION_DEACTIVATED ? "deactivated" : "removed", d->name);
+ sd->stateid = -1;
+ callstate = SKINNY_ONHOOK;
+ lamp = SKINNY_LAMP_OFF;
+ break;
+ case AST_EXTENSION_RINGING:
+ case AST_EXTENSION_UNAVAILABLE:
+ callstate = SKINNY_RINGIN;
+ lamp = SKINNY_LAMP_BLINK;
+ break;
+ case AST_EXTENSION_BUSY: /* callstate = SKINNY_BUSY wasn't wanting to work - I'll settle for this */
+ case AST_EXTENSION_INUSE:
+ callstate = SKINNY_CALLREMOTEMULTILINE;
+ lamp = SKINNY_LAMP_ON;
+ break;
+ case AST_EXTENSION_ONHOLD:
+ callstate = SKINNY_HOLD;
+ lamp = SKINNY_LAMP_WINK;
+ break;
+ case AST_EXTENSION_NOT_INUSE:
+ default:
+ callstate = SKINNY_ONHOOK;
+ lamp = SKINNY_LAMP_OFF;
+ break;
+ }
+
+ if (ast_get_hint(hint, sizeof(hint), NULL, 0, NULL, sd->context, sd->exten)) {
+ /* If they are not registered, we will override notification and show no availability */
+ if (ast_device_state(hint) == AST_DEVICE_UNAVAILABLE) {
+ callstate = SKINNY_ONHOOK;
+ lamp = SKINNY_LAMP_FLASH;
+ }
+ }
+
+ transmit_lamp_indication(s, STIMULUS_LINE, sd->instance, lamp);
+ transmit_callstate(s, sd->instance, callstate, 0);
+ sd->laststate = state;
+
+ return 0;
+}
+
/*
static int has_voicemail(struct skinny_line *l)
{
@@ -2099,17 +2176,25 @@ static struct skinny_device *build_device(const char *cat, struct ast_variable *
if (!(sd = ast_calloc(1, sizeof(struct skinny_speeddial)))) {
return NULL;
} else {
- char *stringp, *exten, *label;
+ char *stringp, *exten, *context, *label;
stringp = v->value;
exten = strsep(&stringp, ",");
- label = strsep(&stringp, ",");
+ if ((context = strchr(exten, '@'))) {
+ *context++ = '\0';
+ }
+ label = stringp;
ast_mutex_init(&sd->lock);
ast_copy_string(sd->exten, exten, sizeof(sd->exten));
- if (label)
- ast_copy_string(sd->label, label, sizeof(sd->label));
- else
- ast_copy_string(sd->label, exten, sizeof(sd->label));
- sd->instance = speeddialInstance++;
+ if (!ast_strlen_zero(context)) {
+ sd->isHint = 1;
+ sd->instance = lineInstance++;
+ ast_copy_string(sd->context, context, sizeof(sd->context));
+ } else {
+ sd->isHint = 0;
+ sd->instance = speeddialInstance++;
+ sd->context[0] = '\0';
+ }
+ ast_copy_string(sd->label, S_OR(label, exten), sizeof(sd->label));
sd->parent = d;
@@ -2833,7 +2918,7 @@ static int skinny_hold(struct skinny_subchannel *sub)
req->data.stopmedia.passThruPartyId = htolel(sub->callid);
transmit_response(s, req);
- transmit_lamp_indication(s, STIMULUS_LINE, l->instance, SKINNY_LAMP_BLINK);
+ transmit_lamp_indication(s, STIMULUS_LINE, l->instance, SKINNY_LAMP_WINK);
sub->onhold = 1;
return 1;
}
@@ -3058,7 +3143,7 @@ static int handle_stimulus_message(struct skinny_req *req, struct skinnysession
ast_verbose("Received Stimulus: SpeedDial(%d)\n", instance);
#if 0
- if (!(sd = find_speeddial_by_instance(d, instance))) {
+ if (!(sd = find_speeddial_by_instance(d, instance, 0))) {
return 0;
}
@@ -3162,7 +3247,7 @@ static int handle_stimulus_message(struct skinny_req *req, struct skinnysession
if (skinnydebug)
ast_verbose("Received Stimulus: Line(%d)\n", instance);
- l = find_line_by_instance(s->device, instance);
+ l = find_line_by_instance(d, instance);
if (!l) {
return 0;
@@ -3175,6 +3260,8 @@ static int handle_stimulus_message(struct skinny_req *req, struct skinnysession
l->hookstate = SKINNY_OFFHOOK;
+ ast_device_state_changed("Skinny/%s@%s", l->name, d->name);
+
if (sub && sub->outgoing) {
/* We're answering a ringing call */
ast_queue_control(sub->owner, AST_CONTROL_ANSWER);
@@ -3216,6 +3303,8 @@ static int handle_stimulus_message(struct skinny_req *req, struct skinnysession
ast_verbose("RECEIVED UNKNOWN STIMULUS: %d(%d)\n", event, instance);
break;
}
+ ast_device_state_changed("Skinny/%s@%s", l->name, d->name);
+
return 1;
}
@@ -3243,15 +3332,16 @@ static int handle_offhook_message(struct skinny_req *req, struct skinnysession *
l = sub->parent;
}
+ transmit_ringer_mode(s, SKINNY_RING_OFF);
+ l->hookstate = SKINNY_OFFHOOK;
+
+ ast_device_state_changed("Skinny/%s@%s", l->name, d->name);
+
if (sub && sub->onhold) {
- transmit_ringer_mode(s, SKINNY_RING_OFF);
- l->hookstate = SKINNY_OFFHOOK;
return 1;
}
- transmit_ringer_mode(s, SKINNY_RING_OFF);
transmit_lamp_indication(s, STIMULUS_LINE, l->instance, SKINNY_LAMP_ON);
- l->hookstate = SKINNY_OFFHOOK;
if (sub && sub->outgoing) {
/* We're answering a ringing call */
@@ -3308,17 +3398,19 @@ static int handle_onhook_message(struct skinny_req *req, struct skinnysession *s
}
l = sub->parent;
- if (sub->onhold) {
- l->hookstate = SKINNY_ONHOOK;
+ if (l->hookstate == SKINNY_ONHOOK) {
+ /* Something else already put us back on hook */
return 0;
}
+ l->hookstate = SKINNY_ONHOOK;
- if (l->hookstate == SKINNY_ONHOOK) {
- /* Something else already put us back on hook */
+ ast_device_state_changed("Skinny/%s@%s", l->name, d->name);
+
+ if (sub->onhold) {
return 0;
}
+
sub->cxmode = SKINNY_CX_RECVONLY;
- l->hookstate = SKINNY_ONHOOK;
transmit_callstate(s, l->instance, l->hookstate, sub->callid);
if (skinnydebug)
ast_verbose("Skinny %s@%s went on hook\n", l->name, d->name);
@@ -3393,7 +3485,7 @@ static int handle_speed_dial_stat_req_message(struct skinny_req *req, struct ski
instance = letohl(req->data.speeddialreq.speedDialNumber);
- sd = find_speeddial_by_instance(d, instance);
+ sd = find_speeddial_by_instance(d, instance, 0);
if (!sd) {
return 0;
@@ -3414,6 +3506,7 @@ static int handle_line_state_req_message(struct skinny_req *req, struct skinnyse
{
struct skinny_device *d = s->device;
struct skinny_line *l;
+ struct skinny_speeddial *sd = NULL;
int instance;
instance = letohl(req->data.line.lineNumber);
@@ -3423,6 +3516,10 @@ static int handle_line_state_req_message(struct skinny_req *req, struct skinnyse
l = find_line_by_instance(d, instance);
if (!l) {
+ sd = find_speeddial_by_instance(d, instance, 1);
+ }
+
+ if (!l && !sd) {
return 0;
}
@@ -3432,10 +3529,13 @@ static int handle_line_state_req_message(struct skinny_req *req, struct skinnyse
return -1;
req->data.linestat.lineNumber = letohl(instance);
- memcpy(req->data.linestat.lineDirNumber, l->name,
- sizeof(req->data.linestat.lineDirNumber));
- memcpy(req->data.linestat.lineDisplayName, l->label,
- sizeof(req->data.linestat.lineDisplayName));
+ if (!l) {
+ memcpy(req->data.linestat.lineDirNumber, sd->label, sizeof(req->data.linestat.lineDirNumber));
+ memcpy(req->data.linestat.lineDisplayName, sd->label, sizeof(req->data.linestat.lineDisplayName));
+ } else {
+ memcpy(req->data.linestat.lineDirNumber, l->name, sizeof(req->data.linestat.lineDirNumber));
+ memcpy(req->data.linestat.lineDisplayName, l->label, sizeof(req->data.linestat.lineDisplayName));
+ }
transmit_response(s,req);
return 1;
}
@@ -3483,6 +3583,37 @@ static int handle_button_template_req_message(struct skinny_req *req, struct ski
for (i=0; i<42; i++) {
int btnSet = 0;
switch (btn[i].buttonDefinition) {
+ case BT_CUST_LINE:
+ /* assume failure */
+ req->data.buttontemplate.definition[i].buttonDefinition = BT_NONE;
+ req->data.buttontemplate.definition[i].instanceNumber = htolel(0);
+
+ for (l = d->lines; l; l = l->next) {
+ if (l->instance == lineInstance) {
+ ast_verbose("Adding button: %d, %d\n", BT_LINE, lineInstance);
+ req->data.buttontemplate.definition[i].buttonDefinition = BT_LINE;
+ req->data.buttontemplate.definition[i].instanceNumber = htolel(lineInstance);
+ lineInstance++;
+ buttonCount++;
+ btnSet = 1;
+ break;
+ }
+ }
+
+ if (!btnSet) {
+ for (sd = d->speeddials; sd; sd = sd->next) {
+ if (sd->isHint && sd->instance == lineInstance) {
+ ast_verbose("Adding button: %d, %d\n", BT_LINE, lineInstance);
+ req->data.buttontemplate.definition[i].buttonDefinition = BT_LINE;
+ req->data.buttontemplate.definition[i].instanceNumber = htolel(lineInstance);
+ lineInstance++;
+ buttonCount++;
+ btnSet = 1;
+ break;
+ }
+ }
+ }
+ break;
case BT_CUST_LINESPEEDDIAL:
/* assume failure */
req->data.buttontemplate.definition[i].buttonDefinition = BT_NONE;
@@ -3502,7 +3633,15 @@ static int handle_button_template_req_message(struct skinny_req *req, struct ski
if (!btnSet) {
for (sd = d->speeddials; sd; sd = sd->next) {
- if (sd->instance == speeddialInstance) {
+ if (sd->isHint && sd->instance == lineInstance) {
+ ast_verbose("Adding button: %d, %d\n", BT_LINE, lineInstance);
+ req->data.buttontemplate.definition[i].buttonDefinition = BT_LINE;
+ req->data.buttontemplate.definition[i].instanceNumber = htolel(lineInstance);
+ lineInstance++;
+ buttonCount++;
+ btnSet = 1;
+ break;
+ } else if (!sd->isHint && sd->instance == speeddialInstance) {
ast_verbose("Adding button: %d, %d\n", BT_SPEEDDIAL, speeddialInstance);
req->data.buttontemplate.definition[i].buttonDefinition = BT_SPEEDDIAL;
req->data.buttontemplate.definition[i].instanceNumber = htolel(speeddialInstance);
@@ -3535,10 +3674,10 @@ static int handle_button_template_req_message(struct skinny_req *req, struct ski
req->data.buttontemplate.definition[i].instanceNumber = 0;
for (sd = d->speeddials; sd; sd = sd->next) {
- if (sd->instance == speeddialInstance) {
+ if (!sd->isHint && sd->instance == speeddialInstance) {
ast_verbose("Adding button: %d, %d\n", BT_SPEEDDIAL, speeddialInstance);
req->data.buttontemplate.definition[i].buttonDefinition = BT_SPEEDDIAL;
- req->data.buttontemplate.definition[i].instanceNumber = htolel(speeddialInstance);
+ req->data.buttontemplate.definition[i].instanceNumber = htolel(speeddialInstance - 1);
speeddialInstance++;
buttonCount++;
btnSet = 1;
@@ -3546,8 +3685,6 @@ static int handle_button_template_req_message(struct skinny_req *req, struct ski
}
}
break;
- case BT_CUST_HINT:
- break;
case BT_NONE:
break;
default:
@@ -3738,6 +3875,8 @@ static int handle_soft_key_event_message(struct skinny_req *req, struct skinnyse
return 0;
}
+ ast_device_state_changed("Skinny/%s@%s", l->name, d->name);
+
switch(event) {
case SOFTKEY_NONE:
if (skinnydebug)
@@ -3965,6 +4104,8 @@ static int handle_soft_key_event_message(struct skinny_req *req, struct skinnyse
ast_verbose("Received unknown Softkey Event: %d(%d)\n", event, instance);
break;
}
+ ast_device_state_changed("Skinny/%s@%s", l->name, d->name);
+
return 1;
}
diff --git a/configs/skinny.conf.sample b/configs/skinny.conf.sample
index 995012083..40b195087 100644
--- a/configs/skinny.conf.sample
+++ b/configs/skinny.conf.sample
@@ -83,7 +83,7 @@ keepalive=120
;linelabel="John"
;mailbox=110
;line => 110
-;speeddial => 111,Jack Smith
-;speeddial => 112,Bob Peterson
+;speeddial => 111,Jack Smith ; Adds a speeddial button to a device.
+;speeddial => 112@hints,Bob Peterson ; When a context is specified, the speeddial watches a dialplan hint.
;addon => 7914
;addon => 7914