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

Dan Austin Dan_Austin at Phoenix.com
Fri Jun 27 12:16:39 CDT 2008


Russell wrote:
> 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.

Yes!

I have been looking at this for awhile, and fully agree.
I tried to see if there were any pointers about doing
the conversion, but I did not find anything.  I am willing
to tackle it, and it would help if I had an idea how to
start

Thanks,
Dan


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.





_______________________________________________
--Bandwidth and Colocation Provided by http://www.api-digital.com--

AstriCon 2008 - September 22 - 25 Phoenix, Arizona
Register Now: http://www.astricon.net

asterisk-dev mailing list
To UNSUBSCRIBE or update options visit:
   http://lists.digium.com/mailman/listinfo/asterisk-dev



More information about the asterisk-dev mailing list