]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
Consolidate setsubstate_* into setsubstate and use a switch.
authorDamien Wedhorn <voip@facts.com.au>
Thu, 12 May 2011 20:44:21 +0000 (20:44 +0000)
committerDamien Wedhorn <voip@facts.com.au>
Thu, 12 May 2011 20:44:21 +0000 (20:44 +0000)
Consolidate the functions and add some debugging info. Allows to be
able to set a substate without explicitly knowing what the state is.

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@318635 65c4cc65-6c06-0410-ace0-fbb531ad65f3

channels/chan_skinny.c

index 77d509949f42b7d1f68d00c87a74528b43fcaba2..db367b14498a3ed3b29513f6576c5d63a03c51a0 100644 (file)
@@ -1204,6 +1204,7 @@ struct skinny_subchannel {
        struct ast_rtp_instance *rtp;
        struct ast_rtp_instance *vrtp;
        unsigned int callid;
+       char exten[AST_MAX_EXTENSION];
        /* time_t lastouttime; */ /* Unused */
        int progress;
        int ringing;
@@ -1407,15 +1408,7 @@ static int skinny_senddigit_end(struct ast_channel *ast, char digit, unsigned in
 static void mwi_event_cb(const struct ast_event *event, void *userdata);
 static int skinny_reload(void);
 
-static void setsubstate_dialing(struct skinny_subchannel *sub, char exten[AST_MAX_EXTENSION]);
-static void setsubstate_ringin(struct skinny_subchannel *sub);
-static void setsubstate_callwait(struct skinny_subchannel *sub);
-static void setsubstate_ringout(struct skinny_subchannel *sub);
-static void setsubstate_connected(struct skinny_subchannel *sub);
-static void setsubstate_busy(struct skinny_subchannel *sub);
-static void setsubstate_congestion(struct skinny_subchannel *sub);
-static void setsubstate_progress(struct skinny_subchannel *sub);
-static void setsubstate_hold(struct skinny_subchannel *sub);
+static void setsubstate(struct skinny_subchannel *sub, int state);
 static void dumpsub(struct skinny_subchannel *sub, int forcehangup);
 
 static struct ast_channel_tech skinny_tech = {
@@ -3999,7 +3992,8 @@ static void *skinny_ss(void *data)
                                        }
                                        return NULL;
                                } else {
-                                       setsubstate_dialing(c->tech_pvt, d->exten);
+                                       ast_copy_string(sub->exten, d->exten, sizeof(sub->exten));
+                                       setsubstate(c->tech_pvt, SUBSTATE_DIALING);
                                        return NULL;
                                }
                        } else {
@@ -4077,7 +4071,7 @@ static int skinny_call(struct ast_channel *ast, char *dest, int timeout)
                return -1;
        }
        
-       setsubstate_ringin(sub);
+       setsubstate(sub, SUBSTATE_RINGIN);
        return res;
 }
 
@@ -4093,7 +4087,7 @@ static int skinny_hangup(struct ast_channel *ast)
        dumpsub(sub, 1);
 
        if (skinnydebug)
-               ast_verb(3,"Destroying subchannel %d\n", sub->callid);
+               ast_verb(3,"Sub %d - Destroying\n", sub->callid);
 
        ast_mutex_lock(&sub->lock);
        sub->owner = NULL;
@@ -4129,7 +4123,7 @@ static int skinny_answer(struct ast_channel *ast)
        if (skinnydebug)
                ast_verb(1, "skinny_answer(%s) on %s@%s-%d\n", ast->name, l->name, d->name, sub->callid);
        
-       setsubstate_connected(sub);
+       setsubstate(sub, SUBSTATE_CONNECTED);
 
        return res;
 }
@@ -4436,16 +4430,16 @@ static int skinny_indicate(struct ast_channel *ast, int ind, const void *data, s
                        skinny_transfer(sub);
                        break;
                }
-               setsubstate_ringout(sub);
+               setsubstate(sub, SUBSTATE_RINGOUT);
                return (d->earlyrtp ? -1 : 0); /* Tell asterisk to provide inband signalling if rtp started */
        case AST_CONTROL_BUSY:
-               setsubstate_busy(sub);
+               setsubstate(sub, SUBSTATE_BUSY);
                return (d->earlyrtp ? -1 : 0); /* Tell asterisk to provide inband signalling if rtp started */
        case AST_CONTROL_CONGESTION:
-               setsubstate_congestion(sub);
+               setsubstate(sub, SUBSTATE_CONGESTION);
                return (d->earlyrtp ? -1 : 0); /* Tell asterisk to provide inband signalling if rtp started */
        case AST_CONTROL_PROGRESS:
-               setsubstate_progress(sub);
+               setsubstate(sub, SUBSTATE_PROGRESS);
                return (d->earlyrtp ? -1 : 0); /* Tell asterisk to provide inband signalling if rtp started */
        case -1:  /* STOP_TONE */
                transmit_stop_tone(d, l->instance, sub->callid);
@@ -4595,6 +4589,8 @@ static char *substate2str(int ind) {
        char *tmp;
 
        switch (ind) {
+       case SUBSTATE_UNSET:
+               return "SUBSTATE_UNSET";
        case SUBSTATE_OFFHOOK:
                return "SUBSTATE_OFFHOOK";
        case SUBSTATE_ONHOOK:
@@ -4625,288 +4621,249 @@ static char *substate2str(int ind) {
        }
 }
 
-static void setsubstate_offhook(struct skinny_subchannel *sub)
+static void setsubstate(struct skinny_subchannel *sub, int state)
 {
        struct skinny_line *l = sub->line;
        struct skinny_device *d = l->device;
+       struct ast_channel *c = sub->owner;
        pthread_t t;
+       int actualstate = state;
 
-       ast_verb(1, "Call-id: %d\n", sub->callid);
-       l->activesub = sub;
-       if (d->hookstate == SKINNY_ONHOOK) {
-               d->hookstate = SKINNY_OFFHOOK;
-               transmit_speaker_mode(d, SKINNY_SPEAKERON);
+       if (sub->substate == SUBSTATE_ONHOOK) {
+               return;
        }
-       transmit_callstate(d, l->instance, sub->callid, SKINNY_OFFHOOK);
-       transmit_activatecallplane(d, l);
-       transmit_clear_display_message(d, l->instance, sub->callid);
-       transmit_start_tone(d, SKINNY_DIALTONE, l->instance, sub->callid);
-       transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_OFFHOOK);
-
-       sub->substate = SUBSTATE_OFFHOOK;
        
-       /* start the switch thread */
-       if (ast_pthread_create(&t, NULL, skinny_ss, sub->owner)) {
-               ast_log(LOG_WARNING, "Unable to create switch thread: %s\n", strerror(errno));
-               ast_hangup(sub->owner);
-       }
-}
-
-static void setsubstate_onhook(struct skinny_subchannel *sub)
-{
-       struct skinny_line *l = sub->line;
-       struct skinny_device *d = l->device;
-
-       AST_LIST_REMOVE(&l->sub, sub, list);
-       if (sub->related) {
-               sub->related->related = NULL;
+       if ((state == SUBSTATE_RINGIN) && (AST_LIST_NEXT(AST_LIST_FIRST(&l->sub), list))) {
+               actualstate = SUBSTATE_CALLWAIT;
        }
        
-       if (sub == l->activesub) {
-               l->activesub = NULL;
-               transmit_closereceivechannel(d, sub);
-               transmit_stopmediatransmission(d, sub);
-               transmit_stop_tone(d, l->instance, sub->callid);
-               transmit_callstate(d, l->instance, sub->callid, SKINNY_ONHOOK);
-               transmit_clearpromptmessage(d, l->instance, sub->callid);
-               transmit_ringer_mode(d, SKINNY_RING_OFF);
-               d->hookstate = SKINNY_ONHOOK;
-               transmit_speaker_mode(d, SKINNY_SPEAKEROFF); 
-               transmit_definetimedate(d); 
-               transmit_lamp_indication(d, STIMULUS_LINE, l->instance, SKINNY_LAMP_OFF);
-       } else {
-               transmit_stop_tone(d, l->instance, sub->callid);
-               transmit_callstate(d, l->instance, sub->callid, SKINNY_ONHOOK);
-               transmit_clearpromptmessage(d, l->instance, sub->callid);
-       }
-
-       sub->cxmode = SKINNY_CX_RECVONLY;       
-       sub->substate = SUBSTATE_ONHOOK;
-       if (sub->rtp) {
-               ast_rtp_instance_destroy(sub->rtp);
-               sub->rtp = NULL;
-       }
-       if (sub->owner) {
-               ast_queue_hangup(sub->owner);
+       if (skinnydebug) {
+               ast_verb(3, "Sub %d - change state from %s to %s\n", sub->callid, substate2str(sub->substate), substate2str(actualstate));
        }
-}
 
-static void setsubstate_dialing(struct skinny_subchannel *sub, char exten[AST_MAX_EXTENSION])
-{
-       struct skinny_line *l = sub->line;
-       struct skinny_device *d = l->device;
-       struct ast_channel *c = sub->owner;
-       pthread_t t;
-       
-       if (ast_strlen_zero(exten) || !ast_exists_extension(c, c->context, exten, 1, l->cid_num)) {
-               ast_log(LOG_WARNING, "Exten (%s) does not exist, unable to set substate DIALING on sub %d\n", exten, sub->callid);
+       if (actualstate == sub->substate) {
+               transmit_callinfo(sub);
+               transmit_callstate(d, l->instance, sub->callid, SKINNY_HOLD);
                return;
        }
 
-       if (d->hookstate == SKINNY_ONHOOK) {
-               d->hookstate = SKINNY_OFFHOOK;
-               transmit_speaker_mode(d, SKINNY_SPEAKERON);
+       switch (actualstate) {
+       case SUBSTATE_OFFHOOK:
+               ast_verb(1, "Call-id: %d\n", sub->callid);
+               l->activesub = sub;
+               if (d->hookstate == SKINNY_ONHOOK) {
+                       d->hookstate = SKINNY_OFFHOOK;
+                       transmit_speaker_mode(d, SKINNY_SPEAKERON);
+               }
                transmit_callstate(d, l->instance, sub->callid, SKINNY_OFFHOOK);
                transmit_activatecallplane(d, l);
-       }
-       transmit_stop_tone(d, l->instance, sub->callid);
-       transmit_clear_display_message(d, l->instance, sub->callid);
-       transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_RINGOUT);
-
-       ast_copy_string(c->exten, exten, sizeof(c->exten));
-       ast_copy_string(l->lastnumberdialed, exten, sizeof(l->lastnumberdialed));
-       memset(d->exten, 0, sizeof(d->exten));
-
-       sub->substate = SUBSTATE_DIALING;
-       
-       if (ast_pthread_create(&t, NULL, skinny_newcall, c)) {
-               ast_log(LOG_WARNING, "Unable to create new call thread: %s\n", strerror(errno));
-               ast_hangup(c);
-       }
-}
+               transmit_clear_display_message(d, l->instance, sub->callid);
+               transmit_start_tone(d, SKINNY_DIALTONE, l->instance, sub->callid);
+               transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_OFFHOOK);
 
-static void setsubstate_ringout(struct skinny_subchannel *sub)
-{
-       struct skinny_line *l = sub->line;
-       struct skinny_device *d = l->device;
-
-       if (!(sub->substate == SUBSTATE_DIALING || sub->substate == SUBSTATE_PROGRESS)) {
-               ast_log(LOG_WARNING, "Cannot set substate to SUBSTATE_RINGOUT from %s (on call-%d)\n", substate2str(sub->substate), sub->callid);
-               return;
-       }
+               sub->substate = SUBSTATE_OFFHOOK;
        
-       if (!d->earlyrtp) {
-               transmit_start_tone(d, SKINNY_ALERT, l->instance, sub->callid);
-       }
-       transmit_callstate(d, l->instance, sub->callid, SKINNY_RINGOUT);
-       transmit_dialednumber(d, l->lastnumberdialed, l->instance, sub->callid);
-       transmit_displaypromptstatus(d, "Ring Out", 0, l->instance, sub->callid);
-       transmit_callinfo(sub);
-       sub->substate = SUBSTATE_RINGOUT;
-}
+               /* start the switch thread */
+               if (ast_pthread_create(&t, NULL, skinny_ss, sub->owner)) {
+                       ast_log(LOG_WARNING, "Unable to create switch thread: %s\n", strerror(errno));
+                       ast_hangup(sub->owner);
+               }
+               break;
+       case SUBSTATE_ONHOOK:
+               AST_LIST_REMOVE(&l->sub, sub, list);
+               if (sub->related) {
+                       sub->related->related = NULL;
+               }
 
-static void setsubstate_ringin(struct skinny_subchannel *sub)
-{
-       struct skinny_line *l = sub->line;
-       struct skinny_device *d = l->device;
-       struct ast_channel *c = sub->owner;
+               if (sub == l->activesub) {
+                       l->activesub = NULL;
+                       transmit_closereceivechannel(d, sub);
+                       transmit_stopmediatransmission(d, sub);
+                       transmit_stop_tone(d, l->instance, sub->callid);
+                       transmit_callstate(d, l->instance, sub->callid, SKINNY_ONHOOK);
+                       transmit_clearpromptmessage(d, l->instance, sub->callid);
+                       transmit_ringer_mode(d, SKINNY_RING_OFF);
+                       d->hookstate = SKINNY_ONHOOK;
+                       transmit_speaker_mode(d, SKINNY_SPEAKEROFF); 
+                       transmit_definetimedate(d); 
+                       transmit_lamp_indication(d, STIMULUS_LINE, l->instance, SKINNY_LAMP_OFF);
+               } else {
+                       transmit_stop_tone(d, l->instance, sub->callid);
+                       transmit_callstate(d, l->instance, sub->callid, SKINNY_ONHOOK);
+                       transmit_clearpromptmessage(d, l->instance, sub->callid);
+               }
 
-       if ((AST_LIST_NEXT(AST_LIST_FIRST(&l->sub), list)) && (d->hookstate == SKINNY_OFFHOOK)) {
-               setsubstate_callwait(sub);
-               return;
-       }
-       
-       transmit_callstate(d, l->instance, sub->callid, SKINNY_RINGIN);
-       transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_RINGIN);
-       transmit_displaypromptstatus(d, "Ring-In", 0, l->instance, sub->callid);
-       transmit_callinfo(sub);
-       transmit_lamp_indication(d, STIMULUS_LINE, l->instance, SKINNY_LAMP_BLINK);
-       transmit_ringer_mode(d, SKINNY_RING_INSIDE);
+               sub->cxmode = SKINNY_CX_RECVONLY;       
+               sub->substate = SUBSTATE_ONHOOK;
+               if (sub->rtp) {
+                       ast_rtp_instance_destroy(sub->rtp);
+                       sub->rtp = NULL;
+               }
+               if (sub->owner) {
+                       ast_queue_hangup(sub->owner);
+               }
+               break;
+       case SUBSTATE_DIALING:
+               if (ast_strlen_zero(sub->exten) || !ast_exists_extension(c, c->context, sub->exten, 1, l->cid_num)) {
+                       ast_log(LOG_WARNING, "Exten (%s) does not exist, unable to set substate DIALING on sub %d\n", sub->exten, sub->callid);
+                       return;
+               }
 
-       if (d->hookstate == SKINNY_ONHOOK) {
-               l->activesub = sub;
-       }
-       
-       if (sub->substate != SUBSTATE_RINGIN || sub->substate != SUBSTATE_CALLWAIT) {
-               ast_setstate(c, AST_STATE_RINGING);
-               ast_queue_control(c, AST_CONTROL_RINGING);
-       }
-       sub->substate = SUBSTATE_RINGIN;
-}
+               if (d->hookstate == SKINNY_ONHOOK) {
+                       d->hookstate = SKINNY_OFFHOOK;
+                       transmit_speaker_mode(d, SKINNY_SPEAKERON);
+                       transmit_callstate(d, l->instance, sub->callid, SKINNY_OFFHOOK);
+                       transmit_activatecallplane(d, l);
+               }
+               transmit_stop_tone(d, l->instance, sub->callid);
+               transmit_clear_display_message(d, l->instance, sub->callid);
+               transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_RINGOUT);
 
-static void setsubstate_callwait(struct skinny_subchannel *sub)
-{
-       struct skinny_line *l = sub->line;
-       struct skinny_device *d = l->device;
-       struct ast_channel *c = sub->owner;
+               ast_copy_string(c->exten, sub->exten, sizeof(c->exten));
+               ast_copy_string(l->lastnumberdialed, sub->exten, sizeof(l->lastnumberdialed));
+               memset(d->exten, 0, sizeof(d->exten));
 
-       transmit_callstate(d, l->instance, sub->callid, SKINNY_CALLWAIT);
-       transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_RINGIN);
-       transmit_displaypromptstatus(d, "Callwaiting", 0, l->instance, sub->callid);
-       transmit_callinfo(sub);
-       transmit_lamp_indication(d, STIMULUS_LINE, l->instance, SKINNY_LAMP_BLINK);
-       transmit_start_tone(d, SKINNY_CALLWAITTONE, l->instance, sub->callid);
+               sub->substate = SUBSTATE_DIALING;
        
-       ast_setstate(c, AST_STATE_RINGING);
-       ast_queue_control(c, AST_CONTROL_RINGING);
-       sub->substate = SUBSTATE_CALLWAIT;
-}
-
-static void setsubstate_connected(struct skinny_subchannel *sub)
-{
-       struct skinny_line *l = sub->line;
-       struct skinny_device *d = l->device;
+               if (ast_pthread_create(&t, NULL, skinny_newcall, c)) {
+                       ast_log(LOG_WARNING, "Unable to create new call thread: %s\n", strerror(errno));
+                       ast_hangup(c);
+               }
+               break;
+       case SUBSTATE_RINGOUT:
+               if (!(sub->substate == SUBSTATE_DIALING || sub->substate == SUBSTATE_PROGRESS)) {
+                       ast_log(LOG_WARNING, "Cannot set substate to SUBSTATE_RINGOUT from %s (on call-%d)\n", substate2str(sub->substate), sub->callid);
+                       return;
+               }
        
-       if (sub->substate == SUBSTATE_HOLD) {
-               ast_queue_control(sub->owner, AST_CONTROL_UNHOLD);
-               transmit_connect(d, sub);
-       }
-       transmit_activatecallplane(d, l);
-       transmit_stop_tone(d, l->instance, sub->callid);
-       transmit_callinfo(sub);
-       transmit_callstate(d, l->instance, sub->callid, SKINNY_CONNECTED);
-       transmit_displaypromptstatus(d, "Connected", 0, l->instance, sub->callid);
-       transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_CONNECTED);
-       if (!sub->rtp) {
-               start_rtp(sub);
-       }
-       if (sub->substate == SUBSTATE_RINGIN || sub->substate == SUBSTATE_CALLWAIT) {
-               ast_queue_control(sub->owner, AST_CONTROL_ANSWER);
-       }
-       if (sub->substate == SUBSTATE_DIALING || sub->substate == SUBSTATE_RINGOUT) {
+               if (!d->earlyrtp) {
+                       transmit_start_tone(d, SKINNY_ALERT, l->instance, sub->callid);
+               }
+               transmit_callstate(d, l->instance, sub->callid, SKINNY_RINGOUT);
                transmit_dialednumber(d, l->lastnumberdialed, l->instance, sub->callid);
-       }
-       if (sub->owner->_state != AST_STATE_UP) {
-               ast_setstate(sub->owner, AST_STATE_UP);
-       }
-       sub->substate = SUBSTATE_CONNECTED;
-       l->activesub = sub;
-}
-
-static void setsubstate_busy(struct skinny_subchannel *sub)
-{
-       struct skinny_line *l = sub->line;
-       struct skinny_device *d = l->device;
+               transmit_displaypromptstatus(d, "Ring Out", 0, l->instance, sub->callid);
+               transmit_callinfo(sub);
+               sub->substate = SUBSTATE_RINGOUT;
+               break;
+       case SUBSTATE_RINGIN:
+               transmit_callstate(d, l->instance, sub->callid, SKINNY_RINGIN);
+               transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_RINGIN);
+               transmit_displaypromptstatus(d, "Ring-In", 0, l->instance, sub->callid);
+               transmit_callinfo(sub);
+               transmit_lamp_indication(d, STIMULUS_LINE, l->instance, SKINNY_LAMP_BLINK);
+               transmit_ringer_mode(d, SKINNY_RING_INSIDE);
 
-       if (!(sub->substate == SUBSTATE_DIALING || sub->substate == SUBSTATE_PROGRESS || sub->substate == SUBSTATE_RINGOUT)) {
-               ast_log(LOG_WARNING, "Cannot set substate to SUBSTATE_BUSY from %s (on call-%d)\n", substate2str(sub->substate), sub->callid);
-               return;
-       }
+               if (d->hookstate == SKINNY_ONHOOK) {
+                       l->activesub = sub;
+               }
        
-       if (!d->earlyrtp) {
-               transmit_start_tone(d, SKINNY_BUSYTONE, l->instance, sub->callid);
-       }
-       transmit_callinfo(sub);
-       transmit_callstate(d, l->instance, sub->callid, SKINNY_BUSY);
-       transmit_displaypromptstatus(d, "Busy", 0, l->instance, sub->callid);
-       sub->substate = SUBSTATE_BUSY;
-}
-
-static void setsubstate_congestion(struct skinny_subchannel *sub)
-{
-       struct skinny_line *l = sub->line;
-       struct skinny_device *d = l->device;
-
-       if (!(sub->substate == SUBSTATE_DIALING || sub->substate == SUBSTATE_PROGRESS || sub->substate == SUBSTATE_RINGOUT)) {
-               ast_log(LOG_WARNING, "Cannot set substate to SUBSTATE_CONGESTION from %s (on call-%d)\n", substate2str(sub->substate), sub->callid);
-               return;
-       }
+               if (sub->substate != SUBSTATE_RINGIN || sub->substate != SUBSTATE_CALLWAIT) {
+                       ast_setstate(c, AST_STATE_RINGING);
+                       ast_queue_control(c, AST_CONTROL_RINGING);
+               }
+               sub->substate = SUBSTATE_RINGIN;
+               break;
+       case SUBSTATE_CALLWAIT:
+               transmit_callstate(d, l->instance, sub->callid, SKINNY_CALLWAIT);
+               transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_RINGIN);
+               transmit_displaypromptstatus(d, "Callwaiting", 0, l->instance, sub->callid);
+               transmit_callinfo(sub);
+               transmit_lamp_indication(d, STIMULUS_LINE, l->instance, SKINNY_LAMP_BLINK);
+               transmit_start_tone(d, SKINNY_CALLWAITTONE, l->instance, sub->callid);
        
-       if (!d->earlyrtp) {
-               transmit_start_tone(d, SKINNY_REORDER, l->instance, sub->callid);
-       }
-       transmit_callinfo(sub);
-       transmit_callstate(d, l->instance, sub->callid, SKINNY_CONGESTION);
-       transmit_displaypromptstatus(d, "Congestion", 0, l->instance, sub->callid);
-       sub->substate = SUBSTATE_CONGESTION;
-}
+               ast_setstate(c, AST_STATE_RINGING);
+               ast_queue_control(c, AST_CONTROL_RINGING);
+               sub->substate = SUBSTATE_CALLWAIT;
+               break;
+       case SUBSTATE_CONNECTED:
+               if (sub->substate == SUBSTATE_HOLD) {
+                       ast_queue_control(sub->owner, AST_CONTROL_UNHOLD);
+                       transmit_connect(d, sub);
+               }
+               transmit_activatecallplane(d, l);
+               transmit_stop_tone(d, l->instance, sub->callid);
+               transmit_callinfo(sub);
+               transmit_callstate(d, l->instance, sub->callid, SKINNY_CONNECTED);
+               transmit_displaypromptstatus(d, "Connected", 0, l->instance, sub->callid);
+               transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_CONNECTED);
+               if (!sub->rtp) {
+                       start_rtp(sub);
+               }
+               if (sub->substate == SUBSTATE_RINGIN || sub->substate == SUBSTATE_CALLWAIT) {
+                       ast_queue_control(sub->owner, AST_CONTROL_ANSWER);
+               }
+               if (sub->substate == SUBSTATE_DIALING || sub->substate == SUBSTATE_RINGOUT) {
+                       transmit_dialednumber(d, l->lastnumberdialed, l->instance, sub->callid);
+               }
+               if (sub->owner->_state != AST_STATE_UP) {
+                       ast_setstate(sub->owner, AST_STATE_UP);
+               }
+               sub->substate = SUBSTATE_CONNECTED;
+               l->activesub = sub;
+               break;
+       case SUBSTATE_BUSY:
+               if (!(sub->substate == SUBSTATE_DIALING || sub->substate == SUBSTATE_PROGRESS || sub->substate == SUBSTATE_RINGOUT)) {
+                       ast_log(LOG_WARNING, "Cannot set substate to SUBSTATE_BUSY from %s (on call-%d)\n", substate2str(sub->substate), sub->callid);
+                       return;
+               }
 
-static void setsubstate_progress(struct skinny_subchannel *sub)
-{
-       struct skinny_line *l = sub->line;
-       struct skinny_device *d = l->device;
+               if (!d->earlyrtp) {
+                       transmit_start_tone(d, SKINNY_BUSYTONE, l->instance, sub->callid);
+               }
+               transmit_callinfo(sub);
+               transmit_callstate(d, l->instance, sub->callid, SKINNY_BUSY);
+               transmit_displaypromptstatus(d, "Busy", 0, l->instance, sub->callid);
+               sub->substate = SUBSTATE_BUSY;
+               break;
+       case SUBSTATE_CONGESTION:
+               if (!(sub->substate == SUBSTATE_DIALING || sub->substate == SUBSTATE_PROGRESS || sub->substate == SUBSTATE_RINGOUT)) {
+                       ast_log(LOG_WARNING, "Cannot set substate to SUBSTATE_CONGESTION from %s (on call-%d)\n", substate2str(sub->substate), sub->callid);
+                       return;
+               }
 
-       if (sub->substate != SUBSTATE_DIALING) {
-               ast_log(LOG_WARNING, "Cannot set substate to SUBSTATE_PROGRESS from %s (on call-%d)\n", substate2str(sub->substate), sub->callid);
-               return;
-       }
-       
-       if (!d->earlyrtp) {
-               transmit_start_tone(d, SKINNY_ALERT, l->instance, sub->callid);
-       }
-       transmit_callinfo(sub);
-       transmit_callstate(d, l->instance, sub->callid, SKINNY_PROGRESS);
-       transmit_displaypromptstatus(d, "Call Progress", 0, l->instance, sub->callid);
-       sub->substate = SUBSTATE_PROGRESS;
-}
+               if (!d->earlyrtp) {
+                       transmit_start_tone(d, SKINNY_REORDER, l->instance, sub->callid);
+               }
+               transmit_callinfo(sub);
+               transmit_callstate(d, l->instance, sub->callid, SKINNY_CONGESTION);
+               transmit_displaypromptstatus(d, "Congestion", 0, l->instance, sub->callid);
+               sub->substate = SUBSTATE_CONGESTION;
+               break;
+       case SUBSTATE_PROGRESS:
+               if (sub->substate != SUBSTATE_DIALING) {
+                       ast_log(LOG_WARNING, "Cannot set substate to SUBSTATE_PROGRESS from %s (on call-%d)\n", substate2str(sub->substate), sub->callid);
+                       return;
+               }
 
-static void setsubstate_hold(struct skinny_subchannel *sub)
-{
-       struct skinny_line *l = sub->line;
-       struct skinny_device *d = l->device;
+               if (!d->earlyrtp) {
+                       transmit_start_tone(d, SKINNY_ALERT, l->instance, sub->callid);
+               }
+               transmit_callinfo(sub);
+               transmit_callstate(d, l->instance, sub->callid, SKINNY_PROGRESS);
+               transmit_displaypromptstatus(d, "Call Progress", 0, l->instance, sub->callid);
+               sub->substate = SUBSTATE_PROGRESS;
+               break;
+       case SUBSTATE_HOLD:
+               if (sub->substate != SUBSTATE_CONNECTED) {
+                       ast_log(LOG_WARNING, "Cannot set substate to SUBSTATE_HOLD from %s (on call-%d)\n", substate2str(sub->substate), sub->callid);
+                       return;
+               }
+               ast_queue_control_data(sub->owner, AST_CONTROL_HOLD,
+                       S_OR(l->mohsuggest, NULL),
+                       !ast_strlen_zero(l->mohsuggest) ? strlen(l->mohsuggest) + 1 : 0);
+
+               transmit_activatecallplane(d, l);
+               transmit_closereceivechannel(d, sub);
+               transmit_stopmediatransmission(d, sub);
 
-       if (!(sub->substate == SUBSTATE_CONNECTED || sub->substate == SUBSTATE_HOLD)) {
-               ast_log(LOG_WARNING, "Cannot set substate to SUBSTATE_HOLD from %s (on call-%d)\n", substate2str(sub->substate), sub->callid);
-               return;
-       }
-       
-       if (sub->substate == SUBSTATE_HOLD) {
                transmit_callstate(d, l->instance, sub->callid, SKINNY_HOLD);
-               return;
+               transmit_lamp_indication(d, STIMULUS_LINE, l->instance, SKINNY_LAMP_WINK);
+               transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_ONHOLD);
+               sub->substate = SUBSTATE_HOLD;
+               break;
+       default:
+               ast_log(LOG_WARNING, "Was asked to change to nonexistant substate %d on Sub-%d\n", state, sub->callid);
        }
-
-       ast_queue_control_data(sub->owner, AST_CONTROL_HOLD,
-               S_OR(l->mohsuggest, NULL),
-               !ast_strlen_zero(l->mohsuggest) ? strlen(l->mohsuggest) + 1 : 0);
-
-       transmit_activatecallplane(d, l);
-       transmit_closereceivechannel(d, sub);
-       transmit_stopmediatransmission(d, sub);
-
-       transmit_callstate(d, l->instance, sub->callid, SKINNY_HOLD);
-       transmit_lamp_indication(d, STIMULUS_LINE, l->instance, SKINNY_LAMP_WINK);
-       transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_ONHOLD);
-       sub->substate = SUBSTATE_HOLD;
 }
 
 static void dumpsub(struct skinny_subchannel *sub, int forcehangup)
@@ -4916,7 +4873,7 @@ static void dumpsub(struct skinny_subchannel *sub, int forcehangup)
        struct skinny_subchannel *tsub;
 
        if (skinnydebug) {
-               ast_verb(3, "Dumping sub %d - state = %s\n", sub->callid, substate2str(sub->substate));
+               ast_verb(3, "Sub %d - Dumping\n", sub->callid);
        }
        
        if (!forcehangup && sub->substate == SUBSTATE_HOLD) {
@@ -4927,22 +4884,22 @@ static void dumpsub(struct skinny_subchannel *sub, int forcehangup)
        if (sub == l->activesub) {
                if (sub->related) {
                        activatesub = sub->related;
-                       setsubstate_onhook(sub);
+                       setsubstate(sub, SUBSTATE_ONHOOK);
                        l->activesub = activatesub;
                        if (l->activesub->substate != SUBSTATE_HOLD) {
                                ast_log(LOG_WARNING, "Sub-%d was related but not at SUBSTATE_HOLD\n", sub->callid);
                                return;
                        }
-                       setsubstate_hold(l->activesub);
+                       setsubstate(l->activesub, SUBSTATE_HOLD);
                } else {
-                       setsubstate_onhook(sub);
+                       setsubstate(sub, SUBSTATE_ONHOOK);
                        AST_LIST_TRAVERSE(&l->sub, tsub, list) {
                                if (tsub->substate == SUBSTATE_CALLWAIT) {
                                        activatesub = tsub;
                                }
                        }
                        if (activatesub) {
-                               setsubstate_ringin(activatesub);
+                               setsubstate(activatesub, SUBSTATE_RINGIN);
                                return;
                        }
                        AST_LIST_TRAVERSE(&l->sub, tsub, list) {
@@ -4951,12 +4908,12 @@ static void dumpsub(struct skinny_subchannel *sub, int forcehangup)
                                }
                        }
                        if (activatesub) {
-                               setsubstate_hold(activatesub);
+                               setsubstate(activatesub, SUBSTATE_HOLD);
                                return;
                        }
                }
        } else {
-               setsubstate_onhook(sub);
+               setsubstate(sub, SUBSTATE_ONHOOK);
        }
 }
 
@@ -4965,13 +4922,13 @@ static int handle_hold_button(struct skinny_subchannel *sub)
        if (!sub)
                return -1;
        if (sub->related) {
-               setsubstate_hold(sub);
-               setsubstate_connected(sub->related);
+               setsubstate(sub, SUBSTATE_HOLD);
+               setsubstate(sub->related, SUBSTATE_CONNECTED);
        } else {
                if (sub->substate == SUBSTATE_HOLD) {
-                       setsubstate_connected(sub->related);
+                       setsubstate(sub, SUBSTATE_CONNECTED);
                } else {
-                       setsubstate_hold(sub);
+                       setsubstate(sub, SUBSTATE_HOLD);
                }
        }
        return 1;
@@ -4995,7 +4952,7 @@ static int handle_transfer_button(struct skinny_subchannel *sub)
        if (!sub->related) {
                /* Another sub has not been created so this must be first XFER press */
                if (!(sub->substate == SUBSTATE_HOLD)) {
-                       setsubstate_hold(sub);
+                       setsubstate(sub, SUBSTATE_HOLD);
                }
                c = skinny_new(l, AST_STATE_DOWN, NULL, SKINNY_OUTGOING);
                if (c) {
@@ -5004,7 +4961,7 @@ static int handle_transfer_button(struct skinny_subchannel *sub)
                        newsub->related = sub;
                        sub->related = newsub;
                        newsub->xferor = 1;
-                       setsubstate_offhook(newsub);
+                       setsubstate(newsub, SUBSTATE_OFFHOOK);
                } else {
                        ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
                }
@@ -5063,7 +5020,7 @@ static int handle_callforward_button(struct skinny_subchannel *sub, int cfwdtype
                transmit_cfwdstate(d, l);
        } else {
                l->getforward = cfwdtype;
-               setsubstate_offhook(sub);
+               setsubstate(sub, SUBSTATE_OFFHOOK);
        }
        return 0;
 }
@@ -5192,7 +5149,8 @@ static int handle_stimulus_message(struct skinny_req *req, struct skinnysession
                        sub = c->tech_pvt;
                        l = sub->line;
                        l->activesub = sub;
-                       setsubstate_dialing(sub, l->lastnumberdialed);
+                       ast_copy_string(sub->exten, l->lastnumberdialed, sizeof(sub->exten));
+                       setsubstate(sub, SUBSTATE_DIALING);
                }
                break;
        case STIMULUS_SPEEDDIAL:
@@ -5216,8 +5174,9 @@ static int handle_stimulus_message(struct skinny_req *req, struct skinnysession
                        sub = c->tech_pvt;
                        l = sub->line;
                        l->activesub = sub;
-                       
-                       setsubstate_dialing(sub, sd->exten);
+
+                       ast_copy_string(sub->exten, sd->exten, sizeof(sub->exten));
+                       setsubstate(sub, SUBSTATE_DIALING);
                }
            }
                break;
@@ -5259,7 +5218,8 @@ static int handle_stimulus_message(struct skinny_req *req, struct skinnysession
                if (sub->substate == SUBSTATE_UNSET || sub->substate == SUBSTATE_OFFHOOK){
                        l = sub->line;
                        l->activesub = sub;
-                       setsubstate_dialing(sub,l->vmexten);
+                       ast_copy_string(sub->exten, l->vmexten, sizeof(sub->exten));
+                       setsubstate(sub, SUBSTATE_DIALING);
                }
                break;
        case STIMULUS_CALLPARK:
@@ -5382,14 +5342,14 @@ static int handle_stimulus_message(struct skinny_req *req, struct skinnysession
                d->hookstate = SKINNY_OFFHOOK;
 
                if (sub && sub->calldirection == SKINNY_INCOMING) {
-                       setsubstate_connected(sub);
+                       setsubstate(sub, SUBSTATE_CONNECTED);
                } else {
                        if (sub && sub->owner) {
                                ast_debug(1, "Current subchannel [%s] already has owner\n", sub->owner->name);
                        } else {
                                c = skinny_new(l, AST_STATE_DOWN, NULL, SKINNY_OUTGOING);
                                if (c) {
-                                       setsubstate_offhook(c->tech_pvt);
+                                       setsubstate(c->tech_pvt, SUBSTATE_OFFHOOK);
                                } else {
                                        ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
                                }
@@ -5454,7 +5414,7 @@ static int handle_offhook_message(struct skinny_req *req, struct skinnysession *
        transmit_lamp_indication(d, STIMULUS_LINE, l->instance, SKINNY_LAMP_ON);
 
        if (sub && sub->calldirection == SKINNY_INCOMING) {
-               setsubstate_connected(sub);
+               setsubstate(sub, SUBSTATE_CONNECTED);
        } else {
                /* Not ideal, but let's send updated time at onhook and offhook, as it clears the display */
                transmit_definetimedate(d);
@@ -5464,7 +5424,7 @@ static int handle_offhook_message(struct skinny_req *req, struct skinnysession *
                } else {
                        c = skinny_new(l, AST_STATE_DOWN, NULL, SKINNY_OUTGOING);
                        if (c) {
-                               setsubstate_offhook(c->tech_pvt);
+                               setsubstate(c->tech_pvt, SUBSTATE_OFFHOOK);
                        } else {
                                ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
                        }
@@ -5805,7 +5765,8 @@ static int handle_enbloc_call_message(struct skinny_req *req, struct skinnysessi
 
                sub = c->tech_pvt;
                l->activesub = sub;
-               setsubstate_dialing(sub, req->data.enbloccallmessage.calledParty);
+               ast_copy_string(sub->exten, req->data.enbloccallmessage.calledParty, sizeof(sub->exten));
+               setsubstate(sub, SUBSTATE_DIALING);
        }
        
        return 1;
@@ -5870,7 +5831,8 @@ static int handle_soft_key_event_message(struct skinny_req *req, struct skinnyse
                } else {
                        sub = c->tech_pvt;
                        l->activesub = sub;
-                       setsubstate_dialing(sub, l->lastnumberdialed);
+                       ast_copy_string(sub->exten, l->lastnumberdialed, sizeof(sub->exten));
+                       setsubstate(sub, SUBSTATE_DIALING);
                }
                break;
        case SOFTKEY_NEWCALL:  /* Actually the DIAL softkey */
@@ -5884,13 +5846,13 @@ static int handle_soft_key_event_message(struct skinny_req *req, struct skinnyse
                if (!c) {
                        ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
                } else {
-                       setsubstate_offhook(sub);
+                       setsubstate(sub, SUBSTATE_OFFHOOK);
                }
                break;
        case SOFTKEY_HOLD:
                if (skinnydebug)
                        ast_verb(1, "Received Softkey Event: Hold(%d/%d)\n", instance, callreference);
-               setsubstate_hold(sub);  
+               setsubstate(sub, SUBSTATE_HOLD);        
                break;
        case SOFTKEY_TRNSFER:
                if (skinnydebug)
@@ -6010,7 +5972,7 @@ static int handle_soft_key_event_message(struct skinny_req *req, struct skinnyse
                if (skinnydebug)
                        ast_verb(1, "Received Softkey Event: Resume(%d/%d)\n", instance, callreference);
 
-               setsubstate_connected(sub);
+               setsubstate(sub, SUBSTATE_CONNECTED);
                break;
        case SOFTKEY_ANSWER:
                if (skinnydebug)
@@ -6024,7 +5986,7 @@ static int handle_soft_key_event_message(struct skinny_req *req, struct skinnyse
                }
 
                if (sub && sub->calldirection == SKINNY_INCOMING) {
-                       setsubstate_connected(sub);
+                       setsubstate(sub, SUBSTATE_CONNECTED);
                }
                break;
        case SOFTKEY_INFO: