]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
add call waiting
authorAnthony Minessale <anthony.minessale@gmail.com>
Mon, 11 Jun 2007 18:15:09 +0000 (18:15 +0000)
committerAnthony Minessale <anthony.minessale@gmail.com>
Mon, 11 Jun 2007 18:15:09 +0000 (18:15 +0000)
git-svn-id: http://svn.openzap.org/svn/openzap/trunk@243 a93c3328-9c30-0410-af19-c9cd2b2d52af

libs/freetdm/mod_openzap/mod_openzap.c
libs/freetdm/src/include/openzap.h
libs/freetdm/src/include/zap_types.h
libs/freetdm/src/zap_analog.c
libs/freetdm/src/zap_io.c

index 21f63022d90cc12e52e5ad53eea5f4e37cafc0a2..070ea50e5dc6c525b0d5cded110818078f76bba4 100644 (file)
@@ -86,7 +86,6 @@ struct private_object {
        switch_mutex_t *mutex;
        switch_mutex_t *flag_mutex;
        zap_channel_t *zchan;
-       int32_t token_id;
        uint32_t wr_error;
 };
 
@@ -106,6 +105,54 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc
 static switch_status_t channel_kill_channel(switch_core_session_t *session, int sig);
 
 
+static switch_core_session_t *zap_channel_get_session(zap_channel_t *channel, int32_t id)
+{
+       switch_core_session_t *session = NULL;
+
+       if (id > ZAP_MAX_TOKENS) {
+               return NULL;
+       }
+
+       if (!switch_strlen_zero(channel->tokens[id])) {
+               session = switch_core_session_locate(channel->tokens[id]);
+       }
+
+       return session;
+}
+
+
+static void cycle_foreground(zap_channel_t *zchan, int flash) {
+       uint32_t i = 0;
+       switch_core_session_t *session;
+       switch_channel_t *channel;
+       private_t *tech_pvt;
+       
+       for (i = 0; i < zchan->token_count; i++) {
+               if ((session = zap_channel_get_session(zchan, i))) {
+                       tech_pvt = switch_core_session_get_private(session);
+                       channel = switch_core_session_get_channel(session);
+                       if (zchan->token_count == 1 && flash) {
+                               if (switch_test_flag(tech_pvt, TFLAG_HOLD)) {
+                                       switch_clear_flag_locked(tech_pvt, TFLAG_HOLD);
+                               } else {
+                                       switch_set_flag_locked(tech_pvt, TFLAG_HOLD);
+                               }
+                       } else if (i) {
+                               switch_set_flag_locked(tech_pvt, TFLAG_HOLD);
+                       } else {
+                               switch_clear_flag_locked(tech_pvt, TFLAG_HOLD);
+                               if (!switch_channel_test_flag(channel, CF_ANSWERED)) {
+                                       switch_channel_mark_answered(channel);
+                               }
+                       }
+                       switch_core_session_rwunlock(session);
+               }
+       }
+}
+
+
+
+
 static switch_status_t tech_init(private_t *tech_pvt, switch_core_session_t *session, zap_channel_t *zchan)
 {
        char *dname = NULL;
@@ -247,7 +294,8 @@ static switch_status_t channel_on_hangup(switch_core_session_t *session)
        tech_pvt = switch_core_session_get_private(session);
        assert(tech_pvt != NULL);
 
-       zap_channel_clear_token(tech_pvt->zchan, tech_pvt->token_id);
+
+       zap_channel_clear_token(tech_pvt->zchan, switch_core_session_get_uuid(session));
        
        switch (tech_pvt->zchan->type) {
        case ZAP_CHAN_TYPE_FXO:
@@ -260,7 +308,11 @@ static switch_status_t channel_on_hangup(switch_core_session_t *session)
        case ZAP_CHAN_TYPE_FXS:
                {
                        if (tech_pvt->zchan->state != ZAP_CHANNEL_STATE_DOWN) {
-                               zap_set_state_locked(tech_pvt->zchan, ZAP_CHANNEL_STATE_HANGUP);
+                               if (tech_pvt->zchan->token_count) {
+                                       cycle_foreground(tech_pvt->zchan, 0);
+                               } else {
+                                       zap_set_state_locked(tech_pvt->zchan, ZAP_CHANNEL_STATE_HANGUP);
+                               }
                        }
                }
                break;
@@ -639,15 +691,15 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi
                status = zap_channel_open(span_id, chan_id, &zchan);
        } else {
                status = zap_channel_open_any(span_id, ZAP_TOP_DOWN, &zchan);
-               
        }
-
-
+       
        if (status != ZAP_SUCCESS) {
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No channels available\n");
                return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
        }
 
+
+
        if ((*new_session = switch_core_session_request(&channel_endpoint_interface, pool)) != 0) {
                private_t *tech_pvt;
                switch_channel_t *channel;
@@ -676,13 +728,27 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi
                
                switch_channel_set_flag(channel, CF_OUTBOUND);
                switch_channel_set_state(channel, CS_INIT);
-               if ((tech_pvt->token_id = zap_channel_add_token(zchan, switch_core_session_get_uuid(*new_session))) < 0) {
+               if (zap_channel_add_token(zchan, switch_core_session_get_uuid(*new_session), zchan->token_count) != ZAP_SUCCESS) {
                        switch_core_session_destroy(new_session);
                        cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
             goto fail;
                }
 
-               zap_channel_outgoing_call(zchan);
+
+               if (zap_channel_outgoing_call(zchan) != ZAP_SUCCESS) {
+                       if (tech_pvt->read_codec.implementation) {
+                               switch_core_codec_destroy(&tech_pvt->read_codec);
+                       }
+                       
+                       if (tech_pvt->write_codec.implementation) {
+                               switch_core_codec_destroy(&tech_pvt->write_codec);
+                       }
+                       switch_core_session_destroy(new_session);
+            cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+            goto fail;
+
+               }
+
 
                return SWITCH_CAUSE_SUCCESS;
        }
@@ -758,7 +824,7 @@ zap_status_t zap_channel_from_event(zap_sigmsg_t *sigmsg, switch_core_session_t
                return ZAP_FAIL;
        }
 
-       if ((tech_pvt->token_id = zap_channel_add_token(sigmsg->channel, switch_core_session_get_uuid(session))) < 0) {
+       if (zap_channel_add_token(sigmsg->channel, switch_core_session_get_uuid(session), 0) != ZAP_SUCCESS) {
                switch_core_session_destroy(&session);
                return ZAP_FAIL;
        }
@@ -767,20 +833,6 @@ zap_status_t zap_channel_from_event(zap_sigmsg_t *sigmsg, switch_core_session_t
     return ZAP_SUCCESS;
 }
 
-static switch_core_session_t *zap_channel_get_session(zap_channel_t *channel, int32_t id)
-{
-       switch_core_session_t *session = NULL;
-
-       if (id > ZAP_MAX_TOKENS) {
-               return NULL;
-       }
-
-       if (!switch_strlen_zero(channel->tokens[id])) {
-               session = switch_core_session_locate(channel->tokens[id]);
-       }
-
-       return session;
-}
 
 static ZIO_SIGNAL_CB_FUNCTION(on_fxo_signal)
 {
@@ -853,24 +905,7 @@ static ZIO_SIGNAL_CB_FUNCTION(on_fxs_signal)
 
     case ZAP_SIGEVENT_FLASH:
                {
-                       uint32_t i = 0;
-                       for (i = 0; i < sigmsg->channel->token_count; i++) {
-                               if ((session = zap_channel_get_session(sigmsg->channel, i))) {
-                                       tech_pvt = switch_core_session_get_private(session);
-                                       if (sigmsg->channel->token_count == 1) {
-                                               if (switch_test_flag(tech_pvt, TFLAG_HOLD)) {
-                                                       switch_clear_flag_locked(tech_pvt, TFLAG_HOLD);
-                                               } else {
-                                                       switch_set_flag_locked(tech_pvt, TFLAG_HOLD);
-                                               }
-                                       } else if (i) {
-                                               switch_set_flag_locked(tech_pvt, TFLAG_HOLD);
-                                       } else {
-                                               switch_clear_flag_locked(tech_pvt, TFLAG_HOLD);
-                                       }
-                                       switch_core_session_rwunlock(session);
-                               }
-                       }
+                       cycle_foreground(sigmsg->channel, 1);
                }
                break;
        }
index 30013ab67f7c76a6b624cc100c369adb3e3a7488..774f3bcd4f3f4883619ceda566cfe5ff3c532cce 100644 (file)
@@ -446,8 +446,8 @@ void zap_channel_rotate_tokens(zap_channel_t *zchan);
 void zap_channel_clear_detected_tones(zap_channel_t *zchan);
 void zap_channel_clear_needed_tones(zap_channel_t *zchan);
 zap_status_t zap_channel_send_fsk_data(zap_channel_t *zchan, zap_fsk_data_state_t *fsk_data, float db_level);
-zap_status_t zap_channel_clear_token(zap_channel_t *zchan, int32_t token_id);
-zap_status_t zap_channel_add_token(zap_channel_t *zchan, char *token);
+zap_status_t zap_channel_clear_token(zap_channel_t *zchan, const char *token);
+zap_status_t zap_channel_add_token(zap_channel_t *zchan, char *token, int end);
 zap_status_t zap_channel_set_state(zap_channel_t *zchan, zap_channel_state_t state);
 zap_status_t zap_span_load_tones(zap_span_t *span, char *mapname);
 zap_size_t zap_channel_dequeue_dtmf(zap_channel_t *zchan, char *dtmf, zap_size_t len);
index 2ae6e7b05d68d493240638a2c1b3f662f064fa83..c6ae837986e41fdd47bf991cfdff81a1bdb57c0d 100644 (file)
@@ -97,9 +97,12 @@ typedef enum {
        ZAP_TONEMAP_FAIL2,
        ZAP_TONEMAP_FAIL3,
        ZAP_TONEMAP_ATTN,
+       ZAP_TONEMAP_CALLWAITING_CAS,
+       ZAP_TONEMAP_CALLWAITING_SAS,
+       ZAP_TONEMAP_CALLWAITING_ACK,
        ZAP_TONEMAP_INVALID
 } zap_tonemap_t;
-#define TONEMAP_STRINGS "NONE", "DIAL", "RING", "BUSY", "FAIL1", "FAIL2", "FAIL3", "ATTN", "INVALID"
+#define TONEMAP_STRINGS "NONE", "DIAL", "RING", "BUSY", "FAIL1", "FAIL2", "FAIL3", "ATTN", "CALLWAITING-CAS", "CALLWAITING-SAS", "CALLWAITING-ACK", "INVALID"
 ZAP_STR2ENUM_P(zap_str2zap_tonemap, zap_tonemap2str, zap_tonemap_t)
 
 typedef enum {
@@ -254,10 +257,11 @@ typedef enum {
        ZAP_CHANNEL_STATE_GENRING,
        ZAP_CHANNEL_STATE_DIALING,
        ZAP_CHANNEL_STATE_GET_CALLERID,
+       ZAP_CHANNEL_STATE_CALLWAITING,
        ZAP_CHANNEL_STATE_INVALID
 } zap_channel_state_t;
 #define CHANNEL_STATE_STRINGS "DOWN", "UP", "HANGUP", "HOLD", "DIALTONE", "COLLECT", \
-               "RING", "BUSY", "ATTN", "IDLE", "GENRING", "DIALING", "GET_CALLERID", "INVALID"
+               "RING", "BUSY", "ATTN", "IDLE", "GENRING", "DIALING", "GET_CALLERID", "CALLWAITING", "INVALID"
 ZAP_STR2ENUM_P(zap_str2zap_channel_state, zap_channel_state2str, zap_channel_state_t)
 
 typedef enum {
index 9463d4fa651f5d84fc6420ad5a7a9118a6e72bfc..7bca77d10a475338c2d4788a735979e5ebd07a00 100644 (file)
@@ -46,13 +46,16 @@ static ZIO_CHANNEL_OUTGOING_CALL_FUNCTION(analog_fxo_outgoing_call)
                zap_thread_create_detached(zap_analog_channel_run, zchan);
                return ZAP_SUCCESS;
        }
+
        return ZAP_FAIL;
 }
 
 static ZIO_CHANNEL_OUTGOING_CALL_FUNCTION(analog_fxs_outgoing_call)
 {
 
-       if (!zap_test_flag(zchan, ZAP_CHANNEL_INTHREAD)) {
+       if (zap_test_flag(zchan, ZAP_CHANNEL_INTHREAD)) {
+               zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_CALLWAITING);
+       } else {
                zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_GENRING);
                zap_thread_create_detached(zap_analog_channel_run, zchan);
        }
@@ -106,6 +109,51 @@ static int teletone_handler(teletone_generation_session_t *ts, teletone_tone_map
        return 0;
 }
 
+static void send_caller_id(zap_channel_t *chan)
+{
+       zap_fsk_data_state_t fsk_data;
+       uint8_t databuf[1024] = "";
+       char time_str[9];
+       struct tm tm;
+       time_t now;
+       zap_mdmf_type_t mt = MDMF_INVALID;
+
+       time(&now);
+#ifdef WIN32
+       _tzset();
+       _localtime64_s(&tm, &now);
+#else
+       localtime_r(&now, &tm);
+#endif
+       strftime(time_str, sizeof(time_str), "%m%d%H%M", &tm);
+
+       zap_fsk_data_init(&fsk_data, databuf, sizeof(databuf));
+       zap_fsk_data_add_mdmf(&fsk_data, MDMF_DATETIME, (uint8_t *) time_str, 8);
+                                       
+       if (zap_strlen_zero(chan->caller_data.cid_num)) {
+               mt = MDMF_NO_NUM;
+               zap_set_string(chan->caller_data.cid_num, "O");
+       } else if (!strcasecmp(chan->caller_data.cid_num, "P") || !strcasecmp(chan->caller_data.cid_num, "O")) {
+               mt = MDMF_NO_NUM;
+       } else {
+               mt = MDMF_PHONE_NUM;
+       }
+       zap_fsk_data_add_mdmf(&fsk_data, mt, (uint8_t *) chan->caller_data.cid_num, (uint8_t)strlen(chan->caller_data.cid_num));
+
+       if (zap_strlen_zero(chan->caller_data.cid_name)) {
+               mt = MDMF_NO_NAME;
+               zap_set_string(chan->caller_data.cid_name, "O");
+       } else if (!strcasecmp(chan->caller_data.cid_name, "P") || !strcasecmp(chan->caller_data.cid_name, "O")) {
+               mt = MDMF_NO_NAME;
+       } else {
+               mt = MDMF_PHONE_NAME;
+       }
+       zap_fsk_data_add_mdmf(&fsk_data, mt, (uint8_t *) chan->caller_data.cid_name, (uint8_t)strlen(chan->caller_data.cid_name));
+                                       
+       zap_fsk_data_add_checksum(&fsk_data);
+       zap_channel_send_fsk_data(chan, &fsk_data, -14);
+}
+
 static void *zap_analog_channel_run(zap_thread_t *me, void *obj)
 {
        zap_channel_t *chan = (zap_channel_t *) obj;
@@ -231,6 +279,37 @@ static void *zap_analog_channel_run(zap_thread_t *me, void *obj)
                                        }
                                }
                                break;
+                       case ZAP_CHANNEL_STATE_CALLWAITING:
+                               {
+                                       int done = 0;
+                                       
+                                       if (chan->detected_tones[ZAP_TONEMAP_CALLWAITING_ACK] == 1) {
+                                               send_caller_id(chan);
+                                               chan->detected_tones[ZAP_TONEMAP_CALLWAITING_ACK]++;
+                                       } else if (state_counter > 600 && !chan->detected_tones[ZAP_TONEMAP_CALLWAITING_ACK]) {
+                                               send_caller_id(chan);
+                                               chan->detected_tones[ZAP_TONEMAP_CALLWAITING_ACK]++;
+                                       } else if (state_counter > 1000 && !chan->detected_tones[ZAP_TONEMAP_CALLWAITING_ACK]) {
+                                               done = 1;
+                                       } else if (state_counter > 10000) {
+                                               if (chan->fsk_buffer) {
+                                                       zap_buffer_zero(chan->fsk_buffer);
+                                               } else {
+                                                       zap_buffer_create(&chan->fsk_buffer, 128, 128, 0);
+                                               }
+                                               
+                                               ts.user_data = chan->fsk_buffer;
+                                               teletone_run(&ts, chan->span->tone_map[ZAP_TONEMAP_CALLWAITING_SAS]);
+                                               ts.user_data = dt_buffer;
+                                               done = 1;
+                                       }
+
+                                       if (done) {
+                                               zap_set_state_locked(chan, ZAP_CHANNEL_STATE_UP);
+                                               zap_clear_flag_locked(chan, ZAP_CHANNEL_STATE_CHANGE);
+                                               chan->detected_tones[ZAP_TONEMAP_CALLWAITING_ACK] = 0;
+                                       }
+                               }
                        case ZAP_CHANNEL_STATE_UP:
                        case ZAP_CHANNEL_STATE_IDLE:
                                {
@@ -267,7 +346,6 @@ static void *zap_analog_channel_run(zap_thread_t *me, void *obj)
                                                zap_buffer_zero(chan->fsk_buffer);
                                        }
 
-
                                        if (chan->type == ZAP_CHAN_TYPE_FXS && zap_test_flag(chan, ZAP_CHANNEL_RINGING)) {
                                                zap_channel_command(chan, ZAP_COMMAND_GENERATE_RING_OFF, NULL);
                                        }
@@ -321,49 +399,24 @@ static void *zap_analog_channel_run(zap_thread_t *me, void *obj)
                                        indicate = 1;
                                }
                                break;
-                       case ZAP_CHANNEL_STATE_GENRING:
+                       case ZAP_CHANNEL_STATE_CALLWAITING:
                                {
-                                       zap_fsk_data_state_t fsk_data;
-                                       uint8_t databuf[1024] = "";
-                                       char time_str[9];
-                                       struct tm tm;
-                                       time_t now;
-                                       zap_mdmf_type_t mt = MDMF_INVALID;
-
-                                       time(&now);
-#ifdef WIN32
-                                       _tzset();
-                                  _localtime64_s(&tm, &now);
-#else
-                                       localtime_r(&now, &tm);
-#endif
-                                       strftime(time_str, sizeof(time_str), "%m%d%H%M", &tm);
-
-                                       zap_fsk_data_init(&fsk_data, databuf, sizeof(databuf));
-                                       zap_fsk_data_add_mdmf(&fsk_data, MDMF_DATETIME, (uint8_t *) time_str, 8);
-                                       
-                                       if (zap_strlen_zero(chan->caller_data.cid_num)) {
-                                               mt = MDMF_NO_NUM;
-                                               zap_set_string(chan->caller_data.cid_num, "O");
-                                       } else if (!strcasecmp(chan->caller_data.cid_num, "P") || !strcasecmp(chan->caller_data.cid_num, "O")) {
-                                               mt = MDMF_NO_NUM;
-                                       } else {
-                                               mt = MDMF_PHONE_NUM;
-                                       }
-                                       zap_fsk_data_add_mdmf(&fsk_data, mt, (uint8_t *) chan->caller_data.cid_num, (uint8_t)strlen(chan->caller_data.cid_num));
-
-                                       if (zap_strlen_zero(chan->caller_data.cid_name)) {
-                                               mt = MDMF_NO_NAME;
-                                               zap_set_string(chan->caller_data.cid_name, "O");
-                                       } else if (!strcasecmp(chan->caller_data.cid_name, "P") || !strcasecmp(chan->caller_data.cid_name, "O")) {
-                                               mt = MDMF_NO_NAME;
+                                       chan->detected_tones[ZAP_TONEMAP_CALLWAITING_ACK] = 0;
+                                       if (chan->fsk_buffer) {
+                                               zap_buffer_zero(chan->fsk_buffer);
                                        } else {
-                                               mt = MDMF_PHONE_NAME;
+                                               zap_buffer_create(&chan->fsk_buffer, 128, 128, 0);
                                        }
-                                       zap_fsk_data_add_mdmf(&fsk_data, mt, (uint8_t *) chan->caller_data.cid_name, (uint8_t)strlen(chan->caller_data.cid_name));
                                        
-                                       zap_fsk_data_add_checksum(&fsk_data);
-                                       zap_channel_send_fsk_data(chan, &fsk_data, -14);
+                                       ts.user_data = chan->fsk_buffer;
+                                       teletone_run(&ts, chan->span->tone_map[ZAP_TONEMAP_CALLWAITING_SAS]);
+                                       teletone_run(&ts, chan->span->tone_map[ZAP_TONEMAP_CALLWAITING_CAS]);
+                                       ts.user_data = dt_buffer;
+                               }
+                               break;
+                       case ZAP_CHANNEL_STATE_GENRING:
+                               {
+                                       send_caller_id(chan);
                                        //zap_channel_command(chan, ZAP_COMMAND_TRACE_OUTPUT, "/tmp/outbound.ul");
                                        zap_channel_command(chan, ZAP_COMMAND_GENERATE_RING_ON, NULL);
                                }
@@ -575,13 +628,18 @@ static zap_status_t process_event(zap_span_t *span, zap_event_t *event)
                break;
        case ZAP_OOB_FLASH:
                {
+                       if (event->channel->state == ZAP_CHANNEL_STATE_CALLWAITING) {
+                               zap_set_state_locked(event->channel, ZAP_CHANNEL_STATE_UP);
+                               zap_clear_flag_locked(event->channel, ZAP_CHANNEL_STATE_CHANGE);
+                               event->channel->detected_tones[ZAP_TONEMAP_CALLWAITING_ACK] = 0;
+                       } 
 
-                       sig.event_id = ZAP_SIGEVENT_FLASH;
                        zap_channel_rotate_tokens(event->channel);
-
+                       
                        if (zap_test_flag(event->channel, ZAP_CHANNEL_HOLD)) {
                                zap_set_state_locked(event->channel,  ZAP_CHANNEL_STATE_UP);
                        } else {
+                               sig.event_id = ZAP_SIGEVENT_FLASH;
                                data->sig_cb(&sig);
                                if (event->channel->token_count == 1) {
                                        zap_set_flag_locked(event->channel, ZAP_CHANNEL_HOLD);
index 720bd9da24986be2bac6ad5f30db82049b28355b..009fafef40226f15a132dc5bc9a980b80a4d96b7 100644 (file)
@@ -426,9 +426,14 @@ zap_status_t zap_channel_send_fsk_data(zap_channel_t *zchan, zap_fsk_data_state_
        if (!zchan->fsk_buffer) {
                zap_buffer_create(&zchan->fsk_buffer, 128, 128, 0);
        }
-       zap_fsk_modulator_init(&fsk_trans, FSK_BELL202, zchan->rate, fsk_data, db_level, 180, 5, 180, zchan_fsk_write_sample, zchan);
-       zap_fsk_modulator_send_all((&fsk_trans));
-       zchan->buffer_delay = 3500 / zchan->effective_interval;
+       if (zchan->token_count > 1) {
+               zap_fsk_modulator_init(&fsk_trans, FSK_BELL202, zchan->rate, fsk_data, db_level, 80, 5, 0, zchan_fsk_write_sample, zchan);
+               zap_fsk_modulator_send_all((&fsk_trans));
+       } else {
+               zap_fsk_modulator_init(&fsk_trans, FSK_BELL202, zchan->rate, fsk_data, db_level, 180, 5, 300, zchan_fsk_write_sample, zchan);
+               zap_fsk_modulator_send_all((&fsk_trans));
+               zchan->buffer_delay = 3500 / zchan->effective_interval;
+       }
        return ZAP_SUCCESS;
 }
 
@@ -441,15 +446,15 @@ zap_status_t zap_channel_set_event_callback(zap_channel_t *zchan, zio_event_cb_t
        return ZAP_SUCCESS;
 }
 
-zap_status_t zap_channel_clear_token(zap_channel_t *zchan, int32_t token_id)
+zap_status_t zap_channel_clear_token(zap_channel_t *zchan, const char *token)
 {
        zap_status_t status = ZAP_FAIL;
        
        zap_mutex_lock(zchan->mutex);
-       if (token_id == -1) {
+       if (token == NULL) {
                memset(zchan->tokens, 0, sizeof(zchan->tokens));
                zchan->token_count = 0;
-       } else if (*zchan->tokens[token_id] != '\0') {
+       } else if (*token != '\0') {
                char tokens[ZAP_MAX_TOKENS][ZAP_TOKEN_STRLEN];
                int32_t i, count = zchan->token_count;
                memcpy(tokens, zchan->tokens, sizeof(tokens));
@@ -457,7 +462,7 @@ zap_status_t zap_channel_clear_token(zap_channel_t *zchan, int32_t token_id)
                zchan->token_count = 0;         
 
                for (i = 0; i < count; i++) {
-                       if (i != token_id) {
+                       if (strcmp(tokens[i], token)) {
                                zap_copy_string(zchan->tokens[zchan->token_count], tokens[i], sizeof(zchan->tokens[zchan->token_count]));
                                zchan->token_count++;
                        }
@@ -479,15 +484,20 @@ void zap_channel_rotate_tokens(zap_channel_t *zchan)
        }
 }
 
-zap_status_t zap_channel_add_token(zap_channel_t *zchan, char *token)
+zap_status_t zap_channel_add_token(zap_channel_t *zchan, char *token, int end)
 {
        zap_status_t status = ZAP_FAIL;
 
        zap_mutex_lock(zchan->mutex);
        if (zchan->token_count < ZAP_MAX_TOKENS) {
-               memmove(zchan->tokens[1], zchan->tokens[0], zchan->token_count * ZAP_TOKEN_STRLEN);
-               zap_copy_string(zchan->tokens[0], token, ZAP_TOKEN_STRLEN);
-               zchan->token_count++;
+               if (end) {
+                       zap_copy_string(zchan->tokens[zchan->token_count++], token, ZAP_TOKEN_STRLEN);
+               } else {
+                       memmove(zchan->tokens[1], zchan->tokens[0], zchan->token_count * ZAP_TOKEN_STRLEN);
+                       zap_copy_string(zchan->tokens[0], token, ZAP_TOKEN_STRLEN);
+                       zchan->token_count++;
+               }
+               status = ZAP_SUCCESS;
        }
        zap_mutex_unlock(zchan->mutex);
 
@@ -672,6 +682,9 @@ zap_status_t zap_channel_open_chan(zap_channel_t *zchan)
        if ((status = zap_mutex_trylock(zchan->mutex)) != ZAP_SUCCESS) {
                return status;
        }
+
+       status = ZAP_FAIL;
+
        if (zap_test_flag(zchan, ZAP_CHANNEL_READY)) {
                status = zchan->span->zio->open(zchan);
                if (status == ZAP_SUCCESS) {
@@ -698,7 +711,10 @@ zap_status_t zap_channel_open(uint32_t span_id, uint32_t chan_id, zap_channel_t
                        goto done;
                }
                
-               if (zap_test_flag(check, ZAP_CHANNEL_READY) && !zap_test_flag(check, ZAP_CHANNEL_INUSE)) {
+               status = ZAP_FAIL;
+
+               if (zap_test_flag(check, ZAP_CHANNEL_READY) && (!zap_test_flag(check, ZAP_CHANNEL_INUSE) || 
+                                                                                                               (check->type == ZAP_CHAN_TYPE_FXS && check->token_count == 1))) {
                        if (!zap_test_flag(check, ZAP_CHANNEL_OPEN)) {
                                status = check->zio->open(check);
                                if (status == ZAP_SUCCESS) {
@@ -714,7 +730,6 @@ zap_status_t zap_channel_open(uint32_t span_id, uint32_t chan_id, zap_channel_t
        }
 
        done:
-       
        zap_mutex_unlock(globals.mutex);
 
        return status;
@@ -824,7 +839,7 @@ static zap_status_t zchan_activate_dtmf_buffer(zap_channel_t *zchan)
 zap_status_t zap_channel_command(zap_channel_t *zchan, zap_command_t command, void *obj)
 {
        zap_status_t status = ZAP_FAIL;
-
+       
        assert(zchan != NULL);
        assert(zchan->zio != NULL);
 
@@ -1453,29 +1468,33 @@ zap_status_t zap_channel_read(zap_channel_t *zchan, void *data, zap_size_t *data
                        if(*digit_str) {
                                zio_event_cb_t event_callback = NULL;
 
-                               zap_channel_queue_dtmf(zchan, digit_str);
+                               if (zchan->state == ZAP_CHANNEL_STATE_CALLWAITING && (*digit_str == 'D' || *digit_str == 'A')) {
+                                       zchan->detected_tones[ZAP_TONEMAP_CALLWAITING_ACK]++;
+                               } else {
+                                       zap_channel_queue_dtmf(zchan, digit_str);
 
-                               if (zchan->span->event_callback) {
-                                       event_callback = zchan->span->event_callback;
-                               } else if (zchan->event_callback) {
-                                       event_callback = zchan->event_callback;
-                               }
+                                       if (zchan->span->event_callback) {
+                                               event_callback = zchan->span->event_callback;
+                                       } else if (zchan->event_callback) {
+                                               event_callback = zchan->event_callback;
+                                       }
 
-                               if (event_callback) {
-                                       zchan->event_header.channel = zchan;
-                                       zchan->event_header.e_type = ZAP_EVENT_DTMF;
-                                       zchan->event_header.data = digit_str;
-                                       event_callback(zchan, &zchan->event_header);
-                                       zchan->event_header.e_type = ZAP_EVENT_NONE;
-                                       zchan->event_header.data = NULL;
-                               }
-                               if (zap_test_flag(zchan, ZAP_CHANNEL_SUPRESS_DTMF)) {
-                                       zchan->skip_read_frames = 20;
+                                       if (event_callback) {
+                                               zchan->event_header.channel = zchan;
+                                               zchan->event_header.e_type = ZAP_EVENT_DTMF;
+                                               zchan->event_header.data = digit_str;
+                                               event_callback(zchan, &zchan->event_header);
+                                               zchan->event_header.e_type = ZAP_EVENT_NONE;
+                                               zchan->event_header.data = NULL;
+                                       }
+                                       if (zap_test_flag(zchan, ZAP_CHANNEL_SUPRESS_DTMF)) {
+                                               zchan->skip_read_frames = 20;
+                                       }
+                                       if (zchan->skip_read_frames > 0) {
+                                               memset(data, 0, *datalen);
+                                               zchan->skip_read_frames--;
+                                       }  
                                }
-                               if (zchan->skip_read_frames > 0) {
-                                       memset(data, 0, *datalen);
-                                       zchan->skip_read_frames--;
-                               }  
                        }
                }
        }
@@ -1523,10 +1542,10 @@ zap_status_t zap_channel_write(zap_channel_t *zchan, void *data, zap_size_t data
        }
 
        if (!zchan->buffer_delay || --zchan->buffer_delay == 0) {
-               if (zchan->fsk_buffer && (blen = zap_buffer_inuse(zchan->fsk_buffer))) {
-                       buffer = zchan->fsk_buffer;
-               } else if (zchan->dtmf_buffer && (blen = zap_buffer_inuse(zchan->dtmf_buffer))) {
+               if (zchan->dtmf_buffer && (blen = zap_buffer_inuse(zchan->dtmf_buffer))) {
                        buffer = zchan->dtmf_buffer;
+               } else if (zchan->fsk_buffer && (blen = zap_buffer_inuse(zchan->fsk_buffer))) {
+                       buffer = zchan->fsk_buffer;                     
                }
        }