[asterisk-dev] mvanbaak: trunk r125096 - /trunk/channels/chan_skinny.c

Russell Bryant russell at digium.com
Fri Jun 27 09:08:18 CDT 2008


If anyone is looking for a janitor-style project, while looking over  
this code I noticed that there is a big need for conversion to linked  
list macros in chan_skinny.


On Jun 25, 2008, at 3:37 PM, SVN commits to the Digium repositories  
wrote:

> Author: mvanbaak
> Date: Wed Jun 25 14:37:40 2008
> New Revision: 125096
>
> URL: http://svn.digium.com/view/asterisk?view=rev&rev=125096
> Log:
> implement transfer functionality in chan_skinny
>
> (closes issue #9939)
> Reported by: wedhorn
> Patches:
>      transfer_v6.diff uploaded by wedhorn (license 30)
>      chan_skinny-transfer-trunk-v10.txt uploaded by DEA (license 3)
>      chan_skinny-transfer-trunk-v12.txt uploaded by mvanbaak  
> (license 7)
> Tested by: DEA, wedhorn, mvanbaak
>
> Modified:
>    trunk/channels/chan_skinny.c
>
> Modified: trunk/channels/chan_skinny.c
> URL: http://svn.digium.com/view/asterisk/trunk/channels/chan_skinny.c?view=diff&rev=125096&r1=125095&r2=125096
> = 
> = 
> = 
> = 
> = 
> = 
> = 
> = 
> ======================================================================
> --- trunk/channels/chan_skinny.c (original)
> +++ trunk/channels/chan_skinny.c Wed Jun 25 14:37:40 2008
> @@ -67,6 +67,7 @@
> #include "asterisk/threadstorage.h"
> #include "asterisk/devicestate.h"
> #include "asterisk/event.h"
> +#include "asterisk/indications.h"
>
> /*************************************
>  * Skinny/Asterisk Protocol Settings *
> @@ -202,14 +203,14 @@
>
> #define OFFHOOK_MESSAGE 0x0006
> struct offhook_message {
> -	uint32_t unknown1;
> -	uint32_t unknown2;
> +	uint32_t instance;
> +	uint32_t reference;
> };
>
> #define ONHOOK_MESSAGE 0x0007
> struct onhook_message {
> -	uint32_t unknown1;
> -	uint32_t unknown2;
> +	uint32_t instance;
> +	uint32_t reference;
> };
>
> #define CAPABILITIES_RES_MESSAGE 0x0010
> @@ -797,6 +798,7 @@
> static const uint8_t soft_key_default_offhookwithfeat[] = {
> 	SOFTKEY_REDIAL,
> 	SOFTKEY_ENDCALL,
> +	SOFTKEY_TRNSFER,
> };
>
> static const uint8_t soft_key_default_unknown[] = {
> @@ -861,6 +863,7 @@
> 	char promptMessage[32];
> 	uint32_t lineInstance;
> 	uint32_t callReference;
> +	uint32_t space[3];
> };
>
> #define CLEAR_PROMPT_MESSAGE  0x0113
> @@ -1139,8 +1142,12 @@
> 	int nat;
> 	int outgoing;
> 	int alreadygone;
> +	int blindxfer;
> +	int xferor;
> +
>
> 	struct skinny_subchannel *next;
> +	struct skinny_subchannel *related;
> 	struct skinny_line *parent;
> };
>
> @@ -1197,6 +1204,7 @@
>
> 	struct ast_codec_pref prefs;
> 	struct skinny_subchannel *sub;
> +	struct skinny_subchannel *activesub;
> 	struct skinny_line *next;
> 	struct skinny_device *parent;
> 	struct ast_variable *chanvars; /*!< Channel variables to set for  
> inbound call */
> @@ -1245,6 +1253,7 @@
> 	struct ast_ha *ha;
> 	struct skinnysession *session;
> 	struct skinny_device *next;
> +	struct skinny_line *activeline;
> } *devices = NULL;
>
> struct skinny_paging_device {
> @@ -1298,6 +1307,7 @@
> };
>
> static int skinny_extensionstate_cb(char *context, char* exten, int  
> state, void *data);
> +static int skinny_transfer(struct skinny_subchannel *sub);
>
> static void *get_button_template(struct skinnysession *s, struct  
> button_definition_template *btn)
> {
> @@ -2096,6 +2106,54 @@
> 	transmit_response(s, req);
> }
>
> +static void transmit_closereceivechannel(struct skinnysession *s,  
> struct skinny_subchannel *sub)
> +{
> +	struct skinny_req *req;
> +
> +	if (!(req = req_alloc(sizeof(struct  
> close_receive_channel_message), CLOSE_RECEIVE_CHANNEL_MESSAGE)))
> +		return;
> +
> +	req->data.closereceivechannel.conferenceId = htolel(0);
> +	req->data.closereceivechannel.partyId = htolel(sub->callid);
> +	transmit_response(s, req);
> +}
> +
> +static void transmit_stopmediatransmission(struct skinnysession *s,  
> struct skinny_subchannel *sub)
> +{
> +	struct skinny_req *req;
> +
> +	if (!(req = req_alloc(sizeof(struct  
> stop_media_transmission_message), STOP_MEDIA_TRANSMISSION_MESSAGE)))
> +		return;
> +
> +	req->data.stopmedia.conferenceId = htolel(0);
> +	req->data.stopmedia.passThruPartyId = htolel(sub->callid);
> +	transmit_response(s, req);
> +}
> +
> +static void transmit_activatecallplane(struct skinnysession *s,  
> struct skinny_line *l)
> +{
> +	struct skinny_req *req;
> +
> +	if (!(req = req_alloc(sizeof(struct activate_call_plane_message),  
> ACTIVATE_CALL_PLANE_MESSAGE)))
> +		return;
> +
> +	req->data.activatecallplane.lineInstance = htolel(l->instance);
> +	transmit_response(s, req);
> +}
> +
> +static void transmit_callstateonly(struct skinnysession *s, struct  
> skinny_subchannel *sub, int state)
> +{
> +	struct skinny_req *req;
> +
> +	if (!(req = req_alloc(sizeof(struct call_state_message),  
> CALL_STATE_MESSAGE)))
> +		return;
> +
> +	req->data.callstate.callState = htolel(state);
> +	req->data.callstate.lineInstance = htolel(sub->parent->instance);
> +	req->data.callstate.callReference = htolel(sub->callid);
> +	transmit_response(s, req);
> +}
> +
> static void transmit_callstate(struct skinnysession *s, int  
> instance, int state, unsigned callid)
> {
> 	struct skinny_req *req;
> @@ -3160,6 +3218,9 @@
> 					l->nat = nat;
> 					l->canreinvite = canreinvite;
>
> +					if (!d->lines) {
> +						d->activeline = l;
> +					}
> 					l->next = d->lines;
> 					d->lines = l;
> 				}
> @@ -3394,7 +3455,7 @@
> 		break;
> 	}
>
> -	transmit_callstate(s, l->instance, SKINNY_RINGIN, sub->callid);
> +	transmit_callstateonly(s, sub, SKINNY_RINGIN);
> 	transmit_selectsoftkeys(s, l->instance, sub->callid, KEYDEF_RINGIN);
> 	transmit_displaypromptstatus(s, "Ring-In", 0, l->instance, sub- 
> >callid);
> 	transmit_callinfo(s, ast->cid.cid_name, ast->cid.cid_num, l- 
> >cid_name, l->cid_num, l->instance, sub->callid, 1);
> @@ -3409,7 +3470,7 @@
>
> static int skinny_hangup(struct ast_channel *ast)
> {
> -	struct skinny_subchannel *sub = ast->tech_pvt;
> +	struct skinny_subchannel *sub = ast->tech_pvt, *tmpsub;
> 	struct skinny_line *l;
> 	struct skinny_device *d;
> 	struct skinnysession *s;
> @@ -3421,22 +3482,88 @@
> 	l = sub->parent;
> 	d = l->parent;
> 	s = d->session;
> -	if (skinnydebug)
> -		ast_verb(1, "skinny_hangup(%s) on %s@%s\n", ast->name, l->name, d- 
> >name);
> +
> +	if (l->sub == sub) {
> +		l->sub = l->sub->next;
> +	} else {
> +		tmpsub = l->sub;
> +		while (tmpsub->next) {
> +			if (tmpsub->next == sub) {
> +				tmpsub->next = tmpsub->next->next;
> +				break;
> +			}
> +		}
> +	}
>
> 	if (d->registered) {
> -		if ((l->type = TYPE_LINE) && (l->hookstate == SKINNY_OFFHOOK)) {
> +		/* Ignoring l->type, doesn't seem relevant and previous code
> +		   assigned rather than tested, ie always true */
> +		if (l->sub) {
> +			if (sub->related) {
> +				sub->related->related = NULL;
> +
> +			}
> +			if (sub == l->activesub) {      /* we are killing the active  
> sub, but there are other subs on the line*/
> +				if (sub->related) {
> +					l->activesub = sub->related;
> +				} else {
> +					if (sub->next) {
> +						l->activesub = sub->next;
> +					} else {
> +						l->activesub = l->sub;
> +					}
> +				}
> +				transmit_activatecallplane(s, l);
> +				transmit_closereceivechannel(s,sub);
> +				transmit_stopmediatransmission(s,sub);
> +				transmit_tone(s, SKINNY_CALLWAITTONE, l->instance, l->activesub- 
> >callid);
> +				transmit_lamp_indication(s, STIMULUS_LINE, l->instance,  
> SKINNY_LAMP_BLINK);
> +			} else {    /* we are killing a background sub on the line with  
> other subs*/
> +				if (l->sub->next) {
> +					transmit_lamp_indication(s, STIMULUS_LINE, l->instance,  
> SKINNY_LAMP_BLINK);
> +				} else {
> +					transmit_lamp_indication(s, STIMULUS_LINE, l->instance,  
> SKINNY_LAMP_ON);
> +				}
> +			}
> +		} else {                                                /* no  
> more subs on line so make idle */
> +
> 			l->hookstate = SKINNY_ONHOOK;
> 			transmit_callstate(s, l->instance, SKINNY_ONHOOK, sub->callid);
> +			l->activesub = NULL;
> 			transmit_lamp_indication(s, STIMULUS_LINE, l->instance,  
> SKINNY_LAMP_OFF);
> -			transmit_speaker_mode(s, SKINNY_SPEAKEROFF);
> +			if (sub->parent == d->activeline) {
> +				transmit_activatecallplane(s, l);
> +				transmit_closereceivechannel(s,sub);
> +				transmit_stopmediatransmission(s,sub);
> +				transmit_speaker_mode(s, SKINNY_SPEAKEROFF);
> +				transmit_ringer_mode(s, SKINNY_RING_OFF);
> +				/* we should check to see if we can start the ringer if another  
> line is ringing */
> +			}
> +		}
> +
> +		/* if ((l->type = TYPE_LINE) && (l->hookstate == SKINNY_OFFHOOK)) {
> +			transmit_callstate(s, l->instance, SKINNY_ONHOOK, sub->callid);
> +			if (onlysub){
> +				if (skinnydebug)
> +					ast_debug(1, "skinny_hangup(%s) on %s@%s is not the only call  
> on this device\n", ast->name, l->name, d->name);
> +				l->hookstate = SKINNY_ONHOOK;
> +				transmit_lamp_indication(s, STIMULUS_LINE, l->instance,  
> SKINNY_LAMP_OFF);
> +				transmit_speaker_mode(s, SKINNY_SPEAKEROFF);
> +				transmit_ringer_mode(s, SKINNY_RING_OFF);
> +			} else {
> +				transmit_ringer_mode(s, SKINNY_RING_OFF);
> +				if (skinnydebug)
> +					ast_debug(1, "skinny_hangup(%s) on %s@%s \n", ast->name, l- 
> >name, d->name);
> +			}
> +			/ends
> +
> 		} else if ((l->type = TYPE_LINE) && (l->hookstate ==  
> SKINNY_ONHOOK)) {
> 			transmit_tone(s, SKINNY_SILENCE, l->instance, sub->callid);
> 			transmit_callstate(s, l->instance, SKINNY_ONHOOK, sub->callid);
> 			transmit_ringer_mode(s, SKINNY_RING_OFF);
> 			transmit_lamp_indication(s, STIMULUS_LINE, l->instance,  
> SKINNY_LAMP_OFF);
> 			do_housekeeping(s);
> -		}
> +		} */
> 	}
> 	ast_mutex_lock(&sub->lock);
> 	sub->owner = NULL;
> @@ -3462,6 +3589,15 @@
>
> 	ast_copy_string(exten, S_OR(ast->macroexten, ast->exten),  
> sizeof(exten));
>
> +	if (sub->blindxfer) {
> +		if (skinnydebug)
> +			ast_debug(1, "skinny_answer(%s) on %s@%s-%d with BlindXFER,  
> transferring\n",
> +				ast->name, l->name, d->name, sub->callid);
> +		ast_setstate(ast, AST_STATE_UP);
> +		skinny_transfer(sub);
> +		return 0;
> +	}
> +
> 	sub->cxmode = SKINNY_CX_SENDRECV;
> 	if (!sub->rtp) {
> 		start_rtp(sub);
> @@ -3477,10 +3613,11 @@
> 	   for some reason, transmit_callinfo must be before  
> transmit_callstate,
> 	   or you won't get keypad messages in some situations. */
> 	transmit_callinfo(s, ast->cid.cid_name, ast->cid.cid_num, exten,  
> exten, l->instance, sub->callid, 2);
> -	transmit_callstate(s, l->instance, SKINNY_CONNECTED, sub->callid);
> +	transmit_callstateonly(s, sub, SKINNY_CONNECTED);
> 	transmit_selectsoftkeys(s, l->instance, sub->callid,  
> KEYDEF_CONNECTED);
> 	transmit_dialednumber(s, exten, l->instance, sub->callid);
> 	transmit_displaypromptstatus(s, "Connected", 0, l->instance, sub- 
> >callid);
> +	l->activesub = sub;
> 	return res;
> }
>
> @@ -3678,6 +3815,68 @@
> 	}
> }
>
> +static int skinny_transfer(struct skinny_subchannel *sub)
> +{
> +	struct skinny_subchannel *xferor; /* the sub doing the  
> transferring */
> +	struct skinny_subchannel *xferee; /* the sub being transferred */
> +	const struct ind_tone_zone_sound *ts = NULL;
> +		
> +	if (ast_bridged_channel(sub->owner) || ast_bridged_channel(sub- 
> >related->owner)) {
> +		if (sub->xferor) {
> +			xferor = sub;
> +			xferee = sub->related;
> +		} else {
> +			xferor = sub;
> +			xferee = sub->related;
> +		}
> +		
> +		if (skinnydebug) {
> +			ast_debug(1, "Transferee channels (local/remote): %s and %s\n",
> +				xferee->owner->name, ast_bridged_channel(xferee->owner)? 
> ast_bridged_channel(xferee->owner)->name:"");
> +			ast_debug(1, "Transferor channels (local/remote): %s and %s\n",
> +				xferor->owner->name, ast_bridged_channel(xferor->owner)? 
> ast_bridged_channel(xferor->owner)->name:"");
> +		}
> +		if (ast_bridged_channel(xferor->owner)) {
> +			if (ast_bridged_channel(xferee->owner)) {
> +				ast_queue_control(xferee->owner, AST_CONTROL_UNHOLD);
> +			}
> +			if (xferor->owner->_state == AST_STATE_RING) {
> +				/* play ringing inband */
> +				ts = ast_get_indication_tone(xferor->owner->zone, "ring");
> +				ast_playtones_start(xferor->owner,0,ts->data, 1);
> +			}
> +			if (skinnydebug)
> +				ast_debug(1, "Transfer Masquerading %s to %s\n",
> +					xferee->owner->name, ast_bridged_channel(xferor->owner)? 
> ast_bridged_channel(xferor->owner)->name:"");
> +			if (ast_channel_masquerade(xferee->owner,  
> ast_bridged_channel(xferor->owner))) {
> +				ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n",
> +					ast_bridged_channel(xferor->owner)->name, xferee->owner->name);
> +				return -1;
> +			}
> +		} else if (ast_bridged_channel(xferee->owner)) {
> +			ast_queue_control(xferee->owner, AST_CONTROL_UNHOLD);
> +			if (xferor->owner->_state == AST_STATE_RING) {
> +				/* play ringing inband */
> +				ts = ast_get_indication_tone(xferor->owner->zone, "ring");
> +				ast_playtones_start(xferor->owner,0,ts->data, 1);
> +			}
> +			if (skinnydebug)
> +				ast_debug(1, "Transfer Masquerading %s to %s\n",
> +					xferor->owner->name, ast_bridged_channel(xferee->owner)? 
> ast_bridged_channel(xferee->owner)->name:"");
> +			if (ast_channel_masquerade(xferor->owner,  
> ast_bridged_channel(xferee->owner))) {
> +				ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n",
> +					ast_bridged_channel(xferee->owner)->name, xferor->owner->name);
> +				return -1;
> +			}
> +			return 0;
> +		} else {
> +			if (option_debug)
> +				ast_log(LOG_DEBUG, "Neither %s nor %s are in a bridge, nothing  
> to transfer\n",
> +					xferor->owner->name, xferee->owner->name);
> +		}
> +	}
> +	return 0;
> +}
>
> static int skinny_indicate(struct ast_channel *ast, int ind, const  
> void *data, size_t datalen)
> {
> @@ -3698,12 +3897,18 @@
> 		ast_verb(3, "Asked to indicate '%s' condition on channel %s\n",  
> control2str(ind), ast->name);
> 	switch(ind) {
> 	case AST_CONTROL_RINGING:
> +		if (sub->blindxfer) {
> +			if (skinnydebug)
> +				ast_debug(1, "Channel %s set up for Blind Xfer, so Xfer rather  
> than ring device\n", ast->name);
> +			skinny_transfer(sub);
> +			break;
> +		}
> 		if (ast->_state != AST_STATE_UP) {
> 			if (!sub->progress) {
> 				if (!d->earlyrtp) {
> 					transmit_tone(s, SKINNY_ALERT, l->instance, sub->callid);
> 				}
> -				transmit_callstate(s, l->instance, SKINNY_RINGOUT, sub->callid);
> +				transmit_callstateonly(s, sub, SKINNY_RINGOUT);
> 				transmit_dialednumber(s, 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, exten,  
> exten, l->instance, sub->callid, 2); /* 2 = outgoing from phone */
> @@ -3719,7 +3924,7 @@
> 			if (!d->earlyrtp) {
> 				transmit_tone(s, SKINNY_BUSYTONE, l->instance, sub->callid);
> 			}
> -			transmit_callstate(s, l->instance, SKINNY_BUSY, sub->callid);
> +			transmit_callstateonly(s, sub, SKINNY_BUSY);
> 			sub->alreadygone = 1;
> 			ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
> 			if (!d->earlyrtp) {
> @@ -3732,7 +3937,7 @@
> 			if (!d->earlyrtp) {
> 				transmit_tone(s, SKINNY_REORDER, l->instance, sub->callid);
> 			}
> -			transmit_callstate(s, l->instance, SKINNY_CONGESTION, sub- 
> >callid);
> +			transmit_callstateonly(s, sub, SKINNY_CONGESTION);
> 			sub->alreadygone = 1;
> 			ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
> 			if (!d->earlyrtp) {
> @@ -3745,7 +3950,7 @@
> 			if (!d->earlyrtp) {
> 				transmit_tone(s, SKINNY_ALERT, l->instance, sub->callid);
> 			}
> -			transmit_callstate(s, l->instance, SKINNY_PROGRESS, sub->callid);
> +			transmit_callstateonly(s, sub, SKINNY_PROGRESS);
> 			transmit_displaypromptstatus(s, "Call Progress", 0, l->instance,  
> sub->callid);
> 			transmit_callinfo(s, ast->cid.cid_name, ast->cid.cid_num, exten,  
> exten, l->instance, sub->callid, 2); /* 2 = outgoing from phone */
> 			sub->progress = 1;
> @@ -3805,9 +4010,14 @@
> 			sub->nat = l->nat;
> 			sub->parent = l;
> 			sub->onhold = 0;
> +			sub->blindxfer = 0;
> +			sub->xferor = 0;
> +			sub->related = NULL;
> +
>
> 			sub->next = l->sub;
> 			l->sub = sub;
> +			l->activesub = sub;
> 		}
> 		tmp->tech = &skinny_tech;
> 		tmp->tech_pvt = sub;
> @@ -3880,7 +4090,6 @@
> 	struct skinny_line *l = sub->parent;
> 	struct skinny_device *d = l->parent;
> 	struct skinnysession *s = d->session;
> -	struct skinny_req *req;
>
> 	/* Don't try to hold a channel that doesn't exist */
> 	if (!sub || !sub->owner)
> @@ -3894,26 +4103,11 @@
> 		S_OR(l->mohsuggest, NULL),
> 		!ast_strlen_zero(l->mohsuggest) ? strlen(l->mohsuggest) + 1 : 0);
>
> -	if (!(req = req_alloc(sizeof(struct activate_call_plane_message),  
> ACTIVATE_CALL_PLANE_MESSAGE)))
> -		return 0;
> -
> -	req->data.activatecallplane.lineInstance = htolel(l->instance);
> -	transmit_response(s, req);
> -
> -	if (!(req = req_alloc(sizeof(struct  
> close_receive_channel_message), CLOSE_RECEIVE_CHANNEL_MESSAGE)))
> -		return 0;
> -
> -	req->data.closereceivechannel.conferenceId = htolel(sub->callid);
> -	req->data.closereceivechannel.partyId = htolel(sub->callid);
> -	transmit_response(s, req);
> -
> -	if (!(req = req_alloc(sizeof(struct  
> stop_media_transmission_message), STOP_MEDIA_TRANSMISSION_MESSAGE)))
> -		return 0;
> -
> -	req->data.stopmedia.conferenceId = htolel(sub->callid);
> -	req->data.stopmedia.passThruPartyId = htolel(sub->callid);
> -	transmit_response(s, req);
> -
> +	transmit_activatecallplane(s, l);
> +	transmit_closereceivechannel(s,sub);
> +	transmit_stopmediatransmission(s,sub);
> +
> +	transmit_callstateonly(s, sub, SKINNY_HOLD);
> 	transmit_lamp_indication(s, STIMULUS_LINE, l->instance,  
> SKINNY_LAMP_WINK);
> 	sub->onhold = 1;
> 	return 1;
> @@ -3924,7 +4118,6 @@
> 	struct skinny_line *l = sub->parent;
> 	struct skinny_device *d = l->parent;
> 	struct skinnysession *s = d->session;
> -	struct skinny_req *req;
>
> 	/* Don't try to unhold a channel that doesn't exist */
> 	if (!sub || !sub->owner)
> @@ -3936,16 +4129,96 @@
>
> 	ast_queue_control(sub->owner, AST_CONTROL_UNHOLD);
>
> -	if (!(req = req_alloc(sizeof(struct activate_call_plane_message),  
> ACTIVATE_CALL_PLANE_MESSAGE)))
> -		return 0;
> -
> -	req->data.activatecallplane.lineInstance = htolel(l->instance);
> -	transmit_response(s, req);
> +	transmit_activatecallplane(s, l);
>
> 	transmit_connect(s, sub);
> +	transmit_callstateonly(s, sub, SKINNY_CONNECTED);
> 	transmit_lamp_indication(s, STIMULUS_LINE, l->instance,  
> SKINNY_LAMP_ON);
> +	l->hookstate = SKINNY_OFFHOOK;
> 	sub->onhold = 0;
> 	return 1;
> +}
> +
> +static int handle_hold_button(struct skinny_subchannel *sub)
> +{
> +	if (!sub)
> +		return -1;
> +	if (sub->related) {
> +		skinny_hold(sub);
> +		skinny_unhold(sub->related);
> +		sub->parent->activesub = sub->related;
> +	} else {
> +		if (sub->onhold) {
> +			skinny_unhold(sub);
> +			transmit_selectsoftkeys(sub->parent->parent->session, sub- 
> >parent->instance, sub->callid, KEYDEF_CONNECTED);
> +		} else {
> +			skinny_hold(sub);
> +			transmit_selectsoftkeys(sub->parent->parent->session, sub- 
> >parent->instance, sub->callid, KEYDEF_ONHOLD);
> +		}
> +	}
> +	return 1;
> +}
> +
> +static int handle_transfer_button(struct skinny_subchannel *sub)
> +{
> +	struct skinny_line *l = sub->parent;
> +	struct skinny_device *d = l->parent;
> +	struct skinnysession *s = d->session;
> +	struct skinny_subchannel *newsub;
> +	struct ast_channel *c;
> +	pthread_t t;
> +
> +	if (!sub) {
> +		ast_verbose("Transfer: No subchannel to transfer\n");
> +		return -1;
> +	}
> +	if (!sub->related) {
> +		/* Another sub has not been created so this must be first XFER  
> press */
> +		if (!sub->onhold) {
> +			skinny_hold(sub);
> +		}
> +		c = skinny_new(l, AST_STATE_DOWN);
> +		if (c) {
> +			newsub = c->tech_pvt;
> +			/* point the sub and newsub at each other so we know they are  
> related */
> +			newsub->related = sub;
> +			sub->related = newsub;
> +			newsub->xferor = 1;
> +			l->activesub = newsub;
> +			transmit_callstate(s, l->instance, SKINNY_OFFHOOK, newsub- 
> >callid);
> +			if (skinnydebug)
> +				ast_debug(1, "Attempting to Clear display on Skinny %s@%s\n", l- 
> >name, d->name);
> +			transmit_displaymessage(s, NULL, l->instance, newsub->callid); / 
> * clear display */
> +			transmit_tone(s, SKINNY_DIALTONE, l->instance, newsub->callid);
> +			transmit_selectsoftkeys(s, l->instance, newsub->callid,  
> KEYDEF_OFFHOOKWITHFEAT);
> +			/* 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, d->name);
> +		}
> +	} else {
> +		/* We already have a related sub so we can either complete XFER  
> or go into BLINDXFER (or cancel BLINDXFER */
> +		if (sub->blindxfer) {
> +			/* toggle blindxfer off */
> +			sub->blindxfer = 0;
> +			sub->related->blindxfer = 0;
> +			/* we really need some indications */
> +		} else {
> +			/* We were doing attended transfer */
> +			if (sub->owner->_state == AST_STATE_DOWN || sub->related->owner- 
> >_state == AST_STATE_DOWN) {
> +				/* one of the subs so we cant transfer yet, toggle blindxfer on  
> */
> +				sub->blindxfer = 1;
> +				sub->related->blindxfer = 1;
> +			} else {
> +				/* big assumption we have two channels, lets transfer */
> +				skinny_transfer(sub);
> +			}
> +		}
> +	}
> +	return 0;
> }
>
> static int handle_keep_alive_message(struct skinny_req *req, struct  
> skinnysession *s)
> @@ -4084,7 +4357,8 @@
> 	if (lineInstance && callReference)
> 		sub = find_subchannel_by_instance_reference(d, lineInstance,  
> callReference);
> 	else
> -		sub = find_subchannel_by_instance_reference(d, d- 
> >lastlineinstance, d->lastcallreference);
> +		sub = d->activeline->activesub;
> +		//sub = find_subchannel_by_instance_reference(d, d- 
> >lastlineinstance, d->lastcallreference);
>
> 	if (!sub)
> 		return 0;
> @@ -4234,20 +4508,15 @@
> 	case STIMULUS_HOLD:
> 		if (skinnydebug)
> 			ast_verb(1, "Received Stimulus: Hold(%d/%d)\n", instance,  
> callreference);
> -
> -		if (!sub)
> -			break;
> -
> -		if (sub->onhold) {
> -			skinny_unhold(sub);
> -		} else {
> -			skinny_hold(sub);
> -		}
> +		handle_hold_button(sub);
> 		break;
> 	case STIMULUS_TRANSFER:
> 		if (skinnydebug)
> 			ast_verb(1, "Received Stimulus: Transfer(%d/%d)\n", instance,  
> callreference);
> -		/* XXX figure out how to transfer */
> +		if (l->transfer)
> +			handle_transfer_button(sub);
> +		else
> +			transmit_displaynotify(s, "Transfer disabled", 10);
> 		break;
> 	case STIMULUS_CONFERENCE:
> 		if (skinnydebug)
> @@ -4406,6 +4675,8 @@
> 			return 0;
> 		}
>
> +		d->activeline = l;
> +
> 		/* turn the speaker on */
> 		transmit_speaker_mode(s, SKINNY_SPEAKERON);
> 		transmit_ringer_mode(s, SKINNY_RING_OFF);
> @@ -4420,7 +4691,7 @@
> 			ast_queue_control(sub->owner, AST_CONTROL_ANSWER);
> 			transmit_callstate(s, l->instance, SKINNY_OFFHOOK, sub->callid);
> 			transmit_tone(s, SKINNY_SILENCE, l->instance, sub->callid);
> -			transmit_callstate(s, l->instance, SKINNY_CONNECTED, sub->callid);
> +			transmit_callstateonly(s, sub, SKINNY_CONNECTED);
> 			transmit_displaypromptstatus(s, "Connected", 0, l->instance, sub- 
> >callid);
> 			transmit_selectsoftkeys(s, l->instance, sub->callid,  
> KEYDEF_CONNECTED);
> 			start_rtp(sub);
> @@ -4466,22 +4737,40 @@
> 	struct skinny_line *l;
> 	struct skinny_subchannel *sub;
> 	struct ast_channel *c;
> +	struct skinny_line *tmp;
> 	pthread_t t;
> -	int unknown1;
> -	int unknown2;
> -
> -	unknown1 = letohl(req->data.offhook.unknown1);
> -	unknown2 = letohl(req->data.offhook.unknown2);
> -
> -	sub = find_subchannel_by_instance_reference(d, d- 
> >lastlineinstance, d->lastcallreference);
> -
> -	if (!sub) {
> -		l = find_line_by_instance(d, d->lastlineinstance);
> -		if (!l) {
> +	int instance;
> +	int reference;
> +
> +	/* if any line on a device is offhook, than the device must be  
> offhook,
> +	   unless we have shared lines CCM seems that it would never get  
> here,
> +	   but asterisk does, so we may need to do more work.  Ugly, we  
> should
> +	   probably move hookstate from line to device, afterall, it's  
> actually
> +	    a device that changes hookstates */
> +
> +	for (tmp = d->lines; tmp; tmp = tmp->next) {
> +		if (tmp->hookstate == SKINNY_OFFHOOK) {
> +			ast_verbose(VERBOSE_PREFIX_3 "Got offhook message when device  
> (%s@%s) already offhook\n", tmp->name, d->name);
> 			return 0;
> 		}
> +	}
> +
> +	instance = letohl(req->data.offhook.instance);
> +	reference = letohl(req->data.offhook.reference);
> +
> +	if (instance) {
> +		sub = find_subchannel_by_instance_reference(d, d- 
> >lastlineinstance, d->lastcallreference);
> +		if (!sub) {
> +			l = find_line_by_instance(d, d->lastlineinstance);
> +			if (!l) {
> +				return 0;
> +			}
> +		} else {
> +			l = sub->parent;
> +		}
> 	} else {
> -		l = sub->parent;
> +		l = d->activeline;
> +		sub = l->activesub;
> 	}
>
> 	transmit_ringer_mode(s, SKINNY_RING_OFF);
> @@ -4498,7 +4787,7 @@
> 	if (sub && sub->outgoing) {
> 		/* We're answering a ringing call */
> 		ast_queue_control(sub->owner, AST_CONTROL_ANSWER);
> -		transmit_callstate(s, l->instance, SKINNY_OFFHOOK, sub->callid);
> +		transmit_callstateonly(s, sub, SKINNY_CONNECTED);
> 		transmit_tone(s, SKINNY_SILENCE, l->instance, sub->callid);
> 		transmit_callstate(s, l->instance, SKINNY_CONNECTED, sub->callid);
> 		transmit_selectsoftkeys(s, l->instance, sub->callid,  
> KEYDEF_CONNECTED);
> @@ -4535,25 +4824,29 @@
> {
> 	struct skinny_device *d = s->device;
> 	struct skinny_line *l;
> -	struct skinny_subchannel *sub;
> -	int unknown1;
> -	int unknown2;
> -
> -	unknown1 = letohl(req->data.onhook.unknown1);
> -	unknown2 = letohl(req->data.onhook.unknown2);
> -
> -	sub = find_subchannel_by_instance_reference(d, d- 
> >lastlineinstance, d->lastcallreference);
> -
> -	if (!sub) {
> -		return 0;
> -	}
> -	l = sub->parent;
> +	struct skinny_subchannel *sub, *tmpsub;
> +	int instance;
> +	int reference;
> +	int onlysub = 0;
> +
> +	instance = letohl(req->data.onhook.instance);
> +	reference = letohl(req->data.onhook.reference);
> +
> +	if (instance && reference) {
> +		sub = find_subchannel_by_instance_reference(d, instance,  
> reference);
> +		if (!sub) {
> +			return 0;
> +		}
> +		l = sub->parent;
> +	} else {
> +		l = d->activeline;
> +		sub = l->activesub;
> +	}
>
> 	if (l->hookstate == SKINNY_ONHOOK) {
> 		/* Something else already put us back on hook */
> 		return 0;
> 	}
> -	l->hookstate = SKINNY_ONHOOK;
>
> 	ast_device_state_changed("Skinny/%s@%s", l->name, d->name);
>
> @@ -4561,28 +4854,39 @@
> 		return 0;
> 	}
>
> +	if (!l->sub->next) {
> +		onlysub = 1;
> +	} else {
> +		tmpsub = l->sub;
> +		while (tmpsub->next){
> +			if ((sub == tmpsub->next) && sub->next) {
> +				tmpsub->next = sub->next;
> +				break;
> +			}
> +			tmpsub = tmpsub->next;
> +		}
> +	}
> +
> 	sub->cxmode = SKINNY_CX_RECVONLY;
> +	if (onlysub || sub->xferor){  /* is this the only call to this  
> device? */
> +		l->hookstate = SKINNY_ONHOOK;
> +		if (skinnydebug)
> +			ast_debug(1, "Skinny %s@%s-%d went on hook\n", l->name, d->name,  
> reference);
> +	}
> +
> 	transmit_callstate(s, l->instance, l->hookstate, sub->callid);
> -	if (skinnydebug)
> -		ast_verb(1, "Skinny %s@%s went on hook\n", l->name, d->name);
> -	if (l->transfer && (sub->owner && sub->next && sub->next->owner)  
> && ((!sub->outgoing) || (sub->next && !sub->next->outgoing))) {
> +	if (l->transfer && sub->xferor && sub->owner->_state >=  
> AST_STATE_RING) {
> 		/* 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 (sub->next && sub->next->owner) {
> -				sub->next->alreadygone = 1;
> -				ast_queue_hangup(sub->next->owner);
> -			}
> -		} else if (res) {
> -			ast_log(LOG_WARNING, "Transfer attempt failed\n");
> -			return 0;
> -		}
> -#endif
> +		handle_transfer_button(sub);
> 	} else {
> 		/* Hangup the current call */
> 		/* If there is another active call, skinny_hangup will ring the  
> phone with the other call */
> +		if (sub->xferor && sub->related){
> +			sub->related->related = NULL;
> +			sub->related->blindxfer = 0;
> +		}
> +
> 		if (sub->owner) {
> 			sub->alreadygone = 1;
> 			ast_queue_hangup(sub->owner);
> @@ -5171,20 +5475,16 @@
> 	case SOFTKEY_HOLD:
> 		if (skinnydebug)
> 			ast_verb(1, "Received Softkey Event: Hold(%d/%d)\n", instance,  
> callreference);
> -
> -		if (sub) {
> -			if (sub->onhold) {
> -				skinny_unhold(sub);
> -			} else {
> -				skinny_hold(sub);
> -			}
> -		}
> -				
> +		handle_hold_button(sub);	
> 		break;
> 	case SOFTKEY_TRNSFER:
> 		if (skinnydebug)
> 			ast_verb(1, "Received Softkey Event: Transfer(%d/%d)\n",  
> instance, callreference);
> -		/* XXX figure out how to transfer */
> +		if (l->transfer)
> +			handle_transfer_button(sub);
> +		else
> +			transmit_displaynotify(s, "Transfer disabled", 10);
> +
> 		break;
> 	case SOFTKEY_DND:
> 		if (skinnydebug)
> @@ -5269,29 +5569,44 @@
> 			break;
> 		}
> 		if (sub) {
> +			int onlysub = 0;
> +			struct skinny_subchannel *tmpsub;
> +
> +			if (!l->sub->next) {
> +				onlysub = 1;
> +			} else {
> +				tmpsub = l->sub;
> +				while (tmpsub->next){
> +					if ((sub == tmpsub->next) && sub->next) {
> +						tmpsub->next = sub->next;
> +						break;
> +					}
> +					tmpsub = tmpsub->next;
> +				}
> +			}
> +
> 			sub->cxmode = SKINNY_CX_RECVONLY;
> -			l->hookstate = SKINNY_ONHOOK;
> +			if (onlysub || sub->xferor){    /*Are there other calls to this  
> device */
> +				l->hookstate = SKINNY_ONHOOK;
> +				if (skinnydebug)
> +					ast_debug(1, "Skinny %s@%s-%d went on hook\n", l->name, d- 
> >name, callreference);
> +			}
> +
> 			transmit_callstate(s, l->instance, l->hookstate, sub->callid);
> 			if (skinnydebug)
> 				ast_verb(1, "Skinny %s@%s went on hook\n", l->name, d->name);
> -			if (l->transfer && (sub->owner && sub->next && sub->next->owner)  
> && ((!sub->outgoing) || (sub->next && !sub->next->outgoing))) {
> +			if (l->transfer && sub->xferor && sub->owner->_state >=  
> AST_STATE_RING) {
> 				/* 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 (sub->next && sub->next->owner) {
> -						sub->next->alreadygone = 1;
> -						ast_queue_hangup(sub->next->owner);
> -					}
> -				} else if (res) {
> -					ast_log(LOG_WARNING, "Transfer attempt failed\n");
> -					break;
> -				}
> -#endif
> +				handle_transfer_button(sub);
> 			} else {
> 				/* Hangup the current call */
> 				/* If there is another active call, skinny_hangup will ring the  
> phone with the other call */
> +				if (sub->xferor && sub->related){
> +					sub->related->related = NULL;
> +					sub->related->blindxfer = 0;
> +				}
> +
> 				if (sub->owner) {
> 					sub->alreadygone = 1;
> 					ast_queue_hangup(sub->owner);
> @@ -5308,6 +5623,17 @@
> 	case SOFTKEY_RESUME:
> 		if (skinnydebug)
> 			ast_verb(1, "Received Softkey Event: Resume(%d/%d)\n", instance,  
> callreference);
> +
> +		if (sub) {
> +			if (sub->onhold) {
> +				skinny_unhold(sub);
> +				transmit_selectsoftkeys(s, l->instance, sub->callid,  
> KEYDEF_CONNECTED);
> +			} else {
> +				skinny_hold(sub);
> +				transmit_selectsoftkeys(s, l->instance, sub->callid,  
> KEYDEF_ONHOLD);
> +			}
> +		}
> +
> 		break;
> 	case SOFTKEY_ANSWER:
> 		if (skinnydebug)
> @@ -5323,7 +5649,7 @@
> 			ast_queue_control(sub->owner, AST_CONTROL_ANSWER);
> 			transmit_callstate(s, l->instance, SKINNY_OFFHOOK, sub->callid);
> 			transmit_tone(s, SKINNY_SILENCE, l->instance, sub->callid);
> -			transmit_callstate(s, l->instance, SKINNY_CONNECTED, sub->callid);
> +			transmit_callstateonly(s, sub, SKINNY_CONNECTED);
> 			transmit_selectsoftkeys(s, l->instance, sub->callid,  
> KEYDEF_CONNECTED);
> 			start_rtp(sub);
> 			ast_setstate(sub->owner, AST_STATE_UP);
> @@ -5454,9 +5780,13 @@
> 		lineInstance = letohl(req->data.keypad.lineInstance);
> 		callReference = letohl(req->data.keypad.callReference);
>
> -		sub = find_subchannel_by_instance_reference(d, lineInstance,  
> callReference);
> -
> -		if (sub && (sub->owner && sub->owner->_state <  AST_STATE_UP)) {
> +		if (lineInstance) {
> +			sub = find_subchannel_by_instance_reference(d, lineInstance,  
> callReference);
> +		} else {
> +			sub = d->activeline->activesub;
> +		}
> +
> +		if (sub && ((sub->owner && sub->owner->_state <  AST_STATE_UP) ||  
> sub->onhold)) {
> 			char dgt;
> 			int digit = letohl(req->data.keypad.button);
>
>
>
> _______________________________________________
> --Bandwidth and Colocation Provided by http://www.api-digital.com--
>
> svn-commits mailing list
> To UNSUBSCRIBE or update options visit:
>   http://lists.digium.com/mailman/listinfo/svn-commits

--
Russell Bryant
Senior Software Engineer
Open Source Team Lead
Digium, Inc.







More information about the asterisk-dev mailing list