From e9446501c9176b6c05b4a59f88090250b7f04fea Mon Sep 17 00:00:00 2001 From: Damien Wedhorn Date: Fri, 25 Jan 2013 05:49:54 +0000 Subject: Add force dial keys to skinny. Adds a dial softkey when the device is in DAFD. The softkey is greyed (unusable) until a possible dialplan match is entered. Code includes updating transmit_selectsoftkeys to allow the use of a button mask. Also add option to use # or * as a dial now button. Original patch by snuffy cleaned up by myself. Review: https://reviewboard.asterisk.org/r/2277/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@380057 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- channels/chan_skinny.c | 128 +++++++++++++++++++++++++++++++++++---------- configs/skinny.conf.sample | 8 +++ 2 files changed, 108 insertions(+), 28 deletions(-) diff --git a/channels/chan_skinny.c b/channels/chan_skinny.c index 570bf2877..6a8b36483 100644 --- a/channels/chan_skinny.c +++ b/channels/chan_skinny.c @@ -202,6 +202,7 @@ static int keep_alive = 120; static int auth_timeout = DEFAULT_AUTH_TIMEOUT; static int auth_limit = DEFAULT_AUTH_LIMIT; static int unauth_sessions = 0; +static char immed_dialchar = '\0'; static char vmexten[AST_MAX_EXTENSION]; /* Voicemail pilot number */ static char used_context[AST_MAX_EXTENSION]; /* placeholder to check if context are already used in regcontext */ static char regcontext[AST_MAX_CONTEXT]; /* Context for auto-extension */ @@ -718,6 +719,31 @@ struct bksp_req_message { #define SOFTKEY_GPICKUP 0x12 #define SOFTKEY_DND 0x13 #define SOFTKEY_IDIVERT 0x14 +#define SOFTKEY_FORCEDIAL 0x15 + +#define KEYMASK_ALL 0xFFFFFFFF +#define KEYMASK_NONE (1 << 0) +#define KEYMASK_REDIAL (1 << 1) +#define KEYMASK_NEWCALL (1 << 2) +#define KEYMASK_HOLD (1 << 3) +#define KEYMASK_TRNSFER (1 << 4) +#define KEYMASK_CFWDALL (1 << 5) +#define KEYMASK_CFWDBUSY (1 << 6) +#define KEYMASK_CFWDNOANSWER (1 << 7) +#define KEYMASK_BKSPC (1 << 8) +#define KEYMASK_ENDCALL (1 << 9) +#define KEYMASK_RESUME (1 << 10) +#define KEYMASK_ANSWER (1 << 11) +#define KEYMASK_INFO (1 << 12) +#define KEYMASK_CONFRN (1 << 13) +#define KEYMASK_PARK (1 << 14) +#define KEYMASK_JOIN (1 << 15) +#define KEYMASK_MEETME (1 << 16) +#define KEYMASK_PICKUP (1 << 17) +#define KEYMASK_GPICKUP (1 << 18) +#define KEYMASK_DND (1 << 29) +#define KEYMASK_IDIVERT (1 << 20) +#define KEYMASK_FORCEDIAL (1 << 21) static struct soft_key_template_definition soft_key_template_default[] = { { "\200\001", SOFTKEY_REDIAL }, @@ -740,6 +766,7 @@ static struct soft_key_template_definition soft_key_template_default[] = { { "\200\022", SOFTKEY_GPICKUP }, { "\200\077", SOFTKEY_DND }, { "\200\120", SOFTKEY_IDIVERT }, + { "Dial", SOFTKEY_FORCEDIAL}, }; /* Localized message "codes" (in octal) @@ -934,6 +961,7 @@ static const uint8_t soft_key_default_connwithtrans[] = { static const uint8_t soft_key_default_dadfd[] = { SOFTKEY_BKSPC, SOFTKEY_ENDCALL, + SOFTKEY_FORCEDIAL, }; static const uint8_t soft_key_default_connwithconf[] = { @@ -2468,20 +2496,44 @@ static void transmit_stop_tone(struct skinny_device *d, int instance, int refere transmit_response(d, req); } -static void transmit_selectsoftkeys(struct skinny_device *d, int instance, int callid, int softkey) +static int keyset_translatebitmask(int keyset, int intmask) +{ + int extmask = 0; + int x, y; + const struct soft_key_definitions *softkeymode = soft_key_default_definitions; + + for(x = 0; x < ARRAY_LEN(soft_key_default_definitions); x++) { + if (softkeymode[x].mode == keyset) { + const uint8_t *defaults = softkeymode[x].defaults; + + for (y = 0; y < softkeymode[x].count; y++) { + if (intmask & (1 << (defaults[y]))) { + extmask |= (1 << ((y))); + } + } + break; + } + } + + return extmask; +} + +static void transmit_selectsoftkeys(struct skinny_device *d, int instance, int callid, int softkey, int mask) { struct skinny_req *req; + int newmask; if (!(req = req_alloc(sizeof(struct select_soft_keys_message), SELECT_SOFT_KEYS_MESSAGE))) return; + newmask = keyset_translatebitmask(softkey, mask); req->data.selectsoftkey.instance = htolel(instance); req->data.selectsoftkey.reference = htolel(callid); req->data.selectsoftkey.softKeySetIndex = htolel(softkey); - req->data.selectsoftkey.validKeyMask = htolel(0xFFFFFFFF); + req->data.selectsoftkey.validKeyMask = htolel(newmask); - SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting SELECT_SOFT_KEYS_MESSAGE to %s, inst %d, callid %d, softkey %d, mask 0xFFFFFFFF\n", - d->name, instance, callid, softkey); + SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting SELECT_SOFT_KEYS_MESSAGE to %s, inst %d, callid %d, softkey %d, mask 0x%08x\n", + d->name, instance, callid, softkey, newmask); transmit_response(d, req); } @@ -2864,6 +2916,7 @@ static void transmit_softkeysetres(struct skinny_device *d) int i; int x; int y; + int keydefcount; const struct soft_key_definitions *softkeymode = soft_key_default_definitions; if (!(req = req_alloc(sizeof(struct soft_key_set_res_message), SOFT_KEY_SET_RES_MESSAGE))) @@ -2871,10 +2924,11 @@ static void transmit_softkeysetres(struct skinny_device *d) SKINNY_DEBUG(DEBUG_TEMPLATE, 3, "Creating Softkey Template\n"); + keydefcount = ARRAY_LEN(soft_key_default_definitions); req->data.softkeysets.softKeySetOffset = htolel(0); - req->data.softkeysets.softKeySetCount = htolel(13); - req->data.softkeysets.totalSoftKeySetCount = htolel(13); - for (x = 0; x < sizeof(soft_key_default_definitions) / sizeof(struct soft_key_definitions); x++) { + req->data.softkeysets.softKeySetCount = htolel(keydefcount); + req->data.softkeysets.totalSoftKeySetCount = htolel(keydefcount); + for (x = 0; x < keydefcount; x++) { const uint8_t *defaults = softkeymode->defaults; /* XXX I wanted to get the size of the array dynamically, but that wasn't wanting to work. This will have to do for now. */ @@ -2899,6 +2953,7 @@ static void transmit_softkeysetres(struct skinny_device *d) static void transmit_softkeytemplateres(struct skinny_device *d) { struct skinny_req *req; + if (!(req = req_alloc(sizeof(struct soft_key_template_res_message), SOFT_KEY_TEMPLATE_RES_MESSAGE))) return; @@ -3070,11 +3125,11 @@ static int skinny_extensionstate_cb(char *context, char *exten, struct ast_state case AST_EXTENSION_INUSE: if (subline->sub && (subline->sub->substate == SKINNY_CONNECTED)) { /* Device has a real call */ transmit_callstate(d, l->instance, subline->callid, SKINNY_CONNECTED); - transmit_selectsoftkeys(d, l->instance, subline->callid, KEYDEF_CONNECTED); + transmit_selectsoftkeys(d, l->instance, subline->callid, KEYDEF_CONNECTED, KEYMASK_ALL); transmit_displaypromptstatus(d, "Connected", 0, l->instance, subline->callid); } else { /* Some other device has active call */ transmit_callstate(d, l->instance, subline->callid, SKINNY_CALLREMOTEMULTILINE); - transmit_selectsoftkeys(d, l->instance, subline->callid, KEYDEF_SLACONNECTEDNOTACTIVE); + transmit_selectsoftkeys(d, l->instance, subline->callid, KEYDEF_SLACONNECTEDNOTACTIVE, KEYMASK_ALL); transmit_displaypromptstatus(d, "In Use", 0, l->instance, subline->callid); } transmit_lamp_indication(d, STIMULUS_LINE, l->instance, SKINNY_LAMP_ON); @@ -3083,14 +3138,14 @@ static int skinny_extensionstate_cb(char *context, char *exten, struct ast_state break; case AST_EXTENSION_ONHOLD: transmit_callstate(d, l->instance, subline->callid, SKINNY_HOLD); - transmit_selectsoftkeys(d, l->instance, subline->callid, KEYDEF_SLAHOLD); + transmit_selectsoftkeys(d, l->instance, subline->callid, KEYDEF_SLAHOLD, KEYMASK_ALL); transmit_displaypromptstatus(d, "Hold", 0, l->instance, subline->callid); transmit_lamp_indication(d, STIMULUS_LINE, l->instance, SKINNY_LAMP_BLINK); transmit_activatecallplane(d, l); break; case AST_EXTENSION_NOT_INUSE: transmit_callstate(d, l->instance, subline->callid, SKINNY_ONHOOK); - transmit_selectsoftkeys(d, l->instance, subline->callid, KEYDEF_ONHOOK); + transmit_selectsoftkeys(d, l->instance, subline->callid, KEYDEF_ONHOOK, KEYMASK_ALL); transmit_clearpromptmessage(d, l->instance, subline->callid); transmit_lamp_indication(d, STIMULUS_LINE, l->instance, SKINNY_LAMP_OFF); transmit_activatecallplane(d, l); @@ -4327,7 +4382,7 @@ static void skinny_dialer(struct skinny_subchannel *sub, int timedout) struct skinny_device *d = l->device; if (timedout || !ast_matchmore_extension(c, ast_channel_context(c), sub->exten, 1, l->cid_num)) { - SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %d - Force dialing '%s'\n", sub->callid, sub->exten); + SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %d - Force dialing '%s' because of %s\n", sub->callid, sub->exten, (timedout ? "timeout" : "exactmatch")); if (ast_exists_extension(c, ast_channel_context(c), sub->exten, 1, l->cid_num)) { if (sub->substate == SUBSTATE_OFFHOOK) { dialandactivatesub(sub, sub->exten); @@ -4342,6 +4397,7 @@ static void skinny_dialer(struct skinny_subchannel *sub, int timedout) } else { SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %d - Wait for more digits\n", sub->callid); if (ast_exists_extension(c, ast_channel_context(c), sub->exten, 1, l->cid_num)) { + transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_DADFD, KEYMASK_ALL); sub->dialer_sched = skinny_sched_add(matchdigittimeout, skinny_dialer_cb, sub); } else { sub->dialer_sched = skinny_sched_add(gendigittimeout, skinny_dialer_cb, sub); @@ -5075,7 +5131,7 @@ static void setsubstate(struct skinny_subchannel *sub, int state) if (subline->callid) { transmit_stop_tone(d, l->instance, sub->callid); transmit_callstate(d, l->instance, subline->callid, SKINNY_CALLREMOTEMULTILINE); - transmit_selectsoftkeys(d, l->instance, subline->callid, KEYDEF_SLACONNECTEDNOTACTIVE); + transmit_selectsoftkeys(d, l->instance, subline->callid, KEYDEF_SLACONNECTEDNOTACTIVE, KEYMASK_ALL); transmit_displaypromptstatus(d, "In Use", 0, l->instance, subline->callid); } @@ -5090,7 +5146,7 @@ static void setsubstate(struct skinny_subchannel *sub, int state) case SUBSTATE_CONNECTED: transmit_activatecallplane(d, l); transmit_stop_tone(d, l->instance, sub->callid); - transmit_selectsoftkeys(d, l->instance, subline->callid, KEYDEF_CONNECTED); + transmit_selectsoftkeys(d, l->instance, subline->callid, KEYDEF_CONNECTED, KEYMASK_ALL); transmit_callstate(d, l->instance, subline->callid, SKINNY_CONNECTED); if (!sub->rtp) { start_rtp(sub); @@ -5117,7 +5173,7 @@ static void setsubstate(struct skinny_subchannel *sub, int state) transmit_stopmediatransmission(d, sub); transmit_callstate(d, l->instance, subline->callid, SKINNY_CALLREMOTEMULTILINE); - transmit_selectsoftkeys(d, l->instance, subline->callid, KEYDEF_SLACONNECTEDNOTACTIVE); + transmit_selectsoftkeys(d, l->instance, subline->callid, KEYDEF_SLACONNECTEDNOTACTIVE, KEYMASK_ALL); transmit_displaypromptstatus(d, "In Use", 0, l->instance, subline->callid); sub->substate = SUBSTATE_HOLD; @@ -5156,7 +5212,7 @@ static void setsubstate(struct skinny_subchannel *sub, int state) transmit_activatecallplane(d, l); transmit_clear_display_message(d, l->instance, sub->callid); transmit_start_tone(d, SKINNY_DIALTONE, l->instance, sub->callid); - transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_OFFHOOK); + transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_OFFHOOK, KEYMASK_ALL); transmit_displaypromptstatus(d, "Enter number", 0, l->instance, sub->callid); sub->substate = SUBSTATE_OFFHOOK; @@ -5214,7 +5270,7 @@ static void setsubstate(struct skinny_subchannel *sub, int state) transmit_callstate(d, l->instance, sub->callid, SKINNY_OFFHOOK); transmit_stop_tone(d, l->instance, sub->callid); transmit_clear_display_message(d, l->instance, sub->callid); - transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_RINGOUT); + transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_RINGOUT, KEYMASK_ALL); transmit_displaypromptstatus(d, "Dialing", 0, l->instance, sub->callid); } @@ -5261,7 +5317,7 @@ static void setsubstate(struct skinny_subchannel *sub, int state) break; case SUBSTATE_RINGIN: transmit_callstate(d, l->instance, sub->callid, SKINNY_RINGIN); - transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_RINGIN); + transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_RINGIN, KEYMASK_ALL); transmit_displaypromptstatus(d, "Ring-In", 0, l->instance, sub->callid); send_callinfo(sub); transmit_lamp_indication(d, STIMULUS_LINE, l->instance, SKINNY_LAMP_BLINK); @@ -5281,7 +5337,7 @@ static void setsubstate(struct skinny_subchannel *sub, int state) case SUBSTATE_CALLWAIT: transmit_callstate(d, l->instance, sub->callid, SKINNY_RINGIN); transmit_callstate(d, l->instance, sub->callid, SKINNY_CALLWAIT); - transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_RINGIN); + transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_RINGIN, KEYMASK_ALL); transmit_displaypromptstatus(d, "Callwaiting", 0, l->instance, sub->callid); send_callinfo(sub); transmit_lamp_indication(d, STIMULUS_LINE, l->instance, SKINNY_LAMP_BLINK); @@ -5305,7 +5361,7 @@ static void setsubstate(struct skinny_subchannel *sub, int state) send_callinfo(sub); transmit_callstate(d, l->instance, sub->callid, SKINNY_CONNECTED); transmit_displaypromptstatus(d, "Connected", 0, l->instance, sub->callid); - transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_CONNECTED); + transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_CONNECTED, KEYMASK_ALL); if (!sub->rtp) { start_rtp(sub); } @@ -5384,7 +5440,7 @@ static void setsubstate(struct skinny_subchannel *sub, int state) transmit_callstate(d, l->instance, sub->callid, SKINNY_HOLD); transmit_lamp_indication(d, STIMULUS_LINE, l->instance, SKINNY_LAMP_WINK); - transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_ONHOLD); + transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_ONHOLD, KEYMASK_ALL); sub->substate = SUBSTATE_HOLD; break; default: @@ -5598,7 +5654,7 @@ static int handle_callforward_button(struct skinny_subchannel *sub, int cfwdtype 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); + 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) { @@ -5664,19 +5720,19 @@ static int handle_keypad_button_message(struct skinny_req *req, struct skinnyses } if ((sub->owner && ast_channel_state(sub->owner) < AST_STATE_UP)) { - if (sub->dialer_sched && !skinny_sched_del(sub->dialer_sched, sub)) { + if (sub->dialer_sched && !skinny_sched_del(sub->dialer_sched, sub)) { SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %d - Got a digit and not timed out, so try dialing\n", sub->callid); sub->dialer_sched = 0; len = strlen(sub->exten); if (len == 0) { transmit_stop_tone(d, l->instance, sub->callid); - transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_DADFD); + transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_DADFD, KEYMASK_ALL&~KEYMASK_FORCEDIAL); } - if (len < sizeof(sub->exten) - 1) { + if (len < sizeof(sub->exten) - 1 && dgt != immed_dialchar) { sub->exten[len] = dgt; sub->exten[len + 1] = '\0'; } - if (len == sizeof(sub->exten) - 1) { + if (len == sizeof(sub->exten) - 1 || dgt == immed_dialchar) { skinny_dialer(sub, 1); } else { skinny_dialer(sub, 0); @@ -6555,7 +6611,7 @@ static int handle_soft_key_event_message(struct skinny_req *req, struct skinnyse sub->exten[len-1] = '\0'; if (len == 1) { transmit_start_tone(d, SKINNY_DIALTONE, l->instance, sub->callid); - transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_OFFHOOK); + transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_OFFHOOK, KEYMASK_ALL); } transmit_backspace(d, l->instance, sub->callid); } @@ -6701,6 +6757,12 @@ static int handle_soft_key_event_message(struct skinny_req *req, struct skinnyse setsubstate(sub, SUBSTATE_CONNECTED); ast_channel_unref(c); } + break; + case SOFTKEY_FORCEDIAL: + SKINNY_DEBUG(DEBUG_PACKET, 3, "Received SOFTKEY_FORCEDIAL from %s, inst %d, callref %d\n", + d->name, instance, callreference); + skinny_dialer(sub, 1); + break; default: SKINNY_DEBUG(DEBUG_PACKET, 3, "Received SOFTKEY_UNKNOWN(%d) from %s, inst %d, callref %d\n", @@ -6814,7 +6876,7 @@ static int handle_message(struct skinny_req *req, struct skinnysession *s) case SOFT_KEY_SET_REQ_MESSAGE: SKINNY_DEBUG(DEBUG_PACKET, 3, "Received SOFT_KEY_SET_REQ_MESSAGE from %s\n", d->name); transmit_softkeysetres(d); - transmit_selectsoftkeys(d, 0, 0, KEYDEF_ONHOOK); + transmit_selectsoftkeys(d, 0, 0, KEYDEF_ONHOOK, KEYMASK_ALL); break; case SOFT_KEY_EVENT_MESSAGE: /* SKINNY_PACKETDEBUG handled in handle_soft_key_event_message */ @@ -7219,6 +7281,16 @@ static void config_parse_variables(int type, void *item, struct ast_variable *vp continue; } else if (!strcasecmp(v->name, "vmexten")) { ast_copy_string(vmexten, v->value, sizeof(vmexten)); + continue; + } else if (!strcasecmp(v->name, "immeddialkey")) { + if (!strcmp(v->value,"#")) { + immed_dialchar = '#'; + } else if (!strcmp(v->value,"*")) { + immed_dialchar = '*'; + } else { + ast_log(LOG_WARNING, "Invalid immeddialkey '%s' at line %d, only # or * accepted. Immeddial key disabled\n", v->value, v->lineno); + } + continue; } else if (!strcasecmp(v->name, "dateformat")) { memcpy(date_format, v->value, sizeof(date_format)); diff --git a/configs/skinny.conf.sample b/configs/skinny.conf.sample index d40823ef7..ba8b2d649 100644 --- a/configs/skinny.conf.sample +++ b/configs/skinny.conf.sample @@ -38,6 +38,14 @@ keepalive=120 ; for framing options ;disallow= +; The imeddialkey option allows for a key to be used to immediately dial the already +; entered number. This is useful where the dialplan includes variable length pattern +; matching. Valid options are '#' and '*'. On devices with soft buttons, a button will +; be available to immediately dial when a pattern than can be dialed has been entered. +; Default is unset, that is no immediated dial key (softbutton still exists). +; +;immeddialkey='#' + ; See https://wiki.asterisk.org/wiki/display/AST/IP+Quality+of+Service for a description of these parameters. ;tos=cs3 ; Sets TOS for signaling packets. ;tos_audio=ef ; Sets TOS for RTP audio packets. -- cgit v1.2.3