From 9950df1b4938afe6130842f26f9e1aa0ff93ae9e Mon Sep 17 00:00:00 2001 From: Jeremy McNamara Date: Thu, 2 Jun 2005 09:11:46 +0000 Subject: Add button templates for 7902, 7935, 7940, 7960, 7970, support big endian machines with proper byte ordering, fixed caller*id on 7910 (others?) and more. Bug #4398 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@5811 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- channels/chan_skinny.c | 695 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 499 insertions(+), 196 deletions(-) diff --git a/channels/chan_skinny.c b/channels/chan_skinny.c index 9d29e2d93..f39df49ec 100755 --- a/channels/chan_skinny.c +++ b/channels/chan_skinny.c @@ -76,6 +76,31 @@ typedef unsigned char UINT8; typedef unsigned short UINT16; typedef unsigned int UINT32; +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define letohl(x) (x) +#define letohs(x) (x) +#define htolel(x) (x) +#define htoles(x) (x) +#else +#ifdef SOLARIS +#define __bswap_16(x) \ + ((((x) & 0xff00) >> 8) | \ + (((x) & 0x00ff) << 8)) +#define __bswap_32(x) \ + ((((x) & 0xff000000) >> 24) | \ + (((x) & 0x00ff0000) >> 8) | \ + (((x) & 0x0000ff00) << 8) | \ + (((x) & 0x000000ff) << 24)) +#else +#include +#endif +#define letohl(x) __bswap_32(x) +#define letohs(x) __bswap_16(x) +#define htolel(x) __bswap_32(x) +#define htoles(x) __bswap_16(x) +#endif + + /************************************************************************************/ /* Protocol Messages */ /************************************************************************************/ @@ -340,6 +365,21 @@ button_definition button_def_12sp[] = { { 9, STIMULUS_SPEEDDIAL } /* Speeddial 9 */ }; +button_definition button_def_7902[] = { + { 1, STIMULUS_LINE }, /* Line 1 */ + { 1, STIMULUS_HOLD }, /* Hold */ + { 1, STIMULUS_TRANSFER }, + { 1, STIMULUS_DISPLAY }, + { 1, STIMULUS_VOICEMAIL }, + { 1, STIMULUS_CONFERENCE }, + { 1, STIMULUS_FORWARDALL }, + { 1, STIMULUS_SPEEDDIAL }, /* Speeddial 1 */ + { 2, STIMULUS_SPEEDDIAL }, /* Speeddial 2 */ + { 3, STIMULUS_SPEEDDIAL }, /* Speeddial 3 */ + { 4, STIMULUS_SPEEDDIAL }, /* Speeddial 4 */ + { 1, STIMULUS_REDIAL } +}; + button_definition button_def_7910[] = { { 1, STIMULUS_LINE }, /* Line 1 */ { 1, STIMULUS_HOLD }, /* Hold */ @@ -362,6 +402,36 @@ button_definition button_def_7920[] = { { 4, STIMULUS_SPEEDDIAL } /* Speeddial 4 */ }; +button_definition button_def_7935[] = { + { 1, STIMULUS_LINE }, /* Line 1 */ + { 2, STIMULUS_LINE } /* Line 2 */ +}; + +button_definition button_def_7940[] = { + { 1, STIMULUS_LINE }, /* Line 1 */ + { 2, STIMULUS_LINE } /* Line 2 */ +}; + +button_definition button_def_7960[] = { + { 1, STIMULUS_LINE }, /* Line 1 */ + { 2, STIMULUS_LINE }, /* Line 2 */ + { 3, STIMULUS_LINE }, /* Line 3 */ + { 1, STIMULUS_SPEEDDIAL }, /* Speeddial 1 */ + { 2, STIMULUS_SPEEDDIAL }, /* Speeddial 2 */ + { 3, STIMULUS_SPEEDDIAL } /* Speeddial 3 */ +}; + +button_definition button_def_7970[] = { + { 1, STIMULUS_LINE }, /* Line 1 */ + { 2, STIMULUS_LINE }, /* Line 2 */ + { 3, STIMULUS_LINE }, /* Line 3 */ + { 1, STIMULUS_SPEEDDIAL }, /* Speeddial 1 */ + { 2, STIMULUS_SPEEDDIAL }, /* Speeddial 2 */ + { 3, STIMULUS_SPEEDDIAL }, /* Speeddial 3 */ + { 4, STIMULUS_SPEEDDIAL }, /* Speeddial 4 */ + { 5, STIMULUS_SPEEDDIAL } /* Speeddial 5 */ +}; + button_definition button_def_none = { 0, STIMULUS_NONE }; typedef struct button_defs { @@ -374,8 +444,13 @@ button_defs_t button_defs[] = { { "12SP", 12, button_def_12sp }, /* First one is used if there's no match */ { "30VIP", 26, button_def_30vip }, + { "7902", 12, button_def_7902 }, { "7910", 10, button_def_7910 }, { "7920", 6, button_def_7920 }, + { "7935", 2, button_def_7935 }, + { "7940", 2, button_def_7940 }, + { "7960", 6, button_def_7960 }, + { "7970", 8, button_def_7970 }, { NULL, 0, NULL } }; @@ -417,24 +492,24 @@ typedef struct soft_key_template_definition { } soft_key_template_definition; soft_key_template_definition soft_key_template_default[] = { - { "Redial", 1 }, - { "NewCall", 2 }, - { "Hold", 3 }, - { "Trnsfer", 4 }, - { "CFwdAll", 5 }, - { "CFwdBusy", 6 }, - { "CFwdNoAnswer", 7 }, - { "<<", 8 }, - { "EndCall", 9 }, - { "Resume", 10 }, - { "Answer", 11 }, - { "Info", 12 }, - { "Confrn", 13 }, - { "Park", 14 }, - { "Join", 15 }, - { "MeetMe", 16 }, - { "PickUp", 17 }, - { "GPickUp", 18 } + { "Redial", htolel(1) }, + { "NewCall", htolel(2) }, + { "Hold", htolel(3) }, + { "Trnsfer", htolel(4) }, + { "CFwdAll", htolel(5) }, + { "CFwdBusy", htolel(6) }, + { "CFwdNoAnswer", htolel(7) }, + { "<<", htolel(8) }, + { "EndCall", htolel(9) }, + { "Resume", htolel(10) }, + { "Answer", htolel(11) }, + { "Info", htolel(12) }, + { "Confrn", htolel(13) }, + { "Park", htolel(14) }, + { "Join", htolel(15) }, + { "MeetMe", htolel(16) }, + { "PickUp", htolel(17) }, + { "GPickUp", htolel(18) } }; typedef struct soft_key_template { @@ -509,11 +584,32 @@ typedef struct call_state_message { int callReference; } call_state_message; +#define DISPLAY_PROMPT_STATUS_MESSAGE 0x0112 +typedef struct display_prompt_status_message { + int messageTimeout; + char promptMessage[32]; + int lineInstance; + int callReference; +} display_prompt_status_message; + +#define DISPLAY_NOTIFY_MESSAGE 0x0114 +typedef struct display_notify_message { + int displayTimeout; + char displayMessage[100]; +} display_notify_message; + #define ACTIVATE_CALL_PLANE_MESSAGE 0x0116 typedef struct activate_call_plane_message { int lineInstance; } activate_call_plane_message; +#define DIALLED_NUMBER_MESSAGE 0x011D +typedef struct dialled_number_message { + char dialledNumber[24]; + int lineInstance; + int callReference; +} dialled_number_message; + /* packet composition */ typedef struct { int len; @@ -528,6 +624,7 @@ typedef struct { version_res_message version; button_template_res_message buttontemplate; displaytext_message displaytext; + display_prompt_status_message displaypromptstatus; definetimedate_message definetimedate; start_tone_message starttone; speed_dial_stat_res_message speeddial; @@ -550,6 +647,8 @@ typedef struct { open_recieve_channel_message openrecievechannel; open_recieve_channel_ack_message openrecievechannelack; close_recieve_channel_message closerecievechannel; + display_notify_message displaynotify; + dialled_number_message diallednumber; } data; } skinny_req; @@ -581,6 +680,7 @@ static int immediate = 0; static int callwaiting = 0; static int callreturn = 0; static int threewaycalling = 0; +static int mwiblink = 0; /* This is for flashhook transfers */ static int transfer = 0; static int cancallforward = 0; @@ -611,12 +711,13 @@ static int callnums = 1; #define SKINNY_PROGRESS 12 #define SKINNY_INVALID 14 -#define SKINNY_SILENCE 0 -#define SKINNY_DIALTONE 33 -#define SKINNY_BUSYTONE 35 -#define SKINNY_ALERT 36 -#define SKINNY_REORDER 37 -#define SKINNY_CALLWAITTONE 45 +#define SKINNY_SILENCE 0x00 +#define SKINNY_DIALTONE 0x21 +#define SKINNY_BUSYTONE 0x23 +#define SKINNY_ALERT 0x24 +#define SKINNY_REORDER 0x25 +#define SKINNY_CALLWAITTONE 0x2D +#define SKINNY_NOTONE 0x7F #define SKINNY_LAMP_OFF 1 #define SKINNY_LAMP_ON 2 @@ -668,6 +769,8 @@ AST_MUTEX_DEFINE_STATIC(netlock); AST_MUTEX_DEFINE_STATIC(sessionlock); /* Protect the device list */ AST_MUTEX_DEFINE_STATIC(devicelock); +/* Protect the paging device list */ +AST_MUTEX_DEFINE_STATIC(pagingdevicelock); /* This is the thread for the monitor which checks for input on the channels which are not currently in use. */ @@ -720,6 +823,7 @@ struct skinny_line { int callwaiting; int transfer; int threewaycalling; + int mwiblink; int cancallforward; int callreturn; int dnd; /* How does this affect callwait? Do we just deny a skinny_request if we're dnd? */ @@ -757,6 +861,13 @@ static struct skinny_device { struct skinny_device *next; } *devices = NULL; +static struct skinny_paging_device { + char name[80]; + char id[16]; + struct skinny_device ** devices; + struct skinny_paging_device *next; +} *paging_devices = NULL; + static struct skinnysession { pthread_t t; ast_mutex_t lock; @@ -858,12 +969,16 @@ static int transmit_response(struct skinnysession *s, skinny_req *req) { int res = 0; ast_mutex_lock(&s->lock); + #if 0 - ast_verbose("writing packet type %d (%d bytes) to socket %d\n", req->e, req->len+8, s->fd); + if (skinnydebug) { + ast_verbose("writing packet type %04X (%d bytes) to socket %d\n", letohl(req->e), letohl(req->len)+8, s->fd); + } #endif - res = write(s->fd, req, req->len+8); - if (res != req->len+8) { - ast_log(LOG_WARNING, "Transmit: write only sent %d out of %d bytes: %s\n", res, req->len+8, strerror(errno)); + + res = write(s->fd, req, 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 1; @@ -885,9 +1000,9 @@ static void transmit_speaker_mode(struct skinnysession *s, int mode) ast_log(LOG_ERROR, "Unable to allocate skinny_request, this is bad\n"); return; } - req->len = sizeof(set_speaker_message)+4; - req->e = SET_SPEAKER_MESSAGE; - req->data.setspeaker.mode = mode; + req->len = htolel(sizeof(set_speaker_message)+4); + req->e = htolel(SET_SPEAKER_MESSAGE); + req->data.setspeaker.mode = htolel(mode); transmit_response(s, req); } @@ -904,39 +1019,64 @@ static void transmit_callstate(struct skinnysession *s, int instance, int state, if (state == SKINNY_ONHOOK) { transmit_speaker_mode(s, SKINNY_SPEAKEROFF); } - req->len = sizeof(call_state_message)+4; - req->e = CALL_STATE_MESSAGE; - req->data.callstate.callState = state; - req->data.callstate.lineInstance = instance; - req->data.callstate.callReference = callid; + req->len = htolel(sizeof(call_state_message)+4); + req->e = htolel(CALL_STATE_MESSAGE); + req->data.callstate.callState = htolel(state); + req->data.callstate.lineInstance = htolel(instance); + req->data.callstate.callReference = htolel(callid); transmit_response(s, req); if (state == SKINNY_OFFHOOK) { memset(req, 0, memsize); - req->len = sizeof(activate_call_plane_message)+4; - req->e = ACTIVATE_CALL_PLANE_MESSAGE; - req->data.activatecallplane.lineInstance = instance; + req->len = htolel(sizeof(activate_call_plane_message)+4); + req->e = htolel(ACTIVATE_CALL_PLANE_MESSAGE); + req->data.activatecallplane.lineInstance = htolel(instance); transmit_response(s, req); } else if (state == SKINNY_ONHOOK) { memset(req, 0, memsize); - req->len = sizeof(activate_call_plane_message)+4; - req->e = ACTIVATE_CALL_PLANE_MESSAGE; + req->len = htolel(sizeof(activate_call_plane_message)+4); + req->e = htolel(ACTIVATE_CALL_PLANE_MESSAGE); req->data.activatecallplane.lineInstance = 0; transmit_response(s, req); memset(req, 0, memsize); - req->len = sizeof(close_recieve_channel_message)+4; - req->e = CLOSE_RECIEVE_CHANNEL_MESSAGE; + req->len = htolel(sizeof(close_recieve_channel_message)+4); + req->e = htolel(CLOSE_RECIEVE_CHANNEL_MESSAGE); req->data.closerecievechannel.conferenceId = 0; req->data.closerecievechannel.partyId = 0; transmit_response(s, req); memset(req, 0, memsize); - req->len = sizeof(stop_media_transmission_message)+4; - req->e = STOP_MEDIA_TRANSMISSION_MESSAGE; + req->len = htolel(sizeof(stop_media_transmission_message)+4); + req->e = htolel(STOP_MEDIA_TRANSMISSION_MESSAGE); req->data.stopmedia.conferenceId = 0; req->data.stopmedia.passThruPartyId = 0; transmit_response(s, req); } } +static void transmit_callinfo(struct skinnysession *s, char *fromname, char *fromnum, char *toname, char *tonum, int instance, int callid, int calltype) +{ + skinny_req *req; + + req = req_alloc(sizeof(struct call_info_message)); + if (!req) { + ast_log(LOG_ERROR, "Unable to allocate skinny_request, this is bad\n"); + return; + } + + req->len = htolel(sizeof(struct call_info_message)); + req->e = htolel(CALL_INFO_MESSAGE); + + strncpy(req->data.callinfo.callingPartyName, fromname, 39); + strncpy(req->data.callinfo.callingParty, fromnum, 23); + strncpy(req->data.callinfo.calledPartyName, toname, 39); + strncpy(req->data.callinfo.calledParty, tonum, 23); + + req->data.callinfo.instance = htolel(instance); + req->data.callinfo.reference = htolel(callid); + req->data.callinfo.type = htolel(calltype); + + transmit_response(s, req); +} + static void transmit_connect(struct skinnysession *s) { skinny_req *req; @@ -947,12 +1087,12 @@ static void transmit_connect(struct skinnysession *s) ast_log(LOG_ERROR, "Unable to allocate skinny_request, this is bad\n"); return; } - req->len = sizeof(struct call_info_message); - req->e = OPEN_RECIEVE_CHANNEL_MESSAGE; + req->len = htolel(sizeof(struct open_recieve_channel_message)); + req->e = htolel(OPEN_RECIEVE_CHANNEL_MESSAGE); req->data.openrecievechannel.conferenceId = 0; req->data.openrecievechannel.partyId = 0; - req->data.openrecievechannel.packets = 20; - req->data.openrecievechannel.capability = convert_cap(l->capability); + req->data.openrecievechannel.packets = htolel(20); + req->data.openrecievechannel.capability = htolel(convert_cap(l->capability)); req->data.openrecievechannel.echo = 0; req->data.openrecievechannel.bitrate = 0; transmit_response(s, req); @@ -971,12 +1111,12 @@ static void transmit_tone(struct skinnysession *s, int tone) return; } if (tone > 0) { - req->len = sizeof(start_tone_message)+4; - req->e = START_TONE_MESSAGE; - req->data.starttone.tone = tone; + req->len = htolel(sizeof(start_tone_message)+4); + req->e = htolel(START_TONE_MESSAGE); + req->data.starttone.tone = htolel(tone); } else { - req->len = 4; - req->e = STOP_TONE_MESSAGE; + req->len = htolel(4); + req->e = htolel(STOP_TONE_MESSAGE); } transmit_response(s, req); } @@ -994,11 +1134,11 @@ static void transmit_selectsoftkeys(struct skinnysession *s, int instance, int c return; } memset(req, 0, memsize); - req->len = sizeof(select_soft_keys_message)+4; - req->e = SELECT_SOFT_KEYS_MESSAGE; - req->data.selectsoftkey.instance = instance; - req->data.selectsoftkey.reference = callid; - req->data.selectsoftkey.softKeySetIndex = softkey; + req->len = htolel(sizeof(select_soft_keys_message)+4); + req->e = htolel(SELECT_SOFT_KEYS_MESSAGE); + req->data.selectsoftkey.instance = htolel(instance); + req->data.selectsoftkey.reference = htolel(callid); + req->data.selectsoftkey.softKeySetIndex = htolel(softkey); transmit_response(s, req); } #endif @@ -1012,11 +1152,11 @@ static void transmit_lamp_indication(struct skinnysession *s, int stimulus, int ast_log(LOG_ERROR, "Unable to allocate skinny_request, this is bad\n"); return; } - req->len = sizeof(set_lamp_message)+4; - req->e = SET_LAMP_MESSAGE; - req->data.setlamp.stimulus = stimulus; - req->data.setlamp.stimulusInstance = instance; - req->data.setlamp.deviceStimulus = indication; + req->len = htolel(sizeof(set_lamp_message)+4); + req->e = htolel(SET_LAMP_MESSAGE); + req->data.setlamp.stimulus = htolel(stimulus); + req->data.setlamp.stimulusInstance = htolel(instance); + req->data.setlamp.deviceStimulus = htolel(indication); transmit_response(s, req); } @@ -1029,9 +1169,9 @@ static void transmit_ringer_mode(struct skinnysession *s, int mode) ast_log(LOG_ERROR, "Unable to allocate skinny_request, this is bad\n"); return; } - req->len = sizeof(set_ringer_message)+4; - req->e = SET_RINGER_MESSAGE; - req->data.setringer.ringerMode = mode; + req->len = htolel(sizeof(set_ringer_message)+4); + req->e = htolel(SET_RINGER_MESSAGE); + req->data.setringer.ringerMode = htolel(mode); transmit_response(s, req); } @@ -1041,14 +1181,14 @@ static void transmit_displaymessage(struct skinnysession *s, char *text) if (text == 0) { req = req_alloc(4); - req->len = 4; - req->e = CLEAR_DISPLAY_MESSAGE; + req->len = htolel(4); + req->e = htolel(CLEAR_DISPLAY_MESSAGE); } else { req = req_alloc(sizeof(struct displaytext_message)); strncpy(req->data.displaytext.text, text, sizeof(req->data.displaytext.text)-1); - req->len = sizeof(displaytext_message) + 4; - req->e = DISPLAYTEXT_MESSAGE; + req->len = htolel(sizeof(displaytext_message) + 4); + req->e = htolel(DISPLAYTEXT_MESSAGE); if (skinnydebug) { ast_verbose("Displaying message '%s'\n", req->data.displaytext.text); } @@ -1061,6 +1201,74 @@ static void transmit_displaymessage(struct skinnysession *s, char *text) transmit_response(s, req); } +static void transmit_displaynotify(struct skinnysession *s, char *text, int t) +{ + skinny_req *req; + + req = req_alloc(sizeof(struct display_notify_message)); + + if (!req) { + ast_log(LOG_ERROR, "Unable to allocate skinny_request, this is bad\n"); + return; + } + + req->e = htolel(DISPLAY_NOTIFY_MESSAGE); + req->len = htolel(sizeof(display_notify_message) + 4); + strncpy(req->data.displaynotify.displayMessage, text, sizeof(req->data.displaynotify.displayMessage)-1); + req->data.displaynotify.displayTimeout = htolel(t); + + if (skinnydebug) { + ast_verbose("Displaying notify '%s'\n", text); + } + + transmit_response(s, req); +} + +static void transmit_displaypromptstatus(struct skinnysession *s, char *text, int t, int instance, int callid) +{ + skinny_req *req; + + req = req_alloc(sizeof(struct display_prompt_status_message)); + + if (!req) { + ast_log(LOG_ERROR, "Unable to allocate skinny_request, this is bad\n"); + return; + } + + req->e = htolel(DISPLAY_PROMPT_STATUS_MESSAGE); + req->len = htolel(sizeof(display_prompt_status_message) + 4); + strncpy(req->data.displaypromptstatus.promptMessage, text, sizeof(req->data.displaypromptstatus.promptMessage)-1); + req->data.displaypromptstatus.messageTimeout = htolel(t); + req->data.displaypromptstatus.lineInstance = htolel(instance); + req->data.displaypromptstatus.callReference = htolel(callid); + + if (skinnydebug) { + ast_verbose("Displaying Prompt Status '%s'\n", text); + } + + transmit_response(s, req); +} + +static void transmit_diallednumber(struct skinnysession *s, char *text, int instance, int callid) +{ + skinny_req *req; + + req = req_alloc(sizeof(struct dialled_number_message)); + + if (!req) { + ast_log(LOG_ERROR, "Unable to allocate skinny_request, this is bad\n"); + return; + } + + req->e = htolel(DIALLED_NUMBER_MESSAGE); + req->len = htolel(sizeof(dialled_number_message) + 4); + strncpy(req->data.diallednumber.dialledNumber, text, sizeof(req->data.diallednumber.dialledNumber)-1); + req->data.diallednumber.lineInstance = htolel(instance); + req->data.diallednumber.callReference = htolel(callid); + + transmit_response(s, req); +} + static int has_voicemail(struct skinny_line *l) { return ast_app_has_voicemail(l->mailbox, NULL); @@ -1070,9 +1278,10 @@ static int has_voicemail(struct skinny_line *l) static void do_housekeeping(struct skinnysession *s) { struct skinny_subchannel *sub; + struct skinny_line *l = s->device->lines; - sub = find_subchannel_by_line(s->device->lines); - transmit_displaymessage(s, 0); + sub = find_subchannel_by_line(l); + transmit_displaymessage(s, NULL); if (skinnydebug) { ast_verbose("Checking for voicemail Skinny %s@%s\n", sub->parent->name, sub->parent->parent->name); @@ -1084,9 +1293,9 @@ static void do_housekeeping(struct skinnysession *s) if (skinnydebug) { ast_verbose("Skinny %s@%s has voicemail! Yay!\n", sub->parent->name, sub->parent->parent->name); } - transmit_lamp_indication(s, STIMULUS_VOICEMAIL, s->device->lines->instance, SKINNY_LAMP_BLINK); + transmit_lamp_indication(s, STIMULUS_VOICEMAIL, l->instance, l->mwiblink?SKINNY_LAMP_BLINK:SKINNY_LAMP_ON); } else { - transmit_lamp_indication(s, STIMULUS_VOICEMAIL, s->device->lines->instance, SKINNY_LAMP_OFF); + transmit_lamp_indication(s, STIMULUS_VOICEMAIL, l->instance, SKINNY_LAMP_OFF); } } @@ -1143,33 +1352,77 @@ static int skinny_no_debug(int fd, int argc, char *argv[]) return RESULT_SUCCESS; } -static int skinny_show_lines(int fd, int argc, char *argv[]) +static int skinny_show_devices(int fd, int argc, char *argv[]) { struct skinny_device *d; struct skinny_line *l; - int haslines = 0; + int numlines = 0; char iabuf[INET_ADDRSTRLEN]; + + if (argc != 3) + return RESULT_SHOWUSAGE; + + ast_mutex_lock(&devicelock); + d = devices; + + ast_cli(fd, "Name DeviceId IP TypeId R Model 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", + 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; + } + ast_mutex_unlock(&devicelock); + + return RESULT_SUCCESS; +} + +static int skinny_show_lines(int fd, int argc, char *argv[]) +{ + + struct skinny_device *d; + struct skinny_line *l; + if (argc != 3) return RESULT_SHOWUSAGE; + ast_mutex_lock(&devicelock); d = devices; while(d) { l = d->lines; - ast_cli(fd, "Device '%s' at %s\n", d->name, ast_inet_ntoa(iabuf, sizeof(iabuf), d->addr.sin_addr)); - while(l) { - ast_cli(fd, " -- '%s@%s in '%s' is %s\n", l->name, d->name, l->context, l->sub->owner ? "active" : "idle"); - haslines = 1; + while (l) { + ast_cli(fd, "%-20s %2d %-20s %-20s %c %c\n", + l->parent->name, + l->instance, + l->name, + l->label, + l->sub->owner?'Y':'N', + l->sub->rtp?'Y':'N'); + l = l->next; } - if (!haslines) { - ast_cli(fd, " << No Lines Defined >> "); - } d = d->next; } ast_mutex_unlock(&devicelock); + return RESULT_SUCCESS; } +static char show_devices_usage[] = +"Usage: skinny show devices\n" +" Lists all devices known to the Skinny subsystem.\n"; + static char show_lines_usage[] = "Usage: skinny show lines\n" " Lists all lines known to the Skinny subsystem.\n"; @@ -1182,13 +1435,23 @@ static char no_debug_usage[] = "Usage: skinny no debug\n" " Disables dumping of Skinny packets for debugging purposes\n"; +static struct ast_cli_entry cli_show_devices = + { { "skinny", "show", "devices", NULL }, skinny_show_devices, "Show defined Skinny devices", show_devices_usage }; + static struct ast_cli_entry cli_show_lines = { { "skinny", "show", "lines", NULL }, skinny_show_lines, "Show defined Skinny lines per device", show_lines_usage }; + static struct ast_cli_entry cli_debug = { { "skinny", "debug", NULL }, skinny_do_debug, "Enable Skinny debugging", debug_usage }; + static struct ast_cli_entry cli_no_debug = { { "skinny", "no", "debug", NULL }, skinny_no_debug, "Disable Skinny debugging", no_debug_usage }; +static struct skinny_paging_device *build_paging_device(char *cat, struct ast_variable *v) +{ + return NULL; +} + static struct skinny_device *build_device(char *cat, struct ast_variable *v) { struct skinny_device *d; @@ -1252,14 +1515,14 @@ static struct skinny_device *build_device(char *cat, struct ast_variable *v) strncpy(mailbox, v->value, sizeof(mailbox) -1); } else if (!strcasecmp(v->name, "callreturn")) { callreturn = ast_true(v->value); - } else if (!strcasecmp(v->name, "immediate")) { - immediate = ast_true(v->value); } else if (!strcasecmp(v->name, "callwaiting")) { callwaiting = ast_true(v->value); } else if (!strcasecmp(v->name, "transfer")) { transfer = ast_true(v->value); } else if (!strcasecmp(v->name, "threewaycalling")) { threewaycalling = ast_true(v->value); + } else if (!strcasecmp(v->name, "mwiblink")) { + mwiblink = ast_true(v->value); } else if (!strcasecmp(v->name, "linelabel")) { strncpy(linelabel, v->value, sizeof(linelabel)-1); } else if (!strcasecmp(v->name, "trunk") || !strcasecmp(v->name, "line")) { @@ -1299,6 +1562,7 @@ static struct skinny_device *build_device(char *cat, struct ast_variable *v) l->callwaiting = callwaiting; l->transfer = transfer; l->threewaycalling = threewaycalling; + l->mwiblink = mwiblink; l->onhooktime = time(NULL); l->instance = 1; /* ASSUME we're onhook at this point*/ @@ -1362,10 +1626,10 @@ static int skinny_register(skinny_req *req, struct skinnysession *s) ast_mutex_lock(&devicelock); d = devices; while (d) { - if (!strcasecmp(req->data.reg.name, d->id)) { - /* XXX Deal with IP authentication */ + if (!strcasecmp(req->data.reg.name, d->id) + && ast_apply_ha(d->ha, &(s->sin))) { s->device = d; - d->type = req->data.reg.type; + d->type = letohl(req->data.reg.type); if (ast_strlen_zero(d->version_id)) { strncpy(d->version_id, version_id, sizeof(d->version_id) - 1); } @@ -1710,25 +1974,16 @@ static int skinny_call(struct ast_channel *ast, char *dest, int timeout) transmit_tone(session, tone); transmit_callstate(session, l->instance, SKINNY_RINGIN, sub->callid); + transmit_displaypromptstatus(session, "Ring-In", 0, l->instance, sub->callid); + transmit_callinfo(session, ast->cid.cid_name, ast->cid.cid_num, l->cid_name, l->cid_num, l->instance, sub->callid, 1); /* 1 = incoming to phone */ - /* XXX need to set the prompt */ /* XXX need to deal with softkeys */ ast_setstate(ast, AST_STATE_RINGING); ast_queue_control(ast, AST_CONTROL_RINGING); sub->outgoing = 1; - if (l->type == TYPE_LINE) { - if (!sub->rtp) { - start_rtp(sub); - } else { - /* do/should we need to anything if there already is an RTP allocated? */ - } - } else { - ast_log(LOG_ERROR, "I don't know how to dial on trunks, yet\n"); - res = -1; - } return res; } @@ -1780,6 +2035,8 @@ static int skinny_answer(struct ast_channel *ast) int res = 0; struct skinny_subchannel *sub = ast->tech_pvt; struct skinny_line *l = sub->parent; + struct skinnysession *s = l->parent->session; + sub->cxmode = SKINNY_CX_SENDRECV; if (!sub->rtp) { start_rtp(sub); @@ -1788,6 +2045,10 @@ static int skinny_answer(struct ast_channel *ast) if (ast->_state != AST_STATE_UP) { ast_setstate(ast, AST_STATE_UP); } + + transmit_tone(s, SKINNY_NOTONE); + transmit_callstate(s, l->instance, SKINNY_CONNECTED, sub->callid); + transmit_displaypromptstatus(s, "Connected", 0, l->instance, sub->callid); return res; } @@ -1873,6 +2134,8 @@ static int skinny_senddigit(struct ast_channel *ast, char digit) } static char *control2str(int ind) { + static char tmp[100]; + switch (ind) { case AST_CONTROL_HANGUP: return "Other end has hungup"; @@ -1900,10 +2163,19 @@ static char *control2str(int ind) { return "Key Radio"; case AST_CONTROL_RADIO_UNKEY: return "Un-Key Radio"; - case -1: - return "Stop tone"; + case AST_CONTROL_PROGRESS: + return "Remote end is making Progress"; + case AST_CONTROL_PROCEEDING: + return "Remote end is proceeding"; + case AST_CONTROL_HOLD: + return "Hold"; + case AST_CONTROL_UNHOLD: + return "Unhold"; + case -1: + return "Stop tone"; } - return "UNKNOWN"; + snprintf(tmp, 100, "UNKNOWN-%d", ind); + return tmp; } @@ -1922,6 +2194,9 @@ static int skinny_indicate(struct ast_channel *ast, int ind) if (!sub->progress) { transmit_tone(s, SKINNY_ALERT); transmit_callstate(s, l->instance, SKINNY_RINGOUT, sub->callid); + transmit_diallednumber(s, ast->exten, l->instance, sub->callid); + transmit_displaypromptstatus(s, "Ring Out", 0, l->instance, sub->callid); + transmit_callinfo(s, ast->cid.cid_name, ast->cid.cid_num, ast->exten, ast->exten, l->instance, sub->callid, 2); /* 2 = outgoing from phone */ sub->ringing = 1; break; } @@ -1947,7 +2222,10 @@ static int skinny_indicate(struct ast_channel *ast, int ind) return -1; case AST_CONTROL_PROGRESS: if ((ast->_state != AST_STATE_UP) && !sub->progress && !sub->outgoing) { + transmit_tone(s, SKINNY_ALERT); transmit_callstate(s, l->instance, SKINNY_PROGRESS, sub->callid); + transmit_displaypromptstatus(s, "Call Progress", 0, l->instance, sub->callid); + transmit_callinfo(s, ast->cid.cid_name, ast->cid.cid_num, ast->exten, ast->exten, l->instance, sub->callid, 2); /* 2 = outgoing from phone */ sub->progress = 1; break; } @@ -1977,6 +2255,7 @@ static struct ast_channel *skinny_new(struct skinny_subchannel *sub, int state) if (!tmp->nativeformats) tmp->nativeformats = capability; fmt = ast_best_codec(tmp->nativeformats); +ast_verbose("chan_skinny: skinny_new: tmp->nativeformats=%d fmt=%d\n", tmp->nativeformats, fmt); snprintf(tmp->name, sizeof(tmp->name), "Skinny/%s@%s-%d", l->name, l->parent->name, sub->callid); if (sub->rtp) tmp->fds[0] = ast_rtp_fd(sub->rtp); @@ -2012,6 +2291,10 @@ static struct ast_channel *skinny_new(struct skinny_subchannel *sub, int state) tmp->cid.cid_name = strdup(l->cid_name); } tmp->priority = 1; + + tmp->adsicpe = AST_ADSI_UNAVAILABLE; + + if (state != AST_STATE_DOWN) { if (ast_pbx_start(tmp)) { ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name); @@ -2037,6 +2320,7 @@ static int handle_message(skinny_req *req, struct skinnysession *s) char name[16]; char addr[4]; char d; + char iabuf[INET_ADDRSTRLEN]; int digit; int res=0; int speedDialNum; @@ -2051,13 +2335,13 @@ static int handle_message(skinny_req *req, struct skinnysession *s) pthread_t t; button_defs_t *b, *buse; - if ( (!s->device) && (req->e != REGISTER_MESSAGE && req->e != ALARM_MESSAGE)) { + 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); free(req); return 0; } - switch(req->e) { + switch(letohl(req->e)) { case ALARM_MESSAGE: /* no response necessary */ break; @@ -2070,8 +2354,8 @@ static int handle_message(skinny_req *req, struct skinnysession *s) ast_log(LOG_ERROR, "Rejecting Device %s: Device not found\n", req->data.reg.name); memcpy(&name, req->data.reg.name, sizeof(req->data.reg.name)); memset(req, 0, sizeof(skinny_req)); - req->len = sizeof(register_rej_message)+4; - req->e = REGISTER_REJ_MESSAGE; + req->len = htolel(sizeof(register_rej_message)+4); + req->e = htolel(REGISTER_REJ_MESSAGE); snprintf(req->data.regrej.errMsg, sizeof(req->data.regrej.errMsg), "No Authority: %s", name); transmit_response(s, req); break; @@ -2080,22 +2364,22 @@ static int handle_message(skinny_req *req, struct skinnysession *s) ast_verbose(VERBOSE_PREFIX_3 "Device '%s' successfuly registered\n", s->device->name); } memset(req, 0, SKINNY_MAX_PACKET); - req->len = sizeof(register_ack_message)+4; - req->e = REGISTER_ACK_MESSAGE; + req->len = htolel(sizeof(register_ack_message)+4); + req->e = htolel(REGISTER_ACK_MESSAGE); req->data.regack.res[0] = '0'; req->data.regack.res[1] = '\0'; - req->data.regack.keepAlive = keep_alive; + req->data.regack.keepAlive = htolel(keep_alive); strncpy(req->data.regack.dateTemplate, date_format, sizeof(req->data.regack.dateTemplate) - 1); req->data.regack.res2[0] = '0'; req->data.regack.res2[1] = '\0'; - req->data.regack.secondaryKeepAlive = keep_alive; + req->data.regack.secondaryKeepAlive = htolel(keep_alive); transmit_response(s, req); if (skinnydebug) { ast_verbose("Requesting capabilities\n"); } memset(req, 0, SKINNY_MAX_PACKET); - req->len = 4; - req->e = CAPABILITIES_REQ_MESSAGE; + req->len = htolel(4); + req->e = htolel(CAPABILITIES_REQ_MESSAGE); transmit_response(s, req); break; case UNREGISTER_MESSAGE: @@ -2105,8 +2389,8 @@ static int handle_message(skinny_req *req, struct skinnysession *s) /* no response necessary */ break; case STIMULUS_MESSAGE: - stimulus = req->data.stimulus.stimulus; - stimulusInstance = req->data.stimulus.stimulusInstance; + stimulus = letohl(req->data.stimulus.stimulus); + stimulusInstance = letohl(req->data.stimulus.stimulusInstance); switch(stimulus) { case STIMULUS_REDIAL: @@ -2173,12 +2457,14 @@ static int handle_message(skinny_req *req, struct skinnysession *s) } s->device->lines->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",find_subchannel_by_line(s->device->lines)->parent->name,find_subchannel_by_line(s->device->lines)->parent->name); } s->device->lines->dnd = 1; transmit_lamp_indication(s, STIMULUS_FORWARDALL, 1, SKINNY_LAMP_OFF); + transmit_displaynotify(s, "DnD enabled",10); } break; case STIMULUS_FORWARDBUSY: @@ -2212,8 +2498,8 @@ static int handle_message(skinny_req *req, struct skinnysession *s) ast_verbose("Version Request\n"); } memset(req, 0, SKINNY_MAX_PACKET); - req->len = sizeof(version_res_message)+4; - req->e = VERSION_RES_MESSAGE; + req->len = htolel(sizeof(version_res_message)+4); + req->e = htolel(VERSION_RES_MESSAGE); snprintf(req->data.version.version, sizeof(req->data.version.version), s->device->version_id); transmit_response(s, req); break; @@ -2222,12 +2508,12 @@ static int handle_message(skinny_req *req, struct skinnysession *s) ast_verbose("Recieved Server Request\n"); } memset(req, 0, SKINNY_MAX_PACKET); - req->len = sizeof(server_res_message)+4; - req->e = SERVER_RES_MESSAGE; + req->len = htolel(sizeof(server_res_message)+4); + req->e = htolel(SERVER_RES_MESSAGE); memcpy(req->data.serverres.server[0].serverName, ourhost, sizeof(req->data.serverres.server[0].serverName)); - req->data.serverres.serverListenPort[0] = ourport; - req->data.serverres.serverIpAddr[0] = __ourip.s_addr; + req->data.serverres.serverListenPort[0] = htolel(ourport); + req->data.serverres.serverIpAddr[0] = htolel(__ourip.s_addr); transmit_response(s, req); break; case BUTTON_TEMPLATE_REQ_MESSAGE: @@ -2238,8 +2524,8 @@ static int handle_message(skinny_req *req, struct skinnysession *s) sub = find_subchannel_by_line(s->device->lines); memset(req, 0, SKINNY_MAX_PACKET); - req->e = BUTTON_TEMPLATE_RES_MESSAGE; - req->len = sizeof(button_template_res_message)+4; + req->e = htolel(BUTTON_TEMPLATE_RES_MESSAGE); + req->len = htolel(sizeof(button_template_res_message)+4); /* Find a matching button definition, default to first in the list */ @@ -2251,8 +2537,8 @@ static int handle_message(skinny_req *req, struct skinnysession *s) } req->data.buttontemplate.buttonOffset = 0; - req->data.buttontemplate.buttonCount = buse->num_buttons; - req->data.buttontemplate.totalButtonCount = buse->num_buttons; + req->data.buttontemplate.buttonCount = htolel(buse->num_buttons); + req->data.buttontemplate.totalButtonCount = htolel(buse->num_buttons); for (i=0; i<42; i++) { if (i < buse->num_buttons) { memcpy(&(req->data.buttontemplate.definition[i]), @@ -2280,11 +2566,11 @@ static int handle_message(skinny_req *req, struct skinnysession *s) ast_verbose("Received SoftKeySetReq\n"); } memset(req, 0, SKINNY_MAX_PACKET); - req->len = sizeof(soft_key_sets)+4; - req->e = SOFT_KEY_SET_RES_MESSAGE; + req->len = htolel(sizeof(soft_key_sets)+4); + req->e = htolel(SOFT_KEY_SET_RES_MESSAGE); req->data.softkeysets.softKeySetOffset = 0; - req->data.softkeysets.softKeySetCount = 11; - req->data.softkeysets.totalSoftKeySetCount = 11; + req->data.softkeysets.softKeySetCount = htolel(11); + req->data.softkeysets.totalSoftKeySetCount = htolel(11); /* XXX Wicked hack XXX */ memcpy(req->data.softkeysets.softKeySetDefinition, soft_key_set_hack, @@ -2296,11 +2582,11 @@ static int handle_message(skinny_req *req, struct skinnysession *s) ast_verbose("Recieved SoftKey Template Request\n"); } memset(req, 0, SKINNY_MAX_PACKET); - req->len = sizeof(soft_key_template)+4; - req->e = SOFT_KEY_TEMPLATE_RES_MESSAGE; + req->len = htolel(sizeof(soft_key_template)+4); + req->e = htolel(SOFT_KEY_TEMPLATE_RES_MESSAGE); req->data.softkeytemplate.softKeyOffset = 0; - req->data.softkeytemplate.softKeyCount = sizeof(soft_key_template_default) / sizeof(soft_key_template_definition); - req->data.softkeytemplate.totalSoftKeyCount = sizeof(soft_key_template_default) / sizeof(soft_key_template_definition); + req->data.softkeytemplate.softKeyCount = htolel(sizeof(soft_key_template_default) / sizeof(soft_key_template_definition)); + req->data.softkeytemplate.totalSoftKeyCount = htolel(sizeof(soft_key_template_default) / sizeof(soft_key_template_definition)); memcpy(req->data.softkeytemplate.softKeyTemplateDefinition, soft_key_template_default, sizeof(soft_key_template_default)); @@ -2311,26 +2597,26 @@ static int handle_message(skinny_req *req, struct skinnysession *s) ast_verbose("Received Time/Date Request\n"); } memset(req, 0, SKINNY_MAX_PACKET); - req->len = sizeof(definetimedate_message)+4; - req->e = DEFINETIMEDATE_MESSAGE; + req->len = htolel(sizeof(definetimedate_message)+4); + req->e = htolel(DEFINETIMEDATE_MESSAGE); timer=time(NULL); cmtime = localtime(&timer); - req->data.definetimedate.year = cmtime->tm_year+1900; - req->data.definetimedate.month = cmtime->tm_mon+1; - req->data.definetimedate.dayofweek = cmtime->tm_wday; - req->data.definetimedate.day = cmtime->tm_mday; - req->data.definetimedate.hour = cmtime->tm_hour; - req->data.definetimedate.minute = cmtime->tm_min; - req->data.definetimedate.seconds = cmtime->tm_sec; + 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); break; case SPEED_DIAL_STAT_REQ_MESSAGE: /* Not really sure how Speed Dial's are different than the Softkey templates */ - speedDialNum = req->data.speeddialreq.speedDialNumber; + speedDialNum = letohl(req->data.speeddialreq.speedDialNumber); memset(req, 0, SKINNY_MAX_PACKET); - req->len = sizeof(speed_dial_stat_res_message)+4; - req->e = SPEED_DIAL_STAT_RES_MESSAGE; + req->len = htolel(sizeof(speed_dial_stat_res_message)+4); + req->e = htolel(SPEED_DIAL_STAT_RES_MESSAGE); #if 0 /* XXX Do this right XXX */ /* If the redial function works the way I think it will, a modification of it @@ -2342,13 +2628,13 @@ static int handle_message(skinny_req *req, struct skinnysession *s) transmit_response(s, req); break; case LINE_STATE_REQ_MESSAGE: - lineNumber = req->data.line.lineNumber; + lineNumber = letohl(req->data.line.lineNumber); if (skinnydebug) { ast_verbose("Received LineStateReq\n"); } memset(req, 0, SKINNY_MAX_PACKET); - req->len = sizeof(line_stat_res_message)+4; - req->e = LINE_STAT_RES_MESSAGE; + req->len = htolel(sizeof(line_stat_res_message)+4); + req->e = htolel(LINE_STAT_RES_MESSAGE); sub = find_subchannel_by_line(s->device->lines); if (!sub) { ast_log(LOG_NOTICE, "No available lines on: %s\n", s->device->name); @@ -2360,7 +2646,7 @@ static int handle_message(skinny_req *req, struct skinnysession *s) lines = lines->next; } ast_mutex_unlock(&devicelock); - req->data.linestat.linenumber = lineNumber; + req->data.linestat.linenumber = letohl(lineNumber); memcpy(req->data.linestat.lineDirNumber, lines->name, sizeof(req->data.linestat.lineDirNumber)); memcpy(req->data.linestat.lineDisplayName, lines->label, @@ -2375,8 +2661,8 @@ static int handle_message(skinny_req *req, struct skinnysession *s) break; case KEEP_ALIVE_MESSAGE: memset(req, 0, SKINNY_MAX_PACKET); - req->len = 4; - req->e = KEEP_ALIVE_ACK_MESSAGE; + req->len = htolel(4); + req->e = htolel(KEEP_ALIVE_ACK_MESSAGE); transmit_response(s, req); do_housekeeping(s); @@ -2393,8 +2679,12 @@ static int handle_message(skinny_req *req, struct skinnysession *s) sub->parent->hookstate = SKINNY_OFFHOOK; if (sub->outgoing) { + /* We're answering a ringing call */ + ast_queue_control(sub->owner, AST_CONTROL_ANSWER); transmit_callstate(s, s->device->lines->instance, SKINNY_OFFHOOK, sub->callid); transmit_tone(s, SKINNY_SILENCE); + transmit_callstate(s, s->device->lines->instance, SKINNY_CONNECTED, sub->callid); + start_rtp(sub); ast_setstate(sub->owner, AST_STATE_UP); /* XXX select the appropriate soft key here */ } else { @@ -2403,7 +2693,7 @@ static int handle_message(skinny_req *req, struct skinnysession *s) if (skinnydebug) { ast_verbose("Attempting to Clear display on Skinny %s@%s\n",sub->parent->name, sub->parent->parent->name); } - transmit_displaymessage(s, 0); /* clear display */ + transmit_displaymessage(s, NULL); /* clear display */ transmit_tone(s, SKINNY_DIALTONE); c = skinny_new(sub, AST_STATE_DOWN); if(c) { @@ -2430,42 +2720,46 @@ static int handle_message(skinny_req *req, struct skinnysession *s) sub->cxmode = SKINNY_CX_RECVONLY; sub->parent->hookstate = SKINNY_ONHOOK; transmit_callstate(s, s->device->lines->instance, sub->parent->hookstate,sub->callid); - if (skinnydebug) { + + if (skinnydebug) { ast_verbose("Skinny %s@%s went on hook\n",sub->parent->name, sub->parent->parent->name); - } - if (sub->parent->transfer && (sub->owner && sub->next->owner) && ((!sub->outgoing) || (!sub->next->outgoing))) { + } + + if (sub->parent->transfer && (sub->owner && sub->next->owner) && ((!sub->outgoing) || (!sub->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 ((res = attempt_transfer(p)) < 0) { if (p->sub->next->owner) { sub->next->alreadygone = 1; ast_queue_hangup(sub->next->owner,1); } - } else if (res) { - ast_log(LOG_WARNING, "Transfer attempt failed\n"); - return -1; - } + } else if (res) { + ast_log(LOG_WARNING, "Transfer attempt failed\n"); + return -1; + } #endif - } else { - /* Hangup the current call */ - /* If there is another active call, skinny_hangup will ring the phone with the other call */ - if (sub->owner) { - sub->alreadygone = 1; - ast_queue_hangup(sub->owner); - } else { - ast_log(LOG_WARNING, "Skinny(%s@%s-%d) channel already destroyed\n", - sub->parent->name, sub->parent->parent->name, sub->callid); - } - } - - if ((sub->parent->hookstate == SKINNY_ONHOOK) && (!sub->next->rtp)) { + } else { + /* Hangup the current call */ + /* If there is another active call, skinny_hangup will ring the phone with the other call */ + if (sub->owner) { + sub->alreadygone = 1; + ast_queue_hangup(sub->owner); + } else { + ast_log(LOG_WARNING, "Skinny(%s@%s-%d) channel already destroyed\n", + sub->parent->name, sub->parent->parent->name, sub->callid); + } + } + + if ((sub->parent->hookstate == SKINNY_ONHOOK) && (!sub->next->rtp)) { do_housekeeping(s); - } + } + + break; - break; case KEYPAD_BUTTON_MESSAGE: - digit = req->data.keypad.button; + digit = letohl(req->data.keypad.button); if (skinnydebug) { ast_verbose("Collected digit: [%d]\n", digit); } @@ -2504,18 +2798,21 @@ static int handle_message(skinny_req *req, struct skinnysession *s) break; case OPEN_RECIEVE_CHANNEL_ACK_MESSAGE: ast_verbose("Recieved Open Recieve Channel Ack\n"); - status = req->data.openrecievechannelack.status; + status = letohl(req->data.openrecievechannelack.status); if (status) { ast_log(LOG_ERROR, "Open Recieve Channel Failure\n"); break; } + /* ENDIAN */ memcpy(addr, req->data.openrecievechannelack.ipAddr, sizeof(addr)); - port = req->data.openrecievechannelack.port; + port = htolel(req->data.openrecievechannelack.port); sin.sin_family = AF_INET; /* I smell endian problems */ memcpy(&sin.sin_addr, addr, sizeof(sin.sin_addr)); sin.sin_port = htons(port); + + ast_verbose("ipaddr = %s:%d\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), ntohs(sin.sin_port)); sub = find_subchannel_by_line(s->device->lines); if (sub->rtp) { @@ -2526,22 +2823,22 @@ static int handle_message(skinny_req *req, struct skinnysession *s) break; } memset(req, 0, SKINNY_MAX_PACKET); - req->len = sizeof(start_media_transmission_message)+4; - req->e = START_MEDIA_TRANSMISSION_MESSAGE; + req->len = htolel(sizeof(start_media_transmission_message)+4); + req->e = htolel(START_MEDIA_TRANSMISSION_MESSAGE); req->data.startmedia.conferenceId = 0; req->data.startmedia.passThruPartyId = 0; memcpy(req->data.startmedia.remoteIp, &s->device->ourip, 4); /* Endian? */ - req->data.startmedia.remotePort = ntohs(us.sin_port); - req->data.startmedia.packetSize = 20; - req->data.startmedia.payloadType = convert_cap(s->device->lines->capability); - req->data.startmedia.qualifier.precedence = 127; + 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); break; default: - ast_verbose("RECEIVED UNKNOWN MESSAGE TYPE: %x\n", req->e); + ast_verbose("RECEIVED UNKNOWN MESSAGE TYPE: %x\n", letohl(req->e)); break; } @@ -2594,10 +2891,10 @@ static int get_input(struct skinnysession *s) ast_log(LOG_WARNING, "Skinny Client sent less data than expected.\n"); return -1; } - dlen = *(int *)s->inbuf; + dlen = letohl(*(int *)s->inbuf); if (dlen+8 > sizeof(s->inbuf)) dlen = sizeof(s->inbuf) - 8; - *(int *)s->inbuf = dlen; + *(int *)s->inbuf = htolel(dlen); res = read(s->fd, s->inbuf+4, dlen+4); ast_mutex_unlock(&s->lock); if (res != (dlen+4)) { @@ -2619,8 +2916,8 @@ static skinny_req *skinny_req_parse(struct skinnysession *s) } memset(req, 0, sizeof(skinny_req)); /* +8 to account for reserved and length fields */ - memcpy(req, s->inbuf, *(int*)(s->inbuf)+8); - if (req->e < 0) { + memcpy(req, s->inbuf, letohl(*(int*)(s->inbuf))+8); + if (letohl(req->e) < 0) { ast_log(LOG_ERROR, "Event Message is NULL from socket %d, This is bad\n", s->fd); free(req); return NULL; @@ -2816,6 +3113,7 @@ static int reload_config(void) char *cat; char iabuf[INET_ADDRSTRLEN]; struct skinny_device *d; + struct skinny_paging_device *p; int oldport = ntohs(bindaddr.sin_port); #if 0 @@ -2889,7 +3187,15 @@ static int reload_config(void) /* load the device sections */ cat = ast_category_browse(cfg, NULL); while(cat) { - if (strcasecmp(cat, "general")) { + if (!strcasecmp(cat, "general")) { + /* Nothing to do */ +#if 0 + } else if (!strncasecmp(cat, "paging-", 7)) { + p = build_paging_device(cat, ast_variable_browse(cfg, cat)); + if (p) { + } +#endif + } else { d = build_device(cat, ast_variable_browse(cfg, cat)); if (d) { if (option_verbose > 2) { @@ -2954,7 +3260,6 @@ static int reload_config(void) return 0; } -#if 0 void delete_devices(void) { struct skinny_device *d, *dlast; @@ -2987,17 +3292,13 @@ void delete_devices(void) devices=NULL; ast_mutex_unlock(&devicelock); } -#endif int reload(void) { -#if 0 -/* XXX Causes Seg - needs to be fixed, or? */ - delete_devices(); reload_config(); restart_monitor(); -#endif + return 0; } @@ -3018,6 +3319,7 @@ int load_module() } } ast_rtp_proto_register(&skinny_rtp); + ast_cli_register(&cli_show_devices); ast_cli_register(&cli_show_lines); ast_cli_register(&cli_debug); ast_cli_register(&cli_no_debug); @@ -3081,6 +3383,7 @@ int unload_module() ast_rtp_proto_register(&skinny_rtp); ast_channel_unregister(&skinny_tech); + ast_cli_register(&cli_show_devices); ast_cli_register(&cli_show_lines); ast_cli_register(&cli_debug); ast_cli_register(&cli_no_debug); -- cgit v1.2.3