[asterisk-commits] branch north/chan_skinny-fixup r30193 -
/team/north/chan_skinny-fixup/channels/
asterisk-commits at lists.digium.com
asterisk-commits at lists.digium.com
Thu May 25 01:33:18 MST 2006
Author: north
Date: Thu May 25 03:33:17 2006
New Revision: 30193
URL: http://svn.digium.com/view/asterisk?rev=30193&view=rev
Log:
Lots of rearranging. Split a function with several hundred lines into multiple handle_* functions.
Added extremely basic support for redial (this might've already been there..I don't recall).
Less segfaulting... "Well, it works here."
I think I fixed the poll()ing too. It was...bad.
Modified:
team/north/chan_skinny-fixup/channels/chan_skinny.c
Modified: team/north/chan_skinny-fixup/channels/chan_skinny.c
URL: http://svn.digium.com/view/asterisk/team/north/chan_skinny-fixup/channels/chan_skinny.c?rev=30193&r1=30192&r2=30193&view=diff
==============================================================================
--- team/north/chan_skinny-fixup/channels/chan_skinny.c (original)
+++ team/north/chan_skinny-fixup/channels/chan_skinny.c Thu May 25 03:33:17 2006
@@ -4,6 +4,7 @@
* Copyright (C) 1999 - 2005, Digium, Inc.
*
* chan_skinny was developed by Jeremy McNamara & Florian Overkamp
+ * chan_skinny was heavily modified/fixed by North Antara
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
@@ -20,7 +21,7 @@
*
* \brief Implementation of the Skinny protocol
*
- * \author Jeremy McNamara & Florian Overkamp
+ * \author Jeremy McNamara & Florian Overkamp & North Antara
* \ingroup channel_drivers
*/
@@ -921,7 +922,7 @@
char version_id[16];
int type;
int registered;
- char model[10];
+// char model[10];
struct sockaddr_in addr;
struct in_addr ourip;
struct skinny_line *lines;
@@ -1098,18 +1099,12 @@
static skinny_req *req_alloc(size_t size, int response_message)
{
skinny_req *req;
- skinny_data *data;
-
- if (!(req = ast_calloc(1, sizeof(skinny_req))))
- return NULL;
-
- if (!(data = ast_calloc(1, size)))
+
+ if (!(req = ast_calloc(1, skinny_header_size + size + 4)))
return NULL;
req->len = htolel(size+4);
req->e = htolel(response_message);
-
- req->data = *data;
return req;
}
@@ -1313,14 +1308,14 @@
if (!(req = req_alloc(sizeof(struct start_tone_message), START_TONE_MESSAGE)))
return;
} else {
- if (!(req = req_alloc(4, STOP_TONE_MESSAGE)))
+ if (!(req = req_alloc(0, STOP_TONE_MESSAGE)))
return;
}
if (tone > 0) {
req->data.starttone.tone = htolel(tone);
} else {
- req->len = htolel(4);
+// req->len = htolel(4);
}
transmit_response(s, req);
}
@@ -1374,10 +1369,9 @@
skinny_req *req;
if (text == 0) {
- if (!(req = req_alloc(4, CLEAR_DISPLAY_MESSAGE)))
+ if (!(req = req_alloc(0, CLEAR_DISPLAY_MESSAGE)))
return;
- req->len = htolel(4);
if (skinnydebug)
ast_verbose("Clearing Display\n");
} else {
@@ -1444,7 +1438,6 @@
{
return ast_app_has_voicemail(l->mailbox, NULL);
}
-
static void do_housekeeping(struct skinnysession *s)
{
@@ -1540,20 +1533,19 @@
ast_mutex_lock(&devicelock);
d = devices;
- ast_cli(fd, "Name DeviceId IP TypeId R Model NL\n");
- ast_cli(fd, "-------------------- ---------------- --------------- ------ - ------ --\n");
+ ast_cli(fd, "Name DeviceId IP TypeId R NL\n");
+ ast_cli(fd, "-------------------- ---------------- --------------- ------ - --\n");
while(d) {
l = d->lines;
numlines = 0;
while(l) { numlines++; l = l->next; }
- ast_cli(fd, "%-20s %-16s %-16s %6X %c %-6s %2d\n",
+ ast_cli(fd, "%-20s %-16s %-15s %6X %c %2d\n",
d->name,
d->id,
ast_inet_ntoa(iabuf, sizeof(iabuf), d->addr.sin_addr),
d->type,
d->registered?'Y':'N',
- d->model,
numlines);
d = d->next;
@@ -1572,10 +1564,13 @@
}
ast_mutex_lock(&devicelock);
d = devices;
+
+ ast_cli(fd, "Device Name Instance Name Label O R\n");
+ ast_cli(fd, "-------------------- -------- -------------------- -------------------- - -\n");
while(d) {
l = d->lines;
while (l) {
- ast_cli(fd, "%-20s %2d %-20s %-20s %c %c\n",
+ ast_cli(fd, "%-20s %8d %-20s %-20s %c %c\n",
l->parent->name,
l->instance,
l->name,
@@ -1657,8 +1652,8 @@
ast_copy_string(d->version_id, v->value, sizeof(d->version_id));
} else if (!strcasecmp(v->name, "nat")) {
nat = ast_true(v->value);
- } else if (!strcasecmp(v->name, "model")) {
- ast_copy_string(d->model, v->value, sizeof(d->model));
+// } else if (!strcasecmp(v->name, "model")) {
+// ast_copy_string(d->model, v->value, sizeof(d->model));
} else if (!strcasecmp(v->name, "callerid")) {
if (!strcasecmp(v->value, "asreceived")) {
cid_num[0] = '\0';
@@ -1899,6 +1894,7 @@
getforward = 0;
} else {
ast_copy_string(chan->exten, exten, sizeof(chan->exten));
+ ast_copy_string(l->lastnumberdialed, exten, sizeof(l->lastnumberdialed));
if (!ast_strlen_zero(l->cid_num)) {
if (!l->hidecallerid) {
chan->cid.cid_num = strdup(l->cid_num);
@@ -2424,9 +2420,13 @@
return tmp;
}
-static int handle_alarm_message(skinny_req *req, struct skinnysession *s)
-{
- /* no response necessary */
+static int handle_keep_alive_message(skinny_req *req, struct skinnysession *s)
+{
+ if (!(req = req_alloc(0, KEEP_ALIVE_ACK_MESSAGE)))
+ return -1;
+
+ transmit_response(s, req);
+ do_housekeeping(s);
return 1;
}
@@ -2463,36 +2463,59 @@
if (skinnydebug)
ast_verbose("Requesting capabilities\n");
- if (!(req = req_alloc(4, CAPABILITIES_REQ_MESSAGE)))
+ if (!(req = req_alloc(0, CAPABILITIES_REQ_MESSAGE)))
return -1;
- req->len = htolel(4);
transmit_response(s, req);
return res;
}
-static int handle_unregister_message(skinny_req *req, struct skinnysession *s)
-{
- /* XXX Actually unregister the device */
+static int handle_ip_port_message(skinny_req *req, struct skinnysession *s)
+{
+ /* no response necessary */
return 1;
}
-static int handle_headset_status_message(skinny_req *req, struct skinnysession *s)
-{
- /* XXX umm...okay? Why do I care? */
- return 1;
-}
-
-static int handle_register_available_lines_message(skinny_req *req, struct skinnysession *s)
-{
- /* XXX I have no clue what this is for, but my phone was sending it, so... */
- return 1;
-}
-
-static int handle_ip_port_message(skinny_req *req, struct skinnysession *s)
-{
- /* no response necessary */
+static int handle_keypad_button_message(skinny_req *req, struct skinnysession *s)
+{
+ struct skinny_line *l;
+ struct ast_frame f = { 0, };
+ char d;
+ int digit;
+
+ digit = letohl(req->data.keypad.button);
+ f.frametype = AST_FRAME_DTMF;
+ if (digit == 14) {
+ d = '*';
+ } else if (digit == 15) {
+ d = '#';
+ } else if (digit >=0 && digit <= 9) {
+ d = '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.
+ */
+ d = '0' + digit;
+ ast_log(LOG_WARNING, "Unsupported digit %d\n", digit);
+ }
+ f.subclass = d;
+ f.src = "skinny";
+ l = s->device->lines;
+ if (l->owner) {
+ /* XXX MUST queue this frame to all lines in threeway call if threeway call is active */
+ ast_queue_frame(l->owner, &f);
+ if (l->next && l->owner) {
+ ast_queue_frame(l->owner, &f);
+ }
+ } else {
+ if (skinnydebug)
+ ast_verbose("No owner: %s\n", l->name);
+ }
return 1;
}
@@ -2528,14 +2551,14 @@
c = skinny_new(l, AST_STATE_DOWN);
if(c) {
if (ast_strlen_zero(l->lastnumberdialed)) {
- ast_log(LOG_WARNING, "User attempted redial, but no previously dialed number found.\n");
+ ast_log(LOG_WARNING, "Attempted redial, but no previously dialed number found.\n");
return 0;
}
if (!ast_ignore_pattern(c->context, l->lastnumberdialed)) {
transmit_tone(s, SKINNY_SILENCE);
}
if (ast_exists_extension(c, c->context, l->lastnumberdialed, 1, l->cid_num)) {
- if (!res || !ast_matchmore_extension(c, c->context, l->lastnumberdialed, 1, l->cid_num)) {
+ if (!ast_matchmore_extension(c, c->context, l->lastnumberdialed, 1, l->cid_num)) {
ast_copy_string(c->exten, l->lastnumberdialed, sizeof(c->exten));
if (!ast_strlen_zero(l->cid_num)) {
if (!l->hidecallerid) {
@@ -2551,14 +2574,9 @@
}
break;
}
- } else if (res == 0) {
- ast_log(LOG_DEBUG, "Not enough digits (and no ambiguous match)...\n");
- transmit_tone(s, SKINNY_REORDER);
- ast_hangup(c);
- break;
}
} else {
- ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", s->device->lines->name, s->device->name);
+ ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, s->device->name);
}
break;
case STIMULUS_SPEEDDIAL:
@@ -2583,8 +2601,9 @@
transmit_tone(s, SKINNY_SILENCE);
}
if (ast_exists_extension(c, c->context, sd->exten, 1, l->cid_num)) {
- if (!res || !ast_matchmore_extension(c, c->context, sd->exten, 1, l->cid_num)) {
+ if (!ast_matchmore_extension(c, c->context, sd->exten, 1, l->cid_num)) {
ast_copy_string(c->exten, sd->exten, sizeof(c->exten));
+ ast_copy_string(l->lastnumberdialed, sd->exten, sizeof(l->lastnumberdialed));
if (!ast_strlen_zero(l->cid_num)) {
if (!l->hidecallerid) {
c->cid.cid_num = strdup(l->cid_num);
@@ -2599,14 +2618,9 @@
}
break;
}
- } else if (res == 0) {
- ast_log(LOG_DEBUG, "Not enough digits (and no ambiguous match)...\n");
- transmit_tone(s, SKINNY_REORDER);
- ast_hangup(c);
- break;
}
} else {
- ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", s->device->lines->name, s->device->name);
+ ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, s->device->name);
}
break;
case STIMULUS_HOLD:
@@ -2644,16 +2658,17 @@
/* Do not disturb */
transmit_tone(s, SKINNY_DIALTONE);
- if (s->device->lines->dnd != 0){
+ l = s->device->lines;
+ if (l->dnd != 0){
if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Disabling DND on %s@%s\n",s->device->lines->name,s->device->lines->name);
- s->device->lines->dnd = 0;
+ ast_verbose(VERBOSE_PREFIX_3 "Disabling DND on %s@%s\n", l->name, l->name);
+ l->dnd = 0;
transmit_lamp_indication(s, STIMULUS_FORWARDALL, 1, SKINNY_LAMP_ON);
transmit_displaynotify(s, "DnD disabled",10);
} else {
if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Enabling DND on %s@%s\n",s->device->lines->name,s->device->lines->name);
- s->device->lines->dnd = 1;
+ ast_verbose(VERBOSE_PREFIX_3 "Enabling DND on %s@%s\n", l->name, l->name);
+ l->dnd = 1;
transmit_lamp_indication(s, STIMULUS_FORWARDALL, 1, SKINNY_LAMP_OFF);
transmit_displaynotify(s, "DnD enabled",10);
}
@@ -2729,25 +2744,181 @@
return 1;
}
-static int handle_version_req_message(skinny_req *req, struct skinnysession *s)
-{
- if (!(req = req_alloc(sizeof(version_res_message), VERSION_RES_MESSAGE)))
+static int handle_offhook_message(skinny_req *req, struct skinnysession *s)
+{
+ struct skinny_line *l;
+ struct ast_channel *c;
+ pthread_t t;
+
+ l = s->device->lines;
+
+ if (!l) {
+ ast_log(LOG_NOTICE, "No available lines on: %s\n", s->device->name);
+ return 0;
+ }
+
+ transmit_ringer_mode(s,SKINNY_RING_OFF);
+ transmit_lamp_indication(s, STIMULUS_LINE, l->instance, SKINNY_LAMP_ON);
+ l->hookstate = SKINNY_OFFHOOK;
+
+ if (l->outgoing) {
+ /* We're answering a ringing call */
+ ast_queue_control(l->owner, AST_CONTROL_ANSWER);
+ transmit_callstate(s, l->instance, SKINNY_OFFHOOK, l->callid);
+ transmit_tone(s, SKINNY_SILENCE);
+ transmit_callstate(s, l->instance, SKINNY_CONNECTED, l->callid);
+ transmit_selectsoftkeys(s, l->instance, l->callid, KEYDEF_CONNECTED);
+ start_rtp(l);
+ ast_setstate(l->owner, AST_STATE_UP);
+ } else {
+ if (!l->owner) {
+ transmit_callstate(s, l->instance, SKINNY_OFFHOOK, l->callid);
+ if (skinnydebug)
+ ast_verbose("Attempting to Clear display on Skinny %s@%s\n", l->name, s->device->name);
+ transmit_displaymessage(s, NULL); /* clear display */
+ transmit_tone(s, SKINNY_DIALTONE);
+ transmit_selectsoftkeys(s, l->instance, l->callid, KEYDEF_OFFHOOK);
+ c = skinny_new(l, AST_STATE_DOWN);
+ if(c) {
+ /* start the switch thread */
+ 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);
+ }
+ } else {
+ ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, s->device->name);
+ }
+ } else {
+ ast_log(LOG_DEBUG, "Current sub [%s] already has owner\n", l->owner->name);
+ }
+ }
+ return 1;
+}
+
+static int handle_onhook_message(skinny_req *req, struct skinnysession *s)
+{
+ struct skinny_line *l;
+
+ l = s->device->lines;
+
+ if (l->hookstate == SKINNY_ONHOOK) {
+ /* Something else already put us back on hook */
+ return 0;
+ }
+ l->cxmode = SKINNY_CX_RECVONLY;
+ l->hookstate = SKINNY_ONHOOK;
+ transmit_callstate(s, l->instance, l->hookstate, l->callid);
+ if (skinnydebug)
+ ast_verbose("Skinny %s@%s went on hook\n", l->name, s->device->name);
+ if (l->transfer && (l->owner && l->next && l->next->owner) && ((!l->outgoing) || (l->next && !l->next->outgoing))) {
+ /* We're allowed to transfer, we have two active calls and
+ we made at least one of the calls. Let's try and transfer */
+
+#if 0
+ if ((res = attempt_transfer(p)) < 0) {
+ if (l->next && l->next->owner) {
+ l->next->alreadygone = 1;
+ ast_queue_hangup(l->next->owner,1);
+ }
+ } else if (res) {
+ ast_log(LOG_WARNING, "Transfer attempt failed\n");
+ return 0;
+ }
+#endif
+ } else {
+ /* Hangup the current call */
+ /* If there is another active call, skinny_hangup will ring the phone with the other call */
+ if (l->owner) {
+ l->alreadygone = 1;
+ ast_queue_hangup(l->owner);
+ } else {
+ ast_log(LOG_WARNING, "Skinny(%s@%s-%d) channel already destroyed\n",
+ l->name, s->device->name, l->callid);
+ }
+ }
+ if ((l->hookstate == SKINNY_ONHOOK) && (l->next && !l->next->rtp)) {
+ do_housekeeping(s);
+ }
+ return 1;
+}
+
+static int handle_capabilities_res_message(skinny_req *req, struct skinnysession *s)
+{
+ /* XXX process the capabilites */
+ return 1;
+}
+
+static int handle_speed_dial_stat_req_message(skinny_req *req, struct skinnysession *s)
+{
+ struct skinny_speeddial *sd;
+ int instance;
+
+ instance = letohl(req->data.speeddialreq.speedDialNumber);
+
+ if (!(req = req_alloc(sizeof(speed_dial_stat_res_message), SPEED_DIAL_STAT_RES_MESSAGE)))
return -1;
- snprintf(req->data.version.version, sizeof(req->data.version.version), s->device->version_id);
+ sd = s->device->speeddials;
+
+ while (sd) {
+ if (sd->instance == instance) {
+ req->data.speeddialreq.speedDialNumber = htolel(instance);
+ snprintf(req->data.speeddial.speedDialDirNumber, sizeof(req->data.speeddial.speedDialDirNumber), sd->exten);
+ snprintf(req->data.speeddial.speedDialDisplayName, sizeof(req->data.speeddial.speedDialDisplayName), "test - use sd->label");
+ break;
+ }
+ }
+
transmit_response(s, req);
return 1;
}
-static int handle_server_request_message(skinny_req *req, struct skinnysession *s)
-{
- if (!(req = req_alloc(sizeof(server_res_message), SERVER_RES_MESSAGE)))
+static int handle_line_state_req_message(skinny_req *req, struct skinnysession *s)
+{
+ struct skinny_line *l;
+ int instance;
+
+ instance = letohl(req->data.line.lineNumber);
+
+ ast_mutex_lock(&devicelock);
+
+ l = find_line_by_instance(s->device, instance);
+
+ if (!l) {
+ return 0;
+ }
+
+ ast_mutex_unlock(&devicelock);
+
+ if (!(req = req_alloc(sizeof(line_stat_res_message), LINE_STAT_RES_MESSAGE)))
return -1;
- memcpy(req->data.serverres.server[0].serverName, ourhost,
- sizeof(req->data.serverres.server[0].serverName));
- req->data.serverres.serverListenPort[0] = htolel(ourport);
- req->data.serverres.serverIpAddr[0] = htolel(__ourip.s_addr);
+ 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));
+ transmit_response(s,req);
+ return 1;
+}
+
+static int handle_time_date_req_message(skinny_req *req, struct skinnysession *s)
+{
+ time_t timer;
+ struct tm *cmtime;
+
+ if (!(req = req_alloc(sizeof(definetimedate_message), DEFINETIMEDATE_MESSAGE)))
+ return -1;
+
+ timer = time(NULL);
+ cmtime = localtime(&timer);
+ req->data.definetimedate.year = htolel(cmtime->tm_year+1900);
+ req->data.definetimedate.month = htolel(cmtime->tm_mon+1);
+ req->data.definetimedate.dayofweek = htolel(cmtime->tm_wday);
+ req->data.definetimedate.day = htolel(cmtime->tm_mday);
+ req->data.definetimedate.hour = htolel(cmtime->tm_hour);
+ req->data.definetimedate.minute = htolel(cmtime->tm_min);
+ req->data.definetimedate.seconds = htolel(cmtime->tm_sec);
transmit_response(s, req);
return 1;
}
@@ -2859,11 +3030,91 @@
req->data.buttontemplate.totalButtonCount = htolel(buttonCount);
if (skinnydebug)
- ast_verbose("Sending %d template to %s@%s (%s)\n",
+ ast_verbose("Sending %d template to %s\n",
s->device->type,
- s->device->lines->name,
- s->device->name,
- s->device->model);
+ s->device->name);
+ transmit_response(s, req);
+ return 1;
+}
+
+static int handle_version_req_message(skinny_req *req, struct skinnysession *s)
+{
+ if (!(req = req_alloc(sizeof(version_res_message), VERSION_RES_MESSAGE)))
+ return -1;
+
+ snprintf(req->data.version.version, sizeof(req->data.version.version), s->device->version_id);
+ transmit_response(s, req);
+ return 1;
+}
+
+static int handle_server_request_message(skinny_req *req, struct skinnysession *s)
+{
+ if (!(req = req_alloc(sizeof(server_res_message), SERVER_RES_MESSAGE)))
+ return -1;
+
+ memcpy(req->data.serverres.server[0].serverName, ourhost,
+ sizeof(req->data.serverres.server[0].serverName));
+ req->data.serverres.serverListenPort[0] = htolel(ourport);
+ req->data.serverres.serverIpAddr[0] = htolel(__ourip.s_addr);
+ transmit_response(s, req);
+ return 1;
+}
+
+static int handle_alarm_message(skinny_req *req, struct skinnysession *s)
+{
+ /* no response necessary */
+ if (skinnydebug)
+ ast_verbose("Received Alarm Message: %s\n", req->data.alarm.displayMessage);
+
+ return 1;
+}
+
+static int handle_open_receive_channel_ack_message(skinny_req *req, struct skinnysession *s)
+{
+ struct skinny_line *l;
+ struct sockaddr_in sin;
+ struct sockaddr_in us;
+ char iabuf[INET_ADDRSTRLEN];
+ char addr[4];
+ int port;
+ int status;
+
+ l = s->device->lines;
+
+ status = letohl(req->data.openreceivechannelack.status);
+ if (status) {
+ ast_log(LOG_ERROR, "Open Receive Channel Failure\n");
+ return 0;
+ }
+ /* ENDIAN */
+ memcpy(addr, req->data.openreceivechannelack.ipAddr, sizeof(addr));
+ port = htolel(req->data.openreceivechannelack.port);
+ sin.sin_family = AF_INET;
+ /* I smell endian problems */
+ memcpy(&sin.sin_addr, addr, sizeof(sin.sin_addr));
+ sin.sin_port = htons(port);
+ if (skinnydebug)
+ ast_verbose("ipaddr = %s:%d\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), ntohs(sin.sin_port));
+ if (l->rtp) {
+ ast_rtp_set_peer(l->rtp, &sin);
+ ast_rtp_get_us(l->rtp, &us);
+ } else {
+ ast_log(LOG_ERROR, "No RTP structure, this is very bad\n");
+ return 0;
+ }
+ if (!(req = req_alloc(sizeof(start_media_transmission_message), START_MEDIA_TRANSMISSION_MESSAGE)))
+ return -1;
+
+ req->data.startmedia.conferenceId = 0;
+ req->data.startmedia.passThruPartyId = 0;
+ memcpy(req->data.startmedia.remoteIp, &s->device->ourip, 4); /* Endian? */
+ req->data.startmedia.remotePort = htolel(ntohs(us.sin_port));
+ req->data.startmedia.packetSize = htolel(20);
+ req->data.startmedia.payloadType = htolel(convert_cap(l->capability));
+ req->data.startmedia.qualifier.precedence = htolel(127);
+ req->data.startmedia.qualifier.vad = 0;
+ req->data.startmedia.qualifier.packets = 0;
+ req->data.startmedia.qualifier.bitRate = 0;
transmit_response(s, req);
return 1;
}
@@ -2907,6 +3158,7 @@
int event;
int instance;
int reference;
+ int res;
event = letohl(req->data.softkeyeventmessage.softKeyEvent);
instance = letohl(req->data.softkeyeventmessage.instance);
@@ -2926,11 +3178,45 @@
ast_verbose("Received Softkey Event: None(%d)\n", instance);
break;
case SOFTKEY_REDIAL:
- /* If we can keep an array of dialed frames we can implement a quick
- and dirty redial, feeding the frames we last got into the queue
- function */
if (skinnydebug)
ast_verbose("Received Softkey Event: Redial(%d)\n", instance);
+
+ transmit_callstate(s, l->instance, SKINNY_OFFHOOK, l->callid);
+ if (skinnydebug)
+ ast_verbose("Attempting to Clear display on Skinny %s@%s\n", l->name, s->device->name);
+ transmit_displaymessage(s, NULL); /* clear display */
+ transmit_tone(s, SKINNY_DIALTONE);
+
+ c = skinny_new(l, AST_STATE_DOWN);
+ if(c) {
+ if (ast_strlen_zero(l->lastnumberdialed)) {
+ ast_log(LOG_WARNING, "Attempted redial, but no previously dialed number found.\n");
+ return 0;
+ }
+ if (!ast_ignore_pattern(c->context, l->lastnumberdialed)) {
+ transmit_tone(s, SKINNY_SILENCE);
+ }
+ if (ast_exists_extension(c, c->context, l->lastnumberdialed, 1, l->cid_num)) {
+ if (!ast_matchmore_extension(c, c->context, l->lastnumberdialed, 1, l->cid_num)) {
+ ast_copy_string(c->exten, l->lastnumberdialed, sizeof(c->exten));
+ if (!ast_strlen_zero(l->cid_num)) {
+ if (!l->hidecallerid) {
+ c->cid.cid_num = strdup(l->cid_num);
+ c->cid.cid_ani = strdup(l->cid_num);
+ }
+ }
+ ast_setstate(c, AST_STATE_RING);
+ res = ast_pbx_run(c);
+ if (res) {
+ ast_log(LOG_WARNING, "PBX exited non-zero\n");
+ transmit_tone(s, SKINNY_REORDER);
+ }
+ break;
+ }
+ }
+ } else {
+ ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, s->device->name);
+ }
break;
case SOFTKEY_NEWCALL:
/* XXX Untested */
@@ -2980,16 +3266,16 @@
/* Do not disturb */
transmit_tone(s, SKINNY_DIALTONE);
- if (s->device->lines->dnd != 0){
+ if (l->dnd != 0){
if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Disabling DND on %s@%s\n",s->device->lines->name,s->device->lines->name);
- s->device->lines->dnd = 0;
+ ast_verbose(VERBOSE_PREFIX_3 "Disabling DND on %s@%s\n", l->name, s->device->name);
+ l->dnd = 0;
transmit_lamp_indication(s, STIMULUS_FORWARDALL, 1, SKINNY_LAMP_ON);
transmit_displaynotify(s, "DnD disabled",10);
} else {
if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Enabling DND on %s@%s\n",s->device->lines->name,s->device->lines->name);
- s->device->lines->dnd = 1;
+ ast_verbose(VERBOSE_PREFIX_3 "Enabling DND on %s@%s\n", l->name, s->device->name);
+ l->dnd = 1;
transmit_lamp_indication(s, STIMULUS_FORWARDALL, 1, SKINNY_LAMP_OFF);
transmit_displaynotify(s, "DnD enabled",10);
}
@@ -3113,6 +3399,12 @@
return 1;
}
+static int handle_unregister_message(skinny_req *req, struct skinnysession *s)
+{
+ /* XXX Actually unregister the device */
+ return 1;
+}
+
static int handle_soft_key_template_req_message(skinny_req *req, struct skinnysession *s)
{
if (!(req = req_alloc(sizeof(soft_key_template_res_message), SOFT_KEY_TEMPLATE_RES_MESSAGE)))
@@ -3128,273 +3420,15 @@
return 1;
}
-static int handle_time_date_req_message(skinny_req *req, struct skinnysession *s)
-{
- time_t timer;
- struct tm *cmtime;
-
- if (!(req = req_alloc(sizeof(definetimedate_message), DEFINETIMEDATE_MESSAGE)))
- return -1;
-
- timer = time(NULL);
- cmtime = localtime(&timer);
- req->data.definetimedate.year = htolel(cmtime->tm_year+1900);
- req->data.definetimedate.month = htolel(cmtime->tm_mon+1);
- req->data.definetimedate.dayofweek = htolel(cmtime->tm_wday);
- req->data.definetimedate.day = htolel(cmtime->tm_mday);
- req->data.definetimedate.hour = htolel(cmtime->tm_hour);
- req->data.definetimedate.minute = htolel(cmtime->tm_min);
- req->data.definetimedate.seconds = htolel(cmtime->tm_sec);
- transmit_response(s, req);
+static int handle_headset_status_message(skinny_req *req, struct skinnysession *s)
+{
+ /* XXX umm...okay? Why do I care? */
return 1;
}
-static int handle_speed_dial_stat_req_message(skinny_req *req, struct skinnysession *s)
-{
- struct skinny_speeddial *sd;
- int instance;
-
- instance = letohl(req->data.speeddialreq.speedDialNumber);
-
- if (!(req = req_alloc(sizeof(speed_dial_stat_res_message), SPEED_DIAL_STAT_RES_MESSAGE)))
- return -1;
-
- sd = s->device->speeddials;
-
- while (sd) {
- if (sd->instance == instance) {
- req->data.speeddialreq.speedDialNumber = htolel(instance);
- snprintf(req->data.speeddial.speedDialDirNumber, sizeof(req->data.speeddial.speedDialDirNumber), sd->exten);
- snprintf(req->data.speeddial.speedDialDisplayName, sizeof(req->data.speeddial.speedDialDisplayName), "test - use sd->label");
- break;
- }
- }
-
- transmit_response(s, req);
- return 1;
-}
-
-static int handle_line_state_req_message(skinny_req *req, struct skinnysession *s)
-{
- struct skinny_line *l;
- int instance;
-
- instance = letohl(req->data.line.lineNumber);
-
- ast_mutex_lock(&devicelock);
-
- l = find_line_by_instance(s->device, instance);
-
- if (!l) {
- return 0;
- }
-
- ast_mutex_unlock(&devicelock);
-
- if (!(req = req_alloc(sizeof(line_stat_res_message), LINE_STAT_RES_MESSAGE)))
- 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));
- transmit_response(s,req);
- return 1;
-}
-
-static int handle_capabilities_res_message(skinny_req *req, struct skinnysession *s)
-{
- /* XXX process the capabilites */
- return 1;
-}
-
-static int handle_keep_alive_message(skinny_req *req, struct skinnysession *s)
-{
- if (!(req = req_alloc(4, KEEP_ALIVE_ACK_MESSAGE)))
- return -1;
-
- req->len = htolel(4);
-
- transmit_response(s, req);
- do_housekeeping(s);
- return 1;
-}
-
-static int handle_offhook_message(skinny_req *req, struct skinnysession *s)
-{
- struct ast_channel *c;
- pthread_t t;
-
- transmit_ringer_mode(s,SKINNY_RING_OFF);
- transmit_lamp_indication(s, STIMULUS_LINE, s->device->lines->instance, SKINNY_LAMP_ON);
- if (!s->device->lines) {
- ast_log(LOG_NOTICE, "No available lines on: %s\n", s->device->name);
- return 0;
- }
- s->device->lines->hookstate = SKINNY_OFFHOOK;
-
- if (s->device->lines->outgoing) {
- /* We're answering a ringing call */
- ast_queue_control(s->device->lines->owner, AST_CONTROL_ANSWER);
- transmit_callstate(s, s->device->lines->instance, SKINNY_OFFHOOK, s->device->lines->callid);
- transmit_tone(s, SKINNY_SILENCE);
- transmit_callstate(s, s->device->lines->instance, SKINNY_CONNECTED, s->device->lines->callid);
- transmit_selectsoftkeys(s, s->device->lines->instance, s->device->lines->callid, KEYDEF_CONNECTED);
- start_rtp(s->device->lines);
- ast_setstate(s->device->lines->owner, AST_STATE_UP);
- } else {
- if (!s->device->lines->owner) {
- transmit_callstate(s, s->device->lines->instance, SKINNY_OFFHOOK, s->device->lines->callid);
- if (skinnydebug)
- ast_verbose("Attempting to Clear display on Skinny %s@%s\n",s->device->lines->name, s->device->name);
- transmit_displaymessage(s, NULL); /* clear display */
- transmit_tone(s, SKINNY_DIALTONE);
- transmit_selectsoftkeys(s, s->device->lines->instance, s->device->lines->callid, KEYDEF_OFFHOOK);
- c = skinny_new(s->device->lines, AST_STATE_DOWN);
- if(c) {
- /* start the switch thread */
- 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);
- }
- } else {
- ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", s->device->lines->name, s->device->name);
- }
- } else {
- ast_log(LOG_DEBUG, "Current sub [%s] already has owner\n", s->device->lines->owner->name);
- }
- }
- return 1;
-}
-
-static int handle_onhook_message(skinny_req *req, struct skinnysession *s)
-{
- if (s->device->lines->hookstate == SKINNY_ONHOOK) {
- /* Something else already put us back on hook */
- return 0;
- }
- s->device->lines->cxmode = SKINNY_CX_RECVONLY;
- s->device->lines->hookstate = SKINNY_ONHOOK;
- transmit_callstate(s, s->device->lines->instance, s->device->lines->hookstate,s->device->lines->callid);
- if (skinnydebug)
- ast_verbose("Skinny %s@%s went on hook\n",s->device->lines->name, s->device->name);
- if (s->device->lines->transfer && (s->device->lines->owner && s->device->lines->next && s->device->lines->next->owner) && ((!s->device->lines->outgoing) || (s->device->lines->next && !s->device->lines->next->outgoing))) {
- /* We're allowed to transfer, we have two active calls and
- we made at least one of the calls. Let's try and transfer */
-
-#if 0
- if ((res = attempt_transfer(p)) < 0) {
- if (s->device->lines->next && s->device->lines->next->owner) {
- s->device->lines->next->alreadygone = 1;
- ast_queue_hangup(s->device->lines->next->owner,1);
- }
- } else if (res) {
- ast_log(LOG_WARNING, "Transfer attempt failed\n");
- return 0;
- }
-#endif
- } else {
- /* Hangup the current call */
- /* If there is another active call, skinny_hangup will ring the phone with the other call */
- if (s->device->lines->owner) {
- s->device->lines->alreadygone = 1;
- ast_queue_hangup(s->device->lines->owner);
- } else {
- ast_log(LOG_WARNING, "Skinny(%s@%s-%d) channel already destroyed\n",
- s->device->lines->name, s->device->name, s->device->lines->callid);
- }
- }
- if ((s->device->lines->hookstate == SKINNY_ONHOOK) && (s->device->lines->next && !s->device->lines->next->rtp)) {
- do_housekeeping(s);
- }
- return 1;
-}
-
-static int handle_keypad_button_message(skinny_req *req, struct skinnysession *s)
-{
- struct ast_frame f = { 0, };
- char d;
- int digit;
-
- digit = letohl(req->data.keypad.button);
- f.frametype = AST_FRAME_DTMF;
- if (digit == 14) {
- d = '*';
- } else if (digit == 15) {
- d = '#';
- } else if (digit >=0 && digit <= 9) {
- d = '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.
- */
- d = '0' + digit;
- ast_log(LOG_WARNING, "Unsupported digit %d\n", digit);
- }
- f.subclass = d;
- f.src = "skinny";
- if (s->device->lines->owner) {
- /* XXX MUST queue this frame to all lines in threeway call if threeway call is active */
- ast_queue_frame(s->device->lines->owner, &f);
- if (s->device->lines->next && s->device->lines->next->owner) {
- ast_queue_frame(s->device->lines->next->owner, &f);
- }
- } else {
- if (skinnydebug)
- ast_verbose("No owner: %s\n", s->device->lines->name);
- }
- return 1;
-}
-
-static int handle_open_receive_channel_ack_message(skinny_req *req, struct skinnysession *s)
-{
- struct sockaddr_in sin;
- struct sockaddr_in us;
- char iabuf[INET_ADDRSTRLEN];
- char addr[4];
- int port;
- int status;
-
- status = letohl(req->data.openreceivechannelack.status);
- if (status) {
- ast_log(LOG_ERROR, "Open Receive Channel Failure\n");
- return 0;
- }
- /* ENDIAN */
- memcpy(addr, req->data.openreceivechannelack.ipAddr, sizeof(addr));
- port = htolel(req->data.openreceivechannelack.port);
- sin.sin_family = AF_INET;
- /* I smell endian problems */
- memcpy(&sin.sin_addr, addr, sizeof(sin.sin_addr));
- sin.sin_port = htons(port);
- if (skinnydebug)
- ast_verbose("ipaddr = %s:%d\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), ntohs(sin.sin_port));
- if (s->device->lines->rtp) {
- ast_rtp_set_peer(s->device->lines->rtp, &sin);
- ast_rtp_get_us(s->device->lines->rtp, &us);
- } else {
- ast_log(LOG_ERROR, "No RTP structure, this is very bad\n");
- return 0;
- }
- if (!(req = req_alloc(sizeof(start_media_transmission_message), START_MEDIA_TRANSMISSION_MESSAGE)))
- return -1;
-
- req->data.startmedia.conferenceId = 0;
- req->data.startmedia.passThruPartyId = 0;
- memcpy(req->data.startmedia.remoteIp, &s->device->ourip, 4); /* Endian? */
- req->data.startmedia.remotePort = htolel(ntohs(us.sin_port));
- req->data.startmedia.packetSize = htolel(20);
- req->data.startmedia.payloadType = htolel(convert_cap(s->device->lines->capability));
- req->data.startmedia.qualifier.precedence = htolel(127);
- req->data.startmedia.qualifier.vad = 0;
- req->data.startmedia.qualifier.packets = 0;
- req->data.startmedia.qualifier.bitRate = 0;
- transmit_response(s, req);
+static int handle_register_available_lines_message(skinny_req *req, struct skinnysession *s)
+{
+ /* XXX I have no clue what this is for, but my phone was sending it, so... */
return 1;
}
@@ -3409,104 +3443,104 @@
}
switch(letohl(req->e)) {
+ case KEEP_ALIVE_MESSAGE:
+ res = handle_keep_alive_message(req, s);
+ break;
+ case REGISTER_MESSAGE:
+ if (skinnydebug)
+ ast_verbose("Device %s is attempting to register\n", req->data.reg.name);
+
+ res = handle_register_message(req, s);
+ break;
+ case IP_PORT_MESSAGE:
+ res = handle_ip_port_message(req, s);
+ break;
+ case KEYPAD_BUTTON_MESSAGE:
+ if (skinnydebug)
+ ast_verbose("Collected digit: [%d]\n", letohl(req->data.keypad.button));
+
+ res = handle_keypad_button_message(req, s);
+ break;
+ case STIMULUS_MESSAGE:
+ res = handle_stimulus_message(req, s);
+ break;
+ case OFFHOOK_MESSAGE:
+ res = handle_offhook_message(req, s);
+ break;
+ case ONHOOK_MESSAGE:
+ res = handle_onhook_message(req, s);
+ break;
+ case CAPABILITIES_RES_MESSAGE:
+ if (skinnydebug)
+ ast_verbose("Received CapabilitiesRes\n");
+
+ res = handle_capabilities_res_message(req, s);
+ break;
+ case SPEED_DIAL_STAT_REQ_MESSAGE:
+ if (skinnydebug)
+ ast_verbose("Received SpeedDialStatRequest\n");
+
+ res = handle_speed_dial_stat_req_message(req, s);
+ break;
+ case LINE_STATE_REQ_MESSAGE:
+ res = handle_line_state_req_message(req, s);
+ break;
+ case TIME_DATE_REQ_MESSAGE:
+ if (skinnydebug)
+ ast_verbose("Received Time/Date Request\n");
+
+ res = handle_time_date_req_message(req, s);
+ break;
+ case BUTTON_TEMPLATE_REQ_MESSAGE:
+ if (skinnydebug)
+ ast_verbose("Buttontemplate requested\n");
+
+ res = handle_button_template_req_message(req, s);
+ break;
+ case VERSION_REQ_MESSAGE:
+ if (skinnydebug)
+ ast_verbose("Version Request\n");
+
+ res = handle_version_req_message(req, s);
+ break;
+ case SERVER_REQUEST_MESSAGE:
+ if (skinnydebug)
+ ast_verbose("Received Server Request\n");
+
+ res = handle_server_request_message(req, s);
+ break;
case ALARM_MESSAGE:
res = handle_alarm_message(req, s);
break;
- case REGISTER_MESSAGE:
- if (skinnydebug)
- ast_verbose("Device %s is attempting to register\n", req->data.reg.name);
-
- res = handle_register_message(req, s);
+ case OPEN_RECEIVE_CHANNEL_ACK_MESSAGE:
+ if (skinnydebug)
+ ast_verbose("Received Open Receive Channel Ack\n");
+
+ res = handle_open_receive_channel_ack_message(req, s);
+ break;
+ case SOFT_KEY_SET_REQ_MESSAGE:
+ if (skinnydebug)
+ ast_verbose("Received SoftKeySetReq\n");
+
+ res = handle_soft_key_set_req_message(req, s);
+ break;
+ case SOFT_KEY_EVENT_MESSAGE:
+ res = handle_soft_key_event_message(req, s);
break;
case UNREGISTER_MESSAGE:
res = handle_unregister_message(req, s);
break;
+ case SOFT_KEY_TEMPLATE_REQ_MESSAGE:
+ if (skinnydebug)
+ ast_verbose("Received SoftKey Template Request\n");
+
+ res = handle_soft_key_template_req_message(req, s);
+ break;
case HEADSET_STATUS_MESSAGE:
res = handle_headset_status_message(req, s);
break;
case REGISTER_AVAILABLE_LINES_MESSAGE:
res = handle_register_available_lines_message(req, s);
- break;
- case IP_PORT_MESSAGE:
- res = handle_ip_port_message(req, s);
- break;
- case STIMULUS_MESSAGE:
- res = handle_stimulus_message(req, s);
- break;
- case VERSION_REQ_MESSAGE:
- if (skinnydebug)
- ast_verbose("Version Request\n");
-
- res = handle_version_req_message(req, s);
- break;
- case SERVER_REQUEST_MESSAGE:
- if (skinnydebug)
- ast_verbose("Received Server Request\n");
-
- res = handle_server_request_message(req, s);
- break;
- case BUTTON_TEMPLATE_REQ_MESSAGE:
- if (skinnydebug)
- ast_verbose("Buttontemplate requested\n");
-
- res = handle_button_template_req_message(req, s);
- break;
- case SOFT_KEY_SET_REQ_MESSAGE:
- if (skinnydebug)
- ast_verbose("Received SoftKeySetReq\n");
-
- res = handle_soft_key_set_req_message(req, s);
- break;
- case SOFT_KEY_EVENT_MESSAGE:
- res = handle_soft_key_event_message(req, s);
- break;
- case SOFT_KEY_TEMPLATE_REQ_MESSAGE:
- if (skinnydebug)
- ast_verbose("Received SoftKey Template Request\n");
-
- res = handle_soft_key_template_req_message(req, s);
- break;
- case TIME_DATE_REQ_MESSAGE:
- if (skinnydebug)
- ast_verbose("Received Time/Date Request\n");
-
- res = handle_time_date_req_message(req, s);
- break;
- case SPEED_DIAL_STAT_REQ_MESSAGE:
- if (skinnydebug)
- ast_verbose("Received SpeedDialStatRequest\n");
-
- res = handle_speed_dial_stat_req_message(req, s);
- break;
- case LINE_STATE_REQ_MESSAGE:
- res = handle_line_state_req_message(req, s);
- break;
- case CAPABILITIES_RES_MESSAGE:
- if (skinnydebug)
- ast_verbose("Received CapabilitiesRes\n");
-
- res = handle_capabilities_res_message(req, s);
- break;
- case KEEP_ALIVE_MESSAGE:
- res = handle_keep_alive_message(req, s);
- break;
- case OFFHOOK_MESSAGE:
- res = handle_offhook_message(req, s);
- break;
- case ONHOOK_MESSAGE:
- res = handle_onhook_message(req, s);
- break;
- case KEYPAD_BUTTON_MESSAGE:
- if (skinnydebug)
- ast_verbose("Collected digit: [%d]\n", letohl(req->data.keypad.button));
-
- res = handle_keypad_button_message(req, s);
- break;
- case OPEN_RECEIVE_CHANNEL_ACK_MESSAGE:
- if (skinnydebug)
- ast_verbose("Received Open Receive Channel Ack\n");
-
- res = handle_open_receive_channel_ack_message(req, s);
break;
default:
if (skinnydebug)
@@ -3555,11 +3589,17 @@
fds[0].fd = s->fd;
fds[0].events = POLLIN;
+ fds[0].revents = 0;
res = poll(fds, 1, -1);
if (res < 0) {
- ast_log(LOG_WARNING, "Select returned error: %s\n", strerror(errno));
- } else if (res > 0) {
+ if (errno != EINTR)
+ {
+ ast_log(LOG_WARNING, "Select returned error: %s\n", strerror(errno));
+ return res;
+ }
+ }
+ if (fds[0].revents) {
ast_mutex_lock(&s->lock);
memset(s->inbuf,0,sizeof(s->inbuf));
res = read(s->fd, s->inbuf, 4);
@@ -3585,8 +3625,9 @@
ast_log(LOG_WARNING, "Skinny Client sent less data than expected.\n");
return -1;
}
- }
- return res;
+ return res;
+ }
+ return 0;
}
static skinny_req *skinny_req_parse(struct skinnysession *s)
@@ -3598,18 +3639,18 @@
req = malloc(SKINNY_MAX_PACKET);
memset(req, 0, sizeof(skinny_req));
#endif
- /* XXX this might be wrong */
- if (!(req = ast_calloc(1, sizeof(skinny_req))))
+
+ if (!(req = ast_calloc(1, SKINNY_MAX_PACKET)))
return NULL;
- if (!(data = ast_calloc(1, sizeof(skinny_data))))
- return NULL;
-
ast_mutex_lock(&s->lock);
- /* +8 to account for reserved and length fields */
+ /* +8 to account for reserved and length fields
memcpy(req, s->inbuf, skinny_header_size);
memcpy(data, s->inbuf+skinny_header_size, letohl(*(int*)(s->inbuf))-4);
- req->data = *data;
+ */
+ memcpy(req, s->inbuf, skinny_header_size);
+ memcpy(&req->data, s->inbuf+skinny_header_size, letohl(*(int*)(s->inbuf))-4);
+
ast_mutex_unlock(&s->lock);
if (letohl(req->e) < 0) {
@@ -3617,6 +3658,7 @@
free(req);
return NULL;
}
+
return req;
}
@@ -3636,15 +3678,18 @@
break;
}
- if (!(req = skinny_req_parse(s))) {
- destroy_session(s);
- return NULL;
- }
-
- res = handle_message(req, s);
- if (res < 0) {
- destroy_session(s);
- return NULL;
+ if (res > 0)
+ {
[... 14 lines stripped ...]
More information about the asterisk-commits
mailing list