diff options
Diffstat (limited to 'channels')
-rw-r--r-- | channels/chan_skinny.c | 117 |
1 files changed, 87 insertions, 30 deletions
diff --git a/channels/chan_skinny.c b/channels/chan_skinny.c index c1ecfa6a8..1a4c10d54 100644 --- a/channels/chan_skinny.c +++ b/channels/chan_skinny.c @@ -998,6 +998,7 @@ static struct skinny_device { int lastlineinstance; int lastcallreference; int capability; + char exten[AST_MAX_EXTENSION]; struct sockaddr_in addr; struct in_addr ourip; struct skinny_line *lines; @@ -1189,6 +1190,9 @@ static struct skinny_line *find_line_by_instance(struct skinny_device *d, int in { struct skinny_line *l; + if (!instance) + instance = 1; + for (l = d->lines; l; l = l->next) { if (l->instance == instance) break; @@ -1246,9 +1250,13 @@ static struct skinny_subchannel *find_subchannel_by_instance_reference(struct sk return NULL; } - for (sub = l->sub; sub; sub = sub->next) { - if (sub->callid == reference) - break; + if (!reference) + sub = l->sub; + else { + for (sub = l->sub; sub; sub = sub->next) { + if (sub->callid == reference) + break; + } } if (!sub) { @@ -2270,36 +2278,39 @@ static void *skinny_ss(void *data) struct skinny_line *l = sub->parent; struct skinny_device *d = l->parent; struct skinnysession *s = d->session; - char exten[AST_MAX_EXTENSION] = ""; int len = 0; int timeout = firstdigittimeout; - int res; + int res = 0; int getforward=0; + int loop_pause = 100; if (option_verbose > 2) ast_verbose( VERBOSE_PREFIX_3 "Starting simple switch on '%s@%s'\n", l->name, d->name); + len = strlen(d->exten); while (len < AST_MAX_EXTENSION-1) { - res = ast_waitfordigit(c, timeout); - timeout = 0; - if (res < 0) { - if (skinnydebug) - ast_verbose("Skinny(%s@%s): waitfordigit returned < 0\n", l->name, d->name); - ast_indicate(c, -1); - ast_hangup(c); - return NULL; - } else if (res) { - exten[len++]=res; - exten[len] = '\0'; + + res = 1; /* Assume we will get a digit */ + while (strlen(d->exten) == len) { + ast_safe_sleep(c, loop_pause); + timeout -= loop_pause; + if (timeout <= 0){ + res = 0; + break; + } } - if (!ast_ignore_pattern(c->context, exten)) { + + len = strlen(d->exten); + + if (len && !ast_ignore_pattern(c->context, d->exten)) { transmit_tone(s, SKINNY_SILENCE); } - if (ast_exists_extension(c, c->context, exten, 1, l->cid_num)) { - if (!res || !ast_matchmore_extension(c, c->context, 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 (getforward) { /* Record this as the forwarding extension */ - ast_copy_string(l->call_forward, exten, sizeof(l->call_forward)); + ast_copy_string(l->call_forward, d->exten, sizeof(l->call_forward)); if (option_verbose > 2) ast_verbose(VERBOSE_PREFIX_3 "Setting call forward to '%s' on channel %s\n", l->call_forward, c->name); @@ -2310,13 +2321,14 @@ static void *skinny_ss(void *data) ast_safe_sleep(c, 500); ast_indicate(c, -1); ast_safe_sleep(c, 1000); - memset(exten, 0, sizeof(exten)); + memset(d->exten, 0, sizeof(d->exten)); transmit_tone(s, SKINNY_DIALTONE); len = 0; getforward = 0; } else { - ast_copy_string(c->exten, exten, sizeof(c->exten)); - ast_copy_string(l->lastnumberdialed, exten, sizeof(l->lastnumberdialed)); + ast_copy_string(c->exten, d->exten, sizeof(c->exten)); + ast_copy_string(l->lastnumberdialed, d->exten, sizeof(l->lastnumberdialed)); + memset (d->exten, 0, sizeof(d->exten)); skinny_newcall(c); return NULL; } @@ -2328,11 +2340,14 @@ static void *skinny_ss(void *data) } else if (res == 0) { ast_log(LOG_DEBUG, "Not enough digits (and no ambiguous match)...\n"); transmit_tone(s, SKINNY_REORDER); - ast_hangup(c); + if (sub->owner && sub->owner->_state != AST_STATE_UP) { + ast_indicate(c, -1); + ast_hangup(c); + } return NULL; - } else if (!ast_canmatch_extension(c, c->context, exten, 1, c->cid.cid_num) && - ((exten[0] != '*') || (!ast_strlen_zero(exten) > 2))) { - ast_log(LOG_WARNING, "Can't match [%s] from '%s' in context %s\n", exten, c->cid.cid_num ? c->cid.cid_num : "<Unknown Caller>", c->context); + } else if (!ast_canmatch_extension(c, c->context, d->exten, 1, c->cid.cid_num) && + ((d->exten[0] != '*') || (!ast_strlen_zero(d->exten) > 2))) { + ast_log(LOG_WARNING, "Can't match [%s] from '%s' in context %s\n", d->exten, c->cid.cid_num ? c->cid.cid_num : "<Unknown Caller>", c->context); transmit_tone(s, SKINNY_REORDER); /* hang out for 3 seconds to let congestion play */ ast_safe_sleep(c, 3000); @@ -2341,11 +2356,13 @@ static void *skinny_ss(void *data) if (!timeout) { timeout = gendigittimeout; } - if (len && !ast_ignore_pattern(c->context, exten)) { + if (len && !ast_ignore_pattern(c->context, d->exten)) { ast_indicate(c, -1); } } - ast_hangup(c); + if (c) + ast_hangup(c); + return NULL; } @@ -4001,6 +4018,10 @@ static int handle_register_available_lines_message(struct skinny_req *req, struc static int handle_message(struct skinny_req *req, struct skinnysession *s) { int res = 0; + struct skinny_device *d = s->device; + struct skinny_subchannel *sub; + int lineInstance; + int callReference; if ((!s->device) && (letohl(req->e) != REGISTER_MESSAGE && letohl(req->e) != ALARM_MESSAGE)) { ast_log(LOG_WARNING, "Client sent message #%d without first registering.\n", req->e); @@ -4025,7 +4046,43 @@ static int handle_message(struct skinny_req *req, struct skinnysession *s) if (skinnydebug) ast_verbose("Collected digit: [%d]\n", letohl(req->data.keypad.button)); - res = handle_keypad_button_message(req, s); + lineInstance = letohl(req->data.keypad.lineInstance); + callReference = letohl(req->data.keypad.callReference); + + sub = find_subchannel_by_instance_reference(d, lineInstance, callReference); + + if (sub && (sub->owner->_state < AST_STATE_UP)) { + char dgt; + int digit = letohl(req->data.keypad.button); + size_t len; + + if (digit == 14) { + dgt = '*'; + } else if (digit == 15) { + dgt = '#'; + } else if (digit >= 0 && digit <= 9) { + dgt = '0' + digit; + } else { + /* digit=10-13 (A,B,C,D ?), or + * digit is bad value + * + * probably should not end up here, but set + * value for backward compatibility, and log + * a warning. + */ + dgt = '0' + digit; + ast_log(LOG_WARNING, "Unsupported digit %d\n", digit); + } + + len = strlen(d->exten); + if (len < sizeof(d->exten) - 1) { + d->exten[len] = dgt; + d->exten[len] = '\0'; + } else { + ast_log(LOG_WARNING, "Dropping digit with value %d because digit queue is full\n", dgt); + } + } else + res = handle_keypad_button_message(req, s); break; case STIMULUS_MESSAGE: res = handle_stimulus_message(req, s); |