Index: channels/chan_skinny.c =================================================================== --- channels/chan_skinny.c (revision 280158) +++ channels/chan_skinny.c (working copy) @@ -443,7 +443,8 @@ char calledPartyVoiceMailbox[24]; char originalCalledPartyVoiceMailbox[24]; char lastRedirectingVoiceMailbox[24]; - uint32_t space[3]; + uint32_t callnumber; + uint32_t space[2]; }; #define FORWARD_STAT_MESSAGE 0x0090 @@ -1241,7 +1242,7 @@ int hookstate; \ int nat; \ int directmedia; \ - int prune; + int prune; struct skinny_line { SKINNY_LINE_OPTIONS @@ -1318,7 +1319,8 @@ int callwaiting; \ int mwiblink; \ int dnd; \ - int prune; + int prune; \ + uint32_t callnumber[16]; struct skinny_device { SKINNY_DEVICE_OPTIONS @@ -2101,9 +2103,8 @@ } #endif -static int transmit_response(struct skinny_device *d, struct skinny_req *req) +static int transmit_response_bysession(struct skinnysession *s, struct skinny_req *req) { - struct skinnysession *s = d->session; int res = 0; if (!s) { @@ -2113,7 +2114,7 @@ ast_mutex_lock(&s->lock); - SKINNY_DEVONLY(if (skinnydebug>1) ast_verb(4, "Transmitting %s to %s\n", message2str(req->e), d->name);) + SKINNY_DEVONLY(if (skinnydebug>1) ast_verb(4, "Transmitting %s to %s\n", message2str(req->e), s->device->name);) if ((letohl(req->len) > SKINNY_MAX_PACKET) || (letohl(req->len) < 0)) { ast_log(LOG_WARNING, "transmit_response: the length of the request (%d) is out of bounds (%d)\n", letohl(req->len), SKINNY_MAX_PACKET); @@ -2142,6 +2143,25 @@ return 1; } +static void transmit_response(struct skinny_device *d, struct skinny_req *req) +{ + transmit_response_bysession(d->session, req); +} + +static void transmit_registerrej(struct skinnysession *s) +{ + struct skinny_req *req; + char name[16]; + + if (!(req = req_alloc(sizeof(struct register_rej_message), REGISTER_REJ_MESSAGE))) + return; + + memcpy(&name, req->data.reg.name, sizeof(name)); + snprintf(req->data.regrej.errMsg, sizeof(req->data.regrej.errMsg), "No Authority: %s", name); + + transmit_response_bysession(s, req); +} + static void transmit_speaker_mode(struct skinny_device *d, int mode) { struct skinny_req *req; @@ -2168,6 +2188,7 @@ static void transmit_callinfo(struct skinny_device *d, const char *fromname, const char *fromnum, const char *toname, const char *tonum, int instance, int callid, int calltype) { struct skinny_req *req; + int count; /* We should not be able to get here without a device */ if (!d) @@ -2194,6 +2215,25 @@ req->data.callinfo.instance = htolel(instance); req->data.callinfo.reference = htolel(callid); req->data.callinfo.type = htolel(calltype); + + for (count = 0; count < 16; count++) { + if (d->callnumber[count] == 0){ + d->callnumber[count] = callid; + count++; + break; + } else { + if (d->callnumber[count] == callid){ + count++; + break; + } + } + } + + if (skinnydebug) + ast_verb(1, "transmit_callinfor setting device callnumber to %d\n", d->callnumber[count-1]); + + req->data.callinfo.callnumber = htolel(count); + transmit_response(d, req); } @@ -2621,7 +2661,63 @@ transmit_response(d, req); } +static void transmit_reset(struct skinny_device *d, int fullrestart) +{ + struct skinny_req *req; + + if (!(req = req_alloc(sizeof(struct reset_message), RESET_MESSAGE))) + return; + + if (fullrestart) + req->data.reset.resetType = 2; + else + req->data.reset.resetType = 1; + ast_verb(3, "%s device %s.\n", (fullrestart) ? "Restarting" : "Resetting", d->id); + transmit_response(d, req); +} + +static void transmit_keepaliveack(struct skinny_device *d) +{ + struct skinny_req *req; + + if (!(req = req_alloc(0, KEEP_ALIVE_ACK_MESSAGE))) + return; + + transmit_response(d, req); +} + +static void transmit_registerack(struct skinny_device *d) +{ + struct skinny_req *req; + + if (!(req = req_alloc(sizeof(struct register_ack_message), REGISTER_ACK_MESSAGE))) + return; + + req->data.regack.res[0] = '0'; + req->data.regack.res[1] = '\0'; + req->data.regack.keepAlive = htolel(keep_alive); + memcpy(req->data.regack.dateTemplate, date_format, sizeof(req->data.regack.dateTemplate)); + req->data.regack.res2[0] = '0'; + req->data.regack.res2[1] = '\0'; + req->data.regack.secondaryKeepAlive = htolel(keep_alive); + + transmit_response(d, req); +} + +static void transmit_capabilitiesreq(struct skinny_device *d) +{ + struct skinny_req *req; + + if (!(req = req_alloc(0, CAPABILITIES_REQ_MESSAGE))) + return; + + if (skinnydebug) + ast_verb(1, "Requesting capabilities\n"); + + transmit_response(d, req); +} + static int skinny_extensionstate_cb(char *context, char *exten, int state, void *data) { struct skinny_speeddial *sd = data; @@ -2866,11 +2962,19 @@ return 0; } +static format_t skinny_get_codec(struct ast_channel *chan) +{ + struct skinny_subchannel *sub = chan->tech_pvt; + struct skinny_line *p = sub->parent; + return p->capability; +} + static struct ast_rtp_glue skinny_rtp_glue = { .type = "Skinny", .get_rtp_info = skinny_get_rtp_peer, .get_vrtp_info = skinny_get_vrtp_peer, .update_peer = skinny_set_rtp_peer, + .get_codec = skinny_get_codec, }; static char *handle_skinny_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) @@ -2983,7 +3087,6 @@ static char *handle_skinny_reset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { struct skinny_device *d; - struct skinny_req *req; switch (cmd) { case CLI_INIT: @@ -3006,19 +3109,10 @@ if (!(d->session)) continue; - if (!(req = req_alloc(sizeof(struct reset_message), RESET_MESSAGE))) - continue; - if (a->argc == 4 && !strcasecmp(a->argv[3], "restart")) fullrestart = 1; - - if (fullrestart) - req->data.reset.resetType = 2; - else - req->data.reset.resetType = 1; - - ast_verb(3, "%s device %s.\n", (fullrestart) ? "Restarting" : "Resetting", d->id); - transmit_response(d, req); + + transmit_reset(d, fullrestart); } } AST_LIST_UNLOCK(&devices); @@ -3970,6 +4064,7 @@ struct skinny_line *l; struct skinny_device *d; struct skinnysession *s; + int count; if (!sub) { ast_debug(1, "Asked to hangup channel not connected\n"); @@ -3983,6 +4078,13 @@ if (skinnydebug) ast_verb(3,"Hanging up %s/%d\n",d->name,sub->callid); + for (count = 0; count < 16; count++) { + if (d->callnumber[count] == sub->callid) { + d->callnumber[count] = 0; + break; + } + } + AST_LIST_REMOVE(&l->sub, sub, list); if (d->registered) { @@ -4004,7 +4106,7 @@ l->activesub = AST_LIST_FIRST(&l->sub); } } - //transmit_callstate(d, l->instance, SKINNY_ONHOOK, sub->callid); + transmit_callstate(d, l->instance, SKINNY_ONHOOK, sub->callid); transmit_activatecallplane(d, l); transmit_closereceivechannel(d, sub); transmit_stopmediatransmission(d, sub); @@ -4017,6 +4119,7 @@ } else { transmit_lamp_indication(d, STIMULUS_LINE, l->instance, SKINNY_LAMP_ON); } + transmit_callstate(d, l->instance, SKINNY_ONHOOK, sub->callid); } } else { /* no more subs on line so make idle */ ast_verb(4,"Killing only sub %d\n", sub->callid); @@ -4731,86 +4834,14 @@ } else { /* big assumption we have two channels, lets transfer */ skinny_transfer(sub); + transmit_callstate(d, l->instance, SKINNY_ONHOOK, sub->callid); + transmit_callstate(d, l->instance, SKINNY_ONHOOK, sub->related->callid); } } } return 0; } -static int handle_keep_alive_message(struct skinny_req *req, struct skinnysession *s) -{ - if (!(req = req_alloc(0, KEEP_ALIVE_ACK_MESSAGE))) - return -1; - - transmit_response(s->device, req); - return 1; -} - -static int handle_register_message(struct skinny_req *req, struct skinnysession *s) -{ - struct skinny_device *d = NULL; - char name[16]; - int res; - - memcpy(&name, req->data.reg.name, sizeof(name)); - - res = skinny_register(req, s); - if (!res) { - ast_log(LOG_ERROR, "Rejecting Device %s: Device not found\n", name); - if (!(req = req_alloc(sizeof(struct register_rej_message), REGISTER_REJ_MESSAGE))) - return -1; - - snprintf(req->data.regrej.errMsg, sizeof(req->data.regrej.errMsg), "No Authority: %s", name); - - /* transmit_respons in line as we don't have a valid d */ - ast_mutex_lock(&s->lock); - - if (letohl(req->len) > SKINNY_MAX_PACKET || letohl(req->len) < 0) { - ast_log(LOG_WARNING, "transmit_response: the length (%d) of the request is out of bounds (%d) \n", letohl(req->len), SKINNY_MAX_PACKET); - ast_mutex_unlock(&s->lock); - return -1; - } - - memset(s->outbuf, 0, sizeof(s->outbuf)); - memcpy(s->outbuf, req, skinny_header_size); - memcpy(s->outbuf+skinny_header_size, &req->data, letohl(req->len)); - - res = write(s->fd, s->outbuf, letohl(req->len)+8); - - if (res != letohl(req->len)+8) { - ast_log(LOG_WARNING, "Transmit: write only sent %d out of %d bytes: %s\n", res, letohl(req->len)+8, strerror(errno)); - } - - ast_mutex_unlock(&s->lock); - - return 0; - } - ast_verb(3, "Device '%s' successfully registered\n", name); - - d = s->device; - - if (!(req = req_alloc(sizeof(struct register_ack_message), REGISTER_ACK_MESSAGE))) - return -1; - - req->data.regack.res[0] = '0'; - req->data.regack.res[1] = '\0'; - req->data.regack.keepAlive = htolel(keep_alive); - memcpy(req->data.regack.dateTemplate, date_format, sizeof(req->data.regack.dateTemplate)); - req->data.regack.res2[0] = '0'; - req->data.regack.res2[1] = '\0'; - req->data.regack.secondaryKeepAlive = htolel(keep_alive); - transmit_response(d, req); - if (skinnydebug) - ast_verb(1, "Requesting capabilities\n"); - - if (!(req = req_alloc(0, CAPABILITIES_REQ_MESSAGE))) - return -1; - - transmit_response(d, req); - - return res; -} - static int handle_callforward_button(struct skinny_subchannel *sub, int cfwdtype) { struct skinny_line *l = sub->parent; @@ -5128,17 +5159,21 @@ if ((sub && sub->owner) && (sub->owner->_state == AST_STATE_UP)){ c = sub->owner; - if (!ast_masq_park_call(ast_bridged_channel(c), c, 0, &extout)) { - snprintf(message, sizeof(message), "Call Parked at: %d", extout); - transmit_displaynotify(d, message, 10); + if (ast_bridged_channel(c)) { + if (!ast_masq_park_call(ast_bridged_channel(c), c, 0, &extout)) { + snprintf(message, sizeof(message), "Call Parked at: %d", extout); + transmit_displaynotify(d, message, 10); + } else { + transmit_displaynotify(d, "Call Park failed", 10); + } } else { - transmit_displaynotify(d, "Call Park failed", 10); + transmit_displaynotify(d, "Call Park not available", 10); } } else { transmit_displaynotify(d, "Call Park not available", 10); } + break; } - break; case STIMULUS_DND: if (skinnydebug) ast_verb(1, "Received Stimulus: DND (%d/%d)\n", instance, callreference); @@ -6089,12 +6124,15 @@ if ((sub && sub->owner) && (sub->owner->_state == AST_STATE_UP)){ c = sub->owner; - if (!ast_masq_park_call(ast_bridged_channel(c), c, 0, &extout)) { - snprintf(message, sizeof(message), "Call Parked at: %d", extout); - transmit_displaynotify(d, message, 10); + if (ast_bridged_channel(c)) { + if (!ast_masq_park_call(ast_bridged_channel(c), c, 0, &extout)) { + snprintf(message, sizeof(message), "Call Parked at: %d", extout); + transmit_displaynotify(d, message, 10); + } else { + transmit_displaynotify(d, "Call Park failed", 10); + } } else { - transmit_displaynotify(d, "Call Park failed", 10); - } + transmit_displaynotify(d, "Call Park not available", 10); } } else { transmit_displaynotify(d, "Call Park not available", 10); } @@ -6145,14 +6183,16 @@ switch(letohl(req->e)) { case KEEP_ALIVE_MESSAGE: - res = handle_keep_alive_message(req, s); + transmit_keepaliveack(s->device); break; case REGISTER_MESSAGE: - if (skinnydebug) - ast_verb(1, "Device %s is attempting to register\n", req->data.reg.name); - - res = handle_register_message(req, s); - break; + if (skinny_register(req, s)) { + ast_verb(3, "Device '%s' successfully registered\n", s->device->name); + transmit_registerack(s->device); + transmit_capabilitiesreq(s->device); + } else { + transmit_registerrej(s); + } case IP_PORT_MESSAGE: res = handle_ip_port_message(req, s); break;