/* 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;
#define SKINNY_TRANSFER 10
#define SKINNY_PARK 11
#define SKINNY_PROGRESS 12
+#define SKINNY_CALLREMOTEMULTILINE 13
#define SKINNY_INVALID 14
#define SKINNY_SILENCE 0x00
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;
/* .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;
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;
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;
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;
}
}
}
-
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;
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;
}
}
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 */
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)
{
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;
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;
}
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;
}
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;
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);
ast_verbose("RECEIVED UNKNOWN STIMULUS: %d(%d)\n", event, instance);
break;
}
+ ast_device_state_changed("Skinny/%s@%s", l->name, d->name);
+
return 1;
}
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 */
}
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);
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;
{
struct skinny_device *d = s->device;
struct skinny_line *l;
+ struct skinny_speeddial *sd = NULL;
int instance;
instance = letohl(req->data.line.lineNumber);
l = find_line_by_instance(d, instance);
if (!l) {
+ sd = find_speeddial_by_instance(d, instance, 1);
+ }
+
+ if (!l && !sd) {
return 0;
}
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;
}
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;
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);
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;
}
}
break;
- case BT_CUST_HINT:
- break;
case BT_NONE:
break;
default:
return 0;
}
+ ast_device_state_changed("Skinny/%s@%s", l->name, d->name);
+
switch(event) {
case SOFTKEY_NONE:
if (skinnydebug)
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;
}