From 03dc3b7b8d734e5a916c0dd48c408e78e6f66f55 Mon Sep 17 00:00:00 2001 From: Arnaldo Pereira Date: Wed, 24 Nov 2010 21:25:24 -0200 Subject: [PATCH 01/78] freetdm: ftdm_channel_read_event() to retrieve events from a channel, removed from ftmod_r2: ftdm_r2_sig_read(), FTDM_R2_PROCESSING flag and locks for ftdmchan --- libs/freetdm/src/ftdm_io.c | 45 +++++ libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c | 145 ++++++-------- .../src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c | 184 +++++++++++++++++- libs/freetdm/src/include/freetdm.h | 4 + libs/freetdm/src/include/private/ftdm_core.h | 17 ++ 5 files changed, 311 insertions(+), 84 deletions(-) diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index 64233a97ac..0065d779f6 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -988,6 +988,51 @@ FT_DECLARE(ftdm_status_t) ftdm_span_next_event(ftdm_span_t *span, ftdm_event_t * return status; } +FT_DECLARE(ftdm_status_t) ftdm_channel_read_event(ftdm_channel_t *ftdmchan, ftdm_event_t **event) +{ + ftdm_status_t status = FTDM_FAIL; + ftdm_sigmsg_t sigmsg; + ftdm_span_t *span = ftdmchan->span; + ftdm_assert_return(span->fio != NULL, FTDM_FAIL, "No I/O module attached to this span!\n"); + + if (!span->fio->channel_next_event) { + ftdm_log(FTDM_LOG_ERROR, "channel_next_event method not implemented in module %s!", span->fio->name); + return FTDM_NOTIMPL; + } + + status = span->fio->channel_next_event(ftdmchan, event); + if (status != FTDM_SUCCESS) { + return status; + } + + /* before returning the event to the user we do some core operations with certain OOB events */ + memset(&sigmsg, 0, sizeof(sigmsg)); + sigmsg.span_id = span->span_id; + sigmsg.chan_id = (*event)->channel->chan_id; + sigmsg.channel = (*event)->channel; + switch ((*event)->enum_id) { + case FTDM_OOB_ALARM_CLEAR: + { + sigmsg.event_id = FTDM_SIGEVENT_ALARM_CLEAR; + ftdm_clear_flag_locked((*event)->channel, FTDM_CHANNEL_IN_ALARM); + ftdm_span_send_signal(span, &sigmsg); + } + break; + case FTDM_OOB_ALARM_TRAP: + { + sigmsg.event_id = FTDM_SIGEVENT_ALARM_TRAP; + ftdm_set_flag_locked((*event)->channel, FTDM_CHANNEL_IN_ALARM); + ftdm_span_send_signal(span, &sigmsg); + } + break; + default: + /* NOOP */ + break; + } + + return status; +} + static ftdm_status_t ftdmchan_fsk_write_sample(int16_t *buf, ftdm_size_t buflen, void *user_data) { ftdm_channel_t *ftdmchan = (ftdm_channel_t *) user_data; diff --git a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c index 30de78857a..7c5f4a46af 100644 --- a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c +++ b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c @@ -57,8 +57,7 @@ typedef enum { } ftdm_r2_flag_t; typedef enum { - FTDM_R2_PROCESSING = (1 << 0), - FTDM_R2_WAITING_ACK = (1 << 1), + FTDM_R2_WAITING_ACK = (1 << 0), } ftdm_r2_call_flag_t; /* private call information stored in ftdmchan->call_data void* ptr */ @@ -398,44 +397,26 @@ static ftdm_status_t ftdm_r2_stop(ftdm_span_t *span) return FTDM_SUCCESS; } -static ftdm_status_t ftdm_r2_sig_read(ftdm_channel_t *ftdmchan, void *data, ftdm_size_t size) -{ - openr2_chan_t *r2chan = R2CALL(ftdmchan)->r2chan; - if (!openr2_chan_get_read_enabled(r2chan)) { - ftdm_mutex_lock(ftdmchan->mutex); - //openr2_chan_process_input(r2chan, data, size); - ftdm_mutex_unlock(ftdmchan->mutex); - } - return FTDM_SUCCESS; -} - /* always called from the monitor thread */ static void ftdm_r2_on_call_init(openr2_chan_t *r2chan) { - //ftdm_status_t status; ftdm_r2_call_t *r2call; ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan); - //ftdm_r2_data_t *r2data = ftdmchan->span->signal_data; ftdm_log_chan_msg(ftdmchan, FTDM_LOG_NOTICE, "Received request to start call\n"); - ftdm_mutex_lock(ftdmchan->mutex); - if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INUSE)) { ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Cannot start call when channel is in use (state = %s)\n", ftdm_channel_state2str(ftdmchan->state)); - ftdm_mutex_unlock(ftdmchan->mutex); return; } if (ftdmchan->state != FTDM_CHANNEL_STATE_DOWN) { ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Cannot handle request to start call in state %s\n", ftdm_channel_state2str(ftdmchan->state)); - ftdm_mutex_unlock(ftdmchan->mutex); return; } if (ftdm_channel_open_chan(ftdmchan) != FTDM_SUCCESS) { ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Failed to open channel during incoming call! [%s]\n", ftdmchan->last_error); - ftdm_mutex_unlock(ftdmchan->mutex); return; } @@ -448,7 +429,6 @@ static void ftdm_r2_on_call_init(openr2_chan_t *r2chan) /* clean the call data structure but keep the R2 processing flag on! */ ft_r2_clean_call(ftdmchan->call_data); r2call = R2CALL(ftdmchan); - ftdm_set_flag(r2call, FTDM_R2_PROCESSING); if (ftdmchan->state == FTDM_CHANNEL_STATE_DOWN) { R2CALL(ftdmchan)->chanstate = FTDM_CHANNEL_STATE_DOWN; @@ -457,7 +437,6 @@ static void ftdm_r2_on_call_init(openr2_chan_t *r2chan) } ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_COLLECT); - ftdm_mutex_unlock(ftdmchan->mutex); } /* only called for incoming calls when the ANI, DNIS etc is complete and the user has to decide either to accept or reject the call */ @@ -574,11 +553,8 @@ static void ftdm_r2_on_protocol_error(openr2_chan_t *r2chan, openr2_protocol_err ftdm_r2_data_t *r2data; ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan); - ftdm_mutex_lock(ftdmchan->mutex); - if (ftdmchan->state == FTDM_CHANNEL_STATE_DOWN) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Got protocol error when we're already down!\n"); - ftdm_mutex_unlock(ftdmchan->mutex); } ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Protocol error\n"); @@ -587,7 +563,6 @@ static void ftdm_r2_on_protocol_error(openr2_chan_t *r2chan, openr2_protocol_err if (!R2CALL(ftdmchan)->ftdm_started) { ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_HANGUP); - ftdm_mutex_unlock(ftdmchan->mutex); return; } @@ -602,8 +577,6 @@ static void ftdm_r2_on_protocol_error(openr2_chan_t *r2chan, openr2_protocol_err r2data = ftdmchan->span->signal_data; ftdm_span_send_signal(ftdmchan->span, &sigev); - - ftdm_mutex_unlock(ftdmchan->mutex); } static void ftdm_r2_on_line_blocked(openr2_chan_t *r2chan) @@ -867,9 +840,37 @@ static int ftdm_r2_io_setup(openr2_chan_t *r2chan) static int ftdm_r2_io_get_oob_event(openr2_chan_t *r2chan, openr2_oob_event_t *event) { - *event = 0; - ftdm_log(FTDM_LOG_ERROR, "I should not be called (I/O get oob event)!!\n"); - return 0; + ftdm_status_t status; + ftdm_event_t *fevent = NULL; + ftdm_channel_t *ftdmchan = openr2_chan_get_fd(r2chan); + + *event = OR2_OOB_EVENT_NONE; + status = ftdm_channel_read_event(ftdmchan, &fevent); + if (status != FTDM_SUCCESS) { + //ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "failed to retrieve freetdm event!\n"); + return -1; + } + if (fevent->e_type != FTDM_EVENT_OOB) + return 0; + switch (fevent->enum_id) { + case FTDM_OOB_CAS_BITS_CHANGE: + { + *event = OR2_OOB_EVENT_CAS_CHANGE; + } + break; + case FTDM_OOB_ALARM_TRAP: + { + *event = OR2_OOB_EVENT_ALARM_ON; + } + break; + case FTDM_OOB_ALARM_CLEAR: + { + *event = OR2_OOB_EVENT_ALARM_OFF; + } + break; + } + ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "returning event: %s\n", ftdm_signal_event2str(*event)); + return 0; } static openr2_io_interface_t ftdm_r2_io_iface = { @@ -1137,7 +1138,7 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_r2_configure_span) span->start = ftdm_r2_start; span->stop = ftdm_r2_stop; - span->sig_read = ftdm_r2_sig_read; + span->sig_read = NULL; span->signal_cb = sig_cb; span->signal_type = FTDM_SIGTYPE_R2; @@ -1350,6 +1351,7 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj) int ms; struct timeval start, end; short *poll_events = ftdm_malloc(sizeof(short)*span->chan_count); + ftdm_event_t *event = NULL; #ifdef __linux__ r2data->monitor_thread_id = syscall(SYS_gettid); @@ -1401,63 +1403,44 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj) continue; } - if (FTDM_SUCCESS == status) { - ftdm_event_t *event; - while (ftdm_span_next_event(span, &event) == FTDM_SUCCESS) { - if (event->enum_id == FTDM_OOB_CAS_BITS_CHANGE) { - r2call = R2CALL(event->channel); - r2chan = r2call->r2chan; + /* XXX + * when ftdm_span_poll_event() returns FTDM_SUCCESS, means there are events pending on the span. + * is it possible to know on which channels those events are pending, without traversing the span? + * XXX */ + for (i = 1; i <= span->chan_count; i++) { + r2chan = R2CALL(span->channels[i])->r2chan; + r2call = R2CALL(ftdmchan); + ftdmchan = openr2_chan_get_client_data(r2chan); - ftdm_log(FTDM_LOG_DEBUG, "Handling CAS on channel %d.\n", openr2_chan_get_number(r2chan)); - // we only expect CAS and other OOB events on this thread/loop, once a call is started - // the MF events (in-band signaling) are handled in the call thread - openr2_chan_process_cas_signaling(r2chan); - } else { - ftdm_log(FTDM_LOG_DEBUG, "Ignoring event %d on channel %d.\n", event->enum_id, openr2_chan_get_number(r2chan)); - // XXX TODO: handle alarms here XXX + status = ftdm_channel_read_event(ftdmchan, &event); + ftdm_mutex_lock(ftdmchan->mutex); + if (status == FTDM_SUCCESS) { + switch (event->enum_id) { + case FTDM_OOB_CAS_BITS_CHANGE: + { + ftdm_log(FTDM_LOG_DEBUG, "Handling CAS on channel %d.\n", i); + openr2_chan_process_cas_signaling(r2chan); + } + break; + case FTDM_OOB_ALARM_TRAP: + case FTDM_OOB_ALARM_CLEAR: + { + ftdm_log(FTDM_LOG_DEBUG, "OOB EVENT: %s\n", ftdm_signal_event2str(event->enum_id)); + openr2_chan_process_oob_events(r2chan); + } + break; } } - /* XXX - * when ftdm_span_poll_event() returns FTDM_SUCCESS, means there are events pending on the span. - * is it possible to know on which channels those events are pending, without traversing the span? - * XXX */ - for (i = 1; i <= span->chan_count; i++) { - r2chan = R2CALL(span->channels[i])->r2chan; - ftdmchan = openr2_chan_get_client_data(r2chan); - r2call = R2CALL(ftdmchan); - - ftdm_mutex_lock(ftdmchan->mutex); - ftdm_set_flag(r2call, FTDM_R2_PROCESSING); - - if (ftdm_r2_state_advance(ftdmchan)) { - ftdm_clear_flag(r2call, FTDM_R2_PROCESSING); - ftdm_mutex_unlock(ftdmchan->mutex); - continue; - } - - /* handle timeout events first if any */ - openr2_chan_run_schedule(r2chan); - - /* process mf tones, if any */ - if (openr2_chan_get_read_enabled(r2chan)) { - openr2_chan_process_mf_signaling(r2chan); - } - - if (ftdm_r2_state_advance(ftdmchan)) { - ftdm_clear_flag(r2call, FTDM_R2_PROCESSING); - ftdm_mutex_unlock(ftdmchan->mutex); - continue; - } - - ftdm_clear_flag(r2call, FTDM_R2_PROCESSING); + if (!ftdm_r2_state_advance(ftdmchan)) { + ftdm_mutex_unlock(ftdmchan->mutex); + } + openr2_chan_process_signaling(r2chan); + if (!ftdm_r2_state_advance(ftdmchan)) { ftdm_mutex_unlock(ftdmchan->mutex); } - } else if (status != FTDM_TIMEOUT) { - ftdm_log(FTDM_LOG_ERROR, "ftdm_span_poll_event returned %d.\n", status); } ftdm_span_trigger_signals(span); - ftdm_sleep(20); } for (i = 1; i <= span->chan_count; i++) { diff --git a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c index c13455dd21..ae46852300 100644 --- a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c +++ b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c @@ -35,6 +35,7 @@ * Moises Silva * David Yat Sin * Nenad Corbic + * Arnaldo Pereira * */ @@ -99,7 +100,8 @@ static struct { /* a bunch of this stuff should go into the wanpipe_tdm_api_iface.h */ FIO_SPAN_POLL_EVENT_FUNCTION(wanpipe_poll_event); -FIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_next_event); +FIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_span_next_event); +FIO_CHANNEL_NEXT_EVENT_FUNCTION(wanpipe_channel_next_event); /** * \brief Poll for event on a wanpipe socket @@ -1110,13 +1112,188 @@ static FIO_GET_ALARMS_FUNCTION(wanpipe_get_alarms) return FTDM_SUCCESS; } +/** + * \brief Retrieves an event from a wanpipe channel + * \param channel Channel to retrieve event from + * \param event FreeTDM event to return + * \return Success or failure + */ +FIO_CHANNEL_NEXT_EVENT_FUNCTION(wanpipe_channel_next_event) +{ + ftdm_status_t status; + ftdm_oob_event_t event_id; + wanpipe_tdm_api_t tdm_api; + ftdm_span_t *span = ftdmchan->span; + + if (ftdmchan->last_event_time && !ftdm_test_flag(ftdmchan, FTDM_CHANNEL_EVENT)) { + uint32_t diff = (uint32_t)(ftdm_current_time_in_ms() - ftdmchan->last_event_time); + /* XX printf("%u %u %u\n", diff, (unsigned)ftdm_current_time_in_ms(), (unsigned)ftdmchan->last_event_time); */ + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_WINK)) { + if (diff > wp_globals.wink_ms) { + ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_WINK); + ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_FLASH); + ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_OFFHOOK); + event_id = FTDM_OOB_OFFHOOK; + goto event; + } + } + + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_FLASH)) { + if (diff > wp_globals.flash_ms) { + ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_FLASH); + ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_WINK); + ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_OFFHOOK); + event_id = FTDM_OOB_ONHOOK; + + if (ftdmchan->type == FTDM_CHAN_TYPE_FXO) { + wanpipe_tdm_api_t tdm_api; + memset(&tdm_api, 0, sizeof(tdm_api)); + + sangoma_tdm_txsig_onhook(ftdmchan->sockfd,&tdm_api); + } + goto event; + } + } + } + + if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_EVENT)) + return FTDM_FAIL; + + memset(&tdm_api, 0, sizeof(tdm_api)); + status = sangoma_tdm_read_event(ftdmchan->sockfd, &tdm_api); + if (status != FTDM_SUCCESS) { + snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno)); + ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Failed to read event from channel: %s\n", strerror(errno)); + return FTDM_FAIL; + } + + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "read wanpipe event %d\n", tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type); + switch(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type) { + + case WP_TDMAPI_EVENT_LINK_STATUS: + { + switch(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_link_status) { + case WP_TDMAPI_EVENT_LINK_STATUS_CONNECTED: + event_id = FTDM_OOB_ALARM_CLEAR; + break; + default: + event_id = FTDM_OOB_ALARM_TRAP; + break; + }; + } + break; + + case WP_TDMAPI_EVENT_RXHOOK: + { + if (ftdmchan->type == FTDM_CHAN_TYPE_FXS) { + event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_hook_state & WP_TDMAPI_EVENT_RXHOOK_OFF ? FTDM_OOB_OFFHOOK : FTDM_OOB_ONHOOK; + if (event_id == FTDM_OOB_OFFHOOK) { + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_FLASH)) { + ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_FLASH); + ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_WINK); + event_id = FTDM_OOB_FLASH; + goto event; + } else { + ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_WINK); + } + } else { + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_WINK)) { + ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_WINK); + ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_FLASH); + event_id = FTDM_OOB_WINK; + goto event; + } else { + ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_FLASH); + } + } + break; + } else { + wanpipe_tdm_api_t onhook_tdm_api; + memset(&onhook_tdm_api, 0, sizeof(onhook_tdm_api)); + status = sangoma_tdm_txsig_onhook(ftdmchan->sockfd, &onhook_tdm_api); + if (status) { + snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "ONHOOK Failed"); + return FTDM_FAIL; + } + event_id = onhook_tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_hook_state & WP_TDMAPI_EVENT_RXHOOK_OFF ? FTDM_OOB_ONHOOK : FTDM_OOB_NOOP; + } + } + break; + case WP_TDMAPI_EVENT_RING_DETECT: + { + event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_ring_state == WP_TDMAPI_EVENT_RING_PRESENT ? FTDM_OOB_RING_START : FTDM_OOB_RING_STOP; + } + break; + /* + disabled this ones when configuring, we don't need them, do we? + case WP_TDMAPI_EVENT_RING_TRIP_DETECT: + { + event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_ring_state == WP_TDMAPI_EVENT_RING_PRESENT ? FTDM_OOB_ONHOOK : FTDM_OOB_OFFHOOK; + } + break; + */ + case WP_TDMAPI_EVENT_RBS: + { + event_id = FTDM_OOB_CAS_BITS_CHANGE; + ftdmchan->rx_cas_bits = wanpipe_swap_bits(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_rbs_bits); + } + break; + case WP_TDMAPI_EVENT_DTMF: + { + char tmp_dtmf[2] = { tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_dtmf_digit, 0 }; + event_id = FTDM_OOB_NOOP; + + if (tmp_dtmf[0] == 'f') { + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Ignoring wanpipe DTMF: %c, fax tones will be passed through!\n", tmp_dtmf[0]); + break; + } + + if (tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_dtmf_type == WAN_EC_TONE_PRESENT) { + ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_MUTE); + } + + if (tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_dtmf_type == WAN_EC_TONE_STOP) { + ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_MUTE); + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INUSE)) { + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Queuing wanpipe DTMF: %c\n", tmp_dtmf[0]); + ftdm_channel_queue_dtmf(ftdmchan, tmp_dtmf); + } + } + } + break; + case WP_TDMAPI_EVENT_ALARM: + { + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Got wanpipe alarms %d\n", tdm_api.wp_tdm_cmd.event.wp_api_event_alarm); + event_id = FTDM_OOB_ALARM_TRAP; + } + break; + default: + { + ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Unhandled wanpipe event %d\n", tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type); + event_id = FTDM_OOB_INVALID; + } + break; + } + +event: + + ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_EVENT); + + ftdmchan->last_event_time = 0; + span->event_header.e_type = FTDM_EVENT_OOB; + span->event_header.enum_id = event_id; + span->event_header.channel = ftdmchan; + *event = &span->event_header; + return FTDM_SUCCESS; +} + /** * \brief Retrieves an event from a wanpipe span * \param span Span to retrieve event from * \param event FreeTDM event to return * \return Success or failure */ -FIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_next_event) +FIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_span_next_event) { uint32_t i,err; ftdm_oob_event_t event_id; @@ -1348,7 +1525,8 @@ static FIO_IO_LOAD_FUNCTION(wanpipe_init) wanpipe_interface.read = wanpipe_read; wanpipe_interface.write = wanpipe_write; wanpipe_interface.poll_event = wanpipe_poll_event; - wanpipe_interface.next_event = wanpipe_next_event; + wanpipe_interface.next_event = wanpipe_span_next_event; + wanpipe_interface.channel_next_event = wanpipe_channel_next_event; wanpipe_interface.channel_destroy = wanpipe_channel_destroy; wanpipe_interface.get_alarms = wanpipe_get_alarms; *fio = &wanpipe_interface; diff --git a/libs/freetdm/src/include/freetdm.h b/libs/freetdm/src/include/freetdm.h index 508c6996d5..9ce213c962 100644 --- a/libs/freetdm/src/include/freetdm.h +++ b/libs/freetdm/src/include/freetdm.h @@ -465,6 +465,7 @@ struct ftdm_memory_handler { #define FIO_SPAN_GET_SIG_STATUS_ARGS (ftdm_span_t *span, ftdm_signaling_status_t *status) #define FIO_SPAN_POLL_EVENT_ARGS (ftdm_span_t *span, uint32_t ms, short *poll_events) #define FIO_SPAN_NEXT_EVENT_ARGS (ftdm_span_t *span, ftdm_event_t **event) +#define FIO_CHANNEL_NEXT_EVENT_ARGS (ftdm_channel_t *ftdmchan, ftdm_event_t **event) #define FIO_SIGNAL_CB_ARGS (ftdm_sigmsg_t *sigmsg) #define FIO_EVENT_CB_ARGS (ftdm_channel_t *ftdmchan, ftdm_event_t *event) #define FIO_CONFIGURE_SPAN_ARGS (ftdm_span_t *span, const char *str, ftdm_chan_type_t type, char *name, char *number) @@ -496,6 +497,7 @@ typedef ftdm_status_t (*fio_span_set_sig_status_t) FIO_SPAN_SET_SIG_STATUS_ARGS; typedef ftdm_status_t (*fio_span_get_sig_status_t) FIO_SPAN_GET_SIG_STATUS_ARGS; typedef ftdm_status_t (*fio_span_poll_event_t) FIO_SPAN_POLL_EVENT_ARGS ; typedef ftdm_status_t (*fio_span_next_event_t) FIO_SPAN_NEXT_EVENT_ARGS ; +typedef ftdm_status_t (*fio_channel_next_event_t) FIO_CHANNEL_NEXT_EVENT_ARGS ; typedef ftdm_status_t (*fio_signal_cb_t) FIO_SIGNAL_CB_ARGS ; typedef ftdm_status_t (*fio_event_cb_t) FIO_EVENT_CB_ARGS ; typedef ftdm_status_t (*fio_configure_span_t) FIO_CONFIGURE_SPAN_ARGS ; @@ -528,6 +530,7 @@ typedef ftdm_status_t (*fio_api_t) FIO_API_ARGS ; #define FIO_SPAN_GET_SIG_STATUS_FUNCTION(name) ftdm_status_t name FIO_SPAN_GET_SIG_STATUS_ARGS #define FIO_SPAN_POLL_EVENT_FUNCTION(name) ftdm_status_t name FIO_SPAN_POLL_EVENT_ARGS #define FIO_SPAN_NEXT_EVENT_FUNCTION(name) ftdm_status_t name FIO_SPAN_NEXT_EVENT_ARGS +#define FIO_CHANNEL_NEXT_EVENT_FUNCTION(name) ftdm_status_t name FIO_CHANNEL_NEXT_EVENT_ARGS #define FIO_SIGNAL_CB_FUNCTION(name) ftdm_status_t name FIO_SIGNAL_CB_ARGS #define FIO_EVENT_CB_FUNCTION(name) ftdm_status_t name FIO_EVENT_CB_ARGS #define FIO_CONFIGURE_SPAN_FUNCTION(name) ftdm_status_t name FIO_CONFIGURE_SPAN_ARGS @@ -566,6 +569,7 @@ struct ftdm_io_interface { fio_write_t write; /*!< Write data to the channel */ fio_span_poll_event_t poll_event; /*!< Poll for events on the whole span */ fio_span_next_event_t next_event; /*!< Retrieve an event from the span */ + fio_channel_next_event_t channel_next_event; /*!< Retrieve an event from channel */ fio_api_t api; /*!< Execute a text command */ }; diff --git a/libs/freetdm/src/include/private/ftdm_core.h b/libs/freetdm/src/include/private/ftdm_core.h index 06f899c8c9..7d3ee68176 100644 --- a/libs/freetdm/src/include/private/ftdm_core.h +++ b/libs/freetdm/src/include/private/ftdm_core.h @@ -615,6 +615,23 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_open_chan(ftdm_channel_t *ftdmchan); */ FT_DECLARE(ftdm_status_t) ftdm_span_next_event(ftdm_span_t *span, ftdm_event_t **event); +/*! + * \brief Retrieves an event from the span + * + * \note + * This function is non-reentrant and not thread-safe. + * The event returned may be modified if the function is called again + * from a different thread or even the same. It is recommended to + * handle events from the same span in a single thread. + * + * \param span The channel to retrieve the event from + * \param event Pointer to store the pointer to the event + * + * \retval FTDM_SUCCESS success (at least one event available) + * \retval FTDM_FAIL failure + */ +FT_DECLARE(ftdm_status_t) ftdm_channel_read_event(ftdm_channel_t *ftdmchan, ftdm_event_t **event); + /*! * \brief Enqueue a DTMF string into the channel * From a5d53b8a38b770f702fa55d72e996ed54a32f181 Mon Sep 17 00:00:00 2001 From: Arnaldo Pereira Date: Wed, 24 Nov 2010 22:14:06 -0200 Subject: [PATCH 02/78] freetdm: removed wrong main loop code --- libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c | 30 +++------------------- 1 file changed, 4 insertions(+), 26 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c index 7c5f4a46af..8a4a826906 100644 --- a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c +++ b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c @@ -847,7 +847,7 @@ static int ftdm_r2_io_get_oob_event(openr2_chan_t *r2chan, openr2_oob_event_t *e *event = OR2_OOB_EVENT_NONE; status = ftdm_channel_read_event(ftdmchan, &fevent); if (status != FTDM_SUCCESS) { - //ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "failed to retrieve freetdm event!\n"); + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "failed to retrieve freetdm event!\n"); return -1; } if (fevent->e_type != FTDM_EVENT_OOB) @@ -1412,33 +1412,11 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj) r2call = R2CALL(ftdmchan); ftdmchan = openr2_chan_get_client_data(r2chan); - status = ftdm_channel_read_event(ftdmchan, &event); ftdm_mutex_lock(ftdmchan->mutex); - if (status == FTDM_SUCCESS) { - switch (event->enum_id) { - case FTDM_OOB_CAS_BITS_CHANGE: - { - ftdm_log(FTDM_LOG_DEBUG, "Handling CAS on channel %d.\n", i); - openr2_chan_process_cas_signaling(r2chan); - } - break; - case FTDM_OOB_ALARM_TRAP: - case FTDM_OOB_ALARM_CLEAR: - { - ftdm_log(FTDM_LOG_DEBUG, "OOB EVENT: %s\n", ftdm_signal_event2str(event->enum_id)); - openr2_chan_process_oob_events(r2chan); - } - break; - } - } - - if (!ftdm_r2_state_advance(ftdmchan)) { - ftdm_mutex_unlock(ftdmchan->mutex); - } + ftdm_r2_state_advance(ftdmchan); openr2_chan_process_signaling(r2chan); - if (!ftdm_r2_state_advance(ftdmchan)) { - ftdm_mutex_unlock(ftdmchan->mutex); - } + ftdm_r2_state_advance(ftdmchan); + ftdm_mutex_unlock(ftdmchan->mutex); } ftdm_span_trigger_signals(span); } From 2b0189becad007b0683272a0a3d46a952cc520ed Mon Sep 17 00:00:00 2001 From: Arnaldo Pereira Date: Wed, 24 Nov 2010 22:58:05 -0200 Subject: [PATCH 03/78] freetdm: now wanpipe_channel_next_event() doesn't expect the flag FTDM_CHANNEL_EVENT to be set. If it is, it just clears it. Also removed unused code from wanpipe_channel_next_event() --- .../src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c | 39 ++----------------- 1 file changed, 4 insertions(+), 35 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c index ae46852300..1a43c4db50 100644 --- a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c +++ b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c @@ -1125,45 +1125,16 @@ FIO_CHANNEL_NEXT_EVENT_FUNCTION(wanpipe_channel_next_event) wanpipe_tdm_api_t tdm_api; ftdm_span_t *span = ftdmchan->span; - if (ftdmchan->last_event_time && !ftdm_test_flag(ftdmchan, FTDM_CHANNEL_EVENT)) { - uint32_t diff = (uint32_t)(ftdm_current_time_in_ms() - ftdmchan->last_event_time); - /* XX printf("%u %u %u\n", diff, (unsigned)ftdm_current_time_in_ms(), (unsigned)ftdmchan->last_event_time); */ - if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_WINK)) { - if (diff > wp_globals.wink_ms) { - ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_WINK); - ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_FLASH); - ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_OFFHOOK); - event_id = FTDM_OOB_OFFHOOK; - goto event; - } - } - - if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_FLASH)) { - if (diff > wp_globals.flash_ms) { - ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_FLASH); - ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_WINK); - ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_OFFHOOK); - event_id = FTDM_OOB_ONHOOK; - - if (ftdmchan->type == FTDM_CHAN_TYPE_FXO) { - wanpipe_tdm_api_t tdm_api; - memset(&tdm_api, 0, sizeof(tdm_api)); - - sangoma_tdm_txsig_onhook(ftdmchan->sockfd,&tdm_api); - } - goto event; - } - } - } - - if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_EVENT)) - return FTDM_FAIL; + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_EVENT)) + ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_EVENT); memset(&tdm_api, 0, sizeof(tdm_api)); status = sangoma_tdm_read_event(ftdmchan->sockfd, &tdm_api); if (status != FTDM_SUCCESS) { +#if 0 snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno)); ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Failed to read event from channel: %s\n", strerror(errno)); +#endif return FTDM_FAIL; } @@ -1277,8 +1248,6 @@ FIO_CHANNEL_NEXT_EVENT_FUNCTION(wanpipe_channel_next_event) event: - ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_EVENT); - ftdmchan->last_event_time = 0; span->event_header.e_type = FTDM_EVENT_OOB; span->event_header.enum_id = event_id; From 9fbecc60bee1601cf7a53775ecaa7e97229cca43 Mon Sep 17 00:00:00 2001 From: Arnaldo Pereira Date: Thu, 25 Nov 2010 00:36:01 -0200 Subject: [PATCH 04/78] freetdm: on ftmod_r2, fixed flags for correctly polling the span, now freeing poll_events pointer, enabling/disabling channel reading flag when needed. also removed the test for FTDM_CHANNEL_OPEN flag on ftdm_channel_wait(). --- libs/freetdm/src/ftdm_io.c | 5 ----- libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c | 18 ++++++++++++------ .../src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c | 2 -- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index 0065d779f6..23ed68c45a 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -2869,11 +2869,6 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_wait(ftdm_channel_t *ftdmchan, ftdm_wait_ assert(ftdmchan != NULL); assert(ftdmchan->fio != NULL); - if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OPEN)) { - snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "channel not open"); - return FTDM_FAIL; - } - if (!ftdmchan->fio->wait) { snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "method not implemented"); return FTDM_FAIL; diff --git a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c index 8a4a826906..52c0f86e6c 100644 --- a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c +++ b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c @@ -781,7 +781,7 @@ static int ftdm_r2_io_wait(openr2_chan_t *r2chan, int *flags, int block) int32_t timeout; ftdm_wait_flag_t ftdmflags = 0; - ftdm_channel_t *ftdm_chan = openr2_chan_get_fd(r2chan); + ftdm_channel_t *fchan = openr2_chan_get_fd(r2chan); timeout = block ? -1 : 0; if (*flags & OR2_IO_READ) { @@ -794,9 +794,10 @@ static int ftdm_r2_io_wait(openr2_chan_t *r2chan, int *flags, int block) ftdmflags |= FTDM_EVENTS; } - status = ftdm_channel_wait(ftdm_chan, &ftdmflags, timeout); + status = ftdm_channel_wait(fchan, &ftdmflags, timeout); if (FTDM_SUCCESS != status && FTDM_TIMEOUT != status) { + ftdm_log_chan_msg(fchan, FTDM_LOG_ERROR, "Failed to wait for events on channel\n"); return -1; } @@ -869,7 +870,6 @@ static int ftdm_r2_io_get_oob_event(openr2_chan_t *r2chan, openr2_oob_event_t *e } break; } - ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "returning event: %s\n", ftdm_signal_event2str(*event)); return 0; } @@ -1212,6 +1212,7 @@ static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan) ftdm_channel_command(ftdmchan, FTDM_COMMAND_GET_INTERVAL, &interval); ftdm_assert(interval != 0, "Invalid interval!"); ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Starting processing of incoming call with interval %d\n", interval); + openr2_chan_enable_read(r2chan); } break; @@ -1223,6 +1224,7 @@ static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan) ftdm_assert(interval != 0, "Invalid interval!"); ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Starting processing of outgoing call in channel with interval %d\n", interval); + openr2_chan_enable_read(r2chan); } break; @@ -1289,7 +1291,6 @@ static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan) { openr2_call_disconnect_cause_t disconnect_cause = ftdm_r2_ftdm_cause_to_openr2_cause(ftdmchan); ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Clearing call, cause = %s\n", openr2_proto_get_disconnect_string(disconnect_cause)); - openr2_chan_enable_read(r2chan); if (!R2CALL(ftdmchan)->disconnect_rcvd) { /* this will disconnect the call, but need to wait for the call end before moving to DOWN */ openr2_chan_disconnect_call(r2chan, disconnect_cause); @@ -1304,7 +1305,6 @@ static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan) case FTDM_CHANNEL_STATE_CANCEL: { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Unable to receive call\n"); - openr2_chan_enable_read(r2chan); openr2_chan_disconnect_call(r2chan, OR2_CAUSE_OUT_OF_ORDER); } break; @@ -1316,6 +1316,7 @@ static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan) if (R2CALL(ftdmchan)->txdrops) { ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "dropped %d tx packets\n", R2CALL(ftdmchan)->txdrops); } + openr2_chan_disable_read(r2chan); ret = 1; } break; @@ -1385,7 +1386,10 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj) for (i = 0; i < span->chan_count; i++) { r2chan = R2CALL(span->channels[(i+1)])->r2chan; ftdmchan = openr2_chan_get_client_data(r2chan); - poll_events[i] = ftdmchan->state == FTDM_CHANNEL_STATE_DOWN ? POLLPRI : (POLLPRI | POLLIN | POLLOUT); + poll_events[i] = POLLPRI; + if (openr2_chan_get_read_enabled(r2chan)) { + poll_events[i] |= POLLIN; + } } status = ftdm_span_poll_event(span, waitms, poll_events); @@ -1426,6 +1430,8 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj) openr2_chan_set_blocked(r2chan); } + ftdm_safe_free(poll_events); + ftdm_clear_flag(r2data, FTDM_R2_RUNNING); ftdm_log(FTDM_LOG_DEBUG, "R2 thread ending.\n"); diff --git a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c index 1a43c4db50..c55d42e8b0 100644 --- a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c +++ b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c @@ -1131,10 +1131,8 @@ FIO_CHANNEL_NEXT_EVENT_FUNCTION(wanpipe_channel_next_event) memset(&tdm_api, 0, sizeof(tdm_api)); status = sangoma_tdm_read_event(ftdmchan->sockfd, &tdm_api); if (status != FTDM_SUCCESS) { -#if 0 snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno)); ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Failed to read event from channel: %s\n", strerror(errno)); -#endif return FTDM_FAIL; } From 37ce4003e129097e179f213c86e00b3307cc1738 Mon Sep 17 00:00:00 2001 From: Arnaldo Pereira Date: Thu, 25 Nov 2010 14:31:30 -0200 Subject: [PATCH 05/78] freetdm: eliminated some warnings from ftmod_r2 windows build --- libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c index 52c0f86e6c..bfe49fd8ca 100644 --- a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c +++ b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c @@ -889,7 +889,7 @@ static openr2_io_interface_t ftdm_r2_io_iface = { static FIO_SIG_CONFIGURE_FUNCTION(ftdm_r2_configure_span) //ftdm_status_t (ftdm_span_t *span, fio_signal_cb_t sig_cb, va_list ap) { - int i = 0; + unsigned int i = 0; int conf_failure = 0; char *var = NULL; char *val = NULL; @@ -1107,11 +1107,6 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_r2_configure_span) openr2_chan_set_log_level(r2chan, r2conf.loglevel); if (r2conf.call_files) { openr2_chan_enable_call_files(r2chan); -#if 0 - if (r2conf.mf_files) { - openr2_chan_enable_mf_files(r2chan); - } -#endif } r2call = ftdm_malloc(sizeof(*r2call)); @@ -1348,8 +1343,8 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj) ftdm_span_t *span = (ftdm_span_t *) obj; ftdm_r2_data_t *r2data = span->signal_data; int waitms = 20; - int i, res; - int ms; + unsigned int i; + int res, ms; struct timeval start, end; short *poll_events = ftdm_malloc(sizeof(short)*span->chan_count); ftdm_event_t *event = NULL; @@ -1413,8 +1408,8 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj) * XXX */ for (i = 1; i <= span->chan_count; i++) { r2chan = R2CALL(span->channels[i])->r2chan; - r2call = R2CALL(ftdmchan); ftdmchan = openr2_chan_get_client_data(r2chan); + r2call = R2CALL(ftdmchan); ftdm_mutex_lock(ftdmchan->mutex); ftdm_r2_state_advance(ftdmchan); @@ -1487,8 +1482,8 @@ static FIO_API_FUNCTION(ftdm_r2_api) char *mycmd = NULL, *argv[10] = { 0 }; int argc = 0; int span_id = 0; - int chan_id = 0; - int i = 0; + unsigned int chan_id = 0; + unsigned int i = 0; ftdm_r2_data_t *r2data = NULL; openr2_chan_t *r2chan = NULL; openr2_context_t *r2context = NULL; From b7c82d4c2efa974e8c867826253732139f9fb385 Mon Sep 17 00:00:00 2001 From: Arnaldo Pereira Date: Thu, 25 Nov 2010 15:40:44 -0200 Subject: [PATCH 06/78] freetdm: moved ftdm_channel_read_event() to freetdm.h --- libs/freetdm/src/include/freetdm.h | 17 +++++++++++++++++ libs/freetdm/src/include/private/ftdm_core.h | 17 ----------------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/libs/freetdm/src/include/freetdm.h b/libs/freetdm/src/include/freetdm.h index 9ce213c962..eff6305913 100644 --- a/libs/freetdm/src/include/freetdm.h +++ b/libs/freetdm/src/include/freetdm.h @@ -888,6 +888,23 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_add_to_group(const char* name, ftdm_chann /*! \brief Remove the channel from a hunt group */ FT_DECLARE(ftdm_status_t) ftdm_channel_remove_from_group(ftdm_group_t* group, ftdm_channel_t* ftdmchan); +/*! + * \brief Retrieves an event from the span + * + * \note + * This function is non-reentrant and not thread-safe. + * The event returned may be modified if the function is called again + * from a different thread or even the same. It is recommended to + * handle events from the same span in a single thread. + * + * \param span The channel to retrieve the event from + * \param event Pointer to store the pointer to the event + * + * \retval FTDM_SUCCESS success (at least one event available) + * \retval FTDM_FAIL failure + */ +FT_DECLARE(ftdm_status_t) ftdm_channel_read_event(ftdm_channel_t *ftdmchan, ftdm_event_t **event); + /*! \brief Find a hunt group by id */ FT_DECLARE(ftdm_status_t) ftdm_group_find(uint32_t id, ftdm_group_t **group); diff --git a/libs/freetdm/src/include/private/ftdm_core.h b/libs/freetdm/src/include/private/ftdm_core.h index 7d3ee68176..06f899c8c9 100644 --- a/libs/freetdm/src/include/private/ftdm_core.h +++ b/libs/freetdm/src/include/private/ftdm_core.h @@ -615,23 +615,6 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_open_chan(ftdm_channel_t *ftdmchan); */ FT_DECLARE(ftdm_status_t) ftdm_span_next_event(ftdm_span_t *span, ftdm_event_t **event); -/*! - * \brief Retrieves an event from the span - * - * \note - * This function is non-reentrant and not thread-safe. - * The event returned may be modified if the function is called again - * from a different thread or even the same. It is recommended to - * handle events from the same span in a single thread. - * - * \param span The channel to retrieve the event from - * \param event Pointer to store the pointer to the event - * - * \retval FTDM_SUCCESS success (at least one event available) - * \retval FTDM_FAIL failure - */ -FT_DECLARE(ftdm_status_t) ftdm_channel_read_event(ftdm_channel_t *ftdmchan, ftdm_event_t **event); - /*! * \brief Enqueue a DTMF string into the channel * From 1bd4de4fd95c4dc33a379f537f93ab36f4134d5f Mon Sep 17 00:00:00 2001 From: Arnaldo Pereira Date: Thu, 25 Nov 2010 22:11:20 -0200 Subject: [PATCH 07/78] freetdm: when protocol errors occurs on ftmod_r2, the channel state is properly set as down now --- libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c | 42 +++++++++++++--------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c index bfe49fd8ca..f089846fae 100644 --- a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c +++ b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c @@ -67,9 +67,9 @@ typedef struct ftdm_r2_call_t { ftdm_r2_call_flag_t flags; int accepted:1; int answer_pending:1; - int state_ack_pending:1; int disconnect_rcvd:1; int ftdm_started:1; + int protocol_error:1; ftdm_channel_state_t chanstate; ftdm_size_t dnis_index; ftdm_size_t ani_index; @@ -456,10 +456,12 @@ static void ftdm_r2_on_call_accepted(openr2_chan_t *r2chan, openr2_call_mode_t m openr2_chan_disable_read(r2chan); R2CALL(ftdmchan)->accepted = 1; if (OR2_DIR_BACKWARD == openr2_chan_get_direction(r2chan)) { - R2CALL(ftdmchan)->state_ack_pending = 1; + ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE); + ftdm_channel_complete_state(ftdmchan); if (R2CALL(ftdmchan)->answer_pending) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Answer was pending, answering now.\n"); ft_r2_answer_call(ftdmchan); + R2CALL(ftdmchan)->answer_pending = 0; return; } } else { @@ -522,7 +524,7 @@ static void ftdm_r2_on_call_end(openr2_chan_t *r2chan) ftdm_log_chan_msg(ftdmchan, FTDM_LOG_NOTICE, "Call finished\n"); /* the call is done as far as the stack is concerned, lets move to down here */ - ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN); + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN); /* in some circumstances openr2 can call on_call_init right after this, so let's advance the state right here */ ftdm_r2_state_advance(ftdmchan); @@ -560,6 +562,7 @@ static void ftdm_r2_on_protocol_error(openr2_chan_t *r2chan, openr2_protocol_err ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Protocol error\n"); R2CALL(ftdmchan)->disconnect_rcvd = 1; + R2CALL(ftdmchan)->protocol_error = 1; if (!R2CALL(ftdmchan)->ftdm_started) { ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_HANGUP); @@ -1173,13 +1176,13 @@ static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan) ret = 0; - if (R2CALL(ftdmchan)->state_ack_pending) { - ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE); - ftdm_channel_complete_state(ftdmchan); - R2CALL(ftdmchan)->state_ack_pending = 0; - } - - if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE) && (R2CALL(ftdmchan)->chanstate != ftdmchan->state)) { + /* because we do not always acknowledge the state change (clearing the FTDM_CHANNEL_STATE_CHANGE flag) due to the accept + * procedure described below, we need the chanstate member to NOT process some states twice, so is valid entering this + * function with the FTDM_CHANNEL_STATE_CHANGE flag set but with a state that was already processed and is just waiting + * to complete (the processing is media-bound) + * */ + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE) + && (R2CALL(ftdmchan)->chanstate != ftdmchan->state)) { ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Executing state handler for %s\n", ftdm_channel_state2str(ftdmchan->state)); R2CALL(ftdmchan)->chanstate = ftdmchan->state; @@ -1188,10 +1191,15 @@ static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan) (ftdmchan->state == FTDM_CHANNEL_STATE_PROGRESS || ftdmchan->state == FTDM_CHANNEL_STATE_PROGRESS_MEDIA || ftdmchan->state == FTDM_CHANNEL_STATE_UP) ) { - /* if an accept ack will be required we should not acknowledge the state change just yet, - it will be done below after processing the MF signals, otherwise we have a race condition between freetdm calling - openr2_chan_answer_call and openr2 accepting the call first, if freetdm calls openr2_chan_answer_call before the accept cycle - completes, openr2 will fail to answer the call */ + /* + Moving to PROGRESS, PROGRESS_MEDIA or UP means that we must accept the call, and accepting + the call in R2 means sending a tone, then waiting for the acknowledge from the other end, + since all of that requires sending and detecting tones, it takes a few milliseconds (I'd say around 100) + which means during that time the user should not try to perform any operations like answer, hangup or anything + else, therefore we DO NOT clear the FTDM_CHANNEL_STATE_CHANGE flag here, we rely on ftdm_io.c to block + the user thread until we're done with the accept (see on_call_accepted callback) and then we clear the state change flag, + otherwise we have a race condition between freetdm calling openr2_chan_answer_call and openr2 accepting the call first, + if freetdm calls openr2_chan_answer_call before the accept cycle completes, openr2 will fail to answer the call */ ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "State ack for state %s will have to wait a bit\n", ftdm_channel_state2str(ftdmchan->state)); } else if (ftdmchan->state != FTDM_CHANNEL_STATE_DOWN){ ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE); @@ -1289,9 +1297,12 @@ static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan) if (!R2CALL(ftdmchan)->disconnect_rcvd) { /* this will disconnect the call, but need to wait for the call end before moving to DOWN */ openr2_chan_disconnect_call(r2chan, disconnect_cause); - } else { + } else if (!R2CALL(ftdmchan)->protocol_error) { /* just ack the hangup, on_call_end will be called by openr2 right after */ openr2_chan_disconnect_call(r2chan, disconnect_cause); + } else { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Clearing call due to protocol error\n"); + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN); } } break; @@ -1347,7 +1358,6 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj) int res, ms; struct timeval start, end; short *poll_events = ftdm_malloc(sizeof(short)*span->chan_count); - ftdm_event_t *event = NULL; #ifdef __linux__ r2data->monitor_thread_id = syscall(SYS_gettid); From 54a3c95cb0aeb52ca1b8f6cbb80ca0e5d0afdf39 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Thu, 25 Nov 2010 23:42:36 -0500 Subject: [PATCH 08/78] freetdm: add r2 loop timing statistics --- libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c | 64 +++++++++++++++++----- 1 file changed, 51 insertions(+), 13 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c index f089846fae..06d1abdc04 100644 --- a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c +++ b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c @@ -123,11 +123,13 @@ typedef struct ftdm_r2_data_s { /* whether accept the call when offered, or wait until the user decides to accept */ int accept_on_offer:1; /* max time spent in ms doing real work in a single loop */ - int jobmax; - /* total working loops */ - unsigned long loops; + int32_t jobmax; + /* Total number of loops performed so far */ + uint64_t total_loops; + /* number of loops per 10ms increment from 0-9ms, 10-19ms .. 100ms and above */ + uint64_t loops[11]; /* LWP */ - unsigned long monitor_thread_id; + uint32_t monitor_thread_id; } ftdm_r2_data_t; /* one element per span will be stored in g_mod_data_hash global var to keep track of them @@ -1356,8 +1358,9 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj) int waitms = 20; unsigned int i; int res, ms; + int index = 0; struct timeval start, end; - short *poll_events = ftdm_malloc(sizeof(short)*span->chan_count); + short *poll_events = ftdm_malloc(sizeof(short) * span->chan_count); #ifdef __linux__ r2data->monitor_thread_id = syscall(SYS_gettid); @@ -1374,14 +1377,20 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj) memset(&start, 0, sizeof(start)); memset(&end, 0, sizeof(end)); while (ftdm_running() && ftdm_test_flag(r2data, FTDM_R2_RUNNING)) { - r2data->loops++; res = gettimeofday(&end, NULL); if (start.tv_sec) { ms = ((end.tv_sec - start.tv_sec) * 1000) + ((( 1000000 + end.tv_usec - start.tv_usec) / 1000) - 1000); + if (ms < 0) { + ms = 0; + } if (ms > r2data->jobmax) { r2data->jobmax = ms; } + index = (ms / 10); + index = (index > 10) ? 10 : index; + r2data->loops[index]++; + r2data->total_loops++; } #ifndef WIN32 @@ -1576,7 +1585,7 @@ static FIO_API_FUNCTION(ftdm_r2_api) goto done; } if (!(r2data = span->signal_data)) { - stream->write_function(stream, "-ERR invalid span. No R2 singal data in span.\n"); + stream->write_function(stream, "-ERR invalid span. No R2 signal data in span.\n"); goto done; } r2context = r2data->r2context; @@ -1587,19 +1596,17 @@ static FIO_API_FUNCTION(ftdm_r2_api) "Max DNIS: %d\n" "ANI First: %s\n" "Immediate Accept: %s\n" - "Side: %s\n" + "Job Thread: %lu\n" "Job Max ms: %d\n" - "Job Loops: %lu\n" - "Monitor Thread: %lu\n", + "Job Loops: %lu\n", openr2_proto_get_variant_string(r2variant), openr2_context_get_max_ani(r2context), openr2_context_get_max_dnis(r2context), openr2_context_get_ani_first(r2context) ? "Yes" : "No", openr2_context_get_immediate_accept(r2context) ? "Yes" : "No", - "no side", + r2data->monitor_thread_id, r2data->jobmax, - r2data->loops, - r2data->monitor_thread_id); + r2data->total_loops); stream->write_function(stream, "\n"); stream->write_function(stream, "%4s %-12.12s %-12.12s\n", "Channel", "Tx CAS", "Rx CAS"); for (i = 1; i <= span->chan_count; i++) { @@ -1618,6 +1625,37 @@ static FIO_API_FUNCTION(ftdm_r2_api) } } + if (!strcasecmp(argv[0], "loopstats")) { + int range; + span_id = atoi(argv[1]); + + if (ftdm_span_find_by_name(argv[1], &span) == FTDM_SUCCESS || ftdm_span_find(span_id, &span) == FTDM_SUCCESS) { + if (span->start != ftdm_r2_start) { + stream->write_function(stream, "-ERR not an R2 span.\n"); + goto done; + } + if (!(r2data = span->signal_data)) { + stream->write_function(stream, "-ERR invalid span. No R2 signal data in span.\n"); + goto done; + } + range = 0; + for (i = 0; i < ftdm_array_len(r2data->loops); i++) { + if ((i + 1) == ftdm_array_len(r2data->loops)) { + stream->write_function(stream, ">= %dms: %llu\n", range, r2data->loops[i]); + } else { + stream->write_function(stream, "%d-%dms: %llu\n", range, range + 9, r2data->loops[i]); + } + range += 10; + } + stream->write_function(stream, "\n"); + stream->write_function(stream, "+OK.\n"); + goto done; + } else { + stream->write_function(stream, "-ERR invalid span.\n"); + goto done; + } + } + } if (argc == 1) { From 86657a6c0aefb1cb52f47c77aae38415bc584dfe Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Fri, 26 Nov 2010 10:42:37 -0500 Subject: [PATCH 09/78] freetdm: ftmod_r2 - process all state changes before moving to openr2 events or going back to sleep --- libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c index 06d1abdc04..84ddea586c 100644 --- a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c +++ b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c @@ -152,6 +152,7 @@ static ftdm_hash_t *g_mod_data_hash; static ftdm_io_interface_t g_ftdm_r2_interface; static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan); +static int ftdm_r2_state_advance_all(ftdm_channel_t *ftdmchan); /* functions not available on windows */ @@ -529,7 +530,7 @@ static void ftdm_r2_on_call_end(openr2_chan_t *r2chan) ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN); /* in some circumstances openr2 can call on_call_init right after this, so let's advance the state right here */ - ftdm_r2_state_advance(ftdmchan); + ftdm_r2_state_advance_all(ftdmchan); } static void ftdm_r2_on_call_read(openr2_chan_t *r2chan, const unsigned char *buf, int buflen) @@ -1347,6 +1348,20 @@ static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan) return ret; } +/* the channel must be locked when calling this function */ +static void ftdm_r2_state_advance_all(ftdm_channel_t *ftdmchan) +{ + /* because we do not always acknowledge the state change (clearing the FTDM_CHANNEL_STATE_CHANGE flag) due to the accept + * procedure described below, we need the chanstate member to NOT process some states twice, so is valid entering this + * function with the FTDM_CHANNEL_STATE_CHANGE flag set but with a state that was already processed and is just waiting + * to complete (the processing is media-bound) + * */ + while (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE) + && (R2CALL(ftdmchan)->chanstate != ftdmchan->state)) { + ftdm_r2_state_advance(ftdmchan); + } +} + static void *ftdm_r2_run(ftdm_thread_t *me, void *obj) { openr2_chan_t *r2chan; @@ -1431,9 +1446,9 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj) r2call = R2CALL(ftdmchan); ftdm_mutex_lock(ftdmchan->mutex); - ftdm_r2_state_advance(ftdmchan); + ftdm_r2_state_advance_all(ftdmchan); openr2_chan_process_signaling(r2chan); - ftdm_r2_state_advance(ftdmchan); + ftdm_r2_state_advance_all(ftdmchan); ftdm_mutex_unlock(ftdmchan->mutex); } ftdm_span_trigger_signals(span); From ef8682507650792e6a3c38b9a5612526ab0b1ecb Mon Sep 17 00:00:00 2001 From: Arnaldo Pereira Date: Fri, 26 Nov 2010 13:49:34 -0200 Subject: [PATCH 10/78] freetdm: ftmod_r2 - fixed ftdm_r2_state_advance_all() definition --- libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c index 84ddea586c..8514569509 100644 --- a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c +++ b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c @@ -152,7 +152,7 @@ static ftdm_hash_t *g_mod_data_hash; static ftdm_io_interface_t g_ftdm_r2_interface; static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan); -static int ftdm_r2_state_advance_all(ftdm_channel_t *ftdmchan); +static void ftdm_r2_state_advance_all(ftdm_channel_t *ftdmchan); /* functions not available on windows */ From 80031c3e17d78c50d533644bd4bbbbbc181d6252 Mon Sep 17 00:00:00 2001 From: Arnaldo Pereira Date: Fri, 26 Nov 2010 14:51:09 -0200 Subject: [PATCH 11/78] freetdm: ftmod_r2 - added percentage to loop timing stats --- libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c index 8514569509..513adfd975 100644 --- a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c +++ b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c @@ -1642,6 +1642,7 @@ static FIO_API_FUNCTION(ftdm_r2_api) if (!strcasecmp(argv[0], "loopstats")) { int range; + float pct; span_id = atoi(argv[1]); if (ftdm_span_find_by_name(argv[1], &span) == FTDM_SUCCESS || ftdm_span_find(span_id, &span) == FTDM_SUCCESS) { @@ -1655,10 +1656,11 @@ static FIO_API_FUNCTION(ftdm_r2_api) } range = 0; for (i = 0; i < ftdm_array_len(r2data->loops); i++) { + pct = 100*r2data->loops[i]/r2data->total_loops; if ((i + 1) == ftdm_array_len(r2data->loops)) { - stream->write_function(stream, ">= %dms: %llu\n", range, r2data->loops[i]); + stream->write_function(stream, ">= %dms: %llu - %.03lf%%\n", range, r2data->loops[i], pct); } else { - stream->write_function(stream, "%d-%dms: %llu\n", range, range + 9, r2data->loops[i]); + stream->write_function(stream, "%d-%dms: %llu - %.03lf%%\n", range, range + 9, r2data->loops[i], pct); } range += 10; } From 2b126a1510abae4364341d29d49cb31711f2119b Mon Sep 17 00:00:00 2001 From: Arnaldo Pereira Date: Fri, 26 Nov 2010 15:03:31 -0200 Subject: [PATCH 12/78] freetdm: ftmod_r2 - cast added --- libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c index 513adfd975..c8d669ca5c 100644 --- a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c +++ b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c @@ -1656,7 +1656,7 @@ static FIO_API_FUNCTION(ftdm_r2_api) } range = 0; for (i = 0; i < ftdm_array_len(r2data->loops); i++) { - pct = 100*r2data->loops[i]/r2data->total_loops; + pct = 100*(float)r2data->loops[i]/r2data->total_loops; if ((i + 1) == ftdm_array_len(r2data->loops)) { stream->write_function(stream, ">= %dms: %llu - %.03lf%%\n", range, r2data->loops[i], pct); } else { From 894dea2803a66ad933899b4377a9154ee3f16394 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Fri, 26 Nov 2010 12:39:30 -0500 Subject: [PATCH 13/78] freetdm: ftmod_wanpipe - flush stats when opening a channel --- libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c index c55d42e8b0..98da73ec92 100644 --- a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c +++ b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c @@ -516,6 +516,7 @@ static FIO_OPEN_FUNCTION(wanpipe_open) memset(&tdm_api,0,sizeof(tdm_api)); sangoma_tdm_flush_bufs(ftdmchan->sockfd, &tdm_api); + sangoma_flush_stats(ftdmchan->sockfd, &tdm_api); if (ftdmchan->type == FTDM_CHAN_TYPE_DQ921 || ftdmchan->type == FTDM_CHAN_TYPE_DQ931) { ftdmchan->native_codec = ftdmchan->effective_codec = FTDM_CODEC_NONE; From 17fc3bd62b640196825f3002732affaa9b22da85 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Fri, 26 Nov 2010 14:03:16 -0500 Subject: [PATCH 14/78] freetdm: ftmod_wanpipe, ftmod_sangoma_isdn and and core - Updated stats code --- .../ftmod_sangoma_isdn_stack_out.c | 14 +-- .../src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c | 86 ++++++++++++------- libs/freetdm/src/include/private/ftdm_core.h | 38 ++++---- 3 files changed, 81 insertions(+), 57 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_out.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_out.c index 2853335efc..b58bef23e5 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_out.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_out.c @@ -600,32 +600,32 @@ void sngisdn_snd_data(ftdm_channel_t *dchan, uint8_t *data, ftdm_size_t len) memcpy(&l1_frame.data, data, len); - if (ftdm_test_flag(&(dchan->iostats.stats.rx), FTDM_IOSTATS_ERROR_CRC)) { + if (ftdm_test_flag(&(dchan->iostats.rx), FTDM_IOSTATS_ERROR_CRC)) { l1_frame.flags |= SNG_L1FRAME_ERROR_CRC; } - if (ftdm_test_flag(&(dchan->iostats.stats.rx), FTDM_IOSTATS_ERROR_FRAME)) { + if (ftdm_test_flag(&(dchan->iostats.rx), FTDM_IOSTATS_ERROR_FRAME)) { l1_frame.flags |= SNG_L1FRAME_ERROR_FRAME; } - if (ftdm_test_flag(&(dchan->iostats.stats.rx), FTDM_IOSTATS_ERROR_ABORT)) { + if (ftdm_test_flag(&(dchan->iostats.rx), FTDM_IOSTATS_ERROR_ABORT)) { l1_frame.flags |= SNG_L1FRAME_ERROR_ABORT; } - if (ftdm_test_flag(&(dchan->iostats.stats.rx), FTDM_IOSTATS_ERROR_FIFO)) { + if (ftdm_test_flag(&(dchan->iostats.rx), FTDM_IOSTATS_ERROR_FIFO)) { l1_frame.flags |= SNG_L1FRAME_ERROR_FIFO; } - if (ftdm_test_flag(&(dchan->iostats.stats.rx), FTDM_IOSTATS_ERROR_DMA)) { + if (ftdm_test_flag(&(dchan->iostats.rx), FTDM_IOSTATS_ERROR_DMA)) { l1_frame.flags |= SNG_L1FRAME_ERROR_DMA; } - if (ftdm_test_flag(&(dchan->iostats.stats.rx), FTDM_IOSTATS_ERROR_QUEUE_THRES)) { + if (ftdm_test_flag(&(dchan->iostats.rx), FTDM_IOSTATS_ERROR_QUEUE_THRES)) { /* Should we trigger congestion here? */ l1_frame.flags |= SNG_L1FRAME_QUEUE_THRES; } - if (ftdm_test_flag(&(dchan->iostats.stats.rx), FTDM_IOSTATS_ERROR_QUEUE_FULL)) { + if (ftdm_test_flag(&(dchan->iostats.rx), FTDM_IOSTATS_ERROR_QUEUE_FULL)) { /* Should we trigger congestion here? */ l1_frame.flags |= SNG_L1FRAME_QUEUE_FULL; } diff --git a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c index 98da73ec92..b97b75cdfc 100644 --- a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c +++ b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c @@ -515,8 +515,10 @@ static FIO_OPEN_FUNCTION(wanpipe_open) wanpipe_tdm_api_t tdm_api; memset(&tdm_api,0,sizeof(tdm_api)); + sangoma_tdm_flush_bufs(ftdmchan->sockfd, &tdm_api); sangoma_flush_stats(ftdmchan->sockfd, &tdm_api); + memset(&ftdmchan->iostats, 0, sizeof(ftdmchan->iostats)); if (ftdmchan->type == FTDM_CHAN_TYPE_DQ921 || ftdmchan->type == FTDM_CHAN_TYPE_DQ931) { ftdmchan->native_codec = ftdmchan->effective_codec = FTDM_CODEC_NONE; @@ -753,6 +755,7 @@ static FIO_COMMAND_FUNCTION(wanpipe_command) case FTDM_COMMAND_FLUSH_IOSTATS: { err = sangoma_flush_stats(ftdmchan->sockfd, &tdm_api); + memset(&ftdmchan->iostats, 0, sizeof(ftdmchan->iostats)); } break; case FTDM_COMMAND_SET_RX_QUEUE_SIZE: @@ -782,42 +785,67 @@ static FIO_COMMAND_FUNCTION(wanpipe_command) static void wanpipe_read_stats(ftdm_channel_t *ftdmchan, wp_tdm_api_rx_hdr_t *rx_stats) { - ftdmchan->iostats.stats.rx.flags = 0; - - ftdmchan->iostats.stats.rx.errors = rx_stats->wp_api_rx_hdr_errors; - ftdmchan->iostats.stats.rx.rx_queue_size = rx_stats->wp_api_rx_hdr_max_queue_length; - ftdmchan->iostats.stats.rx.rx_queue_len = rx_stats->wp_api_rx_hdr_number_of_frames_in_queue; + ftdmchan->iostats.rx.errors = rx_stats->wp_api_rx_hdr_errors; + ftdmchan->iostats.rx.queue_size = rx_stats->wp_api_rx_hdr_max_queue_length; + ftdmchan->iostats.rx.queue_len = rx_stats->wp_api_rx_hdr_number_of_frames_in_queue; - if (rx_stats->wp_api_rx_hdr_error_map & (1<iostats.stats.rx), FTDM_IOSTATS_ERROR_ABORT); - } - if (rx_stats->wp_api_rx_hdr_error_map & (1<iostats.stats.rx), FTDM_IOSTATS_ERROR_DMA); - } - if (rx_stats->wp_api_rx_hdr_error_map & (1<iostats.stats.rx), FTDM_IOSTATS_ERROR_FIFO); - } - if (rx_stats->wp_api_rx_hdr_error_map & (1<iostats.stats.rx), FTDM_IOSTATS_ERROR_CRC); - } - if (rx_stats->wp_api_rx_hdr_error_map & (1<iostats.stats.rx), FTDM_IOSTATS_ERROR_FRAME); + if ((rx_stats->wp_api_rx_hdr_error_map & (1 << WP_ABORT_ERROR_BIT))) { + ftdm_set_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_ABORT); + } else { + ftdm_clear_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_ABORT); } - if (ftdmchan->iostats.stats.rx.rx_queue_len >= (0.8*ftdmchan->iostats.stats.rx.rx_queue_size)) { - ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Rx Queue length exceeded threshold (%d/%d)\n", - ftdmchan->iostats.stats.rx.rx_queue_len, ftdmchan->iostats.stats.rx.rx_queue_size); - - ftdm_set_flag(&(ftdmchan->iostats.stats.rx), FTDM_IOSTATS_ERROR_QUEUE_THRES); + if ((rx_stats->wp_api_rx_hdr_error_map & (1 << WP_DMA_ERROR_BIT))) { + ftdm_set_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_DMA); + } else { + ftdm_clear_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_DMA); + } + + if ((rx_stats->wp_api_rx_hdr_error_map & (1 << WP_FIFO_ERROR_BIT))) { + ftdm_set_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_FIFO); + } else { + ftdm_clear_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_FIFO); + } + + if ((rx_stats->wp_api_rx_hdr_error_map & (1 << WP_CRC_ERROR_BIT))) { + ftdm_set_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_CRC); + } else { + ftdm_clear_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_CRC); + } + + if ((rx_stats->wp_api_rx_hdr_error_map & (1 << WP_FRAME_ERROR_BIT))) { + ftdm_set_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_FRAME); + } else { + ftdm_clear_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_FRAME); + } + + if (ftdmchan->iostats.rx.queue_len >= (0.8 * ftdmchan->iostats.rx.queue_size)) { + ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Rx Queue length exceeded 80% threshold (%d/%d)\n", + ftdmchan->iostats.rx.queue_len, ftdmchan->iostats.rx.queue_size); + ftdm_set_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_QUEUE_THRES); + } else if (ftdm_test_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_QUEUE_THRES)){ + /* any reason we have wanpipe_tdm_api_iface.h in ftmod_wanpipe/ dir? */ + ftdm_log_chan(ftdmchan, FTDM_LOG_NOTICE, "Rx Queue length reduced 80% threshold (%d/%d)\n", + ftdmchan->iostats.rx.queue_len, ftdmchan->iostats.rx.queue_size); + ftdm_clear_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_QUEUE_THRES); } - if (ftdmchan->iostats.stats.rx.rx_queue_len >= ftdmchan->iostats.stats.rx.rx_queue_size) { + if (ftdmchan->iostats.rx.queue_len >= ftdmchan->iostats.rx.queue_size) { ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Rx Queue Full (%d/%d)\n", - ftdmchan->iostats.stats.rx.rx_queue_len, ftdmchan->iostats.stats.rx.rx_queue_size); - - ftdm_set_flag(&(ftdmchan->iostats.stats.rx), FTDM_IOSTATS_ERROR_QUEUE_FULL); + ftdmchan->iostats.rx.queue_len, ftdmchan->iostats.rx.queue_size); + ftdm_set_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_QUEUE_FULL); + } else if (ftdm_test_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_QUEUE_FULL)){ + ftdm_log_chan(ftdmchan, FTDM_LOG_NOTICE, "Rx Queue no longer full (%d/%d)\n", + ftdmchan->iostats.rx.queue_len, ftdmchan->iostats.rx.queue_size); + ftdm_clear_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_QUEUE_FULL); } - return; + + if (!ftdmchan->iostats.rx.packets) { + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "First packet read stats: Rx queue len: %d, Rx queue size: %d\n", + ftdmchan->iostats.rx.queue_len, ftdmchan->iostats.rx.queue_size); + } + + ftdmchan->iostats.rx.packets++; } /** diff --git a/libs/freetdm/src/include/private/ftdm_core.h b/libs/freetdm/src/include/private/ftdm_core.h index 06f899c8c9..5c235ad4ea 100644 --- a/libs/freetdm/src/include/private/ftdm_core.h +++ b/libs/freetdm/src/include/private/ftdm_core.h @@ -368,30 +368,26 @@ typedef struct { } ftdm_channel_history_entry_t; typedef enum { - FTDM_IOSTATS_ERROR_CRC = (1<<0), - FTDM_IOSTATS_ERROR_FRAME = (1<<1), - FTDM_IOSTATS_ERROR_ABORT = (1<<2), - FTDM_IOSTATS_ERROR_FIFO = (1<<3), - FTDM_IOSTATS_ERROR_DMA = (1<<4), - FTDM_IOSTATS_ERROR_QUEUE_THRES = (1<<5), /* Queue reached high threshold */ - FTDM_IOSTATS_ERROR_QUEUE_FULL = (1<<6), /* Queue is full */ + FTDM_IOSTATS_ERROR_CRC = (1 << 0), + FTDM_IOSTATS_ERROR_FRAME = (1 << 1), + FTDM_IOSTATS_ERROR_ABORT = (1 << 2), + FTDM_IOSTATS_ERROR_FIFO = (1 << 3), + FTDM_IOSTATS_ERROR_DMA = (1 << 4), + FTDM_IOSTATS_ERROR_QUEUE_THRES = (1 << 5), /* Queue reached high threshold */ + FTDM_IOSTATS_ERROR_QUEUE_FULL = (1 << 6), /* Queue is full */ } ftdm_iostats_error_type_t; +typedef struct iostats_element { + uint32_t errors; + uint16_t flags; + uint8_t queue_size; /* max queue size configured */ + uint8_t queue_len; /* Current number of elements in queue */ + uint64_t packets; +} iostats_element_t; + typedef struct { - union { - struct { - uint32_t errors; - uint16_t flags; - uint8_t rx_queue_size; /* max queue size configured */ - uint8_t rx_queue_len; /* Current number of elements in queue */ - } rx; - struct { - uint32_t errors; - uint16_t flags; - uint8_t tx_queue_size; /* max queue size configured */ - uint8_t tx_queue_len; /* Current number of elements in queue */ - } tx; - } stats; + iostats_element_t rx; + iostats_element_t tx; } ftdm_channel_iostats_t; /* 2^8 table size, one for each byte (sample) value */ From d53db202435868cfac98ed0ce6fe537d84a4947d Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Fri, 26 Nov 2010 15:06:36 -0500 Subject: [PATCH 15/78] freetdm: ftmod_wanpipe - add tx stats --- .../src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c | 44 +++++++++++++++++++ libs/freetdm/src/include/private/ftdm_core.h | 26 ++++++----- 2 files changed, 60 insertions(+), 10 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c index b97b75cdfc..804c6cfe8f 100644 --- a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c +++ b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c @@ -783,6 +783,47 @@ static FIO_COMMAND_FUNCTION(wanpipe_command) return FTDM_SUCCESS; } +static void wanpipe_write_stats(ftdm_channel_t *ftdmchan, wp_tdm_api_tx_hdr_t *tx_stats) +{ + ftdmchan->iostats.tx.errors = tx_stats->wp_api_tx_hdr_errors; + ftdmchan->iostats.tx.queue_size = tx_stats->wp_api_tx_hdr_max_queue_length; + ftdmchan->iostats.tx.queue_len = tx_stats->wp_api_tx_hdr_number_of_frames_in_queue; + + if (ftdmchan->iostats.tx.queue_len >= (0.8 * ftdmchan->iostats.tx.queue_size)) { + ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Tx Queue length exceeded 80% threshold (%d/%d)\n", + ftdmchan->iostats.tx.queue_len, ftdmchan->iostats.tx.queue_size); + ftdm_set_flag(&(ftdmchan->iostats.tx), FTDM_IOSTATS_ERROR_QUEUE_THRES); + } else if (ftdm_test_flag(&(ftdmchan->iostats.tx), FTDM_IOSTATS_ERROR_QUEUE_THRES)){ + ftdm_log_chan(ftdmchan, FTDM_LOG_NOTICE, "Tx Queue length reduced 80% threshold (%d/%d)\n", + ftdmchan->iostats.tx.queue_len, ftdmchan->iostats.tx.queue_size); + ftdm_clear_flag(&(ftdmchan->iostats.tx), FTDM_IOSTATS_ERROR_QUEUE_THRES); + } + + if (ftdmchan->iostats.tx.queue_len >= ftdmchan->iostats.rx.queue_size) { + ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Tx Queue Full (%d/%d)\n", + ftdmchan->iostats.rx.queue_len, ftdmchan->iostats.rx.queue_size); + ftdm_set_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_QUEUE_FULL); + } else if (ftdm_test_flag(&(ftdmchan->iostats.tx), FTDM_IOSTATS_ERROR_QUEUE_FULL)){ + ftdm_log_chan(ftdmchan, FTDM_LOG_NOTICE, "Tx Queue no longer full (%d/%d)\n", + ftdmchan->iostats.tx.queue_len, ftdmchan->iostats.tx.queue_size); + ftdm_clear_flag(&(ftdmchan->iostats.tx), FTDM_IOSTATS_ERROR_QUEUE_FULL); + } + + if (ftdmchan->iostats.tx.idle_packets < tx_stats->wp_api_tx_hdr_number_of_frames_in_queue) { + ftdmchan->iostats.tx.idle_packets = tx_stats->wp_api_tx_hdr_tx_idle_packets; + ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Tx idle: %d\n", ftdmchan->iostats.tx.idle_packets); + } + + if (!ftdmchan->iostats.tx.packets) { + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "First packet write stats: Tx queue len: %d, Tx queue size: %d, Tx idle: %d\n", + ftdmchan->iostats.tx.queue_len, + ftdmchan->iostats.tx.queue_size, + ftdmchan->iostats.tx.idle_packets); + } + + ftdmchan->iostats.tx.packets++; +} + static void wanpipe_read_stats(ftdm_channel_t *ftdmchan, wp_tdm_api_rx_hdr_t *rx_stats) { ftdmchan->iostats.rx.errors = rx_stats->wp_api_rx_hdr_errors; @@ -906,6 +947,9 @@ static FIO_WRITE_FUNCTION(wanpipe_write) /* should we be checking if bsent == *datalen here? */ if (bsent > 0) { *datalen = bsent; + if (ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_IO_STATS)) { + wanpipe_write_stats(ftdmchan, &hdrframe); + } return FTDM_SUCCESS; } diff --git a/libs/freetdm/src/include/private/ftdm_core.h b/libs/freetdm/src/include/private/ftdm_core.h index 5c235ad4ea..7683ec7145 100644 --- a/libs/freetdm/src/include/private/ftdm_core.h +++ b/libs/freetdm/src/include/private/ftdm_core.h @@ -377,17 +377,23 @@ typedef enum { FTDM_IOSTATS_ERROR_QUEUE_FULL = (1 << 6), /* Queue is full */ } ftdm_iostats_error_type_t; -typedef struct iostats_element { - uint32_t errors; - uint16_t flags; - uint8_t queue_size; /* max queue size configured */ - uint8_t queue_len; /* Current number of elements in queue */ - uint64_t packets; -} iostats_element_t; - typedef struct { - iostats_element_t rx; - iostats_element_t tx; + struct { + uint32_t errors; + uint16_t flags; + uint8_t queue_size; /* max queue size configured */ + uint8_t queue_len; /* Current number of elements in queue */ + uint64_t packets; + } rx; + + struct { + uint32_t errors; + uint16_t flags; + uint8_t idle_packets; + uint8_t queue_size; /* max queue size configured */ + uint8_t queue_len; /* Current number of elements in queue */ + uint64_t packets; + } tx; } ftdm_channel_iostats_t; /* 2^8 table size, one for each byte (sample) value */ From f7279386e423d7f525211f9f929242ca1e4baf1b Mon Sep 17 00:00:00 2001 From: Arnaldo Pereira Date: Fri, 26 Nov 2010 22:10:33 -0200 Subject: [PATCH 16/78] freetdm: ftmod_r2 - replaced deprecated ftdm_r2_configure_span() by ftdm_r2_configure_span_signaling(), all r2 default params now stays on ftmod_r2 --- libs/freetdm/mod_freetdm/mod_freetdm.c | 94 ++-------------- libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c | 122 ++++++++++++--------- 2 files changed, 80 insertions(+), 136 deletions(-) diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index 8d961123cb..18c1d4aebe 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -3212,29 +3212,6 @@ static switch_status_t load_config(void) char *name = (char *) switch_xml_attr(myspan, "name"); ftdm_status_t zstatus = FTDM_FAIL; - /* strings */ - const char *variant = "itu"; - const char *category = "national_subscriber"; - const char *logdir = "/usr/local/freeswitch/log/"; /* FIXME: get PREFIX variable */ - const char *logging = "notice,warning,error"; - const char *advanced_protocol_file = ""; - - /* booleans */ - int call_files = 0; - int get_ani_first = -1; - int immediate_accept = -1; - int double_answer = -1; - int skip_category = -1; - int forced_release = -1; - int charge_calls = -1; - - /* integers */ - int mfback_timeout = -1; - int metering_pulse_timeout = -1; - int allow_collect_calls = -1; - int max_ani = 10; - int max_dnis = 4; - /* common non r2 stuff */ const char *context = "default"; const char *dialplan = "XML"; @@ -3243,53 +3220,16 @@ static switch_status_t load_config(void) uint32_t span_id = 0; ftdm_span_t *span = NULL; + ftdm_conf_parameter_t spanparameters[30]; + unsigned paramindex = 0; + memset(spanparameters, 0, sizeof(spanparameters)); for (param = switch_xml_child(myspan, "param"); param; param = param->next) { char *var = (char *) switch_xml_attr_soft(param, "name"); char *val = (char *) switch_xml_attr_soft(param, "value"); /* string parameters */ - if (!strcasecmp(var, "variant")) { - variant = val; - } else if (!strcasecmp(var, "category")) { - category = val; - } else if (!strcasecmp(var, "logdir")) { - logdir = val; - } else if (!strcasecmp(var, "logging")) { - logging = val; - } else if (!strcasecmp(var, "advanced_protocol_file")) { - advanced_protocol_file = val; - - /* booleans */ - } else if (!strcasecmp(var, "allow_collect_calls")) { - allow_collect_calls = switch_true(val); - } else if (!strcasecmp(var, "immediate_accept")) { - immediate_accept = switch_true(val); - } else if (!strcasecmp(var, "double_answer")) { - double_answer = switch_true(val); - } else if (!strcasecmp(var, "skip_category")) { - skip_category = switch_true(var); - } else if (!strcasecmp(var, "forced_release")) { - forced_release = switch_true(val); - } else if (!strcasecmp(var, "charge_calls")) { - charge_calls = switch_true(val); - } else if (!strcasecmp(var, "get_ani_first")) { - get_ani_first = switch_true(val); - } else if (!strcasecmp(var, "call_files")) { - call_files = switch_true(val); - - /* integers */ - } else if (!strcasecmp(var, "mfback_timeout")) { - mfback_timeout = atoi(val); - } else if (!strcasecmp(var, "metering_pulse_timeout")) { - metering_pulse_timeout = atoi(val); - } else if (!strcasecmp(var, "max_ani")) { - max_ani = atoi(val); - } else if (!strcasecmp(var, "max_dnis")) { - max_dnis = atoi(val); - - /* common non r2 stuff */ - } else if (!strcasecmp(var, "context")) { + if (!strcasecmp(var, "context")) { context = val; } else if (!strcasecmp(var, "dialplan")) { dialplan = val; @@ -3297,11 +3237,15 @@ static switch_status_t load_config(void) dial_regex = val; } else if (!strcasecmp(var, "fail-dial-regex")) { fail_dial_regex = val; + } else { + spanparameters[paramindex].var = var; + spanparameters[paramindex].val = val; + paramindex++; } } if (!id && !name) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "span missing required param 'id'\n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "either 'id' or 'name' required params are missing\n"); continue; } @@ -3327,25 +3271,7 @@ static switch_status_t load_config(void) span_id = ftdm_span_get_id(span); } - if (ftdm_configure_span(span, "r2", on_r2_signal, - "variant", variant, - "max_ani", max_ani, - "max_dnis", max_dnis, - "category", category, - "logdir", logdir, - "logging", logging, - "advanced_protocol_file", advanced_protocol_file, - "allow_collect_calls", allow_collect_calls, - "immediate_accept", immediate_accept, - "double_answer", double_answer, - "skip_category", skip_category, - "forced_release", forced_release, - "charge_calls", charge_calls, - "get_ani_first", get_ani_first, - "call_files", call_files, - "mfback_timeout", mfback_timeout, - "metering_pulse_timeout", metering_pulse_timeout, - FTDM_TAG_END) != FTDM_SUCCESS) { + if (ftdm_configure_span_signaling(span, "r2", on_r2_signal, spanparameters) != FTDM_SUCCESS) { ftdm_log(FTDM_LOG_ERROR, "Error configuring R2 FreeTDM span %d, error: %s\n", span_id, ftdm_span_get_last_error(span)); continue; diff --git a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c index c8d669ca5c..ffc39e8884 100644 --- a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c +++ b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c @@ -892,27 +892,50 @@ static openr2_io_interface_t ftdm_r2_io_iface = { /* .get_oob_event */ ftdm_r2_io_get_oob_event /* never called */ }; -static FIO_SIG_CONFIGURE_FUNCTION(ftdm_r2_configure_span) - //ftdm_status_t (ftdm_span_t *span, fio_signal_cb_t sig_cb, va_list ap) +/* resolve a loglevel string, such as "debug,notice,warning", to an openr2 log level integer */ +static openr2_log_level_t ftdm_r2_loglevel_from_string(const char *level) +{ + openr2_log_level_t tmplevel; + openr2_log_level_t newlevel = 0; + char *clevel = NULL; + char *logval = NULL; + + logval = ftdm_malloc(strlen(level)+1); /* alloca man page scared me, so better to use good ol' malloc */ + if (!logval) { + ftdm_log(FTDM_LOG_WARNING, "Ignoring R2 logging parameter: '%s', failed to alloc memory\n", level); + return newlevel; + } + strcpy(logval, level); + while (logval) { + clevel = strsep(&logval, ","); + if (-1 == (tmplevel = openr2_log_get_level(clevel))) { + ftdm_log(FTDM_LOG_WARNING, "Ignoring invalid R2 logging level: '%s'\n", clevel); + continue; + } + newlevel |= tmplevel; + } + ftdm_safe_free(logval); + return newlevel; +} + +static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_r2_configure_span_signaling) { unsigned int i = 0; int conf_failure = 0; - char *var = NULL; - char *val = NULL; + const char *var = NULL, *val = NULL; + const char *log_level = "notice,warning,error"; /* default loglevel, if none is read from conf */ ftdm_r2_data_t *r2data = NULL; ftdm_r2_span_pvt_t *spanpvt = NULL; ftdm_r2_call_t *r2call = NULL; openr2_chan_t *r2chan = NULL; - openr2_log_level_t tmplevel; - char *clevel = NULL; - char *logval = NULL; + unsigned paramindex = 0; ft_r2_conf_t r2conf = { /* .variant */ OR2_VAR_ITU, /* .category */ OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER, /* .loglevel */ OR2_LOG_ERROR | OR2_LOG_WARNING, - /* .logdir */ NULL, + /* .logdir */ (char *)"/usr/local/freeswitch/log/", /* FIXME: get PREFIX variable */ /* .advanced_protocol_file */ NULL, /* .max_ani */ 10, /* .max_dnis */ 4, @@ -923,7 +946,7 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_r2_configure_span) /* .get_ani_first */ -1, /* .call_files */ 0, /* .mf_files */ 0, - /* .double_answer */ 0, + /* .double_answer */ -1, /* .charge_calls */ -1, /* .forced_release */ -1, /* .allow_collect_calls */ -1 @@ -936,10 +959,12 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_r2_configure_span) return FTDM_FAIL; } - while ((var = va_arg(ap, char *))) { + for (; ftdm_parameters[paramindex].var; paramindex++) { + var = ftdm_parameters[paramindex].var; + val = ftdm_parameters[paramindex].val; ftdm_log(FTDM_LOG_DEBUG, "Reading R2 parameter %s for span %d\n", var, span->span_id); if (!strcasecmp(var, "variant")) { - if (!(val = va_arg(ap, char *))) { + if (!val) { break; } if (ftdm_strlen_zero_buf(val)) { @@ -954,7 +979,7 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_r2_configure_span) } ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d for variant %s\n", span->span_id, val); } else if (!strcasecmp(var, "category")) { - if (!(val = va_arg(ap, char *))) { + if (!val) { break; } if (ftdm_strlen_zero_buf(val)) { @@ -969,87 +994,72 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_r2_configure_span) } ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with default category %s\n", span->span_id, val); } else if (!strcasecmp(var, "logdir")) { - if (!(val = va_arg(ap, char *))) { + if (!val) { break; } if (ftdm_strlen_zero_buf(val)) { ftdm_log(FTDM_LOG_NOTICE, "Ignoring empty R2 logdir parameter\n"); continue; } - r2conf.logdir = val; + r2conf.logdir = (char *)val; ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with logdir %s\n", span->span_id, val); } else if (!strcasecmp(var, "logging")) { - if (!(val = va_arg(ap, char *))) { + if (!val) { break; } if (ftdm_strlen_zero_buf(val)) { ftdm_log(FTDM_LOG_NOTICE, "Ignoring empty R2 logging parameter\n"); continue; } - logval = ftdm_malloc(strlen(val)+1); /* alloca man page scared me, so better to use good ol' malloc */ - if (!logval) { - ftdm_log(FTDM_LOG_WARNING, "Ignoring R2 logging parameter: '%s', failed to alloc memory\n", val); - continue; - } - strcpy(logval, val); - while (logval) { - clevel = strsep(&logval, ","); - if (-1 == (tmplevel = openr2_log_get_level(clevel))) { - ftdm_log(FTDM_LOG_WARNING, "Ignoring invalid R2 logging level: '%s'\n", clevel); - continue; - } - r2conf.loglevel |= tmplevel; - ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with loglevel %s\n", span->span_id, clevel); - } - ftdm_safe_free(logval); + log_level = val; } else if (!strcasecmp(var, "advanced_protocol_file")) { - if (!(val = va_arg(ap, char *))) { + if (!val) { break; } if (ftdm_strlen_zero_buf(val)) { ftdm_log(FTDM_LOG_NOTICE, "Ignoring empty R2 advanced_protocol_file parameter\n"); continue; } - r2conf.advanced_protocol_file = val; + r2conf.advanced_protocol_file = (char *)val; ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with advanced protocol file %s\n", span->span_id, val); } else if (!strcasecmp(var, "allow_collect_calls")) { - r2conf.allow_collect_calls = va_arg(ap, int); + r2conf.allow_collect_calls = ftdm_true(val); ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with allow collect calls max ani = %d\n", span->span_id, r2conf.allow_collect_calls); } else if (!strcasecmp(var, "double_answer")) { - r2conf.double_answer = va_arg(ap, int); + r2conf.double_answer = ftdm_true(val); ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with double answer = %d\n", span->span_id, r2conf.double_answer); } else if (!strcasecmp(var, "immediate_accept")) { - r2conf.immediate_accept = va_arg(ap, int); + r2conf.immediate_accept = ftdm_true(val); ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with immediate accept = %d\n", span->span_id, r2conf.immediate_accept); } else if (!strcasecmp(var, "skip_category")) { - r2conf.skip_category = va_arg(ap, int); + r2conf.skip_category = ftdm_true(val); ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with skip category = %d\n", span->span_id, r2conf.skip_category); } else if (!strcasecmp(var, "forced_release")) { - r2conf.forced_release = va_arg(ap, int); + r2conf.forced_release = ftdm_true(val); ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with forced release = %d\n", span->span_id, r2conf.forced_release); } else if (!strcasecmp(var, "charge_calls")) { - r2conf.charge_calls = va_arg(ap, int); + r2conf.charge_calls = ftdm_true(val); ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with charge calls = %d\n", span->span_id, r2conf.charge_calls); } else if (!strcasecmp(var, "get_ani_first")) { - r2conf.get_ani_first = va_arg(ap, int); + r2conf.get_ani_first = ftdm_true(val); ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with get ani first = %d\n", span->span_id, r2conf.get_ani_first); } else if (!strcasecmp(var, "call_files")) { - r2conf.call_files = va_arg(ap, int); + r2conf.call_files = ftdm_true(val); ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with call files = %d\n", span->span_id, r2conf.call_files); } else if (!strcasecmp(var, "mf_files")) { - r2conf.mf_files = va_arg(ap, int); + r2conf.mf_files = ftdm_true(val); ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with mf files = %d\n", span->span_id, r2conf.mf_files); } else if (!strcasecmp(var, "mfback_timeout")) { - r2conf.mfback_timeout = va_arg(ap, int); + r2conf.mfback_timeout = atoi(val); ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with MF backward timeout = %dms\n", span->span_id, r2conf.mfback_timeout); } else if (!strcasecmp(var, "metering_pulse_timeout")) { - r2conf.metering_pulse_timeout = va_arg(ap, int); + r2conf.metering_pulse_timeout = atoi(val); ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with metering pulse timeout = %dms\n", span->span_id, r2conf.metering_pulse_timeout); } else if (!strcasecmp(var, "max_ani")) { - r2conf.max_ani = va_arg(ap, int); + r2conf.max_ani = atoi(val); ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with max ani = %d\n", span->span_id, r2conf.max_ani); } else if (!strcasecmp(var, "max_dnis")) { - r2conf.max_dnis = va_arg(ap, int); + r2conf.max_dnis = atoi(val); ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with max dnis = %d\n", span->span_id, r2conf.max_dnis); } else { snprintf(span->last_error, sizeof(span->last_error), "Unknown R2 parameter [%s]", var); @@ -1062,6 +1072,10 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_r2_configure_span) return FTDM_FAIL; } + /* set span log level */ + r2conf.loglevel = ftdm_r2_loglevel_from_string(log_level); + ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with loglevel %s\n", span->span_id, log_level); + r2data = ftdm_malloc(sizeof(*r2data)); if (!r2data) { snprintf(span->last_error, sizeof(span->last_error), "Failed to allocate R2 data."); @@ -1387,6 +1401,9 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj) r2chan = R2CALL(span->channels[i])->r2chan; openr2_chan_set_idle(r2chan); openr2_chan_process_cas_signaling(r2chan); + + ftdmchan = openr2_chan_get_client_data(r2chan); + ftdm_channel_set_feature(ftdmchan, FTDM_CHANNEL_FEATURE_IO_STATS); } memset(&start, 0, sizeof(start)); @@ -1762,12 +1779,13 @@ static FIO_SIG_UNLOAD_FUNCTION(ftdm_r2_destroy) } EX_DECLARE_DATA ftdm_module_t ftdm_module = { - "r2", - ftdm_r2_io_init, - NULL, - ftdm_r2_init, - ftdm_r2_configure_span, - ftdm_r2_destroy + /* .name */ "r2", + /* .io_load */ ftdm_r2_io_init, + /* .io_unload */ NULL, + /* .sig_load */ ftdm_r2_init, + /* .sig_configure */ NULL, + /* .sig_unload */ ftdm_r2_destroy, + /* .configure_span_signaling */ ftdm_r2_configure_span_signaling }; From ac2998b61f74e06100ca988eefdb608d312d1098 Mon Sep 17 00:00:00 2001 From: Arnaldo Pereira Date: Mon, 29 Nov 2010 16:48:01 -0200 Subject: [PATCH 17/78] freetdm: ftmod_r2 - set feature FTDM_CHANNEL_FEATURE_IO_STATS just when the channel is in FTDM_CHANNEL_STATE_UP state --- libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c index ffc39e8884..b9e0e1378f 100644 --- a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c +++ b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c @@ -1403,7 +1403,6 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj) openr2_chan_process_cas_signaling(r2chan); ftdmchan = openr2_chan_get_client_data(r2chan); - ftdm_channel_set_feature(ftdmchan, FTDM_CHANNEL_FEATURE_IO_STATS); } memset(&start, 0, sizeof(start)); @@ -1462,6 +1461,12 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj) ftdmchan = openr2_chan_get_client_data(r2chan); r2call = R2CALL(ftdmchan); + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_UP)) { + ftdm_channel_set_feature(ftdmchan, FTDM_CHANNEL_FEATURE_IO_STATS); + } else { + ftdm_channel_clear_feature(ftdmchan, FTDM_CHANNEL_FEATURE_IO_STATS); + } + ftdm_mutex_lock(ftdmchan->mutex); ftdm_r2_state_advance_all(ftdmchan); openr2_chan_process_signaling(r2chan); From 74f04959b4e27f4af677c960c82637e874920395 Mon Sep 17 00:00:00 2001 From: Arnaldo Pereira Date: Mon, 29 Nov 2010 19:27:49 -0200 Subject: [PATCH 18/78] freetdm: ftmod_r2 - reverted last commit --- libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c index b9e0e1378f..ffc39e8884 100644 --- a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c +++ b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c @@ -1403,6 +1403,7 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj) openr2_chan_process_cas_signaling(r2chan); ftdmchan = openr2_chan_get_client_data(r2chan); + ftdm_channel_set_feature(ftdmchan, FTDM_CHANNEL_FEATURE_IO_STATS); } memset(&start, 0, sizeof(start)); @@ -1461,12 +1462,6 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj) ftdmchan = openr2_chan_get_client_data(r2chan); r2call = R2CALL(ftdmchan); - if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_UP)) { - ftdm_channel_set_feature(ftdmchan, FTDM_CHANNEL_FEATURE_IO_STATS); - } else { - ftdm_channel_clear_feature(ftdmchan, FTDM_CHANNEL_FEATURE_IO_STATS); - } - ftdm_mutex_lock(ftdmchan->mutex); ftdm_r2_state_advance_all(ftdmchan); openr2_chan_process_signaling(r2chan); From 136fc8aa954cf7154b75a72297e76b94cb92e3c3 Mon Sep 17 00:00:00 2001 From: Arnaldo Pereira Date: Tue, 30 Nov 2010 13:56:29 -0200 Subject: [PATCH 19/78] freetdm: ftmod_wanpipe - removed 80% tx/rx queue warnings --- .../src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c | 21 ------------------- 1 file changed, 21 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c index 804c6cfe8f..17f0219b1f 100644 --- a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c +++ b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c @@ -789,16 +789,6 @@ static void wanpipe_write_stats(ftdm_channel_t *ftdmchan, wp_tdm_api_tx_hdr_t *t ftdmchan->iostats.tx.queue_size = tx_stats->wp_api_tx_hdr_max_queue_length; ftdmchan->iostats.tx.queue_len = tx_stats->wp_api_tx_hdr_number_of_frames_in_queue; - if (ftdmchan->iostats.tx.queue_len >= (0.8 * ftdmchan->iostats.tx.queue_size)) { - ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Tx Queue length exceeded 80% threshold (%d/%d)\n", - ftdmchan->iostats.tx.queue_len, ftdmchan->iostats.tx.queue_size); - ftdm_set_flag(&(ftdmchan->iostats.tx), FTDM_IOSTATS_ERROR_QUEUE_THRES); - } else if (ftdm_test_flag(&(ftdmchan->iostats.tx), FTDM_IOSTATS_ERROR_QUEUE_THRES)){ - ftdm_log_chan(ftdmchan, FTDM_LOG_NOTICE, "Tx Queue length reduced 80% threshold (%d/%d)\n", - ftdmchan->iostats.tx.queue_len, ftdmchan->iostats.tx.queue_size); - ftdm_clear_flag(&(ftdmchan->iostats.tx), FTDM_IOSTATS_ERROR_QUEUE_THRES); - } - if (ftdmchan->iostats.tx.queue_len >= ftdmchan->iostats.rx.queue_size) { ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Tx Queue Full (%d/%d)\n", ftdmchan->iostats.rx.queue_len, ftdmchan->iostats.rx.queue_size); @@ -860,17 +850,6 @@ static void wanpipe_read_stats(ftdm_channel_t *ftdmchan, wp_tdm_api_rx_hdr_t *rx ftdm_clear_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_FRAME); } - if (ftdmchan->iostats.rx.queue_len >= (0.8 * ftdmchan->iostats.rx.queue_size)) { - ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Rx Queue length exceeded 80% threshold (%d/%d)\n", - ftdmchan->iostats.rx.queue_len, ftdmchan->iostats.rx.queue_size); - ftdm_set_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_QUEUE_THRES); - } else if (ftdm_test_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_QUEUE_THRES)){ - /* any reason we have wanpipe_tdm_api_iface.h in ftmod_wanpipe/ dir? */ - ftdm_log_chan(ftdmchan, FTDM_LOG_NOTICE, "Rx Queue length reduced 80% threshold (%d/%d)\n", - ftdmchan->iostats.rx.queue_len, ftdmchan->iostats.rx.queue_size); - ftdm_clear_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_QUEUE_THRES); - } - if (ftdmchan->iostats.rx.queue_len >= ftdmchan->iostats.rx.queue_size) { ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Rx Queue Full (%d/%d)\n", ftdmchan->iostats.rx.queue_len, ftdmchan->iostats.rx.queue_size); From 006b3165cf7d0e512e4b3d7ed23c92f2bedb1d22 Mon Sep 17 00:00:00 2001 From: root Date: Tue, 30 Nov 2010 19:35:38 +0300 Subject: [PATCH 20/78] fix issues with Progress message type if pre_answer enabled --- src/mod/endpoints/mod_h323/changes.txt | 1 + src/mod/endpoints/mod_h323/mod_h323.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mod/endpoints/mod_h323/changes.txt b/src/mod/endpoints/mod_h323/changes.txt index 19aca46dc8..c01542e2d3 100644 --- a/src/mod/endpoints/mod_h323/changes.txt +++ b/src/mod/endpoints/mod_h323/changes.txt @@ -1,3 +1,4 @@ +fix issues with Progress message type if pre_answer enabled fix crashes on FSH323Connection calls in on_hangup routine in different threads. move PTrace level set to FSH323EndPoint::Initialise partially apply patch from from Peter Olsson, Remove UnLock() when TryLock() failed and DEBUG_RTP_PACKETS directive. diff --git a/src/mod/endpoints/mod_h323/mod_h323.cpp b/src/mod/endpoints/mod_h323/mod_h323.cpp index 142506dd92..6365f9cc0c 100644 --- a/src/mod/endpoints/mod_h323/mod_h323.cpp +++ b/src/mod/endpoints/mod_h323/mod_h323.cpp @@ -1148,7 +1148,7 @@ void FSH323Connection::AnsweringCall(AnswerCallResponse response) if (!mediaWaitForConnect) { // create a new facility PDU if doing AnswerDeferredWithMedia H323SignalPDU want245PDU; - //H225_Progress_UUIE & prog = want245PDU.BuildProgress(*this); + want245PDU.BuildProgress(*this); PBoolean sendPDU = TRUE; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE,"mediaWaitForConnect = FALSE\n"); /* if (SendFastStartAcknowledge(prog.m_fastStart)){ From 3934682e9b616f9117d70f05965e8c5f3bbc3269 Mon Sep 17 00:00:00 2001 From: Arnaldo Pereira Date: Tue, 30 Nov 2010 16:01:08 -0200 Subject: [PATCH 21/78] freetdm: ftmod_r2 - rename ftdm_started flag to ftdm_call_started --- libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c index ffc39e8884..b98f7db99c 100644 --- a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c +++ b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c @@ -68,7 +68,7 @@ typedef struct ftdm_r2_call_t { int accepted:1; int answer_pending:1; int disconnect_rcvd:1; - int ftdm_started:1; + int ftdm_call_started:1; int protocol_error:1; ftdm_channel_state_t chanstate; ftdm_size_t dnis_index; @@ -357,7 +357,7 @@ static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(r2_outgoing_call) } ft_r2_clean_call(ftdmchan->call_data); - R2CALL(ftdmchan)->ftdm_started = 1; + R2CALL(ftdmchan)->ftdm_call_started = 1; R2CALL(ftdmchan)->chanstate = FTDM_CHANNEL_STATE_DOWN; ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DIALING); @@ -503,7 +503,7 @@ static void ftdm_r2_on_call_disconnect(openr2_chan_t *r2chan, openr2_call_discon } /* if the call has not been started yet we must go to HANGUP right here */ - if (!R2CALL(ftdmchan)->ftdm_started) { + if (!R2CALL(ftdmchan)->ftdm_call_started) { ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP); return; } @@ -567,7 +567,7 @@ static void ftdm_r2_on_protocol_error(openr2_chan_t *r2chan, openr2_protocol_err R2CALL(ftdmchan)->disconnect_rcvd = 1; R2CALL(ftdmchan)->protocol_error = 1; - if (!R2CALL(ftdmchan)->ftdm_started) { + if (!R2CALL(ftdmchan)->ftdm_call_started) { ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_HANGUP); return; } @@ -1260,7 +1260,7 @@ static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan) ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_CANCEL); break; } - R2CALL(ftdmchan)->ftdm_started = 1; + R2CALL(ftdmchan)->ftdm_call_started = 1; break; From a669f76f786e2a74d3621cf5d4f9b0ad30d7e89a Mon Sep 17 00:00:00 2001 From: Brian West Date: Tue, 30 Nov 2010 17:38:44 -0600 Subject: [PATCH 22/78] Fix issue when fs_path is used so we pick the correct media IP in our outbound invite this was soemthing that wouldn't work correctly over ATT on the iphone. --- src/mod/endpoints/mod_sofia/mod_sofia.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index 3bb926adf3..74c4c0897e 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -3900,7 +3900,26 @@ static switch_call_cause_t sofia_outgoing_channel(switch_core_session_t *session switch_channel_set_variable_printf(nchannel, "sip_local_network_addr", "%s", profile->extsipip ? profile->extsipip : profile->sipip); switch_channel_set_variable(nchannel, "sip_profile_name", profile_name); - switch_split_user_domain(switch_core_session_strdup(nsession, tech_pvt->dest), NULL, &tech_pvt->remote_ip); + if (switch_stristr("fs_path", tech_pvt->dest)) { + char *remote_host = NULL; + const char *s; + + if ((s = switch_stristr("fs_path=", tech_pvt->dest))) { + s += 8; + } + + if (s) { + remote_host = switch_core_session_strdup(nsession, s); + switch_url_decode(remote_host); + } + if (!zstr(remote_host)) { + switch_split_user_domain(remote_host, NULL, &tech_pvt->remote_ip); + } + } + + if (zstr(tech_pvt->remote_ip)) { + switch_split_user_domain(switch_core_session_strdup(nsession, tech_pvt->dest), NULL, &tech_pvt->remote_ip); + } if (dest_to) { if (strchr(dest_to, '@')) { From 82394b37687cb43ae3805d14a7ed9ca20da95a63 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Tue, 30 Nov 2010 18:22:12 -0600 Subject: [PATCH 23/78] add switch_ivr_insert_file to insert one file into another at an arbitrary sample point --- src/include/switch_ivr.h | 1 + src/switch_ivr.c | 156 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 157 insertions(+) diff --git a/src/include/switch_ivr.h b/src/include/switch_ivr.h index d277bd030f..da366c5b8d 100644 --- a/src/include/switch_ivr.h +++ b/src/include/switch_ivr.h @@ -878,6 +878,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_dmachine_set_realm(switch_ivr_dmachin SWITCH_DECLARE(switch_status_t) switch_ivr_get_file_handle(switch_core_session_t *session, switch_file_handle_t **fh); SWITCH_DECLARE(switch_status_t) switch_ivr_release_file_handle(switch_core_session_t *session, switch_file_handle_t **fh); SWITCH_DECLARE(switch_status_t) switch_ivr_process_fh(switch_core_session_t *session, const char *cmd, switch_file_handle_t *fhp); +SWITCH_DECLARE(switch_status_t) switch_ivr_insert_file(switch_core_session_t *session, const char *file, const char *insert_file, switch_size_t sample_point); /** @} */ diff --git a/src/switch_ivr.c b/src/switch_ivr.c index 00917adc34..46ba4e6659 100644 --- a/src/switch_ivr.c +++ b/src/switch_ivr.c @@ -2681,6 +2681,162 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_process_fh(switch_core_session_t *ses } +#define START_SAMPLES 32768 + +SWITCH_DECLARE(switch_status_t) switch_ivr_insert_file(switch_core_session_t *session, const char *file, const char *insert_file, switch_size_t sample_point) +{ + switch_file_handle_t orig_fh = { 0 }; + switch_file_handle_t new_fh = { 0 }; + switch_codec_implementation_t read_impl = { 0 }; + char *tmp_file; + switch_uuid_t uuid; + char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1]; + int16_t *abuf = NULL; + switch_size_t olen = 0; + int asis = 0; + switch_channel_t *channel = switch_core_session_get_channel(session); + switch_size_t sample_count = 0; + uint32_t pos = 0; + char *ext; + + switch_uuid_get(&uuid); + switch_uuid_format(uuid_str, &uuid); + + if ((ext = strrchr(file, '.'))) { + ext++; + } else { + ext = "wav"; + } + + tmp_file = switch_core_session_sprintf(session, "%s%smsg_%s.%s", + SWITCH_GLOBAL_dirs.temp_dir, SWITCH_PATH_SEPARATOR, uuid_str, ext); + + switch_core_session_get_read_impl(session, &read_impl); + + new_fh.channels = read_impl.number_of_channels; + new_fh.native_rate = read_impl.actual_samples_per_second; + + + if (switch_core_file_open(&new_fh, + tmp_file, + new_fh.channels, + read_impl.actual_samples_per_second, SWITCH_FILE_FLAG_WRITE | SWITCH_FILE_DATA_SHORT, NULL) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Failed to open file %s\n", tmp_file); + goto end; + } + + + if (switch_core_file_open(&orig_fh, + file, + new_fh.channels, + read_impl.actual_samples_per_second, SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Failed to open file %s\n", file); + goto end; + } + + + switch_zmalloc(abuf, START_SAMPLES * sizeof(*abuf)); + + if (switch_test_flag((&orig_fh), SWITCH_FILE_NATIVE)) { + asis = 1; + } + + while (switch_channel_ready(channel)) { + olen = START_SAMPLES; + + if (!asis) { + olen /= 2; + } + + if ((sample_count + olen) > sample_point) { + olen = sample_point - sample_count; + } + + if (!olen || switch_core_file_read(&orig_fh, abuf, &olen) != SWITCH_STATUS_SUCCESS || !olen) { + break; + } + + sample_count += olen; + + switch_core_file_write(&new_fh, abuf, &olen); + } + + switch_core_file_close(&orig_fh); + + + if (switch_core_file_open(&orig_fh, + insert_file, + new_fh.channels, + read_impl.actual_samples_per_second, SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Failed to open file %s\n", file); + goto end; + } + + + while (switch_channel_ready(channel)) { + olen = START_SAMPLES; + + if (!asis) { + olen /= 2; + } + + if (switch_core_file_read(&orig_fh, abuf, &olen) != SWITCH_STATUS_SUCCESS || !olen) { + break; + } + + sample_count += olen; + + switch_core_file_write(&new_fh, abuf, &olen); + } + + switch_core_file_close(&orig_fh); + + if (switch_core_file_open(&orig_fh, + file, + new_fh.channels, + read_impl.actual_samples_per_second, SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Failed to open file %s\n", file); + goto end; + } + + pos = 0; + switch_core_file_seek(&orig_fh, &pos, sample_point, SEEK_SET); + + while (switch_channel_ready(channel)) { + olen = START_SAMPLES; + + if (!asis) { + olen /= 2; + } + + if (switch_core_file_read(&orig_fh, abuf, &olen) != SWITCH_STATUS_SUCCESS || !olen) { + break; + } + + sample_count += olen; + + switch_core_file_write(&new_fh, abuf, &olen); + } + + end: + + if (switch_test_flag((&orig_fh), SWITCH_FILE_OPEN)) { + switch_core_file_close(&orig_fh); + } + + if (switch_test_flag((&new_fh), SWITCH_FILE_OPEN)) { + switch_core_file_close(&new_fh); + } + + switch_file_rename(tmp_file, file, switch_core_session_get_pool(session)); + unlink(tmp_file); + + switch_safe_free(abuf); + + return SWITCH_STATUS_SUCCESS; +} + + /* For Emacs: * Local Variables: From 77a7f93d6799ebf7cfb433af7a78b2c7b6ace60d Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Tue, 30 Nov 2010 18:23:01 -0600 Subject: [PATCH 24/78] reswig --- .../languages/mod_managed/freeswitch_wrap.cxx | 24 +++++++++++++++++++ src/mod/languages/mod_managed/managed/swig.cs | 9 +++++++ 2 files changed, 33 insertions(+) diff --git a/src/mod/languages/mod_managed/freeswitch_wrap.cxx b/src/mod/languages/mod_managed/freeswitch_wrap.cxx index f4bf780086..a65d82d9cb 100644 --- a/src/mod/languages/mod_managed/freeswitch_wrap.cxx +++ b/src/mod/languages/mod_managed/freeswitch_wrap.cxx @@ -28397,6 +28397,30 @@ SWIGEXPORT int SWIGSTDCALL CSharp_switch_ivr_process_fh(void * jarg1, char * jar } +SWIGEXPORT int SWIGSTDCALL CSharp_switch_ivr_insert_file(void * jarg1, char * jarg2, char * jarg3, void * jarg4) { + int jresult ; + switch_core_session_t *arg1 = (switch_core_session_t *) 0 ; + char *arg2 = (char *) 0 ; + char *arg3 = (char *) 0 ; + switch_size_t arg4 ; + switch_status_t result; + switch_size_t *argp4 ; + + arg1 = (switch_core_session_t *)jarg1; + arg2 = (char *)jarg2; + arg3 = (char *)jarg3; + argp4 = (switch_size_t *)jarg4; + if (!argp4) { + SWIG_CSharpSetPendingExceptionArgument(SWIG_CSharpArgumentNullException, "Attempt to dereference null switch_size_t", 0); + return 0; + } + arg4 = *argp4; + result = (switch_status_t)switch_ivr_insert_file(arg1,(char const *)arg2,(char const *)arg3,arg4); + jresult = result; + return jresult; +} + + SWIGEXPORT int SWIGSTDCALL CSharp_SWITCH_RTP_MAX_BUF_LEN_get() { int jresult ; int result; diff --git a/src/mod/languages/mod_managed/managed/swig.cs b/src/mod/languages/mod_managed/managed/swig.cs index 10fd3c6bc6..e024c586f8 100644 --- a/src/mod/languages/mod_managed/managed/swig.cs +++ b/src/mod/languages/mod_managed/managed/swig.cs @@ -4501,6 +4501,12 @@ public class freeswitch { return ret; } + public static switch_status_t switch_ivr_insert_file(SWIGTYPE_p_switch_core_session session, string file, string insert_file, SWIGTYPE_p_switch_size_t sample_point) { + switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_ivr_insert_file(SWIGTYPE_p_switch_core_session.getCPtr(session), file, insert_file, SWIGTYPE_p_switch_size_t.getCPtr(sample_point)); + if (freeswitchPINVOKE.SWIGPendingException.Pending) throw freeswitchPINVOKE.SWIGPendingException.Retrieve(); + return ret; + } + public static switch_status_t switch_rtp_add_crypto_key(SWIGTYPE_p_switch_rtp rtp_session, switch_rtp_crypto_direction_t direction, uint index, switch_rtp_crypto_key_type_t type, SWIGTYPE_p_unsigned_char key, SWIGTYPE_p_switch_size_t keylen) { switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_rtp_add_crypto_key(SWIGTYPE_p_switch_rtp.getCPtr(rtp_session), (int)direction, index, (int)type, SWIGTYPE_p_unsigned_char.getCPtr(key), SWIGTYPE_p_switch_size_t.getCPtr(keylen)); if (freeswitchPINVOKE.SWIGPendingException.Pending) throw freeswitchPINVOKE.SWIGPendingException.Retrieve(); @@ -12292,6 +12298,9 @@ class freeswitchPINVOKE { [DllImport("mod_managed", EntryPoint="CSharp_switch_ivr_process_fh")] public static extern int switch_ivr_process_fh(HandleRef jarg1, string jarg2, HandleRef jarg3); + [DllImport("mod_managed", EntryPoint="CSharp_switch_ivr_insert_file")] + public static extern int switch_ivr_insert_file(HandleRef jarg1, string jarg2, string jarg3, HandleRef jarg4); + [DllImport("mod_managed", EntryPoint="CSharp_SWITCH_RTP_MAX_BUF_LEN_get")] public static extern int SWITCH_RTP_MAX_BUF_LEN_get(); From bc34a24d4c7a70f5b526252495a19ba5f3d2de86 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Tue, 30 Nov 2010 18:35:43 -0600 Subject: [PATCH 25/78] get ready for ClueCon 11 --- build/Makefile.am | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/build/Makefile.am b/build/Makefile.am index 4b426ef6e3..1d57dad528 100644 --- a/build/Makefile.am +++ b/build/Makefile.am @@ -6,8 +6,13 @@ all: @echo " + Install by running: +" @echo " + +" @echo " + $(MK) install +" + @echo " + +" + @echo " + While you're waiting, register for ClueCon! +" + @echo " + http://www.cluecon.com +" + @echo " + +" @echo " +-----------------------------------------------+" + install: @echo " +---------- FreeSWITCH install Complete ----------+" @echo " + FreeSWITCH has been successfully installed. +" From 2343f68597f7f5d2986aeef1f85f579add45b0c4 Mon Sep 17 00:00:00 2001 From: Jeff Lenk Date: Tue, 30 Nov 2010 21:43:28 -0600 Subject: [PATCH 26/78] VS2010 reswig --- .../mod_managed/freeswitch_wrap.2010.cxx | 132 ++++++++++++++++++ .../mod_managed/managed/swig.2010.cs | 103 ++++++++++++++ 2 files changed, 235 insertions(+) diff --git a/src/mod/languages/mod_managed/freeswitch_wrap.2010.cxx b/src/mod/languages/mod_managed/freeswitch_wrap.2010.cxx index 4a0b52efec..8033a8faa5 100644 --- a/src/mod/languages/mod_managed/freeswitch_wrap.2010.cxx +++ b/src/mod/languages/mod_managed/freeswitch_wrap.2010.cxx @@ -6454,6 +6454,42 @@ SWIGEXPORT int SWIGSTDCALL CSharp_switch_core_destroy() { } +SWIGEXPORT int SWIGSTDCALL CSharp_switch_core_session_io_read_lock(void * jarg1) { + int jresult ; + switch_core_session_t *arg1 = (switch_core_session_t *) 0 ; + switch_status_t result; + + arg1 = (switch_core_session_t *)jarg1; + result = (switch_status_t)switch_core_session_io_read_lock(arg1); + jresult = result; + return jresult; +} + + +SWIGEXPORT int SWIGSTDCALL CSharp_switch_core_session_io_write_lock(void * jarg1) { + int jresult ; + switch_core_session_t *arg1 = (switch_core_session_t *) 0 ; + switch_status_t result; + + arg1 = (switch_core_session_t *)jarg1; + result = (switch_status_t)switch_core_session_io_write_lock(arg1); + jresult = result; + return jresult; +} + + +SWIGEXPORT int SWIGSTDCALL CSharp_switch_core_session_io_rwunlock(void * jarg1) { + int jresult ; + switch_core_session_t *arg1 = (switch_core_session_t *) 0 ; + switch_status_t result; + + arg1 = (switch_core_session_t *)jarg1; + result = (switch_status_t)switch_core_session_io_rwunlock(arg1); + jresult = result; + return jresult; +} + + SWIGEXPORT int SWIGSTDCALL CSharp_switch_core_session_read_lock(void * jarg1) { int jresult ; switch_core_session_t *arg1 = (switch_core_session_t *) 0 ; @@ -7336,6 +7372,22 @@ SWIGEXPORT int SWIGSTDCALL CSharp_switch_core_session_execute_application_get_fl } +SWIGEXPORT int SWIGSTDCALL CSharp_switch_core_session_execute_application_async(void * jarg1, char * jarg2, char * jarg3) { + int jresult ; + switch_core_session_t *arg1 = (switch_core_session_t *) 0 ; + char *arg2 = (char *) 0 ; + char *arg3 = (char *) 0 ; + switch_status_t result; + + arg1 = (switch_core_session_t *)jarg1; + arg2 = (char *)jarg2; + arg3 = (char *)jarg3; + result = (switch_status_t)switch_core_session_execute_application_async(arg1,(char const *)arg2,(char const *)arg3); + jresult = result; + return jresult; +} + + SWIGEXPORT int SWIGSTDCALL CSharp_switch_core_session_get_app_flags(char * jarg1, void * jarg2) { int jresult ; char *arg1 = (char *) 0 ; @@ -7566,6 +7618,18 @@ SWIGEXPORT unsigned long SWIGSTDCALL CSharp_switch_core_session_event_count(void } +SWIGEXPORT unsigned long SWIGSTDCALL CSharp_switch_core_session_messages_waiting(void * jarg1) { + unsigned long jresult ; + switch_core_session_t *arg1 = (switch_core_session_t *) 0 ; + uint32_t result; + + arg1 = (switch_core_session_t *)jarg1; + result = (uint32_t)switch_core_session_messages_waiting(arg1); + jresult = (unsigned long)result; + return jresult; +} + + SWIGEXPORT int SWIGSTDCALL CSharp_switch_core_session_dequeue_event(void * jarg1, void * jarg2, int jarg3) { int jresult ; switch_core_session_t *arg1 = (switch_core_session_t *) 0 ; @@ -27597,6 +27661,74 @@ SWIGEXPORT int SWIGSTDCALL CSharp_switch_ivr_dmachine_set_realm(void * jarg1, ch } +SWIGEXPORT int SWIGSTDCALL CSharp_switch_ivr_get_file_handle(void * jarg1, void * jarg2) { + int jresult ; + switch_core_session_t *arg1 = (switch_core_session_t *) 0 ; + switch_file_handle_t **arg2 = (switch_file_handle_t **) 0 ; + switch_status_t result; + + arg1 = (switch_core_session_t *)jarg1; + arg2 = (switch_file_handle_t **)jarg2; + result = (switch_status_t)switch_ivr_get_file_handle(arg1,arg2); + jresult = result; + return jresult; +} + + +SWIGEXPORT int SWIGSTDCALL CSharp_switch_ivr_release_file_handle(void * jarg1, void * jarg2) { + int jresult ; + switch_core_session_t *arg1 = (switch_core_session_t *) 0 ; + switch_file_handle_t **arg2 = (switch_file_handle_t **) 0 ; + switch_status_t result; + + arg1 = (switch_core_session_t *)jarg1; + arg2 = (switch_file_handle_t **)jarg2; + result = (switch_status_t)switch_ivr_release_file_handle(arg1,arg2); + jresult = result; + return jresult; +} + + +SWIGEXPORT int SWIGSTDCALL CSharp_switch_ivr_process_fh(void * jarg1, char * jarg2, void * jarg3) { + int jresult ; + switch_core_session_t *arg1 = (switch_core_session_t *) 0 ; + char *arg2 = (char *) 0 ; + switch_file_handle_t *arg3 = (switch_file_handle_t *) 0 ; + switch_status_t result; + + arg1 = (switch_core_session_t *)jarg1; + arg2 = (char *)jarg2; + arg3 = (switch_file_handle_t *)jarg3; + result = (switch_status_t)switch_ivr_process_fh(arg1,(char const *)arg2,arg3); + jresult = result; + return jresult; +} + + +SWIGEXPORT int SWIGSTDCALL CSharp_switch_ivr_insert_file(void * jarg1, char * jarg2, char * jarg3, void * jarg4) { + int jresult ; + switch_core_session_t *arg1 = (switch_core_session_t *) 0 ; + char *arg2 = (char *) 0 ; + char *arg3 = (char *) 0 ; + switch_size_t arg4 ; + switch_size_t *argp4 ; + switch_status_t result; + + arg1 = (switch_core_session_t *)jarg1; + arg2 = (char *)jarg2; + arg3 = (char *)jarg3; + argp4 = (switch_size_t *)jarg4; + if (!argp4) { + SWIG_CSharpSetPendingExceptionArgument(SWIG_CSharpArgumentNullException, "Attempt to dereference null switch_size_t", 0); + return 0; + } + arg4 = *argp4; + result = (switch_status_t)switch_ivr_insert_file(arg1,(char const *)arg2,(char const *)arg3,arg4); + jresult = result; + return jresult; +} + + SWIGEXPORT int SWIGSTDCALL CSharp_SWITCH_RTP_MAX_BUF_LEN_get() { int jresult ; int result; diff --git a/src/mod/languages/mod_managed/managed/swig.2010.cs b/src/mod/languages/mod_managed/managed/swig.2010.cs index 2897fef1e5..4d14f10879 100644 --- a/src/mod/languages/mod_managed/managed/swig.2010.cs +++ b/src/mod/languages/mod_managed/managed/swig.2010.cs @@ -1113,6 +1113,21 @@ public class freeswitch { return ret; } + public static switch_status_t switch_core_session_io_read_lock(SWIGTYPE_p_switch_core_session session) { + switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_core_session_io_read_lock(SWIGTYPE_p_switch_core_session.getCPtr(session)); + return ret; + } + + public static switch_status_t switch_core_session_io_write_lock(SWIGTYPE_p_switch_core_session session) { + switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_core_session_io_write_lock(SWIGTYPE_p_switch_core_session.getCPtr(session)); + return ret; + } + + public static switch_status_t switch_core_session_io_rwunlock(SWIGTYPE_p_switch_core_session session) { + switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_core_session_io_rwunlock(SWIGTYPE_p_switch_core_session.getCPtr(session)); + return ret; + } + public static switch_status_t switch_core_session_read_lock(SWIGTYPE_p_switch_core_session session) { switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_core_session_read_lock(SWIGTYPE_p_switch_core_session.getCPtr(session)); return ret; @@ -1449,6 +1464,11 @@ public class freeswitch { return ret; } + public static switch_status_t switch_core_session_execute_application_async(SWIGTYPE_p_switch_core_session session, string app, string arg) { + switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_core_session_execute_application_async(SWIGTYPE_p_switch_core_session.getCPtr(session), app, arg); + return ret; + } + public static switch_status_t switch_core_session_get_app_flags(string app, SWIGTYPE_p_int flags) { switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_core_session_get_app_flags(app, SWIGTYPE_p_int.getCPtr(flags)); return ret; @@ -1528,6 +1548,11 @@ public class freeswitch { return ret; } + public static uint switch_core_session_messages_waiting(SWIGTYPE_p_switch_core_session session) { + uint ret = freeswitchPINVOKE.switch_core_session_messages_waiting(SWIGTYPE_p_switch_core_session.getCPtr(session)); + return ret; + } + public static switch_status_t switch_core_session_dequeue_event(SWIGTYPE_p_switch_core_session session, SWIGTYPE_p_p_switch_event arg1, switch_bool_t force) { switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_core_session_dequeue_event(SWIGTYPE_p_switch_core_session.getCPtr(session), SWIGTYPE_p_p_switch_event.getCPtr(arg1), (int)force); return ret; @@ -4471,6 +4496,27 @@ public class freeswitch { return ret; } + public static switch_status_t switch_ivr_get_file_handle(SWIGTYPE_p_switch_core_session session, SWIGTYPE_p_p_switch_file_handle fh) { + switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_ivr_get_file_handle(SWIGTYPE_p_switch_core_session.getCPtr(session), SWIGTYPE_p_p_switch_file_handle.getCPtr(fh)); + return ret; + } + + public static switch_status_t switch_ivr_release_file_handle(SWIGTYPE_p_switch_core_session session, SWIGTYPE_p_p_switch_file_handle fh) { + switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_ivr_release_file_handle(SWIGTYPE_p_switch_core_session.getCPtr(session), SWIGTYPE_p_p_switch_file_handle.getCPtr(fh)); + return ret; + } + + public static switch_status_t switch_ivr_process_fh(SWIGTYPE_p_switch_core_session session, string cmd, switch_file_handle fhp) { + switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_ivr_process_fh(SWIGTYPE_p_switch_core_session.getCPtr(session), cmd, switch_file_handle.getCPtr(fhp)); + return ret; + } + + public static switch_status_t switch_ivr_insert_file(SWIGTYPE_p_switch_core_session session, string file, string insert_file, SWIGTYPE_p_switch_size_t sample_point) { + switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_ivr_insert_file(SWIGTYPE_p_switch_core_session.getCPtr(session), file, insert_file, SWIGTYPE_p_switch_size_t.getCPtr(sample_point)); + if (freeswitchPINVOKE.SWIGPendingException.Pending) throw freeswitchPINVOKE.SWIGPendingException.Retrieve(); + return ret; + } + public static switch_status_t switch_rtp_add_crypto_key(SWIGTYPE_p_switch_rtp rtp_session, switch_rtp_crypto_direction_t direction, uint index, switch_rtp_crypto_key_type_t type, SWIGTYPE_p_unsigned_char key, SWIGTYPE_p_switch_size_t keylen) { switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_rtp_add_crypto_key(SWIGTYPE_p_switch_rtp.getCPtr(rtp_session), (int)direction, index, (int)type, SWIGTYPE_p_unsigned_char.getCPtr(key), SWIGTYPE_p_switch_size_t.getCPtr(keylen)); if (freeswitchPINVOKE.SWIGPendingException.Pending) throw freeswitchPINVOKE.SWIGPendingException.Retrieve(); @@ -7259,6 +7305,15 @@ class freeswitchPINVOKE { [DllImport("mod_managed", EntryPoint="CSharp_switch_core_destroy")] public static extern int switch_core_destroy(); + [DllImport("mod_managed", EntryPoint="CSharp_switch_core_session_io_read_lock")] + public static extern int switch_core_session_io_read_lock(HandleRef jarg1); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_core_session_io_write_lock")] + public static extern int switch_core_session_io_write_lock(HandleRef jarg1); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_core_session_io_rwunlock")] + public static extern int switch_core_session_io_rwunlock(HandleRef jarg1); + [DllImport("mod_managed", EntryPoint="CSharp_switch_core_session_read_lock")] public static extern int switch_core_session_read_lock(HandleRef jarg1); @@ -7463,6 +7518,9 @@ class freeswitchPINVOKE { [DllImport("mod_managed", EntryPoint="CSharp_switch_core_session_execute_application_get_flags")] public static extern int switch_core_session_execute_application_get_flags(HandleRef jarg1, string jarg2, string jarg3, HandleRef jarg4); + [DllImport("mod_managed", EntryPoint="CSharp_switch_core_session_execute_application_async")] + public static extern int switch_core_session_execute_application_async(HandleRef jarg1, string jarg2, string jarg3); + [DllImport("mod_managed", EntryPoint="CSharp_switch_core_session_get_app_flags")] public static extern int switch_core_session_get_app_flags(string jarg1, HandleRef jarg2); @@ -7511,6 +7569,9 @@ class freeswitchPINVOKE { [DllImport("mod_managed", EntryPoint="CSharp_switch_core_session_event_count")] public static extern uint switch_core_session_event_count(HandleRef jarg1); + [DllImport("mod_managed", EntryPoint="CSharp_switch_core_session_messages_waiting")] + public static extern uint switch_core_session_messages_waiting(HandleRef jarg1); + [DllImport("mod_managed", EntryPoint="CSharp_switch_core_session_dequeue_event")] public static extern int switch_core_session_dequeue_event(HandleRef jarg1, HandleRef jarg2, int jarg3); @@ -12242,6 +12303,18 @@ class freeswitchPINVOKE { [DllImport("mod_managed", EntryPoint="CSharp_switch_ivr_dmachine_set_realm")] public static extern int switch_ivr_dmachine_set_realm(HandleRef jarg1, string jarg2); + [DllImport("mod_managed", EntryPoint="CSharp_switch_ivr_get_file_handle")] + public static extern int switch_ivr_get_file_handle(HandleRef jarg1, HandleRef jarg2); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_ivr_release_file_handle")] + public static extern int switch_ivr_release_file_handle(HandleRef jarg1, HandleRef jarg2); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_ivr_process_fh")] + public static extern int switch_ivr_process_fh(HandleRef jarg1, string jarg2, HandleRef jarg3); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_ivr_insert_file")] + public static extern int switch_ivr_insert_file(HandleRef jarg1, string jarg2, string jarg3, HandleRef jarg4); + [DllImport("mod_managed", EntryPoint="CSharp_SWITCH_RTP_MAX_BUF_LEN_get")] public static extern int SWITCH_RTP_MAX_BUF_LEN_get(); @@ -17157,6 +17230,36 @@ namespace FreeSWITCH.Native { using System; using System.Runtime.InteropServices; +public class SWIGTYPE_p_p_switch_file_handle { + private HandleRef swigCPtr; + + internal SWIGTYPE_p_p_switch_file_handle(IntPtr cPtr, bool futureUse) { + swigCPtr = new HandleRef(this, cPtr); + } + + protected SWIGTYPE_p_p_switch_file_handle() { + swigCPtr = new HandleRef(null, IntPtr.Zero); + } + + internal static HandleRef getCPtr(SWIGTYPE_p_p_switch_file_handle obj) { + return (obj == null) ? new HandleRef(null, IntPtr.Zero) : obj.swigCPtr; + } +} + +} +/* ---------------------------------------------------------------------------- + * This file was automatically generated by SWIG (http://www.swig.org). + * Version 2.0.1 + * + * Do not make changes to this file unless you know what you are doing--modify + * the SWIG interface file instead. + * ----------------------------------------------------------------------------- */ + +namespace FreeSWITCH.Native { + +using System; +using System.Runtime.InteropServices; + public class SWIGTYPE_p_p_switch_frame { private HandleRef swigCPtr; From 92f43440729f16831fa9a3e840843486a942906e Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Wed, 1 Dec 2010 09:46:06 -0600 Subject: [PATCH 27/78] FS-2892 --- src/mod/endpoints/mod_sofia/sofia_glue.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index 57a2bfaa6a..451d7881b7 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -3732,6 +3732,14 @@ static switch_t38_options_t *tech_process_udptl(private_object_t *tech_pvt, sdp_ if (!t38_options) { t38_options = switch_core_session_alloc(tech_pvt->session, sizeof(switch_t38_options_t)); + + // set some default value + t38_options->T38FaxVersion = 0; + t38_options->T38MaxBitRate = 9600; + t38_options->T38FaxRateManagement = switch_core_session_strdup(tech_pvt->session, "transferredTCF"); + t38_options->T38FaxUdpEC = switch_core_session_strdup(tech_pvt->session, "t38UDPRedundancy"); + t38_options->T38FaxMaxBuffer = 500; + t38_options->T38FaxMaxDatagram = 500; } t38_options->remote_port = (switch_port_t)m->m_port; From 6b611662c26fbdd1ae96d71dadd243c48b725ab6 Mon Sep 17 00:00:00 2001 From: Arnaldo Pereira Date: Wed, 1 Dec 2010 13:47:17 -0200 Subject: [PATCH 28/78] freetdm: removed ftmod_sangoma_boost, testboost, testsangomaboost, ftmod_sangoma_isdn and ftmod_r2 from default msvc 2008 build --- libs/freetdm/freetdm.2008.sln | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/libs/freetdm/freetdm.2008.sln b/libs/freetdm/freetdm.2008.sln index f059d941d3..c7207a6216 100644 --- a/libs/freetdm/freetdm.2008.sln +++ b/libs/freetdm/freetdm.2008.sln @@ -64,6 +64,9 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ftmod_sangoma_isdn", "src\f EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ftmod_r2", "src\ftmod\ftmod_r2\ftmod_r2.2008.vcproj", "{08C3EA27-A51D-47F8-B47D-B189C649CF30}" + ProjectSection(ProjectDependencies) = postProject + {93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D} + EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -131,7 +134,6 @@ Global {1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}.Release|Win32.ActiveCfg = Release|Win32 {1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}.Release|x64.ActiveCfg = Release|x64 {D021EF2A-460D-4827-A0F7-41FDECF46F1B}.Debug|Win32.ActiveCfg = Debug|Win32 - {D021EF2A-460D-4827-A0F7-41FDECF46F1B}.Debug|Win32.Build.0 = Debug|Win32 {D021EF2A-460D-4827-A0F7-41FDECF46F1B}.Debug|x64.ActiveCfg = Debug|x64 {D021EF2A-460D-4827-A0F7-41FDECF46F1B}.Debug|x64.Build.0 = Debug|x64 {D021EF2A-460D-4827-A0F7-41FDECF46F1B}.Release|Win32.ActiveCfg = Release|Win32 @@ -139,7 +141,6 @@ Global {D021EF2A-460D-4827-A0F7-41FDECF46F1B}.Release|x64.ActiveCfg = Release|x64 {D021EF2A-460D-4827-A0F7-41FDECF46F1B}.Release|x64.Build.0 = Release|x64 {2B1BAF36-0241-43E7-B865-A8338AD48E2E}.Debug|Win32.ActiveCfg = Debug|Win32 - {2B1BAF36-0241-43E7-B865-A8338AD48E2E}.Debug|Win32.Build.0 = Debug|Win32 {2B1BAF36-0241-43E7-B865-A8338AD48E2E}.Debug|x64.ActiveCfg = Debug|x64 {2B1BAF36-0241-43E7-B865-A8338AD48E2E}.Debug|x64.Build.0 = Debug|x64 {2B1BAF36-0241-43E7-B865-A8338AD48E2E}.Release|Win32.ActiveCfg = Release|Win32 @@ -147,7 +148,6 @@ Global {2B1BAF36-0241-43E7-B865-A8338AD48E2E}.Release|x64.ActiveCfg = Release|x64 {2B1BAF36-0241-43E7-B865-A8338AD48E2E}.Release|x64.Build.0 = Release|x64 {0DA69C18-4FA1-4E8C-89CE-12498637C5BE}.Debug|Win32.ActiveCfg = Debug|Win32 - {0DA69C18-4FA1-4E8C-89CE-12498637C5BE}.Debug|Win32.Build.0 = Debug|Win32 {0DA69C18-4FA1-4E8C-89CE-12498637C5BE}.Debug|x64.ActiveCfg = Debug|x64 {0DA69C18-4FA1-4E8C-89CE-12498637C5BE}.Debug|x64.Build.0 = Debug|x64 {0DA69C18-4FA1-4E8C-89CE-12498637C5BE}.Release|Win32.ActiveCfg = Release|Win32 @@ -155,13 +155,11 @@ Global {0DA69C18-4FA1-4E8C-89CE-12498637C5BE}.Release|x64.ActiveCfg = Release|x64 {0DA69C18-4FA1-4E8C-89CE-12498637C5BE}.Release|x64.Build.0 = Release|x64 {B2AF4EA6-0CD7-4529-9EB5-5AF43DB90395}.Debug|Win32.ActiveCfg = Debug|Win32 - {B2AF4EA6-0CD7-4529-9EB5-5AF43DB90395}.Debug|Win32.Build.0 = Debug|Win32 {B2AF4EA6-0CD7-4529-9EB5-5AF43DB90395}.Debug|x64.ActiveCfg = Debug|Win32 {B2AF4EA6-0CD7-4529-9EB5-5AF43DB90395}.Release|Win32.ActiveCfg = Release|Win32 {B2AF4EA6-0CD7-4529-9EB5-5AF43DB90395}.Release|Win32.Build.0 = Release|Win32 {B2AF4EA6-0CD7-4529-9EB5-5AF43DB90395}.Release|x64.ActiveCfg = Release|Win32 {08C3EA27-A51D-47F8-B47D-B189C649CF30}.Debug|Win32.ActiveCfg = Debug|Win32 - {08C3EA27-A51D-47F8-B47D-B189C649CF30}.Debug|Win32.Build.0 = Debug|Win32 {08C3EA27-A51D-47F8-B47D-B189C649CF30}.Debug|x64.ActiveCfg = Debug|Win32 {08C3EA27-A51D-47F8-B47D-B189C649CF30}.Release|Win32.ActiveCfg = Release|Win32 {08C3EA27-A51D-47F8-B47D-B189C649CF30}.Release|Win32.Build.0 = Release|Win32 From 1ba98b02b9b2a44d1504f5c4546a7088907ed4eb Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Wed, 1 Dec 2010 09:54:28 -0600 Subject: [PATCH 29/78] FS-2852 --- src/switch_xml.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/switch_xml.c b/src/switch_xml.c index a7bfe413d0..05cfe9fd4c 100644 --- a/src/switch_xml.c +++ b/src/switch_xml.c @@ -1980,19 +1980,16 @@ static char not_so_threadsafe_error_buffer[256] = ""; SWITCH_DECLARE(switch_xml_t) switch_xml_open_root(uint8_t reload, const char **err) { char path_buf[1024]; - uint8_t hasmain = 0, errcnt = 0; + uint8_t errcnt = 0; switch_xml_t new_main, r = NULL; switch_mutex_lock(XML_LOCK); if (MAIN_XML_ROOT) { - hasmain++; - if (!reload) { r = switch_xml_root(); goto done; } - switch_thread_rwlock_wrlock(RWLOCK); } switch_snprintf(path_buf, sizeof(path_buf), "%s%s%s", SWITCH_GLOBAL_dirs.conf_dir, SWITCH_PATH_SEPARATOR, "freeswitch.xml"); @@ -2007,9 +2004,15 @@ SWITCH_DECLARE(switch_xml_t) switch_xml_open_root(uint8_t reload, const char **e } else { switch_xml_t old_root; *err = "Success"; + + switch_thread_rwlock_wrlock(RWLOCK); + old_root = MAIN_XML_ROOT; MAIN_XML_ROOT = new_main; switch_set_flag(MAIN_XML_ROOT, SWITCH_XML_ROOT); + + switch_thread_rwlock_unlock(RWLOCK); + switch_xml_free(old_root); /* switch_xml_free_in_thread(old_root); */ } @@ -2018,10 +2021,6 @@ SWITCH_DECLARE(switch_xml_t) switch_xml_open_root(uint8_t reload, const char **e errcnt++; } - if (hasmain) { - switch_thread_rwlock_unlock(RWLOCK); - } - if (errcnt == 0) { switch_event_t *event; if (switch_event_create(&event, SWITCH_EVENT_RELOADXML) == SWITCH_STATUS_SUCCESS) { From 43c91d5fce868bc7a6b9055494cd3e0d46ade964 Mon Sep 17 00:00:00 2001 From: Jeff Lenk Date: Wed, 1 Dec 2010 10:25:02 -0600 Subject: [PATCH 30/78] misc windows x64 fixes --- libs/freetdm/freetdm.2008.sln | 2 - .../msvc/testboost/testboost.2008.vcproj | 160 ++-- .../testboost/testsangomaboost.2008.vcproj | 156 ++-- .../ftmod_analog/ftmod_analog.2008.vcproj | 706 +++++++++--------- .../ftmod_analog_em.2008.vcproj | 706 +++++++++--------- .../ftmod_sangoma_boost.2008.vcproj | 156 ++-- 6 files changed, 942 insertions(+), 944 deletions(-) diff --git a/libs/freetdm/freetdm.2008.sln b/libs/freetdm/freetdm.2008.sln index f059d941d3..2e8c7c4adb 100644 --- a/libs/freetdm/freetdm.2008.sln +++ b/libs/freetdm/freetdm.2008.sln @@ -161,10 +161,8 @@ Global {B2AF4EA6-0CD7-4529-9EB5-5AF43DB90395}.Release|Win32.Build.0 = Release|Win32 {B2AF4EA6-0CD7-4529-9EB5-5AF43DB90395}.Release|x64.ActiveCfg = Release|Win32 {08C3EA27-A51D-47F8-B47D-B189C649CF30}.Debug|Win32.ActiveCfg = Debug|Win32 - {08C3EA27-A51D-47F8-B47D-B189C649CF30}.Debug|Win32.Build.0 = Debug|Win32 {08C3EA27-A51D-47F8-B47D-B189C649CF30}.Debug|x64.ActiveCfg = Debug|Win32 {08C3EA27-A51D-47F8-B47D-B189C649CF30}.Release|Win32.ActiveCfg = Release|Win32 - {08C3EA27-A51D-47F8-B47D-B189C649CF30}.Release|Win32.Build.0 = Release|Win32 {08C3EA27-A51D-47F8-B47D-B189C649CF30}.Release|x64.ActiveCfg = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution diff --git a/libs/freetdm/msvc/testboost/testboost.2008.vcproj b/libs/freetdm/msvc/testboost/testboost.2008.vcproj index afb44b6469..5707033f33 100644 --- a/libs/freetdm/msvc/testboost/testboost.2008.vcproj +++ b/libs/freetdm/msvc/testboost/testboost.2008.vcproj @@ -22,7 +22,7 @@ - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + diff --git a/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.2008.vcproj b/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.2008.vcproj index 448f03a545..09349fc05f 100644 --- a/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.2008.vcproj +++ b/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.2008.vcproj @@ -1,353 +1,353 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.2008.vcproj b/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.2008.vcproj index 8ad183797a..837ba7de0f 100644 --- a/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.2008.vcproj +++ b/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.2008.vcproj @@ -1,353 +1,353 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.2008.vcproj b/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.2008.vcproj index e7fc1d6549..73e421818f 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.2008.vcproj +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.2008.vcproj @@ -95,83 +95,6 @@ Name="VCPostBuildEventTool" /> - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + From ca28a80658d50a9fab14f3022c40536b385b6b9b Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Wed, 1 Dec 2010 10:31:28 -0600 Subject: [PATCH 31/78] update caller_profile to have correct uuid when using custom uuid from originate string --- src/switch_core_session.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/switch_core_session.c b/src/switch_core_session.c index fc7648155a..2567d17712 100644 --- a/src/switch_core_session.c +++ b/src/switch_core_session.c @@ -1327,6 +1327,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_set_uuid(switch_core_session { switch_event_t *event; switch_core_session_message_t msg = { 0 }; + switch_caller_profile_t *profile; switch_assert(use_uuid); @@ -1343,6 +1344,10 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_set_uuid(switch_core_session msg.string_array_arg[1] = use_uuid; switch_core_session_receive_message(session, &msg); + if ((profile = switch_channel_get_caller_profile(session->channel))) { + profile->uuid = switch_core_strdup(profile->pool, use_uuid); + } + switch_event_create(&event, SWITCH_EVENT_CHANNEL_UUID); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Old-Unique-ID", session->uuid_str); switch_core_hash_delete(session_manager.session_table, session->uuid_str); From 6b52a43314824943a3ef19b86bd577d5729416eb Mon Sep 17 00:00:00 2001 From: Jeff Lenk Date: Wed, 1 Dec 2010 11:55:05 -0600 Subject: [PATCH 32/78] fix build warnings --- libs/freetdm/src/ftdm_call_utils.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libs/freetdm/src/ftdm_call_utils.c b/libs/freetdm/src/ftdm_call_utils.c index 52d2557a01..69f2fb4fff 100644 --- a/libs/freetdm/src/ftdm_call_utils.c +++ b/libs/freetdm/src/ftdm_call_utils.c @@ -38,7 +38,7 @@ FT_DECLARE(ftdm_status_t) ftdm_set_npi(const char *string, uint8_t *target) { - int val; + uint8_t val; ftdm_status_t status = FTDM_SUCCESS; val = ftdm_str2ftdm_npi(string); @@ -53,7 +53,7 @@ FT_DECLARE(ftdm_status_t) ftdm_set_npi(const char *string, uint8_t *target) FT_DECLARE(ftdm_status_t) ftdm_set_ton(const char *string, uint8_t *target) { - int val; + uint8_t val; ftdm_status_t status = FTDM_SUCCESS; val = ftdm_str2ftdm_ton(string); @@ -68,7 +68,7 @@ FT_DECLARE(ftdm_status_t) ftdm_set_ton(const char *string, uint8_t *target) FT_DECLARE(ftdm_status_t) ftdm_set_bearer_capability(const char *string, uint8_t *target) { - int val; + uint8_t val; ftdm_status_t status = FTDM_SUCCESS; val = ftdm_str2ftdm_bearer_cap(string); @@ -84,7 +84,7 @@ FT_DECLARE(ftdm_status_t) ftdm_set_bearer_capability(const char *string, uint8_t FT_DECLARE(ftdm_status_t) ftdm_set_bearer_layer1(const char *string, uint8_t *target) { - int val; + uint8_t val; ftdm_status_t status = FTDM_SUCCESS; val = ftdm_str2ftdm_usr_layer1_prot(string); @@ -100,7 +100,7 @@ FT_DECLARE(ftdm_status_t) ftdm_set_bearer_layer1(const char *string, uint8_t *ta FT_DECLARE(ftdm_status_t) ftdm_set_screening_ind(const char *string, uint8_t *target) { - int val; + uint8_t val; ftdm_status_t status = FTDM_SUCCESS; val = ftdm_str2ftdm_screening(string); @@ -116,7 +116,7 @@ FT_DECLARE(ftdm_status_t) ftdm_set_screening_ind(const char *string, uint8_t *ta FT_DECLARE(ftdm_status_t) ftdm_set_presentation_ind(const char *string, uint8_t *target) { - int val; + uint8_t val; ftdm_status_t status = FTDM_SUCCESS; val = ftdm_str2ftdm_presentation(string); From 85d2395d26135a862b3bed07b316c0ebbf14b725 Mon Sep 17 00:00:00 2001 From: Arnaldo Pereira Date: Wed, 1 Dec 2010 16:23:21 -0200 Subject: [PATCH 33/78] freetdm: ftmod_r2 - now clearing FTDM_CHANNEL_STATE_CHANGE flag when needed --- libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c | 54 ++++++++++++++++------ 1 file changed, 41 insertions(+), 13 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c index b98f7db99c..73856f000c 100644 --- a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c +++ b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c @@ -56,15 +56,10 @@ typedef enum { FTDM_R2_RUNNING = (1 << 0), } ftdm_r2_flag_t; -typedef enum { - FTDM_R2_WAITING_ACK = (1 << 0), -} ftdm_r2_call_flag_t; - /* private call information stored in ftdmchan->call_data void* ptr */ #define R2CALL(ftdmchan) ((ftdm_r2_call_t*)((ftdmchan)->call_data)) typedef struct ftdm_r2_call_t { openr2_chan_t *r2chan; - ftdm_r2_call_flag_t flags; int accepted:1; int answer_pending:1; int disconnect_rcvd:1; @@ -154,6 +149,12 @@ static ftdm_io_interface_t g_ftdm_r2_interface; static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan); static void ftdm_r2_state_advance_all(ftdm_channel_t *ftdmchan); +/* whether R2 call accept process is pending */ +#define IS_ACCEPTING_PENDING(ftdmchan) \ + ( (!ftdm_test_flag((ftdmchan), FTDM_CHANNEL_OUTBOUND)) && !R2CALL((ftdmchan))->accepted && \ + ((ftdmchan)->state == FTDM_CHANNEL_STATE_PROGRESS || \ + (ftdmchan)->state == FTDM_CHANNEL_STATE_PROGRESS_MEDIA || \ + (ftdmchan)->state == FTDM_CHANNEL_STATE_UP) ) /* functions not available on windows */ #ifdef WIN32 @@ -374,7 +375,6 @@ static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(r2_outgoing_call) if (ftdmchan->state != FTDM_CHANNEL_STATE_DIALING) { ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Collision after call attempt, try another channel, new state = %s\n", ftdm_channel_state2str(ftdmchan->state)); - ftdm_clear_flag(R2CALL(ftdmchan), FTDM_R2_WAITING_ACK); return FTDM_BREAK; } @@ -451,16 +451,43 @@ static void ftdm_r2_on_call_offered(openr2_chan_t *r2chan, const char *ani, cons ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RING); } +/* + * Accepting a call in R2 is a lengthy process due to MF tones, + * when the user sends PROGRESS indication (implicitly moving the + * ftdm channel to PROGRESS state) the R2 processing loop + * does not clear FTDM_CHANNEL_STATE_CHANGE immediately as it does + * for all the other states, instead has to wait for on_call_accepted + * callback from openr2, which means the MF has ended and the progress + * indication is done, in order to clear the flag. However, if + * a protocol error or call disconnection (which is indicated using CAS bits) + * occurrs while accepting, we must clear the pending flag, this function + * takes care of that + * */ +static void clear_accept_pending(ftdm_channel_t *fchan) +{ + if (IS_ACCEPTING_PENDING(fchan)) { + ftdm_clear_flag(fchan, FTDM_CHANNEL_STATE_CHANGE); + ftdm_channel_complete_state(fchan); + } else if (ftdm_test_flag(fchan, FTDM_CHANNEL_STATE_CHANGE)) { + ftdm_log_chan(fchan, FTDM_LOG_CRIT, "State change flag set in state %s, last state = %s\n", + ftdm_channel_state2str(fchan->state), ftdm_channel_state2str(fchan->last_state)); + ftdm_clear_flag(fchan, FTDM_CHANNEL_STATE_CHANGE); + ftdm_channel_complete_state(fchan); + } +} + static void ftdm_r2_on_call_accepted(openr2_chan_t *r2chan, openr2_call_mode_t mode) { ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan); ftdm_log_chan_msg(ftdmchan, FTDM_LOG_NOTICE, "Call accepted\n"); + + clear_accept_pending(ftdmchan); + /* at this point the MF signaling has ended and there is no point on keep reading */ openr2_chan_disable_read(r2chan); R2CALL(ftdmchan)->accepted = 1; + if (OR2_DIR_BACKWARD == openr2_chan_get_direction(r2chan)) { - ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE); - ftdm_channel_complete_state(ftdmchan); if (R2CALL(ftdmchan)->answer_pending) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Answer was pending, answering now.\n"); ft_r2_answer_call(ftdmchan); @@ -493,6 +520,8 @@ static void ftdm_r2_on_call_disconnect(openr2_chan_t *r2chan, openr2_call_discon ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Got openr2 disconnection, clearing call\n"); + clear_accept_pending(ftdmchan); + R2CALL(ftdmchan)->disconnect_rcvd = 1; if (ftdmchan->state == FTDM_CHANNEL_STATE_HANGUP) { @@ -564,6 +593,8 @@ static void ftdm_r2_on_protocol_error(openr2_chan_t *r2chan, openr2_protocol_err ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Protocol error\n"); + clear_accept_pending(ftdmchan); + R2CALL(ftdmchan)->disconnect_rcvd = 1; R2CALL(ftdmchan)->protocol_error = 1; @@ -1204,12 +1235,9 @@ static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan) ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Executing state handler for %s\n", ftdm_channel_state2str(ftdmchan->state)); R2CALL(ftdmchan)->chanstate = ftdmchan->state; - if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND) && !R2CALL(ftdmchan)->accepted && - (ftdmchan->state == FTDM_CHANNEL_STATE_PROGRESS || - ftdmchan->state == FTDM_CHANNEL_STATE_PROGRESS_MEDIA || - ftdmchan->state == FTDM_CHANNEL_STATE_UP) ) { + if (IS_ACCEPTING_PENDING(ftdmchan)) { /* - Moving to PROGRESS, PROGRESS_MEDIA or UP means that we must accept the call, and accepting + Moving to PROGRESS, PROGRESS_MEDIA or UP means that we must accept the call first, and accepting the call in R2 means sending a tone, then waiting for the acknowledge from the other end, since all of that requires sending and detecting tones, it takes a few milliseconds (I'd say around 100) which means during that time the user should not try to perform any operations like answer, hangup or anything From 5df1683c38851b71ac0f74fbf058e32437140c55 Mon Sep 17 00:00:00 2001 From: Geovani Ricardo Wiedenhoft Date: Wed, 1 Dec 2010 16:40:35 -0200 Subject: [PATCH 34/78] - Notifies the pre_answer - Dialplan examples - New version of commons - Priority of contexts - New K3L install script - getk3l.sh - CLI return in XML - More options in GET and SET commands - Events (ESL) to send/receive SMS. - fax-adjustment-timeout implemented - accountcode and language - Owner destroy - Destroy wait for resources release - static const expression - Hangup cause --- build/modules.conf.in | 2 +- conf/autoload_configs/modules.conf.xml | 1 + .../mod_khomp/Install/files/khomp.conf.xml | 61 +- src/mod/endpoints/mod_khomp/Makefile | 20 +- .../mod_khomp/commons/{ => base}/atomic.hpp | 24 +- .../commons/{ => base}/config_commons.hpp | 9 +- .../mod_khomp/commons/base/config_options.cpp | 302 ++++ .../mod_khomp/commons/base/config_options.hpp | 772 +++++++++++ .../commons/base/configurator/configfile.cpp | 241 ++++ .../{ => base}/configurator/configfile.hpp | 70 +- .../commons/base/configurator/option.cpp | 186 +++ .../{ => base}/configurator/option.hpp | 112 +- .../commons/base/configurator/restriction.cpp | 358 +++++ .../commons/base/configurator/restriction.hpp | 269 ++++ .../{ => base}/configurator/section.cpp | 100 +- .../commons/base/configurator/section.hpp | 260 ++++ .../mod_khomp/commons/base/const_this.hpp | 15 + .../mod_khomp/commons/{ => base}/flagger.hpp | 0 .../mod_khomp/commons/{ => base}/format.cpp | 138 +- .../mod_khomp/commons/{ => base}/format.hpp | 505 +++---- .../mod_khomp/commons/{ => base}/function.hpp | 140 +- .../commons/{ => base}/initializer.hpp | 16 +- .../mod_khomp/commons/{ => base}/k3lapi.cpp | 70 +- .../mod_khomp/commons/{ => base}/k3lapi.hpp | 470 ++++--- .../mod_khomp/commons/{ => base}/k3lutil.cpp | 50 +- .../mod_khomp/commons/{ => base}/k3lutil.hpp | 6 +- .../mod_khomp/commons/{ => base}/logger.hpp | 56 +- .../commons/{ => base}/noncopyable.hpp | 0 .../commons/{ => base}/refcounter.hpp | 11 +- .../mod_khomp/commons/{ => base}/regex.cpp | 5 +- .../mod_khomp/commons/{ => base}/regex.hpp | 77 +- .../mod_khomp/commons/base/ringbuffer.cpp | 485 +++++++ .../commons/{ => base}/ringbuffer.hpp | 62 +- .../commons/{ => base}/saved_condition.cpp | 0 .../commons/{ => base}/saved_condition.hpp | 0 .../commons/{ => base}/scoped_lock.hpp | 0 .../commons/{ => base}/simple_lock.hpp | 4 +- .../mod_khomp/commons/{ => base}/strings.cpp | 56 +- .../mod_khomp/commons/{ => base}/strings.hpp | 19 +- .../system}/freeswitch/saved_condition.cpp | 46 +- .../system}/freeswitch/saved_condition.hpp | 32 +- .../system}/freeswitch/simple_lock.hpp | 32 +- .../{ => base/system}/freeswitch/thread.hpp | 66 +- .../commons/{ => base}/tagged_union.hpp | 62 +- .../mod_khomp/commons/{ => base}/thread.hpp | 0 .../mod_khomp/commons/{ => base}/timer.cpp | 14 + .../mod_khomp/commons/{ => base}/timer.hpp | 11 +- .../mod_khomp/commons/{ => base}/types.hpp | 24 +- .../{variant.hpp => base/variable.hpp} | 127 +- .../mod_khomp/commons/{ => base}/verbose.cpp | 980 ++++++------- .../mod_khomp/commons/base/verbose.hpp | 303 ++++ .../mod_khomp/commons/config_options.cpp | 710 ---------- .../mod_khomp/commons/config_options.hpp | 286 ---- .../commons/configurator/configfile.cpp | 241 ---- .../mod_khomp/commons/configurator/option.cpp | 185 --- .../commons/configurator/restriction.cpp | 353 ----- .../commons/configurator/restriction.hpp | 321 ----- .../commons/configurator/section.hpp | 226 --- .../mod_khomp/commons/ringbuffer.cpp | 575 -------- .../commons/tools/generate-verbose-headers.sh | 183 +++ .../endpoints/mod_khomp/commons/verbose.hpp | 505 ------- src/mod/endpoints/mod_khomp/docs/Manual.html | 16 +- src/mod/endpoints/mod_khomp/docs/Manual.pdf | Bin 469674 -> 470343 bytes src/mod/endpoints/mod_khomp/docs/README.pdf | Bin 399120 -> 399119 bytes .../endpoints/mod_khomp/docs/README_en.pdf | Bin 314414 -> 314413 bytes .../endpoints/mod_khomp/docs/User_Guide.html | 18 +- .../endpoints/mod_khomp/docs/User_Guide.pdf | Bin 509356 -> 509260 bytes .../mod_khomp/examples/intercept.xml | 26 + .../endpoints/mod_khomp/examples/transfer.xml | 43 + .../mod_khomp/include/applications.h | 83 +- src/mod/endpoints/mod_khomp/include/cli.h | 254 ++-- src/mod/endpoints/mod_khomp/include/defs.h | 4 +- src/mod/endpoints/mod_khomp/include/frame.h | 2 +- src/mod/endpoints/mod_khomp/include/globals.h | 4 +- .../endpoints/mod_khomp/include/khomp_pvt.h | 66 +- .../mod_khomp/include/khomp_pvt_fxo.h | 6 +- .../mod_khomp/include/khomp_pvt_gsm.h | 4 +- .../mod_khomp/include/khomp_pvt_kxe1.h | 29 +- .../mod_khomp/include/khomp_pvt_passive.h | 8 +- src/mod/endpoints/mod_khomp/include/opt.h | 316 ++--- .../endpoints/mod_khomp/include/revision.h | 2 +- src/mod/endpoints/mod_khomp/include/spec.h | 7 - src/mod/endpoints/mod_khomp/include/utils.h | 90 ++ src/mod/endpoints/mod_khomp/mod_khomp.cpp | 77 +- .../endpoints/mod_khomp/src/applications.cpp | 15 +- src/mod/endpoints/mod_khomp/src/cli.cpp | 1214 +++++++++++++---- src/mod/endpoints/mod_khomp/src/globals.cpp | 4 +- src/mod/endpoints/mod_khomp/src/khomp_pvt.cpp | 270 +++- .../endpoints/mod_khomp/src/khomp_pvt_fxo.cpp | 51 +- .../endpoints/mod_khomp/src/khomp_pvt_gsm.cpp | 31 +- .../mod_khomp/src/khomp_pvt_kxe1.cpp | 187 +-- .../mod_khomp/src/khomp_pvt_passive.cpp | 7 +- src/mod/endpoints/mod_khomp/src/opt.cpp | 416 +++--- src/mod/endpoints/mod_khomp/src/spec.cpp | 40 +- src/mod/endpoints/mod_khomp/src/utils.cpp | 78 +- .../mod_khomp/support/klog-config.cpp | 4 + .../mod_khomp/support/klog-config.hpp | 6 + .../mod_khomp/{install.sh => tools/getk3l.sh} | 12 +- 98 files changed, 7491 insertions(+), 6153 deletions(-) rename src/mod/endpoints/mod_khomp/commons/{ => base}/atomic.hpp (90%) rename src/mod/endpoints/mod_khomp/commons/{ => base}/config_commons.hpp (92%) create mode 100644 src/mod/endpoints/mod_khomp/commons/base/config_options.cpp create mode 100644 src/mod/endpoints/mod_khomp/commons/base/config_options.hpp create mode 100644 src/mod/endpoints/mod_khomp/commons/base/configurator/configfile.cpp rename src/mod/endpoints/mod_khomp/commons/{ => base}/configurator/configfile.hpp (65%) create mode 100644 src/mod/endpoints/mod_khomp/commons/base/configurator/option.cpp rename src/mod/endpoints/mod_khomp/commons/{ => base}/configurator/option.hpp (52%) create mode 100644 src/mod/endpoints/mod_khomp/commons/base/configurator/restriction.cpp create mode 100644 src/mod/endpoints/mod_khomp/commons/base/configurator/restriction.hpp rename src/mod/endpoints/mod_khomp/commons/{ => base}/configurator/section.cpp (59%) create mode 100644 src/mod/endpoints/mod_khomp/commons/base/configurator/section.hpp create mode 100644 src/mod/endpoints/mod_khomp/commons/base/const_this.hpp rename src/mod/endpoints/mod_khomp/commons/{ => base}/flagger.hpp (100%) rename src/mod/endpoints/mod_khomp/commons/{ => base}/format.cpp (89%) rename src/mod/endpoints/mod_khomp/commons/{ => base}/format.hpp (81%) rename src/mod/endpoints/mod_khomp/commons/{ => base}/function.hpp (65%) rename src/mod/endpoints/mod_khomp/commons/{ => base}/initializer.hpp (86%) rename src/mod/endpoints/mod_khomp/commons/{ => base}/k3lapi.cpp (77%) rename src/mod/endpoints/mod_khomp/commons/{ => base}/k3lapi.hpp (50%) rename src/mod/endpoints/mod_khomp/commons/{ => base}/k3lutil.cpp (83%) rename src/mod/endpoints/mod_khomp/commons/{ => base}/k3lutil.hpp (95%) rename src/mod/endpoints/mod_khomp/commons/{ => base}/logger.hpp (89%) rename src/mod/endpoints/mod_khomp/commons/{ => base}/noncopyable.hpp (100%) rename src/mod/endpoints/mod_khomp/commons/{ => base}/refcounter.hpp (94%) rename src/mod/endpoints/mod_khomp/commons/{ => base}/regex.cpp (94%) rename src/mod/endpoints/mod_khomp/commons/{ => base}/regex.hpp (78%) create mode 100644 src/mod/endpoints/mod_khomp/commons/base/ringbuffer.cpp rename src/mod/endpoints/mod_khomp/commons/{ => base}/ringbuffer.hpp (88%) rename src/mod/endpoints/mod_khomp/commons/{ => base}/saved_condition.cpp (100%) rename src/mod/endpoints/mod_khomp/commons/{ => base}/saved_condition.hpp (100%) rename src/mod/endpoints/mod_khomp/commons/{ => base}/scoped_lock.hpp (100%) rename src/mod/endpoints/mod_khomp/commons/{ => base}/simple_lock.hpp (96%) rename src/mod/endpoints/mod_khomp/commons/{ => base}/strings.cpp (87%) rename src/mod/endpoints/mod_khomp/commons/{ => base}/strings.hpp (81%) rename src/mod/endpoints/mod_khomp/commons/{ => base/system}/freeswitch/saved_condition.cpp (83%) rename src/mod/endpoints/mod_khomp/commons/{ => base/system}/freeswitch/saved_condition.hpp (94%) rename src/mod/endpoints/mod_khomp/commons/{ => base/system}/freeswitch/simple_lock.hpp (96%) rename src/mod/endpoints/mod_khomp/commons/{ => base/system}/freeswitch/thread.hpp (94%) rename src/mod/endpoints/mod_khomp/commons/{ => base}/tagged_union.hpp (84%) rename src/mod/endpoints/mod_khomp/commons/{ => base}/thread.hpp (100%) rename src/mod/endpoints/mod_khomp/commons/{ => base}/timer.cpp (96%) rename src/mod/endpoints/mod_khomp/commons/{ => base}/timer.hpp (93%) rename src/mod/endpoints/mod_khomp/commons/{ => base}/types.hpp (88%) rename src/mod/endpoints/mod_khomp/commons/{variant.hpp => base/variable.hpp} (53%) rename src/mod/endpoints/mod_khomp/commons/{ => base}/verbose.cpp (82%) create mode 100644 src/mod/endpoints/mod_khomp/commons/base/verbose.hpp delete mode 100644 src/mod/endpoints/mod_khomp/commons/config_options.cpp delete mode 100644 src/mod/endpoints/mod_khomp/commons/config_options.hpp delete mode 100644 src/mod/endpoints/mod_khomp/commons/configurator/configfile.cpp delete mode 100644 src/mod/endpoints/mod_khomp/commons/configurator/option.cpp delete mode 100644 src/mod/endpoints/mod_khomp/commons/configurator/restriction.cpp delete mode 100644 src/mod/endpoints/mod_khomp/commons/configurator/restriction.hpp delete mode 100644 src/mod/endpoints/mod_khomp/commons/configurator/section.hpp delete mode 100644 src/mod/endpoints/mod_khomp/commons/ringbuffer.cpp create mode 100755 src/mod/endpoints/mod_khomp/commons/tools/generate-verbose-headers.sh delete mode 100644 src/mod/endpoints/mod_khomp/commons/verbose.hpp create mode 100644 src/mod/endpoints/mod_khomp/examples/intercept.xml create mode 100644 src/mod/endpoints/mod_khomp/examples/transfer.xml rename src/mod/endpoints/mod_khomp/{install.sh => tools/getk3l.sh} (93%) diff --git a/build/modules.conf.in b/build/modules.conf.in index 37244a188a..13e655672c 100644 --- a/build/modules.conf.in +++ b/build/modules.conf.in @@ -62,6 +62,7 @@ endpoints/mod_loopback #endpoints/mod_skinny #endpoints/mod_skypopen #endpoints/mod_h323 +#endpoints/mod_khomp #../../libs/openzap/mod_openzap #../../libs/freetdm/mod_freetdm #asr_tts/mod_unimrcp @@ -105,5 +106,4 @@ say/mod_say_ru #say/mod_say_th ## Experimental Modules (don't cry if they're broken) -#endpoints/mod_khomp #../../contrib/mod/xml_int/mod_xml_odbc diff --git a/conf/autoload_configs/modules.conf.xml b/conf/autoload_configs/modules.conf.xml index f5627fe965..118d7c4d81 100644 --- a/conf/autoload_configs/modules.conf.xml +++ b/conf/autoload_configs/modules.conf.xml @@ -38,6 +38,7 @@ + diff --git a/src/mod/endpoints/mod_khomp/Install/files/khomp.conf.xml b/src/mod/endpoints/mod_khomp/Install/files/khomp.conf.xml index 45268f304b..79c00516b9 100644 --- a/src/mod/endpoints/mod_khomp/Install/files/khomp.conf.xml +++ b/src/mod/endpoints/mod_khomp/Install/files/khomp.conf.xml @@ -95,16 +95,6 @@ should be opened for the channel. Limited to 25ms min, 500ms max. --> - - - - - - - - - - diff --git a/src/mod/endpoints/mod_khomp/Makefile b/src/mod/endpoints/mod_khomp/Makefile index 94923c7cda..db1a6fe4e4 100644 --- a/src/mod/endpoints/mod_khomp/Makefile +++ b/src/mod/endpoints/mod_khomp/Makefile @@ -1,6 +1,9 @@ MODNAME := mod_khomp VERBOSE := 1 +#FreeSWITCH source PATH is needed: +# Set FREESWITCH_PATH + ifeq ($(strip $(FREESWITCH_PATH)),) BASE := ../../../../ else @@ -11,12 +14,12 @@ curr_dir := $(shell pwd) versions := -DFS_VERSION_MAJOR=$(shell bash $(curr_dir)/tools/getversion.sh "SWITCH_VERSION_MAJOR" $(BASE)) -DFS_VERSION_MINOR=$(shell bash $(curr_dir)/tools/getversion.sh "SWITCH_VERSION_MINOR" $(BASE)) -DFS_VERSION_MICRO=$(shell bash $(curr_dir)/tools/getversion.sh "SWITCH_VERSION_MICRO" $(BASE)) -LOCAL_CFLAGS = -I./ -I./include -I./commons -I./support -D_REENTRANT -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -DK3L_HOSTSYSTEM -DCOMMONS_LIBRARY_USING_FREESWITCH -g -ggdb #-DDEBUG_FLAGS +LOCAL_CFLAGS = -I./ -I./include -I./commons -I./commons/base -I./support -D_REENTRANT -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -DK3L_HOSTSYSTEM -DCOMMONS_LIBRARY_USING_FREESWITCH -g -ggdb #-DDEBUG_FLAGS LOCAL_CFLAGS += $(versions) LOCAL_LDFLAGS = -lk3l -LOCAL_OBJS = ./commons/k3lapi.o ./commons/k3lutil.o ./commons/config_options.o ./commons/format.o ./commons/strings.o ./commons/ringbuffer.o ./commons/verbose.o ./commons/saved_condition.o ./commons/regex.o ./commons/timer.o ./commons/configurator/configfile.o ./commons/configurator/option.o ./commons/configurator/section.o ./commons/configurator/restriction.o +LOCAL_OBJS = ./commons/base/k3lapi.o ./commons/base/k3lutil.o ./commons/base/config_options.o ./commons/base/format.o ./commons/base/strings.o ./commons/base/ringbuffer.o ./commons/base/verbose.o ./commons/base/saved_condition.o ./commons/base/regex.o ./commons/base/timer.o ./commons/base/configurator/configfile.o ./commons/base/configurator/option.o ./commons/base/configurator/section.o ./commons/base/configurator/restriction.o ./commons/base/verbose_traits.o LOCAL_OBJS += ./support/klog-config.o ./support/klog-options.o ./support/config_defaults.o LOCAL_OBJS += ./src/globals.o ./src/opt.o ./src/frame.o ./src/utils.o ./src/lock.o ./src/spec.o ./src/applications.o ./src/khomp_pvt_fxo.o ./src/khomp_pvt_gsm.o ./src/khomp_pvt_kxe1.o ./src/khomp_pvt_passive.o ./src/khomp_pvt.o ./src/logger.o ./src/cli.o @@ -27,7 +30,20 @@ conf_file_install = $(sysconfdir)/autoload_configs include $(BASE)/build/modmake.rules +local_depend: + @if test ! -f $(curr_dir)/commons/base/verbose_traits.hpp || test ! -f $(curr_dir)/commons/base/verbose_traits.cpp ; then \ + echo "Generating verbose_traits" ;\ + bash $(curr_dir)/commons/tools/generate-verbose-headers.sh commons/base/ include/k3l.h ;\ + fi; + depend_install: + @if test "w`kserver --version 2>/dev/null | grep 2.1`" == "w" ; then \ + echo "###############################################################################" ;\ + echo "Install k3l from KHOMP." ;\ + echo "Run: $(curr_dir)/tools/getk3l.sh" ;\ + echo "###############################################################################" ;\ + exit 1;\ + fi; @echo "Copy $(conf_file_name)" @if test -d $(conf_file_install) ; then \ if test -f $(conf_file_dir)/$(conf_file_name) ; then \ diff --git a/src/mod/endpoints/mod_khomp/commons/atomic.hpp b/src/mod/endpoints/mod_khomp/commons/base/atomic.hpp similarity index 90% rename from src/mod/endpoints/mod_khomp/commons/atomic.hpp rename to src/mod/endpoints/mod_khomp/commons/base/atomic.hpp index daa598c9b4..02278b390c 100644 --- a/src/mod/endpoints/mod_khomp/commons/atomic.hpp +++ b/src/mod/endpoints/mod_khomp/commons/base/atomic.hpp @@ -64,17 +64,31 @@ namespace Atomic PunnedType pval; pval.valtype = VAL; \ unsigned long long vexp = *(pexp.podtype); \ unsigned long long vval = *(pval.podtype); \ - unsigned long long res = (unsigned long long)exp; \ + unsigned long vval32 = (unsigned long)vval; \ unsigned char chg = 0; \ - asm volatile("lock; cmpxchg8b %2; sete %1;" \ + asm volatile( \ + "xchgl %%ebx, %4;" \ + "lock; cmpxchg8b %2; sete %1;" \ + "movl %4, %%ebx; " \ : "+A" (vexp), /* 0 (result) */ \ - "=q" (chg) /* 1 */ \ + "=c" (chg) /* 1 */ \ : "m" (*(unsigned char**)(PTR)), /* 2 */ \ - "b" ((unsigned long)(vval)), \ - "c" ((unsigned long)(vval >> 32))); \ + "c" ((unsigned long)(vval >> 32)), \ + "m" (vval32)); \ *(pexp.podtype) = vexp; \ return (chg != 0 ? true : false); +// "movl %%ecx, %4;" +// +// "m" (*((unsigned long*)(*(pval.podtype)))), +// "m" ((unsigned long)(vval >> 32)) +// +// "m" (*((unsigned long*)(&vval))), +// "m" ((unsigned long)(vval >> 32)) +// +// unsigned long long vval = *(pval.podtype); +// unsigned long long res = (unsigned long long)exp; +// // Types used for making CMPXCHG instructions independent from base type. template < typename ValType, typename PodType > diff --git a/src/mod/endpoints/mod_khomp/commons/config_commons.hpp b/src/mod/endpoints/mod_khomp/commons/base/config_commons.hpp similarity index 92% rename from src/mod/endpoints/mod_khomp/commons/config_commons.hpp rename to src/mod/endpoints/mod_khomp/commons/base/config_commons.hpp index de8f327df4..dad16f4e92 100644 --- a/src/mod/endpoints/mod_khomp/commons/config_commons.hpp +++ b/src/mod/endpoints/mod_khomp/commons/base/config_commons.hpp @@ -63,7 +63,12 @@ #error Unknown implementation selected. Please define COMMONS_LIBRARY_USING_* correctly. #endif -#define COMMONS_INCLUDE(file) +#define COMMONS_INCLUDE(file) + +#define COMMONS_VERSION_MAJOR 1 +#define COMMONS_VERSION_MINOR 1 + +#define COMMONS_AT_LEAST(x,y) \ + (COMMONS_VERSION_MAJOR > x || (COMMONS_VERSION_MAJOR == x && COMMONS_VERSION_MINOR >= y)) #endif /* _CONFIG_COMMONS_HPP_ */ - diff --git a/src/mod/endpoints/mod_khomp/commons/base/config_options.cpp b/src/mod/endpoints/mod_khomp/commons/base/config_options.cpp new file mode 100644 index 0000000000..7412b4b1a0 --- /dev/null +++ b/src/mod/endpoints/mod_khomp/commons/base/config_options.cpp @@ -0,0 +1,302 @@ +/* + KHOMP generic endpoint/channel library. + Copyright (C) 2007-2009 Khomp Ind. & Com. + + The contents of this file are subject to the Mozilla Public License Version 1.1 + (the "License"); you may not use this file except in compliance with the + License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS IS" basis, + WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for + the specific language governing rights and limitations under the License. + + Alternatively, the contents of this file may be used under the terms of the + "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which + case the provisions of "LGPL License" are applicable instead of those above. + + If you wish to allow use of your version of this file only under the terms of + the LGPL License and not to allow others to use your version of this file under + the MPL, indicate your decision by deleting the provisions above and replace them + with the notice and other provisions required by the LGPL License. If you do not + delete the provisions above, a recipient may use your version of this file under + either the MPL or the LGPL License. + + The LGPL header follows below: + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#include + +void Config::Restriction::checkRange(const std::string & name, const SIntType value, const Range < SIntType > & range) +{ + if (value < range.minimum) + throw Failure(STG(FMT("value '%d' out-of-range for option '%s' (too low)") % value % name)); + + if (value > range.maximum) + throw Failure(STG(FMT("value '%d' out-of-range for option '%s' (too high)") % value % name)); + + if (((value - range.minimum) % range.step) != 0) + throw Failure(STG(FMT("value '%d' out-of-range for option '%s' (outside allowed step)") % value % name)); +} + +void Config::Restriction::checkRange(const std::string & name, const UIntType value, const Range < UIntType > & range) +{ + if (value < range.minimum) + throw Failure(STG(FMT("value '%d' out-of-range for option '%s' (too low)") % value % name)); + + if (value > range.maximum) + throw Failure(STG(FMT("value '%d' out-of-range for option '%s' (too high)") % value % name)); + + if (((value - range.minimum) % range.step) != 0) + throw Failure(STG(FMT("value '%d' out-of-range for option '%s' (outside allowed step)") % value % name)); +} + +void Config::Restriction::checkStringSet(const std::string & name, const StringType & value, const StringSet & allowed) +{ + if (allowed.empty()) + return; + + if (allowed.find(value) != allowed.end()) + return; + + std::string strlist; + + for (StringSet::const_iterator i = allowed.begin(); i != allowed.end(); i++) + { + strlist += " '"; + strlist += (*i); + strlist += "'"; + } + + throw Failure(STG(FMT("value '%s' not allowed for option '%s' (allowed values:%s)") + % value % name % strlist)); +} + +Config::Option::Option(std::string name, Config::Option::StringMemberType value, const StringType defvalue, StringSet & allowed, bool listme) +: _myname(name), _option(InnerStringType(name, value, defvalue, allowed)), _listme(listme), _values(NULL) +{}; + +Config::Option::Option(std::string name, Config::Option::StringMemberType value, const StringType defvalue, bool listme) +: _myname(name), _option(InnerStringType(name, value, defvalue)), _listme(listme), _values(NULL) +{}; + +Config::Option::Option(std::string name, Config::Option::BooleanMemberType value, const BooleanType defvalue, bool listme) +: _myname(name), _option(InnerBooleanType(name, value, defvalue)), _listme(listme), _values(NULL) +{}; + +Config::Option::Option(std::string name, Config::Option::SIntMemberType value, const SIntType defvalue, + SIntType min, SIntType max, SIntType step, bool listme) +: _myname(name), _option(InnerSIntType(name, value, defvalue, min, max, step)), _listme(listme), _values(NULL) +{}; + +Config::Option::Option(std::string name, Config::Option::UIntMemberType value, const UIntType defvalue, + UIntType min, UIntType max, UIntType step, bool listme) +: _myname(name), _option(InnerUIntType(name, value, defvalue, min, max, step)), _listme(listme), _values(NULL) +{}; + +Config::Option::Option(const Config::Option & o) +: _myname(o._myname), _option(o._option), _listme(o._listme), _values(o._values) +{}; + +Config::Option::Option(std::string name, Config::Option::FunctionMemberType value, const StringType defvalue, StringSet & allowed, bool listme) +: _myname(name), _option(InnerFunctionType(name, value, defvalue, allowed)), _listme(listme), _values(NULL) +{}; + +Config::Option::Option(std::string name, Config::Option::FunctionMemberType value, const StringType defvalue, bool listme) +: _myname(name), _option(InnerFunctionType(name, value, defvalue)), _listme(listme), _values(NULL) +{}; + +Config::Option::~Option(void) +{ + if (_values) + { + for (unsigned int i = 0; _values[i] != NULL; i++) + delete _values[i]; + + delete[] _values; + _values = NULL; + } +}; + +const char ** Config::Option::values(void) +{ + if (_values != NULL) + return _values; + + /**/ if (_option.check()) + { + _values = new const char*[3]; + + _values[0] = strdup("yes"); + _values[1] = strdup("no"); + _values[2] = NULL; + + } + else if (_option.check()) + { + const InnerSIntType & tmp = _option.get(); + + unsigned int count = ((tmp._range.maximum - tmp._range.minimum) / tmp._range.step) + 1; + unsigned int index = 0; + + _values = new const char*[count + 1]; + + for (SIntType i = tmp._range.minimum; i <= tmp._range.maximum; i += tmp._range.step, ++index) + _values[index] = strdup(STG(FMT("%d") % i).c_str()); + + _values[index] = NULL; + } + else if (_option.check()) + { + const InnerUIntType & tmp = _option.get(); + + unsigned int count = ((tmp._range.maximum - tmp._range.minimum) / tmp._range.step) + 1; + unsigned int index = 0; + + _values = new const char*[count + 1]; + + for (UIntType i = tmp._range.minimum; i <= tmp._range.maximum; i += tmp._range.step, ++index) + _values[index] = strdup(STG(FMT("%d") % i).c_str()); + + _values[index] = NULL; + } + else if (_option.check()) + { + const InnerStringType & tmp = _option.get(); + + _values = new const char*[ tmp._allowed.size() + 1 ]; + + unsigned int index = 0; + + for (StringSet::iterator i = tmp._allowed.begin(); i != tmp._allowed.end(); ++i, ++index) + _values[index] = strdup((*i).c_str()); + + _values[index] = NULL; + } + else if (_option.check()) + { + const InnerFunctionType & tmp = _option.get(); + + _values = new const char*[ tmp._allowed.size() + 1 ]; + + unsigned int index = 0; + + for (StringSet::iterator i = tmp._allowed.begin(); i != tmp._allowed.end(); ++i, ++index) + _values[index] = strdup((*i).c_str()); + + _values[index] = NULL; + } + else + { + throw Failure(STG(FMT("values() not implemented for type used in option '%s'") % _myname)); + } + + return _values; +}; + +/*********************************/ + +Config::Options::Options(void) +: _values(NULL) +{}; + +Config::Options::~Options() +{ + if (_values) + { + for (unsigned int i = 0; _values[i] != NULL; i++) + free((void*)(_values[i])); + + delete[] _values; + _values = NULL; + } +}; + +bool Config::Options::add(Config::Option option) +{ + std::pair ret = _map.insert(OptionPair(option.name(), option)); + + return ret.second; +} + +bool Config::Options::synonym(std::string equiv_opt, std::string main_opt) +{ + std::pair ret = _syn_map.insert(SynOptionPair(equiv_opt, main_opt)); + + return ret.second; +} + +Config::StringSet Config::Options::options(void) +{ + StringSet res; + + for (OptionMap::iterator i = _map.begin(); i != _map.end(); i++) + res.insert(i->first); + + return res; +} + +const char ** Config::Options::values(const char * name) +{ + OptionMap::iterator iter = find_option(name); + + if (iter == _map.end()) + throw Failure(STG(FMT("unknown option '%s'") % name)); + + return iter->second.values(); +} + +const char ** Config::Options::values(void) +{ + if (_values != NULL) + return _values; + + unsigned int count = 0; + + for (OptionMap::iterator i = _map.begin(); i != _map.end(); ++i) + if (i->second.listme()) + ++count; + + _values = new const char*[ count + 1 ]; + + unsigned int index = 0; + + for (OptionMap::iterator i = _map.begin(); i != _map.end(); ++i) + { + if (i->second.listme()) + { + _values[index] = strdup(i->first.c_str()); + ++index; + } + } + + _values[index] = NULL; + + return _values; +} + +Config::Options::OptionMap::iterator Config::Options::find_option(std::string name) +{ + SynOptionMap::iterator syn_iter = _syn_map.find(name); + + if (syn_iter != _syn_map.end()) + name = syn_iter->second; + + OptionMap::iterator iter = _map.find(name); + + return iter; +} diff --git a/src/mod/endpoints/mod_khomp/commons/base/config_options.hpp b/src/mod/endpoints/mod_khomp/commons/base/config_options.hpp new file mode 100644 index 0000000000..59e381f893 --- /dev/null +++ b/src/mod/endpoints/mod_khomp/commons/base/config_options.hpp @@ -0,0 +1,772 @@ +/* + KHOMP generic endpoint/channel library. + Copyright (C) 2007-2009 Khomp Ind. & Com. + + The contents of this file are subject to the Mozilla Public License Version 1.1 + (the "License"); you may not use this file except in compliance with the + License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS IS" basis, + WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for + the specific language governing rights and limitations under the License. + + Alternatively, the contents of this file may be used under the terms of the + "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which + case the provisions of "LGPL License" are applicable instead of those above. + + If you wish to allow use of your version of this file only under the terms of + the LGPL License and not to allow others to use your version of this file under + the MPL, indicate your decision by deleting the provisions above and replace them + with the notice and other provisions required by the LGPL License. If you do not + delete the provisions above, a recipient may use your version of this file under + either the MPL or the LGPL License. + + The LGPL header follows below: + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#ifndef _CONFIG_OPTIONS_HPP_ +#define _CONFIG_OPTIONS_HPP_ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace Config +{ + /* exceptions */ + + struct Failure: public std::runtime_error + { + Failure(const std::string & msg) : std::runtime_error(msg) {}; + }; + + struct EmptyValue: public std::runtime_error + { + EmptyValue(): std::runtime_error("accessed option still not loaded from configuration") {}; + }; + + /* types */ + + typedef int SIntType; + typedef unsigned int UIntType; + typedef bool BooleanType; + typedef std::string StringType; + + template < typename Type > + struct Value; + + template < typename Type > + struct InnerOptionBase; + + template < typename Type > + struct InnerOption; + + struct Option; + + /* here we go! */ + + template < typename Type > + struct Range + { + Range(const Type _minimum, const Type _maximum, const Type _step) + : minimum(_minimum), maximum(_maximum), step(_step) {}; + + const Type minimum, maximum, step; + }; + + typedef std::set < std::string > StringSet; + + template < typename Type > + struct Value: COUNTER_SUPER(Value < Type >) + { + friend class COUNTER_CLASS(Value < Type >); + friend class InnerOptionBase< Type >; + friend class InnerOption < Type >; + friend class Option; + + Value() + : _tmpval(0), _stored(0), _loaded(false), _inited(false) + {}; + + Value(const Value & o) + : COUNTER_REFER(o, Value < Type >), + _tmpval(o._tmpval), _stored(o._stored), + _loaded(o._loaded), _inited(o._inited) + {}; + + const Type & operator()(void) const + { + if (!_inited) + throw EmptyValue(); + + if (!_stored) + return *_tmpval; + + return *_stored; + }; + + const Type & get(void) const { return operator()(); }; + bool loaded(void) const { return _loaded; }; + + void store(const Type val) + { + if (_tmpval) + { + delete _tmpval; + _tmpval = 0; + } + + _tmpval = new Type(val); + + _loaded = true; + _inited = true; + } + + protected: + void unreference(void) + { + _inited = false; + _loaded = false; + + if (_tmpval) + { + delete _tmpval; + _tmpval = 0; + } + + if (_stored) + { + delete _stored; + _stored = 0; + } + }; + + protected: + void commit(Type def) + { + if (_tmpval) + { + { + delete _stored; + _stored = 0; + } + + _stored = _tmpval; + _tmpval = 0; + } + else + { + if (!_stored) + _stored = new Type(def); + } + + _loaded = true; + _inited = true; + }; + + void reset(void) + { + _loaded = false; + } + + protected: + const Type * _tmpval; + const Type * _stored; + bool _loaded; + bool _inited; + }; + + struct FunctionValue + { + friend class InnerFunctionType; + friend class Option; + + FunctionValue() + : _loaded(false), _inited(false) {}; + + virtual ~FunctionValue() {}; + + public: + virtual void operator()(const StringType & val) + { + throw Failure("undefined operator() for value"); + } + + const StringType & get(void) const + { + if (!_inited) + throw EmptyValue(); + + return _stored; + }; + + bool loaded(void) const { return _loaded; }; + + protected: + void commit(const StringType def) + { + if (_tmpval.empty()) + { + _stored = def; + } + else + { + _stored = _tmpval; + _tmpval.clear(); + } + + operator()(_stored); + + _loaded = true; + _inited = true; + }; + + void store(const StringType val) + { + _tmpval = val; + _loaded = true; + _inited = true; + } + + void reset(void) + { + _loaded = false; + } + + private: + StringType _tmpval; + StringType _stored; + bool _loaded; + bool _inited; + }; + + /* NOTE: we use a non-templated classe to place this functions inside the .cpp */ + struct Restriction + { + static void checkRange(const std::string & name, const SIntType value, const Range < SIntType > & range); + static void checkRange(const std::string & name, const UIntType value, const Range < UIntType > & range); + static void checkStringSet(const std::string & name, const StringType & value, const StringSet & allowed); + }; + + template < typename Type > + struct InnerOptionBase + { + typedef Variable < Value < Type > > MemberValue; + + InnerOptionBase(const std::string name, MemberValue option, const Type defvalue) + : _name(name), _option(option), _default(defvalue) {}; + + template < typename Object > + void reset(Object * const obj) const + { + _option(obj).reset(); + } + + template < typename Object > + const Type & get(const Object * const obj) const + { + return _option(obj).get(); + } + + template < typename Object > + bool loaded(const Object * const obj) const + { + return _option(obj).loaded(); + } + + protected: + const std::string _name; + MemberValue _option; + const Type _default; + }; + + template < > + struct InnerOption < SIntType >: public InnerOptionBase < SIntType > + { + typedef InnerOptionBase < SIntType > Super; + typedef Super::MemberValue MemberValue; + + InnerOption(const std::string name, MemberValue option, const SIntType defval, + const SIntType min, const SIntType max, const SIntType step) + : Super(name, option, defval), _range(min, max, step) {}; + + template < typename Object > + void commit(Object * const obj) const + { + Restriction::checkRange(_name, _default, _range); + _option(obj).commit(_default); + }; + + template < typename Object > + void store(Object * const obj, const SIntType stored) const + { + Restriction::checkRange(_name, _default, _range); + _option(obj).store(stored); + } + + using Super::reset; + using Super::get; + + const Range< SIntType > _range; + }; + + template < > + struct InnerOption < UIntType >: public InnerOptionBase < UIntType > + { + typedef InnerOptionBase < UIntType > Super; + typedef Super::MemberValue MemberValue; + + InnerOption(const std::string name, MemberValue option, const UIntType defval, + const UIntType min, const UIntType max, const UIntType step) + : Super(name, option, defval), _range(min, max, step) {}; + + template < typename Object > + void commit(Object * const obj) const + { + Restriction::checkRange(_name, _default, _range); + _option(obj).commit(_default); + }; + + template < typename Object > + void store(Object * const obj, const UIntType stored) const + { + Restriction::checkRange(_name, _default, _range); + _option(obj).store(stored); + } + + using Super::reset; + using Super::get; + + const Range< UIntType > _range; + }; + + template < > + struct InnerOption < BooleanType >: public InnerOptionBase < BooleanType > + { + typedef InnerOptionBase < BooleanType > Super; + typedef Super::MemberValue MemberValue; + + InnerOption(std::string name, MemberValue option, BooleanType defval) + : Super(name, option, defval) {}; + + template < typename Object > + void commit(Object * obj) const + { + _option(obj).commit(_default); + }; + + template < typename Object > + void store(Object * obj, BooleanType stored) const + { + _option(obj).store(stored); + } + + using Super::reset; + using Super::get; + }; + + template < > + struct InnerOption < StringType >: public InnerOptionBase < StringType > + { + typedef InnerOptionBase < StringType > Super; + typedef Super::MemberValue MemberValue; + + InnerOption(const std::string name, MemberValue option, const StringType defval, const StringSet & allowed) + : Super(name, option, defval), _allowed(allowed) {}; + + InnerOption(const std::string name, MemberValue option, const StringType defval) + : Super(name, option, defval) {}; + + template < typename Object > + void commit(Object * const obj) const + { + Restriction::checkStringSet(_name, _default, _allowed); + _option(obj).commit(_default); + }; + + template < typename Object > + void store(Object * const obj, const StringType stored) const + { + Restriction::checkStringSet(_name, _default, _allowed); + _option(obj).store(stored); + } + + using Super::reset; + using Super::get; + + const StringSet _allowed; + }; + + struct InnerFunctionType + { + typedef Variable < FunctionValue > MemberValue; + + InnerFunctionType(const std::string name, MemberValue option, const StringType defval, const StringSet & allowed) + : _name(name), _option(option), _default(defval), _allowed(allowed) {}; + + InnerFunctionType(const std::string name, MemberValue option, const StringType defval) + : _name(name), _option(option), _default(defval) {}; + + template < typename Object > + const StringType & get(const Object * const obj) const + { + return _option(obj).get(); + } + + template < typename Object > + bool loaded(const Object * const obj) const + { + return _option(obj).loaded(); + } + + template < typename Object > + void reset(Object * const obj) const + { + _option(obj).reset(); + } + + template < typename Object > + void commit(Object * const obj) const + { + Restriction::checkStringSet(_name, _default, _allowed); + _option(obj).commit(_default); + }; + + template < typename Object > + void store(Object * const obj, const StringType stored) const + { + Restriction::checkStringSet(_name, _default, _allowed); + _option(obj).store(stored); + } + + protected: + const std::string _name; + MemberValue _option; + const StringType _default; + + public: + const StringSet _allowed; + }; + + struct Option + { + typedef InnerOption < SIntType > InnerSIntType; + typedef InnerOption < UIntType > InnerUIntType; + typedef InnerOption < BooleanType > InnerBooleanType; + typedef InnerOption < StringType > InnerStringType; + + typedef Variable < Value < SIntType > > SIntMemberType; + typedef Variable < Value < UIntType > > UIntMemberType; + typedef Variable < Value < BooleanType > > BooleanMemberType; + typedef Variable < Value < StringType > > StringMemberType; + + typedef Variable < FunctionValue > FunctionMemberType; + + typedef Tagged::Union < InnerStringType, + Tagged::Union < InnerBooleanType, + Tagged::Union < InnerSIntType , + Tagged::Union < InnerUIntType, + Tagged::Union < InnerFunctionType > > > > > + InnerType; + + explicit Option(std::string, StringMemberType, const StringType, StringSet & allowed, bool listme = true); + explicit Option(std::string, StringMemberType, const StringType = "", bool listme = true); + explicit Option(std::string, SIntMemberType, const SIntType = 0, SIntType min = INT_MIN, SIntType max = INT_MAX, SIntType step = 1, bool listme = true); + explicit Option(std::string, UIntMemberType, const UIntType = 0, UIntType min = 0, UIntType max = UINT_MAX, UIntType step = 1, bool listme = true); + explicit Option(std::string, BooleanMemberType, const BooleanType = false, bool listme = true); + + explicit Option(std::string, FunctionMemberType, const StringType, StringSet & allowed, bool listme = true); + explicit Option(std::string, FunctionMemberType, const StringType = "", bool listme = true); + + Option(const Option & o); + + ~Option(void); + + template < typename Object > + void set(Object * object, std::string value) + { + try + { + /**/ if (_option.check()) _option.get().store(object, value); + else if (_option.check()) _option.get().store(object, value); + else if (_option.check()) _option.get().store(object, Strings::toboolean(value)); + else if (_option.check()) _option.get().store(object, Strings::tolong(value)); + else if (_option.check()) _option.get().store(object, Strings::toulong(value)); + else + { + throw Failure(STG(FMT("set() not implemented for type used in option '%s'") % _myname)); + } + } + catch (Strings::invalid_value & e) + { + throw Failure(STG(FMT("got invalid value '%s' for option '%s'") % value % _myname)); + } + catch (EmptyVariable & e) + { + throw Failure(STG(FMT("uninitialized variable while setting value '%s' for option '%s'") % value % _myname)); + } + } + + template < typename Object > + std::string get(const Object * const object) const + { + try + { + /**/ if (_option.check()) return _option.get().get(object); + else if (_option.check()) return _option.get().get(object); + else if (_option.check()) return (_option.get().get(object) ? "yes" : "no"); + else if (_option.check()) return STG(FMT("%d") % _option.get().get(object)); + else if (_option.check()) return STG(FMT("%u") % _option.get().get(object)); + else + { + throw Failure(STG(FMT("get() not implemented for type used in option '%s'") % _myname)); + } + } + catch (EmptyVariable & e) + { + throw Failure(STG(FMT("uninitialized variable while getting value for option '%s'") % _myname)); + } + } + + template < typename Object > + bool loaded(const Object * const object) const + { + try + { + /**/ if (_option.check()) return _option.get().loaded(object); + else if (_option.check()) return _option.get().loaded(object); + else if (_option.check()) return _option.get().loaded(object); + else if (_option.check()) return _option.get().loaded(object); + else if (_option.check()) return _option.get().loaded(object); + else + { + throw Failure(STG(FMT("loaded() not implemented for type used in option '%s'") % _myname)); + } + } + catch (EmptyVariable & e) + { + throw Failure(STG(FMT("uninitialized variable while checking load status for option '%s'") % _myname)); + } + } + + template < typename Object > + void reset(Object * const object) + { + try + { + /**/ if (_option.check()) _option.get().reset(object); + else if (_option.check()) _option.get().reset(object); + else if (_option.check()) _option.get().reset(object); + else if (_option.check()) _option.get().reset(object); + else if (_option.check()) _option.get().reset(object); + else + { + throw Failure(STG(FMT("reset() not implemented for type used in option '%s'") % _myname)); + } + } + catch (EmptyVariable & e) + { + throw Failure(STG(FMT("uninitialized variable while reseting status for option '%s'") % _myname)); + } + } + + template < typename Object > + void commit(Object * const object) + { + try + { + /**/ if (_option.check()) _option.get().commit(object); + else if (_option.check()) _option.get().commit(object); + else if (_option.check()) _option.get().commit(object); + else if (_option.check()) _option.get().commit(object); + else if (_option.check()) _option.get().commit(object); + else + { + throw Failure(STG(FMT("commit() not implemented for type used in option '%s'") % _myname)); + } + } + catch (EmptyVariable & e) + { + throw Failure(STG(FMT("uninitialized variable while commiting option '%s'") % _myname)); + } + } + + const std::string & name(void) const { return _myname; } + bool listme(void) const { return _listme; }; + + const char ** values(void); + + template < typename Object > + void copyFrom(const Object * const srcobj, Object * const dstobj, bool force = false) + { + if (loaded(dstobj) && !force) + return; + + if (loaded(srcobj)) + set(dstobj, get(srcobj)); + else + reset(dstobj); + } + + protected: + const std::string _myname; + InnerType _option; + const bool _listme; + const char ** _values; + }; + + struct Options + { + typedef std::vector < std::string > Messages; + + Options(); + ~Options(); + + typedef std::set < std::string > StringSet; + + typedef std::map < std::string, Option > OptionMap; + typedef std::pair < std::string, Option > OptionPair; + + typedef std::map < std::string, std::string > SynOptionMap; + typedef std::pair < std::string, std::string > SynOptionPair; + + bool add(Option option); + + /* only valid in "process" (for backwards compatibility config files) */ + bool synonym(std::string, std::string); + + template < typename Type > + void set(const std::string & name, Type value) + { + OptionMap::iterator iter = find_option(name); + + if (iter == _map.end()) + throw Failure(STG(FMT("unknown option: %s") % name)); + + iter->second.set(value); + } + + template < typename Object > + std::string get(const Object * const object, const std::string & name) + { + OptionMap::iterator iter = find_option(name); + + if (iter == _map.end()) + throw Failure(STG(FMT("unknown option: %s") % name)); + + return iter->second.get(object); + } + + template < typename Object > + void process(Object * const object, const char * name, const char * value) + { + OptionMap::iterator iter = find_option(name); + + if (iter == _map.end()) + throw Failure(STG(FMT("unknown option '%s'") % name)); + + iter->second.set(object, value); + } + + template < typename Object > + Messages commit(Object * const object) + { + Messages msgs; + + for (OptionMap::iterator i = _map.begin(); i != _map.end(); ++i) + { + try + { + i->second.commit(object); + } + catch (Failure & e) + { + msgs.push_back(e.what()); + } + } + + return msgs; + } + + template < typename Object > + void reset(Object * object) + { + for (OptionMap::iterator i = _map.begin(); i != _map.end(); ++i) + i->second.reset(object); + } + + template < typename Object > + bool loaded(Object * object, std::string name) + { + OptionMap::iterator iter = find_option(name); + + if (iter == _map.end()) + return false; + + return iter->second.loaded(object); + } + + bool exists(const std::string & name) + { + OptionMap::iterator iter = find_option(name); + + return (iter != _map.end()); + } + + StringSet options(void); + + const char ** values(const char *); /* option value */ + const char ** values(void); /* values from options */ + + template < typename Object > + void copyFrom(const std::string & name, const Object * const src_obj, Object * const dst_obj, bool force = false) + { + OptionMap::iterator iter = find_option(name); + + if (iter == _map.end()) + throw Failure(STG(FMT("unknown option '%s'") % name)); + + iter->second.copyFrom(src_obj, dst_obj, force); + } + + template < typename Object > + void copyFrom(Object * src_obj, Object * dst_obj, bool force = false) + { + for (OptionMap::iterator iter = _map.begin(); iter != _map.end(); ++iter) + iter->second.copyFrom(src_obj, dst_obj, force); + } + + protected: + OptionMap::iterator find_option(std::string); + + protected: + OptionMap _map; + SynOptionMap _syn_map; + + const char ** _values; + }; +}; + +#endif /* _CONFIG_OPTIONS_HPP_ */ diff --git a/src/mod/endpoints/mod_khomp/commons/base/configurator/configfile.cpp b/src/mod/endpoints/mod_khomp/commons/base/configurator/configfile.cpp new file mode 100644 index 0000000000..8a46587a59 --- /dev/null +++ b/src/mod/endpoints/mod_khomp/commons/base/configurator/configfile.cpp @@ -0,0 +1,241 @@ +/* + KHOMP generic endpoint/channel library. + Copyright (C) 2007-2009 Khomp Ind. & Com. + + The contents of this file are subject to the Mozilla Public License Version 1.1 + (the "License"); you may not use this file except in compliance with the + License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS IS" basis, + WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for + the specific language governing rights and limitations under the License. + + Alternatively, the contents of this file may be used under the terms of the + "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which + case the provisions of "LGPL License" are applicable instead of those above. + + If you wish to allow use of your version of this file only under the terms of + the LGPL License and not to allow others to use your version of this file under + the MPL, indicate your decision by deleting the provisions above and replace them + with the notice and other provisions required by the LGPL License. If you do not + delete the provisions above, a recipient may use your version of this file under + either the MPL or the LGPL License. + + The LGPL header follows below: + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +*/ +#include + +#include + +#if _MSC_VER >= 1400 +#undef close +#endif + +void Configfile::ignore(const std::string & str) +{ + _ignores.insert(str); +}; + +bool Configfile::select(Section **ptr, const std::string & str) +{ + /* default section == this! */ + *ptr = this; + + /* always success by default */ + return true; +}; + +bool Configfile::adjust(Section * section, const std::string & opt, const std::string & val) +{ + return section->load(opt, val); +}; + +bool Configfile::deserialize(std::ifstream & fd) +{ + Section * section = NULL; + + /* default selection! */ + if (!select(§ion)) + { + _errors.push_back("default selection has failed!"); + return false; + } + + size_t count = 0; + + while (fd.good()) + { + std::string str; + + /* read one line! */ + std::getline(fd, str); + + size_t lst = str.size() - 1; + + if (str.size() >= 1 && str[lst] == '\r') //cuida das quebras de linha do tipo \r\n + { + str.erase(lst,1); + --lst; + } + + /* empty line! */ + if (str.size() == 0) + continue; + + /* comment! */ + if (str[0] == '#') + continue; + + ++count; + + if (str[0] == '[' && str[lst] == ']') + { + str.erase(0,1); --lst; + str.erase(lst,1); --lst; + + if (!select(§ion, str)) + { + _errors.push_back(STG(FMT("erroneous section '%s'") % str)); + + /* ignore this section */ + section = NULL; + continue; + } + } + else + { + std::string::size_type pos = str.find('='); + + if (pos == std::string::npos) + { + _errors.push_back(STG(FMT("erroneous separator '%s'") % str)); + continue; + }; + + if (section == NULL) + { + _errors.push_back(STG(FMT("no section for option '%s'") % str)); + continue; + } + + std::string opt(str.substr(0,pos)); + std::string val(str.substr(pos+1)); + + if (_ignores.find(opt) != _ignores.end()) + continue; + + if (val == "@") val = ""; + + if (adjust(section, opt, val)) + continue; + + _errors.push_back(STG(FMT("option '%s' does " + "not exist or '%s' is not a valid value (at section '%s')") + % opt % val % section->name())); + } + } + + // retorna 'true' se arquivo tinha alguma coisa valida. + return (count != 0); +} + +bool Configfile::obtain() +{ + std::ifstream fd(_filename.c_str()); + + if (!fd.is_open()) + { + _errors.push_back(STG(FMT("unable to open file '%s': %s") + % _filename % strerror(errno))); + return false; + }; + + if (!deserialize(fd)) + { + fd.close(); + return false; + } + + fd.close(); + return true; +}; + +void Configfile::recurse(std::ofstream & fd, Section * section) +{ + typedef Section::SectionMap::const_iterator SectionIter; + typedef Section::OptionMap::const_iterator OptionIter; + + for (OptionIter i = section->option_begin(); i != section->option_end(); i++) + { + std::string res; + + if ((*i).second.store(res)) + { + if (res == "") res = "@"; + fd << (*i).first << "=" << res << std::endl; + } + } + + if (!section->recursive()) + return; + + for (SectionIter j = section->section_begin(); j != section->section_end(); j++) + recurse(fd, (*j).second); +} + +bool Configfile::serialize(std::ofstream & fd) +{ + recurse(fd, this); + return true; +} + +bool Configfile::provide() +{ + std::string tmp(_filename); + tmp += ".new"; + + std::ofstream fd(tmp.c_str()); + + if (!fd.good()) + { + _errors.push_back(STG(FMT("unable to open file '%s': %s") + % tmp % strerror(errno))); + return false; + } + + if (!serialize(fd)) + { + fd.close(); + return false; + } + + fd.close(); + + if (rename(tmp.c_str(), _filename.c_str()) != 0) + { + _errors.push_back(STG(FMT("unable to replace config file '%s': %s") + % _filename % strerror(errno))); + return false; + } + + return true; +} + +#if _MSC_VER >= 1400 +#define close _close +#endif diff --git a/src/mod/endpoints/mod_khomp/commons/configurator/configfile.hpp b/src/mod/endpoints/mod_khomp/commons/base/configurator/configfile.hpp similarity index 65% rename from src/mod/endpoints/mod_khomp/commons/configurator/configfile.hpp rename to src/mod/endpoints/mod_khomp/commons/base/configurator/configfile.hpp index 61f42469af..e725c09964 100644 --- a/src/mod/endpoints/mod_khomp/commons/configurator/configfile.hpp +++ b/src/mod/endpoints/mod_khomp/commons/base/configurator/configfile.hpp @@ -1,7 +1,7 @@ -/* +/* KHOMP generic endpoint/channel library. - Copyright (C) 2007-2009 Khomp Ind. & Com. - + Copyright (C) 2007-2009 Khomp Ind. & Com. + The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ @@ -23,20 +23,20 @@ The LGPL header follows below: - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ #include @@ -53,38 +53,38 @@ struct Configfile: public Section { - typedef std::list < std::string > ErrorVector; - typedef std::set < std::string > NameSet; + typedef std::list < std::string > ErrorVector; + typedef std::set < std::string > NameSet; - Configfile(std::string name, std::string desc) - : Section(name, desc), _good(false) {}; + Configfile(const std::string & name, const std::string & desc) + : Section(name, desc), _good(false) {}; - virtual ~Configfile() {}; + virtual ~Configfile() {}; - bool good() { return _good; }; - std::string & filename() { return _filename; }; + bool good() const { return _good; }; + const std::string & filename() const { return _filename; }; - ErrorVector & errors() { return _errors; }; + const ErrorVector & errors() const { return _errors; }; - void ignore(std::string); + void ignore(const std::string &); - virtual bool obtain(); - virtual bool provide(); + virtual bool obtain(); + virtual bool provide(); protected: - virtual bool select(Section **, std::string str = ""); - virtual bool adjust(Section *, std::string & opt, std::string & val); + virtual bool select(Section **, const std::string & str = ""); + virtual bool adjust(Section *, const std::string & opt, const std::string & val); - virtual bool deserialize(std::ifstream &); - virtual bool serialize(std::ofstream &); + virtual bool deserialize(std::ifstream &); + virtual bool serialize(std::ofstream &); - void recurse(std::ofstream &, Section *); + void recurse(std::ofstream &, Section *); protected: - bool _good; - ErrorVector _errors; - NameSet _ignores; - std::string _filename; + bool _good; + ErrorVector _errors; + NameSet _ignores; + std::string _filename; }; #endif /* _CONFIG_CONFIGFILE_HPP_ */ diff --git a/src/mod/endpoints/mod_khomp/commons/base/configurator/option.cpp b/src/mod/endpoints/mod_khomp/commons/base/configurator/option.cpp new file mode 100644 index 0000000000..6de9212bf3 --- /dev/null +++ b/src/mod/endpoints/mod_khomp/commons/base/configurator/option.cpp @@ -0,0 +1,186 @@ +/* + KHOMP generic endpoint/channel library. + Copyright (C) 2007-2009 Khomp Ind. & Com. + + The contents of this file are subject to the Mozilla Public License Version 1.1 + (the "License"); you may not use this file except in compliance with the + License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS IS" basis, + WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for + the specific language governing rights and limitations under the License. + + Alternatively, the contents of this file may be used under the terms of the + "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which + case the provisions of "LGPL License" are applicable instead of those above. + + If you wish to allow use of your version of this file only under the terms of + the LGPL License and not to allow others to use your version of this file under + the MPL, indicate your decision by deleting the provisions above and replace them + with the notice and other provisions required by the LGPL License. If you do not + delete the provisions above, a recipient may use your version of this file under + either the MPL or the LGPL License. + + The LGPL header follows below: + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#include + +bool Option::equals(const std::string & value) const +{ + switch (_restriction.numeral()) + { + case Restriction::N_UNIQUE: + { + Restriction::Value my_value; + + if (!_restriction.get(Restriction::F_USER, my_value)) + return false; + + return (my_value == value); + } + case Restriction::N_MULTIPLE: + { + Restriction::Vector my_values; + + if (!_restriction.get(Restriction::F_USER, my_values)) + return false; + + for (Restriction::Vector::iterator i = my_values.begin(); i != my_values.end(); i++) + { + if ((*i) == value) + return true; + } + + return false; + } + } + + return false; +} + +bool Option::load(const std::string & value) +{ + bool ret = _restriction.set( (const Restriction::Format)Restriction::F_FILE, value); + + if (ret) _modified = false; + + return ret; +} + +bool Option::change(const std::string & value) +{ + bool ret = _restriction.set(Restriction::F_FILE, value); + + if (ret) _modified = true; + + return ret; +} + +bool Option::store(std::string & value) const +{ + switch (_restriction.numeral()) + { + case Restriction::N_UNIQUE: + return _restriction.get(Restriction::F_FILE, value); + + case Restriction::N_MULTIPLE: + { + Restriction::Vector values; + + if (!_restriction.get(Restriction::F_FILE, values)) + return false; + + Strings::Merger strs; + + for (Restriction::Vector::iterator i = values.begin(); i != values.end(); i++) + strs.add(*i); + + value = strs.merge(","); + + return true; + } + + default: + return false; + } +} + +/* +Option::Flags Option::set(const char * value) +{ + std::string str_value(value); + return set(str_value); +} +*/ + +Option::Flags Option::set(const Restriction::Value & value) +{ + Restriction::Value last_value, curr_value; + Flags flags; + + bool ret1 = _restriction.get(Restriction::F_USER, last_value); + + if (!_restriction.set(Restriction::F_USER, value)) + return flags; + + flags[F_ADJUSTED] = true; + + bool ret2 = _restriction.get(Restriction::F_USER, curr_value); + + if (!ret1 || (ret2 && (last_value != curr_value))) + { + flags[F_MODIFIED] = true; + _modified = true; + } + + return flags; +} + +Option::Flags Option::set(const Restriction::Vector & values) +{ + Restriction::Vector last_values, curr_values; + Flags flags; + + bool ret1 = _restriction.get(Restriction::F_USER, last_values); + + if (!_restriction.set(Restriction::F_USER, values)) + return flags; + + flags[F_ADJUSTED] = true; + + bool ret2 = _restriction.get(Restriction::F_USER, curr_values); + + if (!ret1 || (ret2 && (last_values != curr_values))) + { + flags[F_MODIFIED] = true; + _modified = true; + } + + return flags; +} + +bool Option::get(Restriction::Value & value) const +{ + return _restriction.get(Restriction::F_USER, value); +} + +bool Option::get(Restriction::Vector & values) const +{ + return _restriction.get(Restriction::F_USER, values); +} diff --git a/src/mod/endpoints/mod_khomp/commons/configurator/option.hpp b/src/mod/endpoints/mod_khomp/commons/base/configurator/option.hpp similarity index 52% rename from src/mod/endpoints/mod_khomp/commons/configurator/option.hpp rename to src/mod/endpoints/mod_khomp/commons/base/configurator/option.hpp index 8aa103a0cc..e46ab75902 100644 --- a/src/mod/endpoints/mod_khomp/commons/configurator/option.hpp +++ b/src/mod/endpoints/mod_khomp/commons/base/configurator/option.hpp @@ -1,7 +1,7 @@ -/* +/* KHOMP generic endpoint/channel library. - Copyright (C) 2007-2009 Khomp Ind. & Com. - + Copyright (C) 2007-2009 Khomp Ind. & Com. + The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ @@ -23,20 +23,20 @@ The LGPL header follows below: - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ #include @@ -45,6 +45,7 @@ #include #include +#include #include #include @@ -56,67 +57,72 @@ struct Option { enum FlagTypes { - F_MODIFIED = 0x0, /* if option was modified */ - F_ADJUSTED = 0x1, /* if option was correctly formated */ + F_MODIFIED = 0x0, /* if option was modified */ + F_ADJUSTED = 0x1, /* if option was correctly formated */ }; - struct Flags: public std::vector - { - Flags(): std::vector(2) {}; - }; + struct Flags: public std::vector + { + Flags(): std::vector(2) {}; + }; - typedef Restriction::Value Value; - typedef Restriction::Vector Vector; + typedef Restriction::Value Value; + typedef Restriction::Vector Vector; /* exception */ - struct InvalidDefaultValue + struct InvalidDefaultValue: public std::runtime_error { - InvalidDefaultValue(std::string name, std::string value) - : _name(name), _value(value) {}; + InvalidDefaultValue(const std::string & name, const std::string & value) + : std::runtime_error(STG(FMT("invalid default value '%s' for option '%s'") % value % name)), + _name(name), _value(value) + {}; - std::string & name() { return _name; }; - std::string & value() { return _value; }; + ~InvalidDefaultValue() throw () + {}; + + const std::string & name() const { return _name; }; + const std::string & value() const { return _value; }; protected: - std::string _name; - std::string _value; + const std::string _name; + const std::string _value; }; - Option(std::string name, std::string desc, std::string defvalue, Restriction restriction) - : _name(name), _desc(desc), _restriction(restriction), _modified(true) - { - std::string value(defvalue); + Option(const std::string & name, const std::string & desc, const std::string & defvalue, const Restriction & restriction) + : _name(name), _description(desc), _restriction(restriction), _modified(true) + { +// std::string value(defvalue); - if (!(set(value)[F_ADJUSTED])) + if (!(set(defvalue)[F_ADJUSTED])) throw InvalidDefaultValue(name, defvalue); - } + } - const std::string & name() { return _name; }; - const std::string & description() { return _desc; }; + const std::string & name() const { return _name; }; + const std::string & description() const { return _description; }; - Restriction & restriction() { return _restriction; }; - bool modified() { return _modified; }; + const Restriction & restriction() const { return _restriction; }; + bool modified() const { return _modified; }; public: - bool load(std::string &); - bool change(std::string &); - bool store(std::string &); + bool load(const std::string &); + bool change(const std::string &); + bool store(std::string &) const; - Flags set(const char *); - Flags set(Value &); - Flags set(Vector &); +// Flags set(const char *); + Flags set(const Value &); + Flags set(const Vector &); - bool get(Value &); - bool get(Vector &); + bool get(Value &) const; + bool get(Vector &) const; - bool equals(std::string &); + bool equals(const std::string &) const; protected: - std::string _name; - std::string _desc; + const std::string _name; + const std::string _description; - Restriction _restriction; - bool _modified; + Restriction _restriction; + bool _modified; }; #endif /* _CONFIG_OPTION_HPP_ */ diff --git a/src/mod/endpoints/mod_khomp/commons/base/configurator/restriction.cpp b/src/mod/endpoints/mod_khomp/commons/base/configurator/restriction.cpp new file mode 100644 index 0000000000..52be1ea881 --- /dev/null +++ b/src/mod/endpoints/mod_khomp/commons/base/configurator/restriction.cpp @@ -0,0 +1,358 @@ +/* + KHOMP generic endpoint/channel library. + Copyright (C) 2007-2009 Khomp Ind. & Com. + + The contents of this file are subject to the Mozilla Public License Version 1.1 + (the "License"); you may not use this file except in compliance with the + License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS IS" basis, + WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for + the specific language governing rights and limitations under the License. + + Alternatively, the contents of this file may be used under the terms of the + "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which + case the provisions of "LGPL License" are applicable instead of those above. + + If you wish to allow use of your version of this file only under the terms of + the LGPL License and not to allow others to use your version of this file under + the MPL, indicate your decision by deleting the provisions above and replace them + with the notice and other provisions required by the LGPL License. If you do not + delete the provisions above, a recipient may use your version of this file under + either the MPL or the LGPL License. + + The LGPL header follows below: + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#include +#include + +#include +#include + +#include + +/* internal helper! */ +bool Restriction::equalNumber(const double a, const double b) +{ + char tmp1[64]; + char tmp2[64]; + + snprintf(tmp1, sizeof(tmp1), "%.3f", a); + snprintf(tmp2, sizeof(tmp2), "%.3f", b); + + if (strncmp(tmp1, tmp2, sizeof(tmp1))) + return false; + + return true; +} + +/* process value to our internal representation */ + +bool Restriction::process(Restriction::Format fmt, + const Restriction::Value & value, Restriction::Value & final) const +{ + switch (_bounds) + { + case B_RANGE: + { + if (_kind != K_NUMBER) + return false; + + std::string tmpvalue; + + Restriction::Value::const_iterator itr = value.begin(); + Restriction::Value::const_iterator end = value.end(); + + tmpvalue.reserve(value.size()); + + // f*cking dot/comma notation! + for (; itr != end; ++itr) + tmpvalue += ((*itr) != ',' ? (*itr) : '.'); + + try + { + double newvalue = Strings::todouble(tmpvalue); + + if (newvalue < _init && newvalue > _fini) + return false; + + double res = (newvalue - _init) / _step; + + if (!Restriction::equalNumber(res, rint(res))) + return false; + + final = value; + return true; + } + catch (...) + { + return false; + } + } + + case B_LIST: + for (List::const_iterator i = _list.begin(); i != _list.end(); i++) + { + const Value & tmp = (*i); + + if (tmp == value) + { + final = value; + return true; + } + } + return false; + + case B_MAPS: + switch (fmt) + { + case F_USER: + { + Map::const_iterator i = _map_from_usr.find(value); + + if (i == _map_from_usr.end()) + return false; + + const Value & tmp = (*i).second; + + final = tmp; + return true; + } + + case F_FILE: + { + Map::const_iterator i = _map_from_cfg.find(value); + + if (i == _map_from_cfg.end()) + return false; + + final = value; + return true; + } + + default: + break; + } + return false; + + case B_FREE: + final = value; + return true; + + default: + break; + } + + return false; +} + +/* unprocess the value (outputs the external representation) */ + +bool Restriction::unprocess(Restriction::Format fmt, + const Restriction::Value & value, Restriction::Value & final) const +{ + switch (_bounds) + { + case B_MAPS: + + switch (fmt) + { + case F_USER: + { + Map::const_iterator i = _map_from_cfg.find(value); + + if (i == _map_from_cfg.end()) + return false; + + final = (*i).second; + return true; + } + default: + break; + } + + default: + final = value; + return true; + } +} + +/***************************** *****************************/ + +bool Restriction::get(Restriction::Format fmt, Restriction::Value & value) const +{ + if (_numeral != N_UNIQUE) + return false; + + if (!unprocess(fmt, _value._unique, value)) + return false; + + return true; +} + +bool Restriction::get(Restriction::Format fmt, Restriction::Vector & values) const +{ + if (_numeral != N_MULTIPLE) + return false; + + const List & my_values = _value._multiple; + + for (List::const_iterator i = my_values.begin(); i != my_values.end(); i++) + { + const Value & value = (*i); + + Value final; + + if (!unprocess(fmt, value, final)) + return false; + + values.push_back(final); + }; + + return true; +} + +/***************************** *****************************/ + +bool Restriction::set(Restriction::Format fmt, const Restriction::Value & value) +{ + switch (_numeral) + { + case N_UNIQUE: + { + Value final; + + if (!constThis().process(fmt, value, final)) + return false; + + _value._unique = final; + return true; + } + + case N_MULTIPLE: + { + if (value == "@" || value == "#" || value == "") + { + _value._multiple.clear(); + return true; + } + + Strings::vector_type values; + Strings::tokenize(value, values, ","); + + return set(fmt, values); + } + + default: + return false; + } +} + +bool Restriction::set(Restriction::Format fmt, const Restriction::Vector & values) +{ + if (_numeral != N_MULTIPLE) + return false; + + if (values.empty()) + { + _value._multiple.clear(); + } + else + { + /* list needed to store temporary values */ + List finals; + + for (Vector::const_iterator i = values.begin(); i != values.end(); i++) + { + const Value & value = (*i); + + Value final; + + if (!constThis().process(fmt, value, final)) + return false; + + finals.push_back(final); + } + + List & lst = _value._multiple; + + /* need to clear values set before */ + lst.clear(); + + for (List::iterator i = finals.begin(); i != finals.end(); i++) + { + Value value = (*i); + lst.push_back(value); + } + }; + + return true; +} + +/***************************** *****************************/ + +void Restriction::allowed(Restriction::Vector & vals) const +{ + switch (_bounds) + { + case B_FREE: + return; + + case B_LIST: + for (List::const_iterator i = _list.begin(); i != _list.end(); i++) + vals.push_back(*i); + break; + + case B_MAPS: + for (Map::const_iterator i = _map_from_usr.begin(); i != _map_from_usr.end(); i++) + vals.push_back(i->first); + break; + + case B_RANGE: + { + if (_kind != K_NUMBER) + return; + + // is there any fraction? + bool has_fraction = + (!Restriction::equalNumber(_init, rint(_init))) || + (!Restriction::equalNumber(_fini, rint(_fini))) || + (!Restriction::equalNumber(_step, rint(_step))); + + const char * format = (has_fraction ? "%.2f" : "%02.0f"); + + for (double i = _init; i <= _fini; i += _step) + { + char tmp[32]; + snprintf(tmp, sizeof(tmp), format, i); + vals.push_back(std::string(tmp)); + } + break; + } + + default: + break; + } +} + +void Restriction::init_class() +{ + _value._unique.clear(); + _value._multiple.clear(); +} diff --git a/src/mod/endpoints/mod_khomp/commons/base/configurator/restriction.hpp b/src/mod/endpoints/mod_khomp/commons/base/configurator/restriction.hpp new file mode 100644 index 0000000000..576560dbd4 --- /dev/null +++ b/src/mod/endpoints/mod_khomp/commons/base/configurator/restriction.hpp @@ -0,0 +1,269 @@ +/* + KHOMP generic endpoint/channel library. + Copyright (C) 2007-2009 Khomp Ind. & Com. + + The contents of this file are subject to the Mozilla Public License Version 1.1 + (the "License"); you may not use this file except in compliance with the + License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS IS" basis, + WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for + the specific language governing rights and limitations under the License. + + Alternatively, the contents of this file may be used under the terms of the + "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which + case the provisions of "LGPL License" are applicable instead of those above. + + If you wish to allow use of your version of this file only under the terms of + the LGPL License and not to allow others to use your version of this file under + the MPL, indicate your decision by deleting the provisions above and replace them + with the notice and other provisions required by the LGPL License. If you do not + delete the provisions above, a recipient may use your version of this file under + either the MPL or the LGPL License. + + The LGPL header follows below: + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#include + +#include +#include +#include +#include + +#include + +#ifndef _CONFIG_RESTRICTION_HPP_ +#define _CONFIG_RESTRICTION_HPP_ + +struct Restriction: public ConstThis < Restriction > +{ + /* generic types */ + + // TODO: change this type name for something different + // to avoid conflicting with "format.hpp". + enum Format + { + F_USER, + F_FILE + }; + + enum Kind + { + K_STRING, + K_NUMBER // = K_INTEGER // compatibility + }; + + enum Bounds + { + B_FREE, + B_RANGE, + B_LIST, + B_MAPS + }; + + enum Numeral + { + N_UNIQUE, + N_MULTIPLE + }; + + typedef std::string Value; + + /* types used for data input */ + struct Pair + { + const char *pretty; + const char *value; + }; + + typedef std::pair < Value, Value > PairMap; + typedef std::list < PairMap > ListMap; + + /* types used internally */ + typedef std::map < Value, Value > Map; + typedef std::vector < Value > Vector; + + typedef std::list < Value > List; + typedef std::pair < Value, Value > MapPair; + + struct Generic + { + Value _unique; + List _multiple; + }; + + Restriction(Kind kind, Numeral num) + : _kind(kind), _bounds(B_FREE), _numeral(num), _unit(""), + _init(-1), _fini(-1), _step(-1) + { + init_class(); + } + + Restriction(Kind kind, Numeral num, + double init, double fini, double step = 1) + : _kind(kind), _bounds(B_RANGE), _numeral(num), _unit(""), + _init(init), _fini(fini), _step(step) + { + init_class(); + } + + Restriction(Kind kind, Numeral num, + const char *unit, double init, double fini, double step = 1.0) + : _kind(kind), _bounds(B_RANGE), _numeral(num), _unit(unit), + _init(init), _fini(fini), _step(step) + { + init_class(); + } + + Restriction(Kind kind, Numeral num, + std::string unit, double init, double fini, double step = 1.0) + : _kind(kind), _bounds(B_RANGE), _numeral(num), _unit(unit), + _init(init), _fini(fini), _step(step) + { + init_class(); + } + + Restriction(Kind kind, Numeral num, + const char *first, ...) + : _kind(kind), _bounds(B_LIST), _numeral(num), _unit(""), + _init(-1), _fini(-1), _step(-1) + { + _list.push_back(std::string(first)); + + va_list ap; + va_start(ap, first); + + while (true) + { + const char *arg = va_arg(ap, const char *); + + if (arg == NULL) break; + + _list.push_back(std::string(arg)); + } + + init_class(); + } + + Restriction(Kind kind, const char *unit, Numeral num, + const char *first, ...) + : _kind(kind), _bounds(B_LIST), _numeral(num), _unit(unit), + _init(-1), _fini(-1), _step(-1) + { + _list.push_back(std::string(first)); + + va_list ap; + va_start(ap, first); + + while (true) + { + const char *arg = va_arg(ap, const char *); + + if (arg == NULL) break; + + _list.push_back(std::string(arg)); + } + + init_class(); + } + + Restriction(Kind kind, Numeral num, + const struct Pair first, ...) + : _kind(kind), _bounds(B_MAPS), _numeral(num), _unit(""), + _init(-1), _fini(-1), _step(-1) + { + _map_from_usr.insert(MapPair(Value(first.pretty), Value(first.value))); + _map_from_cfg.insert(MapPair(Value(first.value), Value(first.pretty))); + + va_list ap; + va_start(ap, first); + + while (true) + { + Pair arg = va_arg(ap, Pair); + + if (arg.pretty == NULL) break; + + _map_from_usr.insert(MapPair(Value(arg.pretty), Value(arg.value))); + _map_from_cfg.insert(MapPair(Value(arg.value), Value(arg.pretty))); + } + + init_class(); + } + + Restriction(Kind kind, Numeral num, List list) + : _kind(kind), _bounds(B_LIST), _numeral(num), _unit(""), + _init(-1), _fini(-1), _step(-1), _list(list) + { + init_class(); + } + + Restriction(Kind kind, Numeral num, ListMap map) + : _kind(kind), _bounds(B_MAPS), _numeral(num), _unit(""), + _init(-1), _fini(-1), _step(-1) + { + for (ListMap::iterator i = map.begin(); i != map.end(); i++) + { + _map_from_usr.insert(MapPair(Value((*i).first), Value((*i).second))); + _map_from_cfg.insert(MapPair(Value((*i).second), Value((*i).first))); + } + + init_class(); + } + + const Kind kind() const { return _kind; }; + const Bounds bounds() const { return _bounds; }; + const Numeral numeral() const { return _numeral; }; + + const std::string & unit() const { return _unit; }; + + bool set(Format, const Vector &); + bool set(Format, const Value &); + + bool get(Format, Vector &) const; + bool get(Format, Value &) const; + + void allowed(Vector &) const; + + private: + bool process(const Format, const Value &, Value &) const; + bool unprocess(const Format, const Value &, Value &) const; + + void init_class(); + + static bool equalNumber(const double, const double); + + protected: + const Kind _kind; + const Bounds _bounds; + const Numeral _numeral; + + Value _unit; + + const double _init, _fini, _step; + + Map _map_from_usr, + _map_from_cfg; + + List _list; + + Generic _value; +}; + +#endif /* _CONFIG_RESTRICTION_HPP_ */ diff --git a/src/mod/endpoints/mod_khomp/commons/configurator/section.cpp b/src/mod/endpoints/mod_khomp/commons/base/configurator/section.cpp similarity index 59% rename from src/mod/endpoints/mod_khomp/commons/configurator/section.cpp rename to src/mod/endpoints/mod_khomp/commons/base/configurator/section.cpp index 5d26858054..9ed775b044 100644 --- a/src/mod/endpoints/mod_khomp/commons/configurator/section.cpp +++ b/src/mod/endpoints/mod_khomp/commons/base/configurator/section.cpp @@ -1,7 +1,7 @@ -/* +/* KHOMP generic endpoint/channel library. - Copyright (C) 2007-2009 Khomp Ind. & Com. - + Copyright (C) 2007-2009 Khomp Ind. & Com. + The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ @@ -23,108 +23,114 @@ The LGPL header follows below: - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ #include -void Section::options(Section::OptionVector & vec) +void Section::options(Section::OptionVector & vec) const { - for (OptionMap::iterator it = _options.begin(); it != _options.end();) - { - vec.push_back(&((*it).second)); - ++it; - } + for (OptionMap::const_iterator it = _options.begin(); it != _options.end();) + { + vec.push_back(const_cast< Option * >(&(it->second))); + ++it; + } } -void Section::sections(Section::SectionVector & vec) +void Section::sections(Section::SectionVector & vec) const { - for (SectionMap::iterator it = _sections.begin(); it != _sections.end();) - { - vec.push_back((*it).second); - ++it; - } + for (SectionMap::const_iterator it = _sections.begin(); it != _sections.end();) + { + vec.push_back(const_cast< Section * >(it->second)); + ++it; + } } /*********/ -Option * Section::option_find(std::string & str, bool recurse) +Option * Section::option_find(const std::string & str, bool recurse) const { - OptionMap::iterator i = _options.find(str); + OptionMap::const_iterator i = _options.find(str); - if (i == _options.end()) + if (i == _options.end()) { if (!recurse) - throw not_found(); + throw OptionNotFound(str, _name); +// throw not_found(); - for (SectionMap::iterator i = _sections.begin(); i != _sections.end(); i++) + for (SectionMap::const_iterator i = _sections.begin(); i != _sections.end(); i++) { try { return i->second->option_find(str, recurse); } - catch (not_found & e) + catch (NotFound & e) { /* keep looping! */ }; } - throw not_found(); +// throw not_found(); + throw OptionNotFound(str, _name); } - return &((*i).second); + return const_cast< Option * >(&(i->second)); } +/* Option * Section::option_find(const char * str, bool recurse) { - std::string sstr(str); - return option_find(sstr, recurse); + std::string sstr(str); + return option_find(sstr, recurse); } +*/ /*********/ -Section * Section::section_find(std::string & str, bool recurse) +Section * Section::section_find(const std::string & str, bool recurse) const { - SectionMap::iterator i = _sections.find(str); + SectionMap::const_iterator i = _sections.find(str); - if (i == _sections.end()) + if (i == _sections.end()) { if (!recurse) - throw not_found(); + throw SectionNotFound(str, _name); - for (SectionMap::iterator i = _sections.begin(); i != _sections.end(); i++) + for (SectionMap::const_iterator i = _sections.begin(); i != _sections.end(); i++) { try { return i->second->section_find(str, recurse); } - catch (not_found & e) + catch (NotFound & e) { /* keep looping! */ }; } - throw not_found(); + throw SectionNotFound(str, _name); } - return ((*i).second); + return const_cast< Section * >(i->second); } +/* Section * Section::section_find(const char * str, bool recurse) { - std::string sstr(str); - return section_find(sstr, recurse); + std::string sstr(str); + return section_find(sstr, recurse); } +*/ diff --git a/src/mod/endpoints/mod_khomp/commons/base/configurator/section.hpp b/src/mod/endpoints/mod_khomp/commons/base/configurator/section.hpp new file mode 100644 index 0000000000..d5a8c95688 --- /dev/null +++ b/src/mod/endpoints/mod_khomp/commons/base/configurator/section.hpp @@ -0,0 +1,260 @@ +/* + KHOMP generic endpoint/channel library. + Copyright (C) 2007-2009 Khomp Ind. & Com. + + The contents of this file are subject to the Mozilla Public License Version 1.1 + (the "License"); you may not use this file except in compliance with the + License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS IS" basis, + WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for + the specific language governing rights and limitations under the License. + + Alternatively, the contents of this file may be used under the terms of the + "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which + case the provisions of "LGPL License" are applicable instead of those above. + + If you wish to allow use of your version of this file only under the terms of + the LGPL License and not to allow others to use your version of this file under + the MPL, indicate your decision by deleting the provisions above and replace them + with the notice and other provisions required by the LGPL License. If you do not + delete the provisions above, a recipient may use your version of this file under + either the MPL or the LGPL License. + + The LGPL header follows below: + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#ifndef _CONFIG_SECTION_HPP_ +#define _CONFIG_SECTION_HPP_ + +#include +#include +#include +#include +#include + +#include + +#include + +struct Section +{ + typedef std::map < std::string, Option > OptionMap; + typedef std::vector< Option * > OptionVector; + + typedef std::map < std::string, Section * > SectionMap; + typedef std::vector < Section * > SectionVector; + + struct NotFound: public std::runtime_error + { + NotFound(const std::string & type, const std::string & name, const std::string & me) + : std::runtime_error(STG(FMT("%s '%s' not found on section '%s'") % type % name % me)) {}; + }; + + struct OptionNotFound: public NotFound + { + OptionNotFound(const std::string & name, const std::string & me) + : NotFound("option", name, me) {}; + }; + + struct SectionNotFound: public NotFound + { + SectionNotFound(const std::string & name, const std::string & me) + : NotFound("section", name, me) {}; + }; + + typedef NotFound not_found; /* backward compatibility */ + +// protected: + Section(const std::string & name, const std::string & desc, bool recursive = true) + : _name(name), _description(desc), _recursive(recursive) {}; + + void add(const Option & o) + { + _options.insert(std::pair(o.name(), o)); + }; + + void del(const std::string & name) + { + _options.erase(name); + }; + + void add(Section * s) + { + _sections.insert(std::pair< std::string, Section * >(s->name(), s)); + }; + + public: + const std::string & name() const { return _name; }; + const std::string & description() const { return _description; }; + + const bool recursive() const { return _recursive; }; + + OptionMap::const_iterator option_begin() const { return _options.begin(); }; + OptionMap::const_iterator option_end() const { return _options.end(); }; + + SectionMap::const_iterator section_begin() const { return _sections.begin(); }; + SectionMap::const_iterator section_end() const { return _sections.end(); }; + + /**/ + +// Option * option_find(const char *, bool recurse = false) const; +// Section * section_find(const char *, bool recurse = false) const; + + Option * option_find(const std::string &, bool recurse = false) const; + Section * section_find(const std::string &, bool recurse = false) const; + + /**/ + + void options(OptionVector &) const; + void sections(SectionVector &) const; + + /**/ + + template < typename T, typename F > + bool search_and_apply(const std::string & key, T & value, F f) + { + OptionMap::iterator i = _options.find(key); + + if (i != _options.end()) + return f(i->second); + + if (!_recursive) + return false; + + return (find_if(_sections.begin(), _sections.end(), f) != _sections.end()); + } + + private: + struct ConstKeyValue + { + ConstKeyValue(const std::string & k, const std::string &v) + : _k(k), _v(v) {}; + + const std::string & _k; + const std::string & _v; + }; + + struct KeyValue + { + KeyValue(const std::string & k, std::string &v) + : _k(k), _v(v) {}; + + const std::string & _k; + std::string & _v; + }; + + struct load_section: protected ConstKeyValue + { + load_section(const std::string & k, const std::string & v): ConstKeyValue(k,v) {}; + + bool operator()(Option & o) { return o.load(_v); }; + bool operator()(SectionMap::value_type & v) { return v.second->load(_k,_v); }; + }; + + struct change_section: protected ConstKeyValue + { + change_section(const std::string & k, const std::string & v): ConstKeyValue(k,v) {}; + + bool operator()(Option & o) { return o.change(_v); }; + bool operator()(SectionMap::value_type & v) { return v.second->change(_k,_v); }; + }; + + struct store_section: protected KeyValue + { + store_section(const std::string & k, std::string & v): KeyValue(k,v) {}; + + bool operator()(Option & o) { return o.store(_v); }; + bool operator()(SectionMap::value_type & v) { return v.second->store(_k,_v); }; + }; + + struct set_section: protected ConstKeyValue + { + set_section(const std::string & k, const std::string & v): ConstKeyValue(k,v) {}; + + bool operator()(Option & o) { return (o.set(_v))[Option::F_ADJUSTED]; }; + bool operator()(SectionMap::value_type & v) { return v.second->set(_k,_v); }; + }; + + struct get_section: protected KeyValue + { + get_section(const std::string & k, std::string & v): KeyValue(k,v) {}; + + bool operator()(Option & o) { return o.get(_v); }; + bool operator()(SectionMap::value_type & v) { return v.second->get(_k,_v); }; + }; + + struct modified_section + { + bool operator()(const OptionMap::value_type & v) { return v.second.modified(); }; + bool operator()(const SectionMap::value_type & v) { return v.second->modified(); }; + }; + + public: +/* + bool load(const char * key, const std::string value) + { + std::string skey(key); + return search_and_apply(skey, value, load_section(skey, value)); + } +*/ + bool load(const std::string & key, const std::string & value) + { + return search_and_apply(key, value, load_section(key, value)); + } + + bool change(const std::string & key, const std::string & value) + { + return search_and_apply(key, value, change_section(key, value)); + } + + bool store(const std::string & key, std::string & value) + { + return search_and_apply(key, value, store_section(key, value)); + } + + bool set(const std::string & key, const std::string & value) + { + return search_and_apply(key, value, set_section(key, value)); + } + + bool get(const std::string & key, std::string & value) + { + return search_and_apply(key, value, get_section(key, value)); + } + + bool modified() const + { + return ((find_if(_options.begin(), _options.end(), modified_section()) != _options.end()) || + (find_if(_sections.begin(), _sections.end(), modified_section()) != _sections.end())); + } + + private: + Section(): _name(""), _description(""), _recursive(false) {}; + + protected: + const std::string _name; + const std::string _description; + + OptionMap _options; + SectionMap _sections; + + const bool _recursive; +}; + +#endif /* _CONFIG_SECTION_HPP_ */ diff --git a/src/mod/endpoints/mod_khomp/commons/base/const_this.hpp b/src/mod/endpoints/mod_khomp/commons/base/const_this.hpp new file mode 100644 index 0000000000..48e3c1e32f --- /dev/null +++ b/src/mod/endpoints/mod_khomp/commons/base/const_this.hpp @@ -0,0 +1,15 @@ + +#ifndef _CONST_THIS_H_ +#define _CONST_THIS_H_ + +template < typename T > +struct ConstThis +{ + T const & constThis() const + { + // TODO: will this return the right reference? + return static_cast(*this); + } +}; + +#endif /* _CONST_THIS_H_ */ diff --git a/src/mod/endpoints/mod_khomp/commons/flagger.hpp b/src/mod/endpoints/mod_khomp/commons/base/flagger.hpp similarity index 100% rename from src/mod/endpoints/mod_khomp/commons/flagger.hpp rename to src/mod/endpoints/mod_khomp/commons/base/flagger.hpp diff --git a/src/mod/endpoints/mod_khomp/commons/format.cpp b/src/mod/endpoints/mod_khomp/commons/base/format.cpp similarity index 89% rename from src/mod/endpoints/mod_khomp/commons/format.cpp rename to src/mod/endpoints/mod_khomp/commons/base/format.cpp index 20f79204ec..74223cc406 100644 --- a/src/mod/endpoints/mod_khomp/commons/format.cpp +++ b/src/mod/endpoints/mod_khomp/commons/base/format.cpp @@ -42,27 +42,7 @@ #include "format.hpp" //#include -Format::Format(const char * format_string, bool raise_exception) -: _format(format_string), _valid(true), _raise(raise_exception) -{ - initialize(format_string); -} - -/* -Format::Format(std::string & format_string, bool raise_exception) -: _format(NULL), _valid(true), _raise(raise_exception) -{ - initialize(format_string.c_str()); -} -*/ - -Format::Format(std::string format_string, bool raise_exception) -: _format(format_string), _valid(true), _raise(raise_exception) -{ - initialize(format_string.c_str()); -} - -void Format::initialize(const char * format_string) +void FormatTraits::initialize(const char * format_string) { std::string txt; @@ -82,7 +62,6 @@ void Format::initialize(const char * format_string) if (*ptr2 == '%') { txt += *ptr; - ptr += 2; continue; } @@ -238,36 +217,20 @@ void Format::initialize(const char * format_string) push_argument(txt, T_LITERAL); } -void Format::mark_invalid(std::string & msg) +void FormatTraits::push_argument(std::string & data, FormatTraits::Type type) { - if (_valid) - { - _valid = false; +// std::cerr << "pushing type (" << type << ") with format (" << data << ")" << std::endl; - std::string finalmsg; - - finalmsg += "** INVALID FORMAT: "; - finalmsg += msg; - finalmsg += " **"; - - _result = finalmsg; - } + _args.push(Argument(data, type)); + data.clear(); } -void Format::raise_check(void) +void FormatTraits::pop_argument(void) { - if (!_valid && _raise) - throw InvalidFormat(_result); + _args.pop(); } -bool Format::validity_check(void) -{ - raise_check(); - - return _valid; -} - -const Format::Argument * Format::next_argument(void) +const FormatTraits::Argument * FormatTraits::next_argument(void) { // std::cerr << "size: " << _args.size() << std::endl; @@ -294,38 +257,81 @@ const Format::Argument * Format::next_argument(void) } } -void Format::pop_argument(void) +/******************************************************************/ + +#if 0 +Format::Format(const char * format_string, bool raise_exception) +: _format(format_string), _valid(true), _raise(raise_exception) { - _args.pop(); + FormatTraits::initialize(format_string); } -void Format::push_argument(std::string & data, Format::Type type) +Format::Format(std::string format_string, bool raise_exception) +: _format(format_string), _valid(true), _raise(raise_exception) { -// std::cerr << "pushing type (" << type << ") with format (" << data << ")" << std::endl; + FormatTraits::initialize(format_string.c_str()); +} - _args.push(Argument(data, type)); - data.clear(); +/* +Format::Format(std::string & format_string, bool raise_exception) +: _format(NULL), _valid(true), _raise(raise_exception) +{ + initialize(format_string.c_str()); +} +*/ + +void Format::mark_invalid(std::string & msg) +{ + if (_valid) + { + _valid = false; + + _result = "** INVALID FORMAT: "; + _result += msg; + _result += " **"; + } +} + +void Format::raise(void) const +{ + if (!_valid) + { + // call specialized class + FormatException::raise(_result); + } +} + +bool Format::valid(void) const +{ +// raise(); + return _valid; } std::string Format::str() { - if (!validity_check()) + if (!valid()) return _result; - if (next_argument() == NULL) +// try +// { + if (next_argument() != NULL) + { + std::string msg; + + msg += "too few arguments passed for format '"; + msg += _format; + msg += "' ("; + msg += _format; + msg += ")"; + + mark_invalid(msg); + return _result; - - std::string msg; - - msg += "too few arguments passed for format '"; - msg += _format; - msg += "' ("; - msg += _format; - msg += ")"; - - mark_invalid(msg); - - return _result; + } +// catch (NoArgumentLeft e) +// { +// return _result; +// } } - +#endif diff --git a/src/mod/endpoints/mod_khomp/commons/format.hpp b/src/mod/endpoints/mod_khomp/commons/base/format.hpp similarity index 81% rename from src/mod/endpoints/mod_khomp/commons/format.hpp rename to src/mod/endpoints/mod_khomp/commons/base/format.hpp index b1ebe74396..0469e4fdf9 100644 --- a/src/mod/endpoints/mod_khomp/commons/format.hpp +++ b/src/mod/endpoints/mod_khomp/commons/base/format.hpp @@ -52,37 +52,35 @@ #include #ifdef WIN32 // WINDOWS -#include +# include #endif - -/* macros used for shortening lines and making the code clearer */ -#define STG(x) (x).str() -#define FMT(x) Format(x) - -struct Format +struct InvalidFormat { - static const unsigned int strings_base_length = 64; - static const unsigned int generic_base_length = 64; + InvalidFormat(std::string _msg) : msg(_msg) {} + const std::string msg; +}; - struct InvalidFormat +template < bool E > +struct FormatException +{ + void raise(const std::string & msg) const { - InvalidFormat(std::string msg) : _msg(msg) {} - - std::string _msg; + /* DO NOTHING */ }; +}; - explicit Format(const char * format_string, bool raise_exception = false); - explicit Format(std::string format_string, bool raise_exception = false); - - void initialize(const char *); - - std::string str(void); - - //////////////////////////////////////////////////////////// - - protected: +template < > +struct FormatException < true > +{ + void raise(const std::string & msg) const + { + throw InvalidFormat(msg); + }; +}; +struct FormatTraits +{ enum Type { T_ANYTHING = 1, @@ -113,24 +111,240 @@ struct Format Argument(std::string fmts, Type type) : _fmts(fmts), _type(type) {}; - Type type(void) const { return _type; } + const Type type(void) const { return _type; } const std::string & fmts(void) const { return _fmts; } protected: - std::string _fmts; - Type _type; + const std::string _fmts; + const Type _type; }; typedef std::queue < Argument > ArgumentQueue; - //////////////////////////////////////////////////////////// - - public: + ////////////////////////////////// template < typename V > - Format & operator%( V value ) + bool number_verify_signed_short( V value ) const { - if (!validity_check()) + return + ((typeid(V) == typeid(short int) || + typeid(V) == typeid(short) || + typeid(V) == typeid(const short int) || + typeid(V) == typeid(const short) || + typeid(V) == typeid(volatile short int) || + typeid(V) == typeid(volatile short)) && + sizeof(V) == sizeof(short)); + } + + template < typename V > + bool number_verify_unsigned_short( V value ) const + { + return + ((typeid(V) == typeid(unsigned short int) || + typeid(V) == typeid(unsigned short) || + typeid(V) == typeid(const unsigned short int) || + typeid(V) == typeid(const unsigned short) || + typeid(V) == typeid(volatile unsigned short int) || + typeid(V) == typeid(volatile unsigned short)) && + sizeof(V) == sizeof(unsigned short)); + } + + template < typename V > + bool number_verify_signed_long( V value ) const + { + return + ((typeid(V) == typeid(long int) || + typeid(V) == typeid(long) || + typeid(V) == typeid(const long int) || + typeid(V) == typeid(const long) || + typeid(V) == typeid(volatile long int) || + typeid(V) == typeid(volatile long)) && + sizeof(V) == sizeof(long)); + } + + template < typename V > + bool number_verify_unsigned_long( V value ) const + { + return + ((typeid(V) == typeid(unsigned long int) || + typeid(V) == typeid(unsigned long) || + typeid(V) == typeid(const unsigned long int) || + typeid(V) == typeid(const unsigned long) || + typeid(V) == typeid(volatile unsigned long int) || + typeid(V) == typeid(volatile unsigned long)) && + sizeof(V) == sizeof(long long)); + } + + template < typename V > + bool number_verify_signed_long_long( V value ) const + { + return + ((typeid(V) == typeid(long long int) || + typeid(V) == typeid(long long) || + typeid(V) == typeid(const long long int) || + typeid(V) == typeid(const long long) || + typeid(V) == typeid(volatile long long) || + typeid(V) == typeid(volatile long long int)) && + sizeof(V) == sizeof(long long)); + } + + template < typename V > + bool number_verify_unsigned_long_long( V value ) const + { + return + ((typeid(V) == typeid(unsigned long long int) || + typeid(V) == typeid(unsigned long long) || + typeid(V) == typeid(const unsigned long long int) || + typeid(V) == typeid(const unsigned long long) || + typeid(V) == typeid(volatile unsigned long long) || + typeid(V) == typeid(volatile unsigned long long int)) && + sizeof(V) == sizeof(unsigned long long)); + } + + template < typename V > + bool number_verify_signed_int( V value ) const + { + return + (sizeof(V) <= sizeof(int) || + typeid(V) == typeid(int) || + typeid(V) == typeid(const int) || + typeid(V) == typeid(volatile int)); + } + + template < typename V > + bool number_verify_unsigned_int( V value ) const + { + return + (sizeof(V) <= sizeof(unsigned int) || + typeid(V) == typeid(unsigned int) || + typeid(V) == typeid(const unsigned int) || + typeid(V) == typeid(volatile unsigned int)); + } + + template < typename V > + bool generic_verify( V value, const Type type ) const + { + switch (type) + { + /* EXCEPTION: consider any number an valid input. */ + case T_SIGNED_INT: + case T_UNSIGNED_INT: + return + (number_verify_signed_int(value) || + number_verify_unsigned_int(value) || + number_verify_signed_long(value) || + number_verify_unsigned_long(value) || + number_verify_signed_short(value) || + number_verify_unsigned_short(value)); + + case T_SIGNED_SHORT_SHORT: + return (typeid(V) == typeid(char) || typeid(V) == typeid(const char)); + + case T_SIGNED_SHORT: + return number_verify_signed_short(value); + + case T_SIGNED_LONG: + return number_verify_signed_long(value); + + case T_SIGNED_LONG_LONG: + return number_verify_signed_long_long(value); + + case T_UNSIGNED_SHORT_SHORT: + return (typeid(V) == typeid(unsigned char) || typeid(V) == typeid(unsigned char)); + + case T_UNSIGNED_SHORT: + return number_verify_unsigned_short(value); + + case T_UNSIGNED_LONG: + return number_verify_unsigned_long(value); + + case T_UNSIGNED_LONG_LONG: + return number_verify_unsigned_long_long(value); + + case T_FLOAT: + return (typeid(V) == typeid(float)) || (typeid(V) == typeid(double) || + typeid(V) == typeid(const float)) || (typeid(V) == typeid(const double)); + + case T_CHAR: + return (typeid(V) == typeid(char)) || (typeid(V) == typeid(unsigned char) || + typeid(V) == typeid(const char)) || (typeid(V) == typeid(const unsigned char)); + + case T_POINTER: + case T_STRING: + return false; + + case T_ANYTHING: + return true; + + case T_LITERAL: + return false; + } + + return false; + }; + + const Argument * next_argument(void); + + void push_argument(std::string & data, const Type type); + void pop_argument(void); + + void initialize(const char *); + + protected: + ArgumentQueue _args; + std::string _result; + +}; + +template < bool E = false > +struct FormatBase: protected FormatTraits, protected FormatException < E > +{ + static const unsigned int strings_base_length = 64; + static const unsigned int generic_base_length = 64; + + explicit FormatBase(const char * format_string) + : _format(format_string), _valid(true) + { + FormatTraits::initialize(format_string); + }; + + explicit FormatBase(std::string format_string) + : _format(format_string), _valid(true) + { + FormatTraits::initialize(format_string.c_str()); + }; + + bool valid(void) const + { + return _valid; + } + + const std::string str() + { + if (valid() && (next_argument() != NULL)) + { + std::string msg; + + // TODO: why format appears two times? + msg += "too few arguments passed for format '"; + msg += _format; + msg += "' ("; + msg += _format; + msg += ")"; + + mark_invalid(msg); + } + + raise(); + return _result; + }; + + //////////////////////////////////////////////////////////// + + template < typename V > + FormatBase & operator%( V value ) + { + if (!valid()) return *this; const Argument * top = next_argument(); @@ -149,7 +363,7 @@ struct Format { char temp[generic_base_length]; - if (!generic_verify(value, top->type())) + if (!FormatTraits::generic_verify(value, top->type())) { std::string msg; @@ -171,14 +385,14 @@ struct Format pop_argument(); } - raise_check(); + raise(); return *this; } template < typename V > - Format & operator%( V * value ) + FormatBase & operator%( V * value ) { - if (!validity_check()) + if (!valid()) return *this; const Argument * top = next_argument(); @@ -256,20 +470,13 @@ struct Format pop_argument(); } - raise_check(); + raise(); return *this; } -/* - Format & operator%( std::string value ) + FormatBase & operator%( const std::string value ) { - return operator%(value); - } -*/ - - Format & operator%( const std::string value ) - { - if (!validity_check()) + if (!valid()) return *this; const Argument * top = next_argument(); @@ -313,200 +520,42 @@ struct Format pop_argument(); } - raise_check(); + raise(); return *this; } - protected: - - template < typename V > - bool number_verify_signed_short( V value ) + protected: + void mark_invalid(std::string & msg) { - return - ((typeid(V) == typeid(short int) || - typeid(V) == typeid(short) || - typeid(V) == typeid(const short int) || - typeid(V) == typeid(const short) || - typeid(V) == typeid(volatile short int) || - typeid(V) == typeid(volatile short)) && - sizeof(V) == sizeof(short)); - } - - template < typename V > - bool number_verify_unsigned_short( V value ) - { - return - ((typeid(V) == typeid(unsigned short int) || - typeid(V) == typeid(unsigned short) || - typeid(V) == typeid(const unsigned short int) || - typeid(V) == typeid(const unsigned short) || - typeid(V) == typeid(volatile unsigned short int) || - typeid(V) == typeid(volatile unsigned short)) && - sizeof(V) == sizeof(unsigned short)); - } - - template < typename V > - bool number_verify_signed_long( V value ) - { - return - ((typeid(V) == typeid(long int) || - typeid(V) == typeid(long) || - typeid(V) == typeid(const long int) || - typeid(V) == typeid(const long) || - typeid(V) == typeid(volatile long int) || - typeid(V) == typeid(volatile long)) && - sizeof(V) == sizeof(long)); - } - - template < typename V > - bool number_verify_unsigned_long( V value ) - { - return - ((typeid(V) == typeid(unsigned long int) || - typeid(V) == typeid(unsigned long) || - typeid(V) == typeid(const unsigned long int) || - typeid(V) == typeid(const unsigned long) || - typeid(V) == typeid(volatile unsigned long int) || - typeid(V) == typeid(volatile unsigned long)) && - sizeof(V) == sizeof(long long)); - } - - template < typename V > - bool number_verify_signed_long_long( V value ) - { - return - ((typeid(V) == typeid(long long int) || - typeid(V) == typeid(long long) || - typeid(V) == typeid(const long long int) || - typeid(V) == typeid(const long long) || - typeid(V) == typeid(volatile long long) || - typeid(V) == typeid(volatile long long int)) && - sizeof(V) == sizeof(long long)); - } - - template < typename V > - bool number_verify_unsigned_long_long( V value ) - { - return - ((typeid(V) == typeid(unsigned long long int) || - typeid(V) == typeid(unsigned long long) || - typeid(V) == typeid(const unsigned long long int) || - typeid(V) == typeid(const unsigned long long) || - typeid(V) == typeid(volatile unsigned long long) || - typeid(V) == typeid(volatile unsigned long long int)) && - sizeof(V) == sizeof(unsigned long long)); - } - - template < typename V > - bool number_verify_signed_int( V value ) - { - return - (sizeof(V) <= sizeof(int) || - typeid(V) == typeid(int) || - typeid(V) == typeid(const int) || - typeid(V) == typeid(volatile int)); - } - - template < typename V > - bool number_verify_unsigned_int( V value ) - { - return - (sizeof(V) <= sizeof(unsigned int) || - typeid(V) == typeid(unsigned int) || - typeid(V) == typeid(const unsigned int) || - typeid(V) == typeid(volatile unsigned int)); - } - - template < typename V > - bool generic_verify( V value, Type type ) - { - switch (type) + if (_valid) { - /* EXCEPTION: consider any number an valid input. */ - case T_SIGNED_INT: - case T_UNSIGNED_INT: - return - (number_verify_signed_int(value) || - number_verify_unsigned_int(value) || - number_verify_signed_long(value) || - number_verify_unsigned_long(value) || - number_verify_signed_short(value) || - number_verify_unsigned_short(value)); + _valid = false; - case T_SIGNED_SHORT_SHORT: - return (typeid(V) == typeid(char) || typeid(V) == typeid(const char)); - - case T_SIGNED_SHORT: - return number_verify_signed_short(value); - - case T_SIGNED_LONG: - return number_verify_signed_long(value); - - case T_SIGNED_LONG_LONG: - return number_verify_signed_long_long(value); - - case T_UNSIGNED_SHORT_SHORT: - return (typeid(V) == typeid(unsigned char) || typeid(V) == typeid(unsigned char)); - - case T_UNSIGNED_SHORT: - return number_verify_unsigned_short(value); - - case T_UNSIGNED_LONG: - return number_verify_unsigned_long(value); - - case T_UNSIGNED_LONG_LONG: - return number_verify_unsigned_long_long(value); - - case T_FLOAT: - return (typeid(V) == typeid(float)) || (typeid(V) == typeid(double) || - typeid(V) == typeid(const float)) || (typeid(V) == typeid(const double)); - - case T_CHAR: - return (typeid(V) == typeid(char)) || (typeid(V) == typeid(unsigned char) || - typeid(V) == typeid(const char)) || (typeid(V) == typeid(const unsigned char)); - - case T_POINTER: - case T_STRING: - return false; - - case T_ANYTHING: - return true; - - case T_LITERAL: - return false; + _result = "** INVALID FORMAT: "; + _result += msg; + _result += " **"; } + } - return false; - }; - - void mark_invalid(std::string &); - - bool validity_check(void); - void raise_check(void); - -/* - struct NoArgumentLeft + void raise(void) const { - NoArgumentLeft(): empty(0) {}; - - unsigned int empty; - }; -*/ - - const Argument * next_argument(void); - - void pop_argument(void); - void push_argument(std::string & data, Type type); + if (!_valid) + { + // call specialized class + FormatException< E >::raise(_result); + } + } private: - std::string _format; - - bool _valid; - bool _raise; - - std::string _result; - ArgumentQueue _args; + const std::string _format; + bool _valid; }; -#endif /* _FORMAT_H_ */ +/* useful typedef for general usage (not generating exceptions) */ +typedef FormatBase<> Format; +/* macros used for shortening lines and making the code clearer */ +#define STG(x) (x).str() +#define FMT(x) Format(x) + +#endif /* _FORMAT_H_ */ diff --git a/src/mod/endpoints/mod_khomp/commons/function.hpp b/src/mod/endpoints/mod_khomp/commons/base/function.hpp similarity index 65% rename from src/mod/endpoints/mod_khomp/commons/function.hpp rename to src/mod/endpoints/mod_khomp/commons/base/function.hpp index c448299acd..7470bf245d 100644 --- a/src/mod/endpoints/mod_khomp/commons/function.hpp +++ b/src/mod/endpoints/mod_khomp/commons/base/function.hpp @@ -46,12 +46,13 @@ namespace Function { - struct EmptyFunction {}; + struct EmptyFunction {}; + struct NonMemberFunction {}; /**/ template < typename FunctionTraits > - struct StorageBase: NEW_REFCOUNTER(StorageBase < FunctionTraits >) + struct StorageBase: COUNTER_SUPER(StorageBase < FunctionTraits >) { typedef typename FunctionTraits::BaseType BaseType; @@ -59,27 +60,33 @@ namespace Function typedef typename FunctionTraits::ObjType ObjType; template < typename Functor > - StorageBase(Functor f) - : _object(reinterpret_cast(new Functor(f))), - _function(reinterpret_cast(&(Functor::operator()))), + StorageBase(const Functor f) + : _object(reinterpret_cast< ObjType >(new Functor(f))), + _function(reinterpret_cast< FunType >(&Functor::operator())), _malloced(true) {}; template < typename Functor > StorageBase(Functor & f, bool malloced) - : _object(reinterpret_cast((malloced ? new Functor(f) : &f))), - _function(reinterpret_cast(&(Functor::operator()))), + : _object(reinterpret_cast< ObjType >((malloced ? new Functor(f) : &f))), + _function(reinterpret_cast< FunType >(&Functor::operator())), _malloced(malloced) {}; + StorageBase(FunType const * member) + : _object(reinterpret_cast< ObjType >(0)), + _function(reinterpret_cast< FunType >(member)), + _malloced(false) + {}; + StorageBase() - : _object(reinterpret_cast(0)), - _function(reinterpret_cast(0)), + : _object(reinterpret_cast< ObjType >(0)), + _function(reinterpret_cast< FunType >(0)), _malloced(false) {}; StorageBase(const StorageBase & o) - : INC_REFCOUNTER(o, StorageBase < FunctionTraits >), + : COUNTER_REFER(o, StorageBase < FunctionTraits >), _object(o._object), _function(o._function), _malloced(o._malloced) {}; @@ -95,9 +102,9 @@ namespace Function template < typename Functor > void operator=(Functor f) { - _object = reinterpret_cast(new Functor(f)), - _function = reinterpret_cast(&(Functor::operator())); - _malloced = false; + _object = reinterpret_cast< ObjType >(new Functor(f)), + _function = reinterpret_cast< FunType >(&Functor::operator()); + _malloced = true; } protected: @@ -229,10 +236,15 @@ namespace Function typedef StorageBase < Function0Traits < R > > Storage; template < typename Functor > - Function0(Functor f): Storage(f) {}; + Function0(const Functor f) + : Storage(f) {}; template < typename Functor > - Function0(Functor & f, bool m): Storage(f, m) {}; + Function0(Functor & f, bool m) + : Storage(f, m) {}; + + Function0(const typename Function0Traits < R >::FunType * m) + : Storage(m) {}; Function0() {}; @@ -243,6 +255,18 @@ namespace Function return ((Storage::_object)->*(Storage::_function))(); } + + template < typename Object > + R operator()(Object * object) + { + if (reinterpret_cast(Storage::_function) == 0) + throw EmptyFunction(); + + if (reinterpret_cast(Storage::_object) != 0) + throw NonMemberFunction(); + + return (reinterpret_cast< typename Function0Traits < R >::ObjType *>(object)->*(Storage::_function))(); + } }; template < typename R, typename A0 > @@ -251,10 +275,15 @@ namespace Function typedef StorageBase < Function1Traits < R, A0 > > Storage; template < typename Functor > - Function1(Functor f): Storage(f) {}; + Function1(const Functor f) + : Storage(f) {}; template < typename Functor > - Function1(Functor & f, bool m): Storage(f, m) {}; + Function1(Functor & f, bool m) + : Storage(f, m) {}; + + Function1(const typename Function1Traits < R, A0 >::FunType * m) + : Storage(m) {}; Function1() {}; @@ -265,6 +294,18 @@ namespace Function return ((Storage::_object)->*(Storage::_function))(a0); } + + template < typename Object > + R operator()(Object * object, A0 a0) + { + if (reinterpret_cast(Storage::_function) == 0) + throw EmptyFunction(); + + if (reinterpret_cast(Storage::_object) != 0) + throw NonMemberFunction(); + + return (reinterpret_cast< typename Function1Traits < R, A0 >::ObjType *>(object)->*(Storage::_function))(a0); + } }; template < typename R, typename A0, typename A1 > @@ -273,10 +314,15 @@ namespace Function typedef StorageBase < Function2Traits < R, A0, A1 > > Storage; template < typename Functor > - Function2(Functor f): Storage(f) {}; + Function2(const Functor f) + : Storage(f) {}; template < typename Functor > - Function2(Functor & f, bool m): Storage(f, m) {}; + Function2(Functor & f, bool m) + : Storage(f, m) {}; + + Function2(const typename Function2Traits < R, A0, A1 >::FunType * m) + : Storage(m) {}; Function2() {}; @@ -287,6 +333,18 @@ namespace Function return ((Storage::_object)->*(Storage::_function))(a0, a1); } + + template < typename Object > + R operator()(Object * object, A0 a0, A1 a1) + { + if (reinterpret_cast(Storage::_function) == 0) + throw EmptyFunction(); + + if (reinterpret_cast(Storage::_object) != 0) + throw NonMemberFunction(); + + return (reinterpret_cast< typename Function2Traits < R, A0, A1 >::ObjType *>(object)->*(Storage::_function))(a0, a1); + } }; template < typename R, typename A0, typename A1, typename A2 > @@ -295,20 +353,37 @@ namespace Function typedef StorageBase < Function3Traits < R, A0, A1, A2 > > Storage; template < typename Functor > - Function3(Functor f): Storage(f) {}; + Function3(const Functor f) + : Storage(f) {}; template < typename Functor > - Function3(Functor & f, bool m): Storage(f, m) {}; + Function3(Functor & f, bool m) + : Storage(f, m) {}; + + Function3(const typename Function3Traits < R, A0, A1, A2 >::FunType * m) + : Storage(m) {}; Function3() {}; R operator()(A0 a0, A1 a1, A2 a2) { - if (reinterpret_cast(Storage::_object) == 0) + if (reinterpret_cast(Storage::_object) == 0) throw EmptyFunction(); return ((Storage::_object)->*(Storage::_function))(a0, a1, a2); } + + template < typename Object > + R operator()(Object * object, A0 a0, A1 a1, A2 a2) + { + if (reinterpret_cast(Storage::_function) == 0) + throw EmptyFunction(); + + if (reinterpret_cast(Storage::_object) != 0) + throw NonMemberFunction(); + + return (reinterpret_cast< typename Function3Traits < R, A0, A1, A2 >::ObjType *>(object)->*(Storage::_function))(a0, a1, a2); + } }; template < typename R, typename A0, typename A1, typename A2, typename A3 > @@ -317,10 +392,15 @@ namespace Function typedef StorageBase < Function4Traits < R, A0, A1, A2, A3 > > Storage; template < typename Functor > - Function4(Functor f): Storage(f) {}; + Function4(const Functor f) + : Storage(f) {}; template < typename Functor > - Function4(Functor & f, bool m): Storage(f, m) {}; + Function4(Functor & f, bool m) + : Storage(f, m) {}; + + Function4(const typename Function4Traits < R, A0, A1, A2, A3 >::FunType * m) + : Storage(m) {}; Function4() {}; @@ -331,6 +411,18 @@ namespace Function return ((Storage::_object)->*(Storage::_function))(a0, a1, a2, a3); } + + template < typename Object > + R operator()(Object * object, A0 a0, A1 a1, A2 a2, A3 a3) + { + if (reinterpret_cast(Storage::_function) == 0) + throw EmptyFunction(); + + if (reinterpret_cast(Storage::_object) != 0) + throw NonMemberFunction(); + + return (reinterpret_cast< typename Function4Traits < R, A0, A1, A2, A3 >::ObjType *>(object)->*(Storage::_function))(a0, a1, a2, a3); + } }; }; diff --git a/src/mod/endpoints/mod_khomp/commons/initializer.hpp b/src/mod/endpoints/mod_khomp/commons/base/initializer.hpp similarity index 86% rename from src/mod/endpoints/mod_khomp/commons/initializer.hpp rename to src/mod/endpoints/mod_khomp/commons/base/initializer.hpp index e0e110d49c..16359e8c97 100644 --- a/src/mod/endpoints/mod_khomp/commons/initializer.hpp +++ b/src/mod/endpoints/mod_khomp/commons/base/initializer.hpp @@ -47,32 +47,32 @@ template < typename Type > struct Initializer: public std::vector< Type > { - typedef std::vector< Type > super; + typedef std::vector< Type > Super; - Initializer(Type e) { push_back(e); }; - Initializer(Type & e) { push_back(e); }; + Initializer(Type e) { Super::push_back(e); }; + Initializer(Type & e) { Super::push_back(e); }; - Initializer & operator&(Initializer v) + Initializer & operator&(const Initializer v) { - insert(super::end(), v.begin(), v.end()); + Super::insert(Super::end(), v.begin(), v.end()); return *this; }; Initializer & operator&(Initializer & v) { - insert(super::end(), v.begin(), v.end()); + Super::insert(Super::end(), v.begin(), v.end()); return *this; }; Initializer & operator&(Type v) { - insert(super::end(), v); + Super::insert(Super::end(), v); return *this; }; Initializer & operator&(Type & v) { - insert(super::end(), v); + Super::insert(Super::end(), v); return *this; }; }; diff --git a/src/mod/endpoints/mod_khomp/commons/k3lapi.cpp b/src/mod/endpoints/mod_khomp/commons/base/k3lapi.cpp similarity index 77% rename from src/mod/endpoints/mod_khomp/commons/k3lapi.cpp rename to src/mod/endpoints/mod_khomp/commons/base/k3lapi.cpp index f5afa1348f..09f5c81c0e 100644 --- a/src/mod/endpoints/mod_khomp/commons/k3lapi.cpp +++ b/src/mod/endpoints/mod_khomp/commons/base/k3lapi.cpp @@ -41,18 +41,16 @@ #include -#include -#include +#include -K3LAPI::K3LAPI(bool has_exceptions) -: _has_exceptions(has_exceptions), - _device_count(0), _channel_count(0), _link_count(0), +K3LAPIBase::K3LAPIBase() +: _device_count(0), _channel_count(0), _link_count(0), _device_config(0), _channel_config(0), _link_config(0) {}; /* initialize the whole thing! */ -void K3LAPI::start(void) +void K3LAPIBase::start(void) { /* tie the used k3l to the compiled k3l version */ char *ret = k3lStart(k3lApiMajorVersion, k3lApiMinorVersion, 0); //k3lApiBuildVersion); @@ -64,7 +62,7 @@ void K3LAPI::start(void) init(); } -void K3LAPI::stop(void) +void K3LAPIBase::stop(void) { k3lStop(); fini(); @@ -72,7 +70,7 @@ void K3LAPI::stop(void) /* envio de comandos para placa */ -void K3LAPI::mixer(int32 dev, int32 obj, byte track, KMixerSource src, int32 index) +void K3LAPIBase::mixer(int32 dev, int32 obj, byte track, KMixerSource src, int32 index) const { KMixerCommand mix; @@ -83,7 +81,7 @@ void K3LAPI::mixer(int32 dev, int32 obj, byte track, KMixerSource src, int32 ind command(dev, obj, CM_MIXER, (const char *) &mix); } -void K3LAPI::mixerRecord(int32 dev, int32 obj, byte track, KMixerSource src, int32 index) +void K3LAPIBase::mixerRecord(int32 dev, KDeviceType type, int32 obj, byte track, KMixerSource src, int32 index) const { /* estes buffers *NAO PODEM SER ESTATICOS*! */ char cmd[] = { 0x3f, 0x03, (char)obj, (char)track, 0xff, 0xff }; @@ -131,12 +129,12 @@ void K3LAPI::mixerRecord(int32 dev, int32 obj, byte track, KMixerSource src, int break; } - int32 dsp = get_dsp(dev, DSP_AUDIO); + int32 dsp = get_dsp(type, DSP_AUDIO); raw_command(dev, dsp, cmd, sizeof(cmd)); } -void K3LAPI::mixerCTbus(int32 dev, int32 obj, byte track, KMixerSource src, int32 index) +void K3LAPIBase::mixerCTbus(int32 dev, int32 obj, byte track, KMixerSource src, int32 index) const { KMixerCommand mix; @@ -147,12 +145,12 @@ void K3LAPI::mixerCTbus(int32 dev, int32 obj, byte track, KMixerSource src, int3 command(dev, obj, CM_MIXER_CTBUS, (const char *) &mix); } -void K3LAPI::command(int32 dev, int32 obj, int32 code, std::string & str) +void K3LAPIBase::command(int32 dev, int32 obj, int32 code, std::string & str) const { command(dev, obj, code, str.c_str()); } -void K3LAPI::command (int32 dev, int32 obj, int32 code, const char * parms) +void K3LAPIBase::command (int32 dev, int32 obj, int32 code, const char * parms) const { K3L_COMMAND cmd; @@ -166,12 +164,12 @@ void K3LAPI::command (int32 dev, int32 obj, int32 code, const char * parms) throw failed_command(code, dev, obj, rc); } -void K3LAPI::raw_command(int32 dev, int32 dsp, std::string & str) +void K3LAPIBase::raw_command(int32 dev, int32 dsp, std::string & str) const { raw_command(dev, dsp, str.data(), str.size()); } -void K3LAPI::raw_command(int32 dev, int32 dsp, const char * cmds, int32 size) +void K3LAPIBase::raw_command(int32 dev, int32 dsp, const char * cmds, int32 size) const { std::string str(cmds, size); @@ -181,7 +179,7 @@ void K3LAPI::raw_command(int32 dev, int32 dsp, const char * cmds, int32 size) throw failed_raw_command(dev, dsp, rc); } -KLibraryStatus K3LAPI::get_param(K3L_EVENT *ev, const char *name, std::string &res) +KLibraryStatus K3LAPIBase::get_param(K3L_EVENT *ev, const char *name, std::string &res) const { char tmp_param[256]; memset((void*)tmp_param, 0, sizeof(tmp_param)); @@ -195,7 +193,7 @@ KLibraryStatus K3LAPI::get_param(K3L_EVENT *ev, const char *name, std::string &r return ksSuccess; } -std::string K3LAPI::get_param(K3L_EVENT *ev, const char *name) +std::string K3LAPIBase::get_param(K3L_EVENT *ev, const char *name) const { std::string res; @@ -207,7 +205,7 @@ std::string K3LAPI::get_param(K3L_EVENT *ev, const char *name) return res; } -void K3LAPI::init(void) +void K3LAPIBase::init(void) { if (_device_count != 0) return; @@ -217,20 +215,16 @@ void K3LAPI::init(void) _device_config = new device_conf_type[_device_count]; _channel_config = new channel_ptr_conf_type[_device_count]; _link_config = new link_ptr_conf_type[_device_count]; - _channel_count = new unsigned int[_device_count]; - _link_count = new unsigned int[_device_count]; + _channel_count = new unsigned int[_device_count]; + _link_count = new unsigned int[_device_count]; for (unsigned int dev = 0; dev < _device_count; dev++) { - KLibraryStatus ret = ksSuccess; - _device_type[dev] = (KDeviceType) k3lGetDeviceType(dev); /* caches each device config */ - ret = (KLibraryStatus)k3lGetDeviceConfig(dev, ksoDevice + dev, &(_device_config[dev]), sizeof(_device_config[dev])); - - if (ret != ksSuccess) - throw start_failed(STG(FMT("k3lGetDeviceConfig(dev=%d): %s") % dev % Verbose::status(ret))); + if (k3lGetDeviceConfig(dev, ksoDevice + dev, &(_device_config[dev]), sizeof(_device_config[dev])) != ksSuccess) + throw start_failed("k3lGetDeviceConfig(device)"); /* adjust channel/link count for device */ _channel_count[dev] = _device_config[dev].ChannelCount; @@ -241,10 +235,9 @@ void K3LAPI::init(void) for (unsigned int obj = 0; obj < _channel_count[dev]; obj++) { - ret = (KLibraryStatus)k3lGetDeviceConfig(dev, ksoChannel + obj, &(_channel_config[dev][obj]), sizeof(_channel_config[dev][obj])); - - if (ret != ksSuccess) - throw start_failed(STG(FMT("k3lGetDeviceConfig(dev=%d,chan=%d): %s") % dev % obj % Verbose::status(ret))); + if (k3lGetDeviceConfig(dev, ksoChannel + obj, &(_channel_config[dev][obj]), + sizeof(_channel_config[dev][obj])) != ksSuccess) + throw start_failed("k3lGetDeviceConfig(channel)"); } /* adjust link count for device */ @@ -255,15 +248,14 @@ void K3LAPI::init(void) for (unsigned int obj = 0; obj < _link_count[dev]; obj++) { - ret = (KLibraryStatus)k3lGetDeviceConfig(dev, ksoLink + obj, &(_link_config[dev][obj]), sizeof(_link_config[dev][obj])); - - if (ret != ksSuccess) - throw start_failed(STG(FMT("k3lGetDeviceConfig(dev=%d,link=%d): %s") % dev % obj % Verbose::status(ret))); + if (k3lGetDeviceConfig(dev, ksoLink + obj, &(_link_config[dev][obj]), + sizeof(_link_config[dev][obj])) != ksSuccess) + throw start_failed("k3lGetDeviceConfig(link)"); } } } -void K3LAPI::fini(void) +void K3LAPIBase::fini(void) { for (unsigned int dev = 0; dev < _device_count; dev++) { @@ -290,9 +282,9 @@ void K3LAPI::fini(void) if (_link_count) { delete[] _link_count; _link_count = NULL; } } -int32 K3LAPI::get_dsp(int32 dev, K3LAPI::DspType type) +int32 K3LAPIBase::get_dsp(KDeviceType devtype, K3LAPI::DspType type) const { - switch (device_type(dev)) + switch (devtype) { case kdtFXO: case kdtFXOVoIP: @@ -311,3 +303,7 @@ int32 K3LAPI::get_dsp(int32 dev, K3LAPI::DspType type) } } +int32 K3LAPIBase::get_dsp(const K3LAPIBase::GenericTarget & tgt, K3LAPI::DspType type) const +{ + return get_dsp(_device_type[tgt.device], type); +} diff --git a/src/mod/endpoints/mod_khomp/commons/k3lapi.hpp b/src/mod/endpoints/mod_khomp/commons/base/k3lapi.hpp similarity index 50% rename from src/mod/endpoints/mod_khomp/commons/k3lapi.hpp rename to src/mod/endpoints/mod_khomp/commons/base/k3lapi.hpp index 596548405b..ef12a3f676 100644 --- a/src/mod/endpoints/mod_khomp/commons/k3lapi.hpp +++ b/src/mod/endpoints/mod_khomp/commons/base/k3lapi.hpp @@ -40,6 +40,9 @@ */ #include +#include + +#include #include @@ -59,15 +62,110 @@ #ifndef _K3LAPI_HPP_ #define _K3LAPI_HPP_ -struct K3LAPI +struct K3LAPITraits { + struct invalid_device; + struct invalid_channel; + struct invalid_link; + + struct invalid_target: public std::runtime_error + { + friend class invalid_device; + friend class invalid_channel; + friend class invalid_link; + + const int32 device, object; + + protected: + invalid_target(int32 _device, int32 _object, const std::string & msg) + : std::runtime_error(msg), device(_device), object(_object) {}; + }; + + struct invalid_device: public invalid_target + { + invalid_device(int32 _device) + : invalid_target(_device, -1, STG(FMT("invalid device number '%d'") % _device)) {}; + }; + + struct invalid_channel: public invalid_target + { + invalid_channel(int32 _device, int32 _channel) + : invalid_target(_device, _channel, STG(FMT("invalid channel number '%d' on device '%d'") % _channel % _device)) {}; + }; + + struct invalid_link: public invalid_target + { + invalid_link(int32 _device, int32 _link) + : invalid_target(_device, _link, STG(FMT("invalid link number '%d' on device '%d'") % _link % _device)) {}; + }; +}; + +struct K3LAPIBase +{ + /* High level checked object identifier. */ + + struct GenericTarget + { + typedef enum { DEVICE, CHANNEL, MIXER, LINK } Type; + + GenericTarget(const K3LAPIBase & k3lapi, Type _type, int32 _device, int32 _object) + : type(_type), device((unsigned int)_device), object((unsigned int)_object) + { + switch (_type) + { + case DEVICE: + if (!k3lapi.valid_device(_device)) + throw K3LAPITraits::invalid_device(_device); + break; + + case CHANNEL: + case MIXER: + if (!k3lapi.valid_channel(_device, _object)) + throw K3LAPITraits::invalid_channel(_device, _object); + break; + + case LINK: + if (!k3lapi.valid_link(_device, _object)) + throw K3LAPITraits::invalid_link(_device, _object); + break; + } + }; + + const Type type; + + const unsigned int device; + const unsigned int object; + }; + +/* + struct LinkTarget : public GenericTarget + { + LinkTarget(const K3LAPIBase & k3lapi, int32 _device, int32 _object) + : GenericTarget(k3lapi, GenericTarget::LINK, _device, _object) {}; + }; + + struct ChannelTarget : public GenericTarget + { + ChannelTarget(const K3LAPIBase & k3lapi, int32 _device, int32 _object) + : GenericTarget(k3lapi, GenericTarget::CHANNEL, _device, _object) {}; + }; + +*/ + template < GenericTarget::Type T > + struct Target: public GenericTarget + { + Target(const K3LAPIBase & k3lapi, int32 _device, int32 _object) + : GenericTarget(k3lapi, T, _device, _object) {}; + +// operator const GenericTarget&() const { return static_cast(*this); }; + }; + /* exceptions */ - struct start_failed + struct start_failed: public std::runtime_error { - start_failed(const char * _msg) : msg(_msg) {}; - start_failed(std::string _msg) : msg(_msg) {}; - std::string msg; + start_failed(const char * msg) + : std::runtime_error(msg) {}; }; struct failed_command @@ -91,30 +189,6 @@ struct K3LAPI int32 rc; }; - struct invalid_device - { - invalid_device(int32 _device) - : device(_device) {}; - - int32 device; - }; - - struct invalid_channel - { - invalid_channel(int32 _device, int32 _channel) - : device(_device), channel(_channel) {}; - - int32 device, channel; - }; - - struct invalid_link - { - invalid_link(unsigned int _device, unsigned int _link) - : device(_device), link(_link) {}; - - int32 device, link; - }; - struct get_param_failed { get_param_failed(std::string _name, int32 _rc) @@ -124,6 +198,8 @@ struct K3LAPI KLibraryStatus rc; }; + /* typedefs essenciais */ + typedef K3L_DEVICE_CONFIG device_conf_type; typedef K3L_CHANNEL_CONFIG channel_conf_type; typedef K3L_CHANNEL_CONFIG * channel_ptr_conf_type; @@ -132,8 +208,8 @@ struct K3LAPI /* constructors/destructors */ - K3LAPI(bool has_exceptions = false); - virtual ~K3LAPI() {}; + K3LAPIBase(); + virtual ~K3LAPIBase() {}; /* (init|final)ialize the whole thing! */ @@ -142,239 +218,106 @@ struct K3LAPI /* verificacao de intervalos */ - inline bool valid_device(int32 dev) + inline bool valid_device(int32 dev) const { return (dev >= 0 && dev < ((int32)_device_count)); } - inline bool valid_channel(int32 dev, int32 obj) + inline bool valid_channel(int32 dev, int32 obj) const { return (valid_device(dev) && obj >= 0 && obj < ((int32)_channel_count[dev])); } - inline bool valid_link(int32 dev, int32 obj) + inline bool valid_link(int32 dev, int32 obj) const { return (valid_device(dev) && obj >= 0 && obj < ((int32)_link_count[dev])); } - /*! - \brief High level object identifier - Since Khomp works with an object concept, this is used to map the - object id with its proper type. - */ - struct target - { - /*! The types a target can have */ - typedef enum { DEVICE, CHANNEL, MIXER, LINK } target_type; - - target(K3LAPI & k3lapi, target_type type_init, int32 device_value, int32 object_value) - : type(type_init), - device((unsigned short)device_value), - object((unsigned short)object_value) - { - switch (type_init) - { - case DEVICE: - if (!k3lapi.valid_device(device_value)) - throw invalid_device(device_value); - break; - - case CHANNEL: - case MIXER: - if (!k3lapi.valid_channel(device_value, object_value)) - throw invalid_channel(device_value, object_value); - break; - - case LINK: - if (!k3lapi.valid_link(device_value, object_value)) - throw invalid_link(device_value, object_value); - break; - } - - }; - - const target_type type; - - const unsigned short device; - const unsigned short object; - }; - /* envio de comandos para placa (geral) */ - void raw_command(int32 dev, int32 dsp, std::string & str); - void raw_command(int32 dev, int32 dsp, const char * cmds, int32 size); + void raw_command(int32 dev, int32 dsp, std::string & str) const; + void raw_command(int32 dev, int32 dsp, const char * cmds, int32 size) const; /* obter dados 'cacheados' (geral) */ - inline unsigned int device_count(void) + inline unsigned int device_count(void) const { return _device_count; } /* envio de comandos para placa (sem identificadores) */ - void mixer(int32 dev, int32 obj, byte track, KMixerSource src, int32 index); - void mixerRecord(int32 dev, int32 obj, byte track, KMixerSource src, int32 index); - void mixerCTbus(int32 dev, int32 obj, byte track, KMixerSource src, int32 index); + void mixer(int32 dev, int32 obj, byte track, KMixerSource src, int32 index) const; + void mixerRecord(int32 dev, KDeviceType type, int32 obj, byte track, KMixerSource src, int32 index) const; + void mixerCTbus(int32 dev, int32 obj, byte track, KMixerSource src, int32 index) const; - void command (int32 dev, int32 obj, int32 code, std::string & str); - void command (int32 dev, int32 obj, int32 code, const char * parms = NULL); + void command (int32 dev, int32 obj, int32 code, std::string & str) const; + void command (int32 dev, int32 obj, int32 code, const char * parms = NULL) const; - /* obter dados 'cacheados' (sem identificadores) */ - - inline unsigned int channel_count(int32 dev) - { - if (!valid_device(dev)) - { - if (_has_exceptions) - throw invalid_device(dev); - else - return 0; - } - - return _channel_count[dev]; - } - - inline unsigned int link_count(int32 dev) - { - if (!valid_device(dev)) - { - if (_has_exceptions) - throw invalid_device(dev); - else - return 0; - } - - return _link_count[dev]; - } - - inline uint32 channel_stats(int32 dev, int32 obj, uint32 index) - { - if (!valid_channel(dev, obj)) - { - if (_has_exceptions) - throw invalid_channel(dev, obj); - else - return 0; - } - - uint32 res_value = (uint32)-1; - stt_code stt_res = ksFail; - -#if K3L_AT_LEAST(2,1,0) - stt_res = k3lGetChannelStats(dev, obj, index, &res_value); -#endif - - if(stt_res != ksSuccess) - { - return (uint32)-1; - } - - return res_value; - } - - KDeviceType device_type(int32 dev) - { - if (!valid_device(dev)) - { - if (_has_exceptions) - throw invalid_device(dev); - else - return kdtDevTypeCount; - } - - return _device_type[dev]; - } - - - K3L_DEVICE_CONFIG & device_config(int32 dev) - { - if (!valid_device(dev)) - throw invalid_device(dev); - - return _device_config[dev]; - } - - K3L_CHANNEL_CONFIG & channel_config(int32 dev, int32 obj) - { - if (!valid_channel(dev, obj)) - throw invalid_channel(dev, obj); - - return _channel_config[dev][obj]; - } - - K3L_LINK_CONFIG & link_config(int32 dev, int32 obj) - { - if (!valid_link(dev, obj)) - throw invalid_channel(dev, obj); - - return _link_config[dev][obj]; - } /* envio de comandos para placa (com identificadores) */ - void mixer(target & tgt, byte track, KMixerSource src, int32 index) + void mixer(const GenericTarget & tgt, byte track, KMixerSource src, int32 index) const { - mixer((int32)tgt.device, (int32)tgt.object, track, src, index); + mixer(tgt.device, tgt.object, track, src, index); } - void mixerRecord(target & tgt, byte track, KMixerSource src, int32 index) + void mixerRecord(const GenericTarget & tgt, byte track, KMixerSource src, int32 index) const { - mixerRecord((int32)tgt.device, (int32)tgt.object, track, src, index); + mixerRecord((int32)tgt.device, _device_type[tgt.device], (int32)tgt.object, track, src, index); } - void mixerCTbus(target & tgt, byte track, KMixerSource src, int32 index) + void mixerCTbus(const GenericTarget & tgt, byte track, KMixerSource src, int32 index) const { mixerCTbus((int32)tgt.device, (int32)tgt.object, track, src, index); } - void command (target & tgt, int32 code, std::string & str) + void command(const GenericTarget & tgt, int32 code, std::string & str) const { command((int32)tgt.device, (int32)tgt.object, code, str); }; - void command (target & tgt, int32 code, const char * parms = NULL) + void command(const GenericTarget & tgt, int32 code, const char * parms = NULL) const { command((int32)tgt.device, (int32)tgt.object, code, parms); }; /* obter dados 'cacheados' (com indentificadores) */ - inline unsigned int channel_count(target & tgt) + inline unsigned int channel_count(const GenericTarget & tgt) const { return _channel_count[tgt.device]; } - inline unsigned int link_count(target & tgt) + inline unsigned int link_count(const GenericTarget & tgt) const { return _link_count[tgt.device]; } - KDeviceType device_type(target & tgt) + KDeviceType device_type(const GenericTarget & tgt) const { return _device_type[tgt.device]; } - - K3L_DEVICE_CONFIG & device_config(target & tgt) + const K3L_DEVICE_CONFIG & device_config(const GenericTarget & tgt) const { return _device_config[tgt.device]; } - K3L_CHANNEL_CONFIG & channel_config(target & tgt) + const K3L_CHANNEL_CONFIG & channel_config(const Target & tgt) const { return _channel_config[tgt.device][tgt.object]; } - K3L_LINK_CONFIG & link_config(target & tgt) + const K3L_LINK_CONFIG & link_config(const Target & tgt) const { return _link_config[tgt.device][tgt.object]; } /* pega valores em strings de eventos */ - KLibraryStatus get_param(K3L_EVENT *ev, const char *name, std::string &res); - std::string get_param(K3L_EVENT *ev, const char *name); + KLibraryStatus get_param(K3L_EVENT *ev, const char *name, std::string &res) const; + std::string get_param(K3L_EVENT *ev, const char *name) const; /* inicializa valores em cache */ @@ -389,12 +332,12 @@ struct K3LAPI DSP_SIGNALING, }; - int32 get_dsp(int32, DspType); + int32 get_dsp(KDeviceType, DspType) const; + + int32 get_dsp(const GenericTarget &, DspType) const; protected: - const bool _has_exceptions; - unsigned int _device_count; unsigned int * _channel_count; unsigned int * _link_count; @@ -405,4 +348,145 @@ struct K3LAPI KDeviceType * _device_type; }; +/* exceptions */ +template < bool E = false > +struct K3LAPIException +{ + void invalid_device(const int32 device) const + { + /* NOTHING */ + } + + void invalid_channel(const int32 device, const int32 channel) const + { + /* NOTHING */ + } + + void invalid_link(const int32 device, const int32 link) const + { + /* NOTHING */ + } +}; + +template < > +struct K3LAPIException < true > +{ + void invalid_device(const int32 device) const + { + throw K3LAPITraits::invalid_device(device); + } + + void invalid_channel(const int32 device, const int32 channel) const + { + throw K3LAPITraits::invalid_channel(device, channel); + } + + void invalid_link(const int32 device, const int32 link) const + { + throw K3LAPITraits::invalid_link(device, link); + } +}; + +template < bool E = false > +struct K3LAPITemplate: public K3LAPIBase, protected K3LAPIException < E > +{ + using K3LAPIBase::device_config; + using K3LAPIBase::channel_config; + using K3LAPIBase::link_config; + + using K3LAPIBase::device_type; + using K3LAPIBase::get_dsp; + + using K3LAPIBase::mixerRecord; + + /* obter dados 'cacheados' (sem identificadores) */ + + inline unsigned int channel_count(int32 dev) const + { + if (!valid_device(dev)) + { + K3LAPIException< E >::invalid_device(dev); + return 0; + } + + return _channel_count[dev]; + } + + inline unsigned int link_count(int32 dev) const + { + if (!valid_device(dev)) + { + K3LAPIException< E >::invalid_device(dev); + return 0; + } + + return _link_count[dev]; + } + + inline uint32 channel_stats(int32 dev, int32 obj, uint32 index) const + { + if (!valid_channel(dev, obj)) + { + K3LAPIException< E >::invalid_channel(dev, obj); + return 0u; + } + + uint32 res_value = 0u; + +#if K3L_AT_LEAST(2,1,0) + if (k3lGetChannelStats(dev, obj, index, &res_value) != ksSuccess) + return 0u; + + return res_value; +#endif + } + + KDeviceType device_type(int32 dev) const + { + if (!valid_device(dev)) + { + K3LAPIException< E >::invalid_device(dev); + return kdtDevTypeCount; + } + + return _device_type[dev]; + } + + const K3L_DEVICE_CONFIG & device_config(int32 dev) const + { + if (!valid_device(dev)) + throw K3LAPITraits::invalid_device(dev); + + return _device_config[dev]; + } + + const K3L_CHANNEL_CONFIG & channel_config(int32 dev, int32 obj) const + { + if (!valid_channel(dev, obj)) + throw K3LAPITraits::invalid_channel(dev, obj); + + return _channel_config[dev][obj]; + } + + const K3L_LINK_CONFIG & link_config(int32 dev, int32 obj) const + { + if (!valid_link(dev, obj)) + throw K3LAPITraits::invalid_link(dev, obj); + + return _link_config[dev][obj]; + } + + int32 get_dsp(int32 dev, DspType type) const + { + return get_dsp(device_type(dev), type); + } + + void mixerRecord(int32 dev, int32 obj, byte track, KMixerSource src, int32 index) const + { + mixerRecord(dev, device_type(dev), obj, track, src, index); + } +}; + +typedef K3LAPITemplate<> K3LAPI; + #endif /* _K3LAPI_HPP_ */ diff --git a/src/mod/endpoints/mod_khomp/commons/k3lutil.cpp b/src/mod/endpoints/mod_khomp/commons/base/k3lutil.cpp similarity index 83% rename from src/mod/endpoints/mod_khomp/commons/k3lutil.cpp rename to src/mod/endpoints/mod_khomp/commons/base/k3lutil.cpp index 83ac82efae..3fda813a03 100644 --- a/src/mod/endpoints/mod_khomp/commons/k3lutil.cpp +++ b/src/mod/endpoints/mod_khomp/commons/base/k3lutil.cpp @@ -46,7 +46,8 @@ std::string K3LUtil::channelStatus(int32 dev, int32 channel, { try { - K3L_CHANNEL_CONFIG & config = _k3lapi.channel_config(dev, channel); + const K3L_CHANNEL_CONFIG & config = _k3lapi.channel_config(dev, channel); + K3L_CHANNEL_STATUS status; KLibraryStatus ret = (KLibraryStatus) k3lGetDeviceStatus (dev, @@ -60,7 +61,7 @@ std::string K3LUtil::channelStatus(int32 dev, int32 channel, : "Unknown (fail)"); } } - catch(K3LAPI::invalid_channel & e) + catch(K3LAPITraits::invalid_channel & e) { return (fmt == Verbose::EXACT ? "" : "Unknown (fail)"); } @@ -83,64 +84,35 @@ std::string K3LUtil::callStatus(int32 dev, int32 channel, } std::string K3LUtil::linkStatus(int32 dev, int32 link, - Verbose::Presentation fmt, KSignaling sig) + Verbose::Presentation fmt, KSignaling signaling, bool simpleStatus) { try { - if (sig == ksigInactive) + if (signaling == ksigInactive) { - K3L_LINK_CONFIG & config = _k3lapi.link_config(dev, link); - sig = config.Signaling; + const K3L_LINK_CONFIG & config = _k3lapi.link_config(dev, link); + signaling = config.Signaling; } - K3L_LINK_STATUS status; + K3L_LINK_STATUS status; KLibraryStatus ret = (KLibraryStatus) k3lGetDeviceStatus (dev, link + ksoLink, &status, sizeof(status)); switch (ret) { - case ksSuccess: return Verbose::linkStatus(sig, status.E1, fmt); + case ksSuccess: return Verbose::linkStatus(signaling, status.E1, fmt, simpleStatus); default: return (fmt == Verbose::EXACT ? "" : "Unknown (failure)"); } } - catch(K3LAPI::invalid_channel & e) + catch(K3LAPITraits::invalid_channel & e) { return (fmt == Verbose::EXACT ? "" : "Unknown (failure)"); } } -std::string K3LUtil::getLinkStatus(int32 dev, int32 link, - Verbose::Presentation fmt) -{ - switch (_k3lapi.device_type(dev)) - { -#if K3L_AT_LEAST(1,6,0) - case kdtFXS: - case kdtFXSSpx: - return linkStatus(dev, link, fmt, ksigAnalogTerminal); - -#if K3L_AT_LEAST(2,1,0) - case kdtE1FXSSpx: - if (link == 1) - return linkStatus(dev, link, fmt, ksigAnalogTerminal); -#endif -#endif - default: - break; - } - - K3L_LINK_CONFIG & conf = _k3lapi.link_config(dev, link); - - std::string res = linkStatus(dev, link, fmt); - - if (conf.ReceivingClock & 0x01) - res += (fmt == Verbose::EXACT ? ",sync" : " (sync)"); - - return res; -} unsigned int K3LUtil::physicalLinkCount(int32 dev, bool count_virtual) { @@ -199,7 +171,7 @@ unsigned int K3LUtil::physicalLinkCount(int32 dev, bool count_virtual) break; } } - catch(K3LAPI::invalid_device & e) + catch(K3LAPITraits::invalid_device & e) { return 0; } diff --git a/src/mod/endpoints/mod_khomp/commons/k3lutil.hpp b/src/mod/endpoints/mod_khomp/commons/base/k3lutil.hpp similarity index 95% rename from src/mod/endpoints/mod_khomp/commons/k3lutil.hpp rename to src/mod/endpoints/mod_khomp/commons/base/k3lutil.hpp index e547f3df6e..9d87d8b0f6 100644 --- a/src/mod/endpoints/mod_khomp/commons/k3lutil.hpp +++ b/src/mod/endpoints/mod_khomp/commons/base/k3lutil.hpp @@ -64,10 +64,8 @@ struct K3LUtil std::string linkStatus(int32, int32, Verbose::Presentation fmt = Verbose::HUMAN, - KSignaling sig = ksigInactive); - - std::string getLinkStatus(int32, int32, - Verbose::Presentation fmt = Verbose::HUMAN); + KSignaling sig = ksigInactive, + bool simpleStatus = false); unsigned int physicalLinkCount(int32 dev, bool count_virtual = false); diff --git a/src/mod/endpoints/mod_khomp/commons/logger.hpp b/src/mod/endpoints/mod_khomp/commons/base/logger.hpp similarity index 89% rename from src/mod/endpoints/mod_khomp/commons/logger.hpp rename to src/mod/endpoints/mod_khomp/commons/base/logger.hpp index 6fcf7bffe3..6c333e7b87 100644 --- a/src/mod/endpoints/mod_khomp/commons/logger.hpp +++ b/src/mod/endpoints/mod_khomp/commons/base/logger.hpp @@ -55,6 +55,7 @@ #if defined(COMMONS_LIBRARY_USING_ASTERISK) extern "C" { + #include #include } #elif defined(COMMONS_LIBRARY_USING_CALLWEAVER) @@ -443,35 +444,17 @@ struct Logger localtime_r (&tv, <); #endif - out_msg += STG(FMT("[%04d-%02d-%02d %02d:%02d:%02d] ") - % (lt.tm_year + 1900) % (lt.tm_mon + 1) % lt.tm_mday % lt.tm_hour - % lt.tm_min % lt.tm_sec); - -#elif defined(COMMONS_LIBRARY_USING_CALLWEAVER) +#elif defined(COMMONS_LIBRARY_USING_CALLWEAVER) || defined(COMMONS_LIBRARY_USING_FREESWITCH) time_t tv; struct tm lt; time (&tv); localtime_r (&tv, <); - - out_msg += STG(FMT("[%04d-%02d-%02d %02d:%02d:%02d] ") - % (lt.tm_year + 1900) % (lt.tm_mon + 1) % lt.tm_mday % lt.tm_hour - % lt.tm_min % lt.tm_sec); - -#elif defined(COMMONS_LIBRARY_USING_FREESWITCH) - time_t tv; - struct tm lt; - - time (&tv); - - localtime_r (&tv, <); - - out_msg += STG(FMT("[%04d-%02d-%02d %02d:%02d:%02d] ") - % (lt.tm_year + 1900) % (lt.tm_mon + 1) % lt.tm_mday % lt.tm_hour - % lt.tm_min % lt.tm_sec); - #endif + out_msg += STG(FMT("[%02d-%02d-%02d %02d:%02d:%02d] ") + % (lt.tm_year % 100) % (lt.tm_mon + 1) % lt.tm_mday % lt.tm_hour + % lt.tm_min % lt.tm_sec); } if (opt._flags[Option::DATETIMEMS]) @@ -497,16 +480,16 @@ struct Logger #endif #if ASTERISK_AT_LEAST(1,6,0) - out_msg += STG(FMT("[%04d-%02d-%02d %02d:%02d:%02d:%04d] ") - % (lt.tm_year + 1900) % (lt.tm_mon + 1) % lt.tm_mday % lt.tm_hour % lt.tm_min + out_msg += STG(FMT("[%02d-%02d-%02d %02d:%02d:%02d:%04d] ") + % (lt.tm_year % 100) % (lt.tm_mon + 1) % lt.tm_mday % lt.tm_hour % lt.tm_min % lt.tm_sec % (tv.tv_usec / 1000)); #else - out_msg += STG(FMT("[%04d-%02d-%02d %02d:%02d:%02d:%04d] ") - % (lt.tm_year + 1900) % (lt.tm_mon + 1) % lt.tm_mday % lt.tm_hour % lt.tm_min + out_msg += STG(FMT("[%02d-%02d-%02d %02d:%02d:%02d:%04d] ") + % (lt.tm_year % 100) % (lt.tm_mon + 1) % lt.tm_mday % lt.tm_hour % lt.tm_min % lt.tm_sec % (tv * 1000)); #endif -#elif defined(COMMONS_LIBRARY_USING_CALLWEAVER) +#elif defined(COMMONS_LIBRARY_USING_CALLWEAVER) || defined(COMMONS_LIBRARY_USING_FREESWITCH) time_t tv; struct tm lt; @@ -514,22 +497,9 @@ struct Logger localtime_r (&tv, <); - out_msg += STG(FMT("[%04d-%02d-%02d %02d:%02d:%02d:%04d] ") - % (lt.tm_year + 1900) % (lt.tm_mon + 1) % lt.tm_mday % lt.tm_hour % lt.tm_min + out_msg += STG(FMT("[%02d-%02d-%02d %02d:%02d:%02d:%04d] ") + % (lt.tm_year % 100) % (lt.tm_mon + 1) % lt.tm_mday % lt.tm_hour % lt.tm_min % lt.tm_sec % (tv * 1000)); - -#elif defined(COMMONS_LIBRARY_USING_FREESWITCH) - time_t tv; - struct tm lt; - - time (&tv); - - localtime_r (&tv, <); - - out_msg += STG(FMT("[%04d-%02d-%02d %02d:%02d:%02d:%04d] ") - % (lt.tm_year + 1900) % (lt.tm_mon + 1) % lt.tm_mday % lt.tm_hour % lt.tm_min - % lt.tm_sec % (tv * 1000)); - #endif } @@ -538,7 +508,7 @@ struct Logger if (opt._flags[Option::THREADID]) { #if defined (COMMONS_LIBRARY_USING_ASTERISK) || defined(COMMONS_LIBRARY_USING_CALLWEAVER) || defined(COMMONS_LIBRARY_USING_FREESWITCH) - out_msg += STG(FMT("t=%08p ") % ((void*)pthread_self())); + out_msg += STG(FMT("%08x ") % ((unsigned long)pthread_self())); #endif } diff --git a/src/mod/endpoints/mod_khomp/commons/noncopyable.hpp b/src/mod/endpoints/mod_khomp/commons/base/noncopyable.hpp similarity index 100% rename from src/mod/endpoints/mod_khomp/commons/noncopyable.hpp rename to src/mod/endpoints/mod_khomp/commons/base/noncopyable.hpp diff --git a/src/mod/endpoints/mod_khomp/commons/refcounter.hpp b/src/mod/endpoints/mod_khomp/commons/base/refcounter.hpp similarity index 94% rename from src/mod/endpoints/mod_khomp/commons/refcounter.hpp rename to src/mod/endpoints/mod_khomp/commons/base/refcounter.hpp index 6ba8ae8b2f..d1738185bb 100644 --- a/src/mod/endpoints/mod_khomp/commons/refcounter.hpp +++ b/src/mod/endpoints/mod_khomp/commons/base/refcounter.hpp @@ -45,6 +45,11 @@ #ifndef _REFCOUNTER_HPP_ #define _REFCOUNTER_HPP_ +#define COUNTER_CLASS(...) ReferenceCounter< __VA_ARGS__ > +#define COUNTER_SUPER(...) public COUNTER_CLASS( __VA_ARGS__ ) +#define COUNTER_REFER(o, ...) COUNTER_CLASS( __VA_ARGS__ )(static_cast< const COUNTER_CLASS( __VA_ARGS__ ) & >(o)) + +// DEPRECATED DECLARATIONS /// #define NEW_REFCOUNTER(...) public ReferenceCounter< __VA_ARGS__ > #define INC_REFCOUNTER(o, ...) ReferenceCounter< __VA_ARGS__ >(static_cast< const ReferenceCounter < __VA_ARGS__ > & >(o)) @@ -179,13 +184,13 @@ struct ReferenceCounter }; template < typename T > -struct ReferenceContainer: NEW_REFCOUNTER(ReferenceContainer< T >) +struct ReferenceContainer: COUNTER_SUPER(ReferenceContainer< T >) { /* type */ typedef T Type; /* shorthand */ - typedef ReferenceCounter < ReferenceContainer< Type > > Counter; + typedef COUNTER_CLASS(ReferenceContainer< Type >) Counter; // TODO: make this a generic exception someday struct NotFound {}; @@ -249,7 +254,7 @@ struct ReferenceContainer: NEW_REFCOUNTER(ReferenceContainer< T >) }; // return value (pointer)! - Type * operator()(void) + Type * operator()(void) const { return _reference_value; }; diff --git a/src/mod/endpoints/mod_khomp/commons/regex.cpp b/src/mod/endpoints/mod_khomp/commons/base/regex.cpp similarity index 94% rename from src/mod/endpoints/mod_khomp/commons/regex.cpp rename to src/mod/endpoints/mod_khomp/commons/base/regex.cpp index 61f941c214..d2b8cd0469 100644 --- a/src/mod/endpoints/mod_khomp/commons/regex.cpp +++ b/src/mod/endpoints/mod_khomp/commons/base/regex.cpp @@ -74,7 +74,7 @@ void Regex::Expression::initialize(void) _errorstate = regcomp(&_comp_regex, _expression, _flags); } -std::string Regex::Expression::regerror_as_string(void) +std::string Regex::Expression::regerror_as_string(void) const { unsigned int count = regerror(_errorstate, &_comp_regex, 0, 0) + 1; @@ -95,6 +95,7 @@ void Regex::Match::initialize(void) { _subcounter = (_expression.subcount() + 2); // 0 + N.. + invalid _submatches = new regmatch_t[_subcounter]; + _subcaching = new std::string[_subcounter]; _have_match = (regexec(_expression.repr(), _basestring.c_str(), _subcounter, _submatches, _flags) == 0); } @@ -117,7 +118,7 @@ std::string Regex::Match::replace(Regex::ReplaceMap & map) try { if (_submatches[0].rm_so != 0 && (map.find(0) != map.end())) - return _basestring.replace(_submatches[0].rm_so, _submatches[0].rm_eo - _submatches[0].rm_so, map.find(0)->second); + return buffer.replace(_submatches[0].rm_so, _submatches[0].rm_eo - _submatches[0].rm_so, map.find(0)->second); for (unsigned int n = 1; (_submatches[n].rm_so != -1) && (n < _subcounter); n++) { diff --git a/src/mod/endpoints/mod_khomp/commons/regex.hpp b/src/mod/endpoints/mod_khomp/commons/base/regex.hpp similarity index 78% rename from src/mod/endpoints/mod_khomp/commons/regex.hpp rename to src/mod/endpoints/mod_khomp/commons/base/regex.hpp index daf20147a8..61325238b8 100644 --- a/src/mod/endpoints/mod_khomp/commons/regex.hpp +++ b/src/mod/endpoints/mod_khomp/commons/base/regex.hpp @@ -111,12 +111,12 @@ struct Regex } } - bool valid(void) { return (_errorstate == 0); } + bool valid(void) const { return (_errorstate == 0); } - unsigned int subcount(void) { return _subcounter; } - const regex_t * repr(void) { return &_comp_regex; } + unsigned int subcount(void) const { return _subcounter; } + const regex_t * repr(void) const { return &_comp_regex; } - std::string error(void) + std::string error(void) const { switch (_errorstate) { @@ -127,31 +127,33 @@ struct Regex } private: - void initialize(void); - std::string regerror_as_string(void); + std::string regerror_as_string(void) const; + + private: + void initialize(void); protected: const char * _expression; - bool _alloced; + const bool _alloced; unsigned int _subcounter; int _errorstate; regex_t _comp_regex; - unsigned int _flags; + const unsigned int _flags; }; - struct Match: NEW_REFCOUNTER(Match) + struct Match: COUNTER_SUPER(Match) { - Match(const char * basestring, Expression & expression, unsigned int flags = 0) + Match(const char * basestring, const Expression & expression, unsigned int flags = 0) : _basestring(basestring), _expression(expression), _subcounter(0), _submatches(0), _have_match(false), _flags(flags) { initialize(); } - Match(std::string & basestring, Expression & expression, unsigned int flags = 0) + Match(const std::string & basestring, const Expression & expression, unsigned int flags = 0) : _basestring(basestring), _expression(expression), _subcounter(0), _submatches(0), _have_match(false), _flags(flags) { @@ -159,7 +161,7 @@ struct Regex } Match(const Match & o) - : INC_REFCOUNTER(o, Match), + : COUNTER_REFER(o, Match), _basestring(o._basestring), _expression(o._expression), _subcounter(o._subcounter), _submatches(o._submatches), _have_match(o._have_match), _flags(o._flags) @@ -169,6 +171,10 @@ struct Regex void unreference() { delete[] _submatches; + delete[] _subcaching; + + _submatches = 0; + _subcaching = 0; } bool matched(void) @@ -184,34 +190,23 @@ struct Regex return false; } - std::string submatch(int number) + const std::string & submatch(int number) { if (!matched(number)) - return ""; + return _subcaching[_subcounter - 1 /* invalid, always empty! */ ]; - return _basestring.substr(_submatches[number].rm_so, - _submatches[number].rm_eo - _submatches[number].rm_so); - } - - /** - * \brief gets a map with all matches - * \return std::map with all matches - * \note index 0 in map, is the complete string - * \author Eduardo Nunes Pereira - * - * If fails the empty map is returned - */ - std::map obtain_match_map() - { - int match_counter = 0; - std::map tmp_map; - while(matched(match_counter)) + if (_subcaching[number].empty()) { - tmp_map.insert(std::make_pair(match_counter,submatch(match_counter))); - match_counter++; + _subcaching[number].assign(_basestring, _submatches[number].rm_so, + _submatches[number].rm_eo - _submatches[number].rm_so); } - return tmp_map; + return _subcaching[number]; + } + + const std::string & operator[](int number) + { + return submatch(number); } /** @@ -226,25 +221,21 @@ struct Regex std::string replace(ReplaceMap &); std::string replace(std::string, unsigned int index = REP_BASE); - std::string operator[](int number) - { - return submatch(number); - } - // NOTE: there is already a way to get subcount defined on EXPRESSION class! private: void initialize(void); protected: - std::string _basestring; - Expression & _expression; + const std::string _basestring; + const Expression & _expression; unsigned int _subcounter; regmatch_t * _submatches; - + std::string * _subcaching; bool _have_match; - unsigned int _flags; + + const unsigned int _flags; }; }; diff --git a/src/mod/endpoints/mod_khomp/commons/base/ringbuffer.cpp b/src/mod/endpoints/mod_khomp/commons/base/ringbuffer.cpp new file mode 100644 index 0000000000..42056307e0 --- /dev/null +++ b/src/mod/endpoints/mod_khomp/commons/base/ringbuffer.cpp @@ -0,0 +1,485 @@ +/* + KHOMP generic endpoint/channel library. + Copyright (C) 2007-2009 Khomp Ind. & Com. + + The contents of this file are subject to the Mozilla Public License Version 1.1 + (the "License"); you may not use this file except in compliance with the + License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS IS" basis, + WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for + the specific language governing rights and limitations under the License. + + Alternatively, the contents of this file may be used under the terms of the + "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which + case the provisions of "LGPL License" are applicable instead of those above. + + If you wish to allow use of your version of this file only under the terms of + the LGPL License and not to allow others to use your version of this file under + the MPL, indicate your decision by deleting the provisions above and replace them + with the notice and other provisions required by the LGPL License. If you do not + delete the provisions above, a recipient may use your version of this file under + either the MPL or the LGPL License. + + The LGPL header follows below: + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#include + +// #include + + + /* Documentation of the formula used in the buffer arithmetic. + * + * [0|1|2|3|4|5|6|7] => size=8 + * | | + * reader | + * writer + * + * => writer has places [5,6,7,0,1] to write (5 places). + * + * => 8 - (4-2+1) = 8 - (2+1) = 8 - 3 = 5 + * + * > writer goes 1 up, amount goes 1 down. + * > reader goes 1 up, amount goes 1 up. + * > size goes 1 down, amount goes 1 down. + * + */ + +/********** BUFFER FUNCTIONS **********/ + +/* writes everything or nothing */ +bool Ringbuffer_traits::traits_provide(char * buffer, const char * value, unsigned int amount, bool do_not_overwrite) +{ + /* avoid using different values */ + Buffer_table cache = _pointers; + + bool need_overwrite = false; + + if (amount > free_blocks(cache)) + { + if (do_not_overwrite) + return false; + + /* if we are allowed to overwrite, just the buffer size matters for us */ + if (amount >= _size) + return false; + + /* we need to change reader pointer below... */ + need_overwrite = true; + } + + const unsigned int wr = cache.writer.complete; + const unsigned int wp = cache.writer.complete - 1; + + /* should we go around the buffer for writing? */ + if ((wr + amount) > _size) + { +// fprintf(stderr, "%p> first if matched\n", this); + + if (need_overwrite) + { + do + { + Buffer_pointer extra(cache.reader); + extra.complete = ((wr + amount) % _size); // (extra.complete + amount) % _size; +// extra.complete = (extra.complete + amount) % _size; + + if (update(cache.reader, extra)) + break; + } + while (true); + } + + unsigned int wr1 = _size - wr + 1; /* writer is already 1 position after */ + unsigned int wr2 = amount - wr1; + +// fprintf(stderr, "%p> partial write: (%d/%d) %d/%d [%d/%d]\n", this, wr1, wr2, amount, _size, reader, writer); + + /* two partial writes (one at the end, another at the beginning) */ + memcpy((void *) &(buffer[wp]), (const void *) (value), _block * wr1); + memcpy((void *) (buffer), (const void *) &(value[wr1]), _block * wr2); + } + else + { +// fprintf(stderr, "%p> second if matched\n", this); + + if (need_overwrite) + { + do + { + Buffer_pointer extra(cache.reader); + extra.complete = ((wr + amount) % _size); // (extra.complete + amount) % _size; + + if (update(cache.reader, extra)) + break; + } + while (true); + } + +// fprintf(stderr, "%p> full write: a=%d/s=%d [r=%d/w=%d]\n", this, amount, _size, reader, writer); + + /* we are talking about buffers here, man! */ + memcpy((void *) &(buffer[wp]), (const void *) value, _block * amount); + } + + _pointers.writer.complete = ((wp + amount) % _size) + 1; + _pointers.writer.partial = 1; + +// if (need_overwrite) +// fprintf(stdout, "%p> write end: w=%d/r=%d\n", this, _pointers.writer.complete, _pointers.reader.complete); + + return true; +} + +/* returns the number of itens that have been read */ +unsigned int Ringbuffer_traits::traits_consume(const char * buffer, char * value, unsigned int amount, bool atomic_mode) +{ + /* avoid using different values */ + Buffer_table cache = _pointers; + + const unsigned int available = used_blocks(cache); + + if (atomic_mode && amount > available) + return false; + + const unsigned int rd = _pointers.reader.complete; + + unsigned int total = std::min(amount, available); + + /* should we go around the buffer for reading? */ + if ((rd + total) >= _size) + { + unsigned int rd1 = _size - rd; + unsigned int rd2 = total - rd1; + +// fprintf(stderr, "%p> partial read: (%d/%d) %d/%d [%d/%d]\n", this, rd1, rd2, total, _size, reader, writer); + + /* two partial consumes (one at the end, another at the beginning) */ + memcpy((void *) (value), (const void *) &(buffer[rd]), _block * rd1); + memcpy((void *) &(value[rd1]), (const void *) (buffer), _block * rd2); + } + else + { +// fprintf(stderr, "%p> full read: %d/%d [%d/%d]\n", this, total, _size, reader, writer); + + /* we are talking about buffers here, man! */ + memcpy((void *) value, (const void *) &(buffer[rd]), _block * total); + } + + do + { + /* jump the reader forward */ + Buffer_pointer index((cache.reader.complete + total) % _size, 0); + + if (update(cache.reader, index)) + break; + } + while (true); + +// fprintf(stderr, "%p> read end: %d [block=%d]\n", this, reader, _block); + + return total; +} + +/********** TWO-PHASE BUFFER FUNCTIONS ***********/ + +/* returns the number of itens that have been read */ +unsigned int Ringbuffer_traits::traits_consume_begins(const char * buffer, char * value, unsigned int amount, bool atomic_mode) +{ + /* avoid using different values */ + Buffer_table cache = _pointers; + + const unsigned int available = used_blocks(cache); + + if (amount > available) + { + if (atomic_mode) + return false; + } + + const unsigned int rd = _pointers.reader.complete; + + unsigned int total = std::min(amount, available); + + /* should we go around the buffer for reading? */ + if ((rd + total) >= _size) + { + unsigned int rd1 = _size - rd; + unsigned int rd2 = total - rd1; + +// fprintf(stderr, "%p> partial read: (%d/%d) %d/%d [%d/%d]\n", this, rd1, rd2, total, _size, reader, writer); + + /* two partial consumes (one at the end, another at the beginning) */ + memcpy((void *) (value), (const void *) &(buffer[rd]), _block * rd1); + memcpy((void *) &(value[rd1]), (const void *) (buffer), _block * rd2); + } + else + { +// fprintf(stderr, "%p> full read: %d/%d [%d/%d]\n", this, total, _size, reader, writer); + + /* we are talking about buffers here, man! */ + memcpy((void *) value, (const void *) &(buffer[rd]), _block * total); + } + + return total; +} + +bool Ringbuffer_traits::traits_consume_commit(unsigned int amount) +{ + if (amount == 0) + return true; + + /* avoid using different values */ + Buffer_table cache = _pointers; + + const unsigned int available = used_blocks(cache); + + /* cannot commit more than available! */ + if (amount > available) + return false; + + unsigned int total = std::min(amount, available); + + do + { + /* jump the reader forward */ + Buffer_pointer index((cache.reader.complete + total) % _size, 0); + + if (update(cache.reader, index)) + break; + } + while (true); + +// fprintf(stderr, "%p> read end: %d [block=%d]\n", this, reader, _block); + + return true; +} + +/********** PARTIAL BUFFER FUNCTIONS (bytes) ***********/ + +/* writes everything or nothing */ +bool Ringbuffer_traits::traits_provide_partial(char * buffer, const char * value, unsigned int amount) +{ + /* avoid using different values */ + Buffer_table cache = _pointers; + + const unsigned int memsize = (_size * _block); + + if (amount > (free_blocks(cache) * _block)) + return false; + + const unsigned int wr = ((cache.writer.complete - 1) * _block) + cache.writer.partial; + const unsigned int wp = wr - 1; + + /* should we go around the buffer for writing? */ + if ((wr + amount) > memsize) + { +// fprintf(stderr, "%p> first if matched\n", this); + + unsigned int wr1 = memsize - wr + 1; /* writer is already 1 position after */ + unsigned int wr2 = amount - wr1; + +// fprintf(stderr, "%p> partial write: (%d/%d) %d/%d [%d/%d]\n", this, wr1, wr2, amount, _size, reader, writer); + + /* two partial writes (one at the end, another at the beginning) */ + memcpy((void *) &(buffer[wp]), (const void *) (value), wr1); + memcpy((void *) (buffer), (const void *) &(value[wr1]), wr2); + } + else + { +// fprintf(stderr, "%p> second if matched\n", this); + +// fprintf(stderr, "%p> full write: a=%d/s=%d [r=%d/w=%d]\n", this, amount, _size, reader, writer); + + /* we are talking about buffers here, man! */ + memcpy((void *) &(buffer[wp]), (const void *) value, amount); + } + + const unsigned int new_wp = (wp + amount) % memsize; + + _pointers.writer.complete = (unsigned int)(floor((double)new_wp / (double)_block) + 1); + _pointers.writer.partial = (new_wp % _block) + 1; + +// if (need_overwrite) +// fprintf(stdout, "%p> write end: w=%d/r=%d\n", this, _pointers.writer.complete, _pointers.reader.complete); + + return true; +} + +/* returns the number of bytes that have been read */ +unsigned int Ringbuffer_traits::traits_consume_partial(const char * buffer, char * value, unsigned int amount) +{ + /* avoid using different values */ + Buffer_table cache = _pointers; + + const unsigned int available = used_blocks(cache) * _block; + + const unsigned int rd = (_pointers.reader.complete * _block) + _pointers.reader.partial; + + const unsigned int memsize = _size * _block; + + unsigned int total = std::min(amount, available); + + /* should we go around the buffer for reading? */ + if ((rd + total) >= _size) + { + unsigned int rd1 = memsize - rd; + unsigned int rd2 = total - rd1; + +// fprintf(stderr, "%p> partial read: (%d/%d) %d/%d [%d/%d]\n", this, rd1, rd2, total, _size, reader, writer); + + /* two partial consumes (one at the end, another at the beginning) */ + memcpy((void *) (value), (const void *) &(buffer[rd]), rd1); + memcpy((void *) &(value[rd1]), (const void *) (buffer), rd2); + } + else + { +// fprintf(stderr, "%p> full read: %d/%d [%d/%d]\n", this, total, _size, reader, writer); + + /* we are talking about buffers here, man! */ + memcpy((void *) value, (const void *) &(buffer[rd]), total); + } + + do + { + const unsigned int new_rd = (((cache.reader.complete * _block) + cache.reader.partial) + total) % memsize; + + /* jump the reader forward */ + Buffer_pointer index((unsigned int)floor((double)new_rd / (double)_block), (unsigned short)(new_rd % _block)); + + if (update(cache.reader, index)) + break; + } + while (true); + +// fprintf(stderr, "%p> read end: %d [block=%d]\n", this, reader, _block); + + return total; +} + +/********** IO FUNCTIONS **********/ + +/* returns the number of items written to from buffer to stream */ +unsigned int Ringbuffer_traits::traits_put(const char * buffer, std::ostream &fd, unsigned int amount) +{ + /* avoid using different values */ + Buffer_table cache = _pointers; + + const unsigned int available = used_blocks(cache); + + if (amount > available) + return false; + + const unsigned int wr = _pointers.writer.complete; + const unsigned int rd = _pointers.reader.complete; + + unsigned int total = std::min(amount, available); + + /* should we go around the buffer for reading? */ + if ((rd + total) >= _size) + { + unsigned int rd1 = _size - rd; + unsigned int rd2 = total - rd1; + +// fprintf(stderr, "%p> partial read: (%d/%d) %d/%d [%d/%d]\n", this, rd1, rd2, total, _size, reader, writer); + + /* two partial consumes (one at the end, another at the beginning) */ + fd.write((const char *) &(buffer[rd]), _block * rd1); + fd.write((const char *) (buffer), _block * rd2); + } + else + { +// fprintf(stderr, "%p> full read: %d/%d [%d/%d]\n", this, total, _size, reader, writer); + fd.write((const char *) &(buffer[rd]), _block * total); + } + + do + { + /* jump the reader forward */ + Buffer_pointer index((cache.reader.complete + total) % _size, 0); + + if (update(cache.reader, index)) + break; + } + while (true); + +// fprintf(stderr, "%p> read end: %d [block=%d]\n", this, reader, _block); + + return total; +} + +/* returns number of items read from stream to buffer */ +unsigned int Ringbuffer_traits::traits_get(char * buffer, std::istream &fd, unsigned int amount) +{ + /* avoid using different values */ + Buffer_table cache = _pointers; + + if (amount > free_blocks(cache)) + return false; + + const unsigned int wr = cache.writer.complete; + const unsigned int wp = cache.writer.complete - 1; + + unsigned int real_amount = 0; + + /* should we go around the buffer for writing? */ + if ((wr + amount) > _size) + { +// fprintf(stderr, "%p> first if matched\n", this); + + unsigned int wr1 = _size - wr + 1; /* writer is already 1 position after */ + unsigned int wr2 = amount - wr1; + +// fprintf(stderr, "%p> partial write: (%d/%d) %d/%d [%d/%d]\n", this, wr1, wr2, amount, _size, reader, writer); + + /* two partial writes (one at the end, another at the beginning) */ + unsigned int char_amount = 0; + + /* one partial write on the buffer (at the end) */ + fd.read((char *) &(buffer[wp]), _block * wr1); + char_amount += fd.gcount(); + + if (fd.gcount() == (int)(_block * wr1)) + { + /* another partial write on the buffer (at the beginning) */ + fd.read((char *) (buffer), _block * wr2); + char_amount += fd.gcount(); + } + + real_amount = char_amount / _block; + } + else + { +// fprintf(stderr, "%p> second if matched\n", this); + +// fprintf(stderr, "%p> full write: a=%d/s=%d [r=%d/w=%d]\n", this, amount, _size, reader, writer); + + /* we are talking about buffers here, man! */ + fd.read((char *) &(buffer[wp]), _block * amount); + + real_amount = fd.gcount() / _block; + } + + _pointers.writer.complete = ((wp + amount) % _size) + 1; + _pointers.writer.partial = 1; + +// fprintf(stdout, "%p> write end: %d\n", this, _pointers.writer.complete); + + return real_amount; +} diff --git a/src/mod/endpoints/mod_khomp/commons/ringbuffer.hpp b/src/mod/endpoints/mod_khomp/commons/base/ringbuffer.hpp similarity index 88% rename from src/mod/endpoints/mod_khomp/commons/ringbuffer.hpp rename to src/mod/endpoints/mod_khomp/commons/base/ringbuffer.hpp index 39f8ffe8fb..b9ecd7e6bd 100644 --- a/src/mod/endpoints/mod_khomp/commons/ringbuffer.hpp +++ b/src/mod/endpoints/mod_khomp/commons/base/ringbuffer.hpp @@ -46,6 +46,12 @@ Also, it works only for single-reader + single-writer, since it does not depends on external mutex functions. + + NOTE: for single element provide/consume, this abstraction has standard C++ semantics. + + for multiple and partial element provide/consume, memcpy is used - thus complex C++ + objects which need correct copy constructor semantics should not copied this way. + */ #include @@ -61,7 +67,7 @@ struct Buffer_pointer { - Buffer_pointer(unsigned int _complete = 0u, unsigned short _partial = 0u) + Buffer_pointer(unsigned int _complete, unsigned short _partial) : complete(_complete), partial(_partial) {}; @@ -134,6 +140,10 @@ __attribute__((packed)); struct Ringbuffer_traits { + struct BufferFull {}; + struct BufferEmpty {}; + + protected: Ringbuffer_traits(unsigned int block, unsigned int size) : _block(block), _size(size) {}; @@ -155,6 +165,28 @@ struct Ringbuffer_traits return Atomic::doCAS(&(_pointers.reader), &cache, update); } + inline unsigned int free_blocks(const Buffer_table & cache) const + { + const unsigned int r = cache.reader.complete; + const unsigned int w = cache.writer.complete; + + if (r >= w) + return (r - w); + + return _size - (w - r); + } + + inline unsigned int used_blocks(const Buffer_table & cache) const + { + const unsigned int r = cache.reader.complete; + const unsigned int w = cache.writer.complete; + + if (r >= w) + return (_size - (r - w)) - 1; + + return (w - r) - 1; + } + protected: const unsigned int _block; const unsigned int _size; @@ -163,11 +195,8 @@ struct Ringbuffer_traits }; template -struct Ringbuffer: protected Ringbuffer_traits, public NonCopyable +struct Ringbuffer: public Ringbuffer_traits, public NonCopyable { - struct BufferFull {}; - struct BufferEmpty {}; - Ringbuffer(unsigned int size) : Ringbuffer_traits(sizeof(T), size) { @@ -189,15 +218,17 @@ struct Ringbuffer: protected Ringbuffer_traits, public NonCopyable } /***** GENERIC RANGE/INDEX CALCULATION FUNCTIONS *****/ - bool may_write(Buffer_table & cache) + + protected: + inline bool may_write(const Buffer_table & cache) const { const unsigned int r = cache.reader.complete; const unsigned int w = cache.writer.complete; - return (((r - w) != 1) && (!(r == 0 && w == _size))); + return (((r - w) != 0) && (!(r == 0 && w == _size))); } - bool may_read(Buffer_table & cache) + inline bool may_read(const Buffer_table & cache) const { if ((cache.writer.complete - cache.reader.complete) == 1) return false; @@ -205,7 +236,7 @@ struct Ringbuffer: protected Ringbuffer_traits, public NonCopyable return true; } - unsigned int writer_next(Buffer_pointer & cache, Buffer_pointer & index) + inline unsigned int writer_next(const Buffer_pointer & cache, Buffer_pointer & index) const { unsigned int dest = cache.complete - 1, temp = cache.complete + 1; @@ -218,7 +249,7 @@ struct Ringbuffer: protected Ringbuffer_traits, public NonCopyable return dest; }; - void reader_next(Buffer_pointer & cache, Buffer_pointer & index) + inline void reader_next(const Buffer_pointer & cache, Buffer_pointer & index) const { unsigned int temp = cache.complete + 1; @@ -230,6 +261,7 @@ struct Ringbuffer: protected Ringbuffer_traits, public NonCopyable /***** BUFFER FUNCTIONS *****/ + public: bool provide(const T & value) { Buffer_table cache = _pointers; @@ -280,9 +312,9 @@ struct Ringbuffer: protected Ringbuffer_traits, public NonCopyable } /* writes everything or nothing */ - inline bool provide(const T * value, unsigned int amount, bool skip_overwrite = true) + inline bool provide(const T * value, unsigned int amount, bool do_not_overwrite = true) { - return traits_provide((char *)_buffer, (const char *) value, amount, skip_overwrite); + return traits_provide((char *)_buffer, (const char *) value, amount, do_not_overwrite); } /* returns the number of items that have been read (atomic_mode == true means 'all or nothing') */ @@ -337,7 +369,7 @@ struct Ringbuffer: protected Ringbuffer_traits, public NonCopyable // fprintf(stderr, "%p> write: %d/%d [%d/%d]\n", this, _pointers.reader, _pointers.writer, _pointers.reader_partial, _pointers.writer_partial); } - T & consumer_start(void) + const T & consumer_start(void) { Buffer_table cache = _pointers; @@ -391,13 +423,13 @@ struct Ringbuffer: protected Ringbuffer_traits, public NonCopyable /* returns the number of items written to from buffer to stream */ inline unsigned int put(std::ostream &fd, unsigned int amount) { - return traits_put((char *)_buffer, fd, amount); + return traits_put((const char *)_buffer, fd, amount); } /* returns number of items read from stream to buffer */ inline unsigned int get(std::istream &fd, unsigned int amount) { - return traits_get((const char *)_buffer, fd, amount); + return traits_get((char *)_buffer, fd, amount); } void clear() diff --git a/src/mod/endpoints/mod_khomp/commons/saved_condition.cpp b/src/mod/endpoints/mod_khomp/commons/base/saved_condition.cpp similarity index 100% rename from src/mod/endpoints/mod_khomp/commons/saved_condition.cpp rename to src/mod/endpoints/mod_khomp/commons/base/saved_condition.cpp diff --git a/src/mod/endpoints/mod_khomp/commons/saved_condition.hpp b/src/mod/endpoints/mod_khomp/commons/base/saved_condition.hpp similarity index 100% rename from src/mod/endpoints/mod_khomp/commons/saved_condition.hpp rename to src/mod/endpoints/mod_khomp/commons/base/saved_condition.hpp diff --git a/src/mod/endpoints/mod_khomp/commons/scoped_lock.hpp b/src/mod/endpoints/mod_khomp/commons/base/scoped_lock.hpp similarity index 100% rename from src/mod/endpoints/mod_khomp/commons/scoped_lock.hpp rename to src/mod/endpoints/mod_khomp/commons/base/scoped_lock.hpp diff --git a/src/mod/endpoints/mod_khomp/commons/simple_lock.hpp b/src/mod/endpoints/mod_khomp/commons/base/simple_lock.hpp similarity index 96% rename from src/mod/endpoints/mod_khomp/commons/simple_lock.hpp rename to src/mod/endpoints/mod_khomp/commons/base/simple_lock.hpp index 4f6619f456..8f22fe6bdb 100644 --- a/src/mod/endpoints/mod_khomp/commons/simple_lock.hpp +++ b/src/mod/endpoints/mod_khomp/commons/base/simple_lock.hpp @@ -55,7 +55,7 @@ * implement the "unreference()" method for releasing resources. */ template < typename Implementor > -struct SimpleLockCommon: NEW_REFCOUNTER( SimpleLockCommon < Implementor > ) +struct SimpleLockCommon: COUNTER_SUPER( SimpleLockCommon < Implementor > ) { friend class ReferenceCounter < SimpleLockCommon < Implementor > >; @@ -71,7 +71,7 @@ struct SimpleLockCommon: NEW_REFCOUNTER( SimpleLockCommon < Implementor > ) {}; SimpleLockCommon(const SimpleLockCommon & o) - : INC_REFCOUNTER(o, SimpleLockCommon) + : COUNTER_REFER(o, SimpleLockCommon) {}; virtual ~SimpleLockCommon() diff --git a/src/mod/endpoints/mod_khomp/commons/strings.cpp b/src/mod/endpoints/mod_khomp/commons/base/strings.cpp similarity index 87% rename from src/mod/endpoints/mod_khomp/commons/strings.cpp rename to src/mod/endpoints/mod_khomp/commons/base/strings.cpp index 5e1cbc7004..b7b84025a8 100644 --- a/src/mod/endpoints/mod_khomp/commons/strings.cpp +++ b/src/mod/endpoints/mod_khomp/commons/base/strings.cpp @@ -141,6 +141,38 @@ unsigned int Strings::tokenize(const std::string & str, Strings::vector_type & t return (cur_token - 1); } +long Strings::tolong(const std::string & str, int base) +{ + return tolong(str.c_str(), base); +} + +unsigned long Strings::toulong(const std::string & str, int base) +{ + return toulong(str.c_str(), base); +} + +unsigned long long Strings::toulonglong(const std::string & str, int base) +{ + return toulonglong(str.c_str(), base); +} + +double Strings::todouble(const std::string & str) +{ + return todouble(str.c_str()); +} + +long Strings::tolong(const char * str, int base) +{ + char *str_end = 0; + + unsigned long value = strtol(str, &str_end, base); + + if (str_end && *str_end == 0) + return value; + + throw invalid_value(str); +} + bool Strings::toboolean(std::string str) { std::string tmp(str); @@ -153,11 +185,11 @@ bool Strings::toboolean(std::string str) throw invalid_value(str); } -long Strings::tolong(std::string str, int base) +unsigned long Strings::toulong(const char * str, int base) { char *str_end = 0; - unsigned long value = strtol(str.c_str(), &str_end, base); + unsigned long value = strtoul(str, &str_end, base); if (str_end && *str_end == 0) return value; @@ -165,26 +197,14 @@ long Strings::tolong(std::string str, int base) throw invalid_value(str); } -unsigned long Strings::toulong(std::string str, int base) -{ - char *str_end = 0; - - unsigned long value = strtoul(str.c_str(), &str_end, base); - - if (str_end && *str_end == 0) - return value; - - throw invalid_value(str); -} - -unsigned long long Strings::toulonglong(std::string str, int base) +unsigned long long Strings::toulonglong(const char * str, int base) { #if defined(_WINDOWS) || defined(_Windows) || defined(_WIN32) || defined(WIN32) throw not_implemented(); #else char *str_end = 0; - unsigned long long value = strtoull(str.c_str(), &str_end, base); + unsigned long long value = strtoull(str, &str_end, base); if (str_end && *str_end == 0) return value; @@ -193,11 +213,11 @@ unsigned long long Strings::toulonglong(std::string str, int base) #endif } -double Strings::todouble(std::string str) +double Strings::todouble(const char * str) { char *str_end = 0; - double value = strtod(str.c_str(), &str_end); + double value = strtod(str, &str_end); if (str_end && *str_end == 0) return value; diff --git a/src/mod/endpoints/mod_khomp/commons/strings.hpp b/src/mod/endpoints/mod_khomp/commons/base/strings.hpp similarity index 81% rename from src/mod/endpoints/mod_khomp/commons/strings.hpp rename to src/mod/endpoints/mod_khomp/commons/base/strings.hpp index 056b9335c6..947da384d9 100644 --- a/src/mod/endpoints/mod_khomp/commons/strings.hpp +++ b/src/mod/endpoints/mod_khomp/commons/base/strings.hpp @@ -68,6 +68,8 @@ struct Strings bool empty() { return _list.empty(); }; + const list_type & list() { return _list; }; + protected: list_type _list; }; @@ -75,8 +77,8 @@ struct Strings public: struct invalid_value { - invalid_value(const char * value): _value(value) {}; - invalid_value(std::string value): _value(value) {}; + invalid_value(const char * value): _value(value) {}; + invalid_value(const std::string & value): _value(value) {}; std::string & value() { return _value; } @@ -92,10 +94,15 @@ struct Strings static bool toboolean(std::string); static std::string fromboolean(bool); - static long tolong(std::string, int base = 10); - static unsigned long toulong(std::string, int base = 10); - static unsigned long long toulonglong(std::string, int base = 10); - static double todouble(std::string); + static long tolong(const std::string &, int base = 10); + static unsigned long toulong(const std::string &, int base = 10); + static unsigned long long toulonglong(const std::string &, int base = 10); + static double todouble(const std::string &); + + static long tolong(const char *, int base = 10); + static unsigned long toulong(const char *, int base = 10); + static unsigned long long toulonglong(const char *, int base = 10); + static double todouble(const char *); static std::string lower(std::string); static std::string hexadecimal(std::string); diff --git a/src/mod/endpoints/mod_khomp/commons/freeswitch/saved_condition.cpp b/src/mod/endpoints/mod_khomp/commons/base/system/freeswitch/saved_condition.cpp similarity index 83% rename from src/mod/endpoints/mod_khomp/commons/freeswitch/saved_condition.cpp rename to src/mod/endpoints/mod_khomp/commons/base/system/freeswitch/saved_condition.cpp index 29169f3d54..d4d9861f5c 100644 --- a/src/mod/endpoints/mod_khomp/commons/freeswitch/saved_condition.cpp +++ b/src/mod/endpoints/mod_khomp/commons/base/system/freeswitch/saved_condition.cpp @@ -1,7 +1,7 @@ -/* +/* KHOMP generic endpoint/channel library. - Copyright (C) 2007-2009 Khomp Ind. & Com. - + Copyright (C) 2007-2009 Khomp Ind. & Com. + The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ @@ -23,40 +23,40 @@ The LGPL header follows below: - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ #include "saved_condition.hpp" bool SavedCondition::wait(unsigned int msec) { - bool ret = true; + bool ret = true; switch_mutex_lock(_mutex); if (!_signaled) - { + { /* msec * 1000 = The amount of time in microseconds to wait. */ - if (switch_thread_cond_timedwait(_condition, _mutex, (switch_interval_time_t)msec * 1000) != 0) - ret = false; - } - + if (switch_thread_cond_timedwait(_condition, _mutex, (switch_interval_time_t)msec * 1000) != 0) + ret = false; + } + _signaled = false; - switch_mutex_unlock(_mutex); + switch_mutex_unlock(_mutex); - return ret; + return ret; } diff --git a/src/mod/endpoints/mod_khomp/commons/freeswitch/saved_condition.hpp b/src/mod/endpoints/mod_khomp/commons/base/system/freeswitch/saved_condition.hpp similarity index 94% rename from src/mod/endpoints/mod_khomp/commons/freeswitch/saved_condition.hpp rename to src/mod/endpoints/mod_khomp/commons/base/system/freeswitch/saved_condition.hpp index 8acf0f3e0b..b34e40b0c0 100644 --- a/src/mod/endpoints/mod_khomp/commons/freeswitch/saved_condition.hpp +++ b/src/mod/endpoints/mod_khomp/commons/base/system/freeswitch/saved_condition.hpp @@ -1,7 +1,7 @@ -/* +/* KHOMP generic endpoint/channel library. - Copyright (C) 2007-2009 Khomp Ind. & Com. - + Copyright (C) 2007-2009 Khomp Ind. & Com. + The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ @@ -23,20 +23,20 @@ The LGPL header follows below: - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ #ifndef _SAVED_CONDITION_ @@ -104,7 +104,7 @@ struct SavedCondition : public SavedConditionCommon// : public RefCounter < Save if (!_signaled) switch_thread_cond_wait(_condition, _mutex); - + _signaled = false; switch_mutex_unlock(_mutex); diff --git a/src/mod/endpoints/mod_khomp/commons/freeswitch/simple_lock.hpp b/src/mod/endpoints/mod_khomp/commons/base/system/freeswitch/simple_lock.hpp similarity index 96% rename from src/mod/endpoints/mod_khomp/commons/freeswitch/simple_lock.hpp rename to src/mod/endpoints/mod_khomp/commons/base/system/freeswitch/simple_lock.hpp index 530d912ee1..acae57648d 100644 --- a/src/mod/endpoints/mod_khomp/commons/freeswitch/simple_lock.hpp +++ b/src/mod/endpoints/mod_khomp/commons/base/system/freeswitch/simple_lock.hpp @@ -1,7 +1,7 @@ -/* +/* KHOMP generic endpoint/channel library. - Copyright (C) 2007-2009 Khomp Ind. & Com. - + Copyright (C) 2007-2009 Khomp Ind. & Com. + The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ @@ -23,20 +23,20 @@ The LGPL header follows below: - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ #ifndef _SIMPLE_LOCK_HPP_ @@ -72,7 +72,7 @@ struct SimpleLockBasic: public SimpleLockCommon < Implementor > { /* do nothing */ }; - + void unreference() { switch_mutex_destroy(_mutex); diff --git a/src/mod/endpoints/mod_khomp/commons/freeswitch/thread.hpp b/src/mod/endpoints/mod_khomp/commons/base/system/freeswitch/thread.hpp similarity index 94% rename from src/mod/endpoints/mod_khomp/commons/freeswitch/thread.hpp rename to src/mod/endpoints/mod_khomp/commons/base/system/freeswitch/thread.hpp index af50240307..9e5abc4372 100644 --- a/src/mod/endpoints/mod_khomp/commons/freeswitch/thread.hpp +++ b/src/mod/endpoints/mod_khomp/commons/base/system/freeswitch/thread.hpp @@ -1,7 +1,7 @@ -/* +/* KHOMP generic endpoint/channel library. - Copyright (C) 2007-2009 Khomp Ind. & Com. - + Copyright (C) 2007-2009 Khomp Ind. & Com. + The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ @@ -23,20 +23,20 @@ The LGPL header follows below: - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ #ifndef _THREAD_HPP_ @@ -66,7 +66,7 @@ struct Thread : ThreadCommon T _data; A _arg; }; - + template struct ThreadData < T, R, void > : ThreadDataCommon { @@ -79,7 +79,7 @@ struct Thread : ThreadCommon T _data; }; - + template struct ThreadData < T, void, A > : ThreadDataCommon { @@ -111,7 +111,7 @@ struct Thread : ThreadCommon }; template - Thread(T obj, switch_memory_pool_t *pool=NULL) : + Thread(T obj, switch_memory_pool_t *pool=NULL) : _thread_info(new ThreadData::Return, void>(obj)), _pool(pool), _can_delete_pool(false) @@ -134,7 +134,7 @@ struct Thread : ThreadCommon } switch_threadattr_stacksize_set( - (switch_threadattr_t *)_thread_info->_attribute, + (switch_threadattr_t *)_thread_info->_attribute, SWITCH_THREAD_STACKSIZE); if(!priority()) @@ -143,9 +143,9 @@ struct Thread : ThreadCommon } } - + template - Thread(T obj, A arg, switch_memory_pool_t *pool=NULL) : + Thread(T obj, A arg, switch_memory_pool_t *pool=NULL) : _thread_info(new ThreadData::Return, A>(obj, arg)), _pool(pool), _can_delete_pool(false) @@ -168,7 +168,7 @@ struct Thread : ThreadCommon } switch_threadattr_stacksize_set( - (switch_threadattr_t *)_thread_info->_attribute, + (switch_threadattr_t *)_thread_info->_attribute, SWITCH_THREAD_STACKSIZE); if(!priority()) @@ -178,11 +178,11 @@ struct Thread : ThreadCommon } - ~Thread() + ~Thread() { if(_thread_info) delete _thread_info; - + if (_can_delete_pool) switch_core_destroy_memory_pool(&_pool); } @@ -202,10 +202,10 @@ struct Thread : ThreadCommon if(!_pool || !_thread_info->_attribute) return false; - switch_thread_create((switch_thread_t**)&_thread_info->_self, - (switch_threadattr_t *)_thread_info->_attribute, - run, - _thread_info, + switch_thread_create((switch_thread_t**)&_thread_info->_self, + (switch_threadattr_t *)_thread_info->_attribute, + run, + _thread_info, _pool); if(!_thread_info->_self) @@ -223,13 +223,13 @@ struct Thread : ThreadCommon * * SWITCH_DECLARE(switch_status_t) switch_thread_join(switch_status_t *retval, switch_thread_t *thd); */ - + if(!_thread_info->_self) return -2; int retval = 0; - if(switch_thread_join((switch_status_t*)&retval, + if(switch_thread_join((switch_status_t*)&retval, (switch_thread_t *)_thread_info->_self) != 0) return -1; @@ -267,7 +267,7 @@ private: { #ifndef WIN32 struct sched_param param; - + struct apr_threadattr_t *myattr = (struct apr_threadattr_t *)_thread_info->_attribute; if (pthread_attr_setschedpolicy( @@ -307,13 +307,13 @@ protected: static void *SWITCH_THREAD_FUNC run(BaseThreadType *thread, void * obj) { - //switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + //switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, // "Starting new Thread\n"); ThreadDataCommon * data = (ThreadDataCommon *)obj; int retval = data->run(); - //switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + //switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, // "Stopping new Thread = %d\n", retval); ((Thread *)(data->_thread))->exit(retval); diff --git a/src/mod/endpoints/mod_khomp/commons/tagged_union.hpp b/src/mod/endpoints/mod_khomp/commons/base/tagged_union.hpp similarity index 84% rename from src/mod/endpoints/mod_khomp/commons/tagged_union.hpp rename to src/mod/endpoints/mod_khomp/commons/base/tagged_union.hpp index 1616268c5f..f46aab0b75 100644 --- a/src/mod/endpoints/mod_khomp/commons/tagged_union.hpp +++ b/src/mod/endpoints/mod_khomp/commons/base/tagged_union.hpp @@ -42,11 +42,14 @@ #ifndef _TAGGED_UNION_HPP_ #define _TAGGED_UNION_HPP_ -#include - -#include #include +#include +#include +#include + +#include + namespace Tagged { struct EmptyUnion @@ -69,7 +72,7 @@ namespace Tagged ~EmptyUnion() { _adjusted = false; }; - bool operator==(const EmptyUnion & o) + bool operator==(const EmptyUnion & o) const { return true; }; @@ -80,24 +83,24 @@ namespace Tagged void setup(void) { _adjusted = true; }; protected: - bool value_set(void) { return false; }; - bool value_get(void) { return false; }; + bool value_set(void) const { return false; }; + bool value_get(void) const { return false; }; - bool value_check(void) { return false; }; + bool value_check(void) const { return false; }; template < typename S > - bool value_visit(S & visitor, typename S::ReturnType & ret) + bool value_visit(S & visitor, typename S::ReturnType & ret) const { return false; }; template < typename S > - bool value_visit_void(S & visitor) + bool value_visit_void(S & visitor) const { return false; }; - bool adjusted() { return _adjusted; }; + bool adjusted() const { return _adjusted; }; private: bool _adjusted; @@ -114,7 +117,7 @@ namespace Tagged // constructor with initializer template < typename U > - Union( U value ) + Union(U value) : _value(0) { set(value); @@ -123,7 +126,7 @@ namespace Tagged // copy constructor Union(const Union & o) : E(static_cast(o)), - _value( (o._value ? new const V(*(o._value)) : 0) ) + _value( (o._value ? new V(*(o._value)) : 0) ) {}; // copy assignment operator @@ -137,7 +140,7 @@ namespace Tagged if (o._value) { - _value = new const V(*(o._value)); + _value = new V(*(o._value)); } E::operator=(static_cast(o)); @@ -163,18 +166,21 @@ namespace Tagged } template < typename U > - bool check(void) + bool check(void) const { - return value_check(static_cast(0)); + return value_check(static_cast< const U * const>(0)); }; template < typename U > - const U & get(void) + U & get(void) const { - const U * res = 0; + U * res = 0; + + if (!E::adjusted()) + throw std::runtime_error("tagged union empty!"); if (!value_get(&res) || !res) - throw std::runtime_error("type mismatch"); + throw std::runtime_error(STG(FMT("type mismatch when asked for '%s'") % typeid(U).name())); return *res; }; @@ -190,7 +196,7 @@ namespace Tagged }; template < typename S > - typename S::ReturnType visit(S visitor) + typename S::ReturnType visit(S visitor) const { typename S::ReturnType ret; @@ -201,7 +207,7 @@ namespace Tagged }; template < typename S > - void visit_void(S visitor) + void visit_void(S visitor) const { if (!value_visit_void(visitor)) throw std::runtime_error("unable to visit empty value"); @@ -219,7 +225,7 @@ namespace Tagged }; // compare (equal) operator - bool operator==(const Union & o) + bool operator==(const Union & o) const { bool are_equal = false; @@ -236,7 +242,7 @@ namespace Tagged }; // compare types - bool sameType(const Union & o) + bool sameType(const Union & o) const { if ((!(_value) && !(o._value)) || (_value && o._value)) return E::operator==(static_cast(o)); @@ -254,13 +260,13 @@ namespace Tagged bool value_set(V val) { - _value = new const V(val); + _value = new V(val); E::setup(); return true; }; - bool value_get(const V ** val) + bool value_get(V ** val) const { if (!_value) return false; @@ -269,14 +275,14 @@ namespace Tagged return true; } - bool value_check(const V * const junk) + bool value_check(const V * const junk) const { (void)junk; return (_value != 0); }; template < typename S > - bool value_visit(S & visitor, typename S::ReturnType & ret) + bool value_visit(S & visitor, typename S::ReturnType & ret) const { if (_value) { @@ -288,7 +294,7 @@ namespace Tagged }; template < typename S > - bool value_visit_void(S & visitor) + bool value_visit_void(S & visitor) const { if (_value) { @@ -300,7 +306,7 @@ namespace Tagged }; private: - const V * _value; + V * _value; }; }; diff --git a/src/mod/endpoints/mod_khomp/commons/thread.hpp b/src/mod/endpoints/mod_khomp/commons/base/thread.hpp similarity index 100% rename from src/mod/endpoints/mod_khomp/commons/thread.hpp rename to src/mod/endpoints/mod_khomp/commons/base/thread.hpp diff --git a/src/mod/endpoints/mod_khomp/commons/timer.cpp b/src/mod/endpoints/mod_khomp/commons/base/timer.cpp similarity index 96% rename from src/mod/endpoints/mod_khomp/commons/timer.cpp rename to src/mod/endpoints/mod_khomp/commons/base/timer.cpp index 36e32f521a..0cb0ac4340 100644 --- a/src/mod/endpoints/mod_khomp/commons/timer.cpp +++ b/src/mod/endpoints/mod_khomp/commons/base/timer.cpp @@ -276,6 +276,20 @@ bool TimerTraits::traits_restart (TimerTraits::Index & idx, bool force) return ret; } +void TimerTraits::traits_setup(TimerTraits::Index * idx, unsigned int msecs, const void * func, void * data, unsigned int value) +{ + _mutex.lock(); + + if (idx->valid) + { + (void)traits_del_unlocked(*idx); + } + + *idx = traits_add_unlocked(msecs, func, data, value); + + _mutex.unlock(); +} + bool TimerTraits::traits_del_unlocked (TimerTraits::Index & idx) { bool ret = false; diff --git a/src/mod/endpoints/mod_khomp/commons/timer.hpp b/src/mod/endpoints/mod_khomp/commons/base/timer.hpp similarity index 93% rename from src/mod/endpoints/mod_khomp/commons/timer.hpp rename to src/mod/endpoints/mod_khomp/commons/base/timer.hpp index 382efa1645..24d115d991 100644 --- a/src/mod/endpoints/mod_khomp/commons/timer.hpp +++ b/src/mod/endpoints/mod_khomp/commons/base/timer.hpp @@ -125,6 +125,8 @@ struct TimerTraits bool traits_del (Index & idx); bool traits_del (const void * func, const void * data = 0, unsigned int value = 0); + void traits_setup(Index * idx, unsigned int msecs, const void * func, void * data = 0, unsigned int value = 0); + /* timer start/stop functions */ bool start(void); bool stop(void); @@ -169,7 +171,7 @@ struct TimerTraits }; template < typename F, typename D > -struct TimerTemplate: NEW_REFCOUNTER(TimerTemplate< F, D >) +struct TimerTemplate: COUNTER_SUPER(TimerTemplate< F, D >) { typedef TimerTraits::Index Index; typedef TimerTraits::Control Control; @@ -179,7 +181,7 @@ struct TimerTemplate: NEW_REFCOUNTER(TimerTemplate< F, D >) {}; TimerTemplate(const TimerTemplate< F, D > & o) - : INC_REFCOUNTER(o, TimerTemplate< F, D >), + : COUNTER_REFER(o, TimerTemplate< F, D >), _timer(o._timer) {}; @@ -192,6 +194,11 @@ struct TimerTemplate: NEW_REFCOUNTER(TimerTemplate< F, D >) bool start() { return _timer->start(); } bool stop() { return _timer->stop(); } + inline void setup(Index * idx, unsigned int msecs, F * func, D data = 0, unsigned int value = 0) + { + _timer->traits_setup(idx, msecs, (const void *)func, (void *)(data), value); + } + inline Index add(unsigned int msecs, F * func, D data = 0, unsigned int value = 0) { return _timer->traits_add(msecs, (const void *)func, (void *)(data), value); diff --git a/src/mod/endpoints/mod_khomp/commons/types.hpp b/src/mod/endpoints/mod_khomp/commons/base/types.hpp similarity index 88% rename from src/mod/endpoints/mod_khomp/commons/types.hpp rename to src/mod/endpoints/mod_khomp/commons/base/types.hpp index adbd8abe36..5ab6d292c6 100644 --- a/src/mod/endpoints/mod_khomp/commons/types.hpp +++ b/src/mod/endpoints/mod_khomp/commons/base/types.hpp @@ -55,15 +55,33 @@ /*** Used for checking information on classes and stuff.. ***/ template< typename T > -class IsClass +struct IsClass { protected: - template< typename X > static char ( &A( void(X::*)() ) )[1]; - template< typename X > static char ( &A( X ) )[2]; + template < typename X > static char ( &A( void(X::*)() ) )[1]; + template < typename X > static char ( &A( X ) )[2]; public: static bool const Result = sizeof( A< T >(0) ) == 1; }; +template < typename T > +struct IsConst +{ + static bool const Result = false; +}; + +template < typename T > +struct IsConst< const T > +{ + static bool const Result = true; +}; + +template < typename T > +struct IsConst< T const * > +{ + static bool const Result = true; +}; + /*** Used for template metaprogramming ***/ template < bool Value, typename Then, typename Else > diff --git a/src/mod/endpoints/mod_khomp/commons/variant.hpp b/src/mod/endpoints/mod_khomp/commons/base/variable.hpp similarity index 53% rename from src/mod/endpoints/mod_khomp/commons/variant.hpp rename to src/mod/endpoints/mod_khomp/commons/base/variable.hpp index 410a770a6e..efeb0f53b7 100644 --- a/src/mod/endpoints/mod_khomp/commons/variant.hpp +++ b/src/mod/endpoints/mod_khomp/commons/base/variable.hpp @@ -11,7 +11,7 @@ the specific language governing rights and limitations under the License. Alternatively, the contents of this file may be used under the terms of the - "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which + "GNU Lesser General Public License 2.1" license (the "LGPL" License), in which case the provisions of "LGPL License" are applicable instead of those above. If you wish to allow use of your version of this file only under the terms of @@ -41,87 +41,84 @@ #include -#include +#ifndef _VARIABLE_HPP_ +#define _VARIABLE_HPP_ -#ifndef _VARIANT_H_ -#define _VARIANT_H_ - -/* this is internal, should not be used by the user */ -struct NoArgumentDefined {}; - -template < typename UserReturnType, typename UserArgumentType = NoArgumentDefined > -struct VariantBaseType +template < typename R > +struct VariableBaseTable { - typedef UserReturnType ReturnType; - typedef UserArgumentType ArgumentType; - - virtual ~VariantBaseType() {}; - - virtual int which() = 0; - - virtual ReturnType visit(void) { return ReturnType(); }; - virtual ReturnType visit(ArgumentType) { return ReturnType(); }; + R value; }; -template < typename BaseType = VariantBaseType < void > > -struct Variant: NEW_REFCOUNTER(Variant < BaseType >) +struct EmptyVariable {}; + +template < typename R > +struct Variable { - typedef typename BaseType::ReturnType ReturnType; - typedef typename BaseType::ArgumentType ArgumentType; + protected: + typedef VariableBaseTable< R > BaseType; - struct InvalidType {}; + typedef const BaseType * ConstObjType; + typedef BaseType * ObjType; + typedef R BaseType::* VarType; - Variant(BaseType * value, bool is_owner = false) - : _value(value), _is_owner(is_owner) {}; + public: + template < typename ConstructorObjType > + Variable(R ConstructorObjType::* v) + : _adjusted(true), + _variable(reinterpret_cast(v)) + {}; - Variant(const Variant & v) - : INC_REFCOUNTER(v, Variant < BaseType >), - _value(v._value), _is_owner(v._is_owner) {}; + Variable() + : _adjusted(false) + {}; - virtual ~Variant() {}; - - void unreference() + template < typename MemberType > + void operator=(const MemberType v) { - if (_is_owner && _value) - { - delete _value; - _value = 0; - } - }; - - template < typename ValueType > - ValueType & get(void) - { - try - { - ValueType & ret = dynamic_cast < ValueType & > (*_value); - return ret; - } - catch (std::bad_cast & e) - { - throw InvalidType(); - } - }; - - int which() - { - return _value->which(); + _adjusted = true; + _variable = reinterpret_cast(v); } - ReturnType visit(void) + template < typename Type > + R & operator()(Type * obj) const { - return _value->visit(); + if (!_adjusted) + throw EmptyVariable(); + + return (reinterpret_cast< ObjType >(obj))->*(_variable); } - ReturnType visit(ArgumentType arg) + template < typename Type > + R & operator()(Type & obj) const { - return _value->visit(arg); + if (!_adjusted) + throw EmptyVariable(); + + return (reinterpret_cast< ObjType >(&obj))->*(_variable); } - protected: - BaseType * _value; - bool _is_owner; + template < typename Type > + const R & operator()(const Type * obj) const + { + if (!_adjusted) + throw EmptyVariable(); + + return (reinterpret_cast< ConstObjType >(obj))->*(_variable); + } + + template < typename Type > + const R & operator()(const Type & obj) const + { + if (!_adjusted) + throw EmptyVariable(); + + return (reinterpret_cast< ConstObjType >(&obj))->*(_variable); + } + + protected: + bool _adjusted; + VarType _variable; }; -#endif /* _VARIANT_H_ */ - +#endif /* _VARIABLE_HPP_ */ diff --git a/src/mod/endpoints/mod_khomp/commons/verbose.cpp b/src/mod/endpoints/mod_khomp/commons/base/verbose.cpp similarity index 82% rename from src/mod/endpoints/mod_khomp/commons/verbose.cpp rename to src/mod/endpoints/mod_khomp/commons/base/verbose.cpp index 182d159ca1..bdc412e231 100644 --- a/src/mod/endpoints/mod_khomp/commons/verbose.cpp +++ b/src/mod/endpoints/mod_khomp/commons/base/verbose.cpp @@ -54,11 +54,11 @@ /********************************************/ -std::string Verbose::channelStatus(int32 dev, int32 obj, int32 cs, Verbose::Presentation fmt) +std::string Verbose::channelStatus(const int32 dev, const int32 obj, const int32 cs, const Verbose::Presentation fmt) const { try { - K3L_CHANNEL_CONFIG & config = _api.channel_config(dev, obj); + const K3L_CHANNEL_CONFIG & config = _api.channel_config(dev, obj); return Verbose::channelStatus(config.Signaling, cs, fmt); } catch (...) @@ -68,14 +68,14 @@ std::string Verbose::channelStatus(int32 dev, int32 obj, int32 cs, Verbose::Pres } #if K3L_AT_LEAST(2,0,0) -std::string Verbose::event(int32 obj, K3L_EVENT *ev, R2CountryType r2_country, Verbose::Presentation fmt) +std::string Verbose::event(const int32 obj, const K3L_EVENT * const ev, const R2CountryType r2_country, const Verbose::Presentation fmt) const #else -std::string Verbose::event(int32 obj, K3L_EVENT *ev, Verbose::Presentation fmt) +std::string Verbose::event(const int32 obj, const K3L_EVENT * const ev, const Verbose::Presentation fmt) const #endif { try { - K3L_CHANNEL_CONFIG & config = _api.channel_config(ev->DeviceId, obj); + const K3L_CHANNEL_CONFIG & config = _api.channel_config(ev->DeviceId, obj); #if K3L_AT_LEAST(2,0,0) return Verbose::event(config.Signaling, obj, ev, r2_country, fmt); #else @@ -94,7 +94,7 @@ std::string Verbose::event(int32 obj, K3L_EVENT *ev, Verbose::Presentation fmt) /********************************************/ -std::string Verbose::echoLocation(KEchoLocation ec, Verbose::Presentation fmt) +std::string Verbose::echoLocation(const KEchoLocation ec, const Verbose::Presentation fmt) { switch (ec) { @@ -109,7 +109,7 @@ std::string Verbose::echoLocation(KEchoLocation ec, Verbose::Presentation fmt) return presentation(fmt, "", "Unknown"); }; -std::string Verbose::echoCancellerConfig(KEchoCancellerConfig ec, Verbose::Presentation fmt) +std::string Verbose::echoCancellerConfig(KEchoCancellerConfig ec, const Verbose::Presentation fmt) { switch (ec) { @@ -124,21 +124,24 @@ std::string Verbose::echoCancellerConfig(KEchoCancellerConfig ec, Verbose::Prese return presentation(fmt, "", "Unknown"); }; -// TODO: internal_deviceType / internal_deviceModel +std::string Verbose::deviceName(const KDeviceType dt, const int32 model, const Verbose::Presentation fmt) +{ + return deviceName(dt, model, 0, fmt); +} -std::string Verbose::deviceName(KDeviceType dt, int32 model, Verbose::Presentation fmt) +std::string Verbose::deviceName(const KDeviceType dt, const int32 model, const int32 count, const Verbose::Presentation fmt) { try { std::string value; - value += internal_deviceType(dt); + value += internal_deviceType(dt, count); value += "-"; - value += internal_deviceModel(dt, model); + value += internal_deviceModel(dt, model, count); return value; } - catch (internal_not_found & e) + catch (internal_not_found e) { PRESENTATION_CHECK_RETURN(fmt, STG(FMT("[type/model='%d/%d']") % (int)dt % (int)model), @@ -146,13 +149,18 @@ std::string Verbose::deviceName(KDeviceType dt, int32 model, Verbose::Presentati } } -std::string Verbose::deviceType(KDeviceType dt, Verbose::Presentation fmt) +std::string Verbose::deviceType(const KDeviceType dt, const Verbose::Presentation fmt) +{ + return deviceType(dt, 0, fmt); +} + +std::string Verbose::deviceType(const KDeviceType dt, const int32 count, const Verbose::Presentation fmt) { try { - return internal_deviceType(dt); + return internal_deviceType(dt, count); } - catch (internal_not_found & e) + catch (internal_not_found e) { PRESENTATION_CHECK_RETURN(fmt, STG(FMT("[type='%d']") % (int)dt), @@ -160,11 +168,11 @@ std::string Verbose::deviceType(KDeviceType dt, Verbose::Presentation fmt) } } -std::string Verbose::internal_deviceType(KDeviceType dt) +std::string Verbose::internal_deviceType(const KDeviceType dt, const int32 count) { switch (dt) { - case kdtE1: return "K2E1"; + case kdtE1: return (count > 34 || count == 0 ? "K2E1" : "K1E1"); #if K3L_AT_LEAST(1,6,0) case kdtFXO: return "KFXO"; @@ -183,10 +191,10 @@ std::string Verbose::internal_deviceType(KDeviceType dt) #endif #if K3L_AT_LEAST(1,5,0) - case kdtE1IP: return "K2E1"; + case kdtE1IP: return (count > 90 || count == 0 ? "K2E1" : "K1E1"); #endif #if K3L_AT_LEAST(1,5,1) - case kdtE1Spx: return "K2E1"; + case kdtE1Spx: return (count > 30 || count == 0 ? "K2E1" : "K1E1"); case kdtGWIP: return "KGWIP"; #endif @@ -202,7 +210,6 @@ std::string Verbose::internal_deviceType(KDeviceType dt) case kdtGSMUSBSpx: return "KGSMUSB"; case kdtE1FXSSpx: return "KE1FXS"; - case kdtDevTypeCount: return "DevTypeCount"; #endif #if K3L_EXACT(2,1,0) @@ -212,18 +219,24 @@ std::string Verbose::internal_deviceType(KDeviceType dt) #if K3L_AT_LEAST(2,2,0) case kdtE1AdHoc: return "KE1AdHoc"; #endif + case kdtDevTypeCount: break; } throw internal_not_found(); } -std::string Verbose::deviceModel(KDeviceType dt, int32 model, Verbose::Presentation fmt) +std::string Verbose::deviceModel(const KDeviceType dt, const int32 model, const Verbose::Presentation fmt) +{ + return deviceModel(dt, model, 0, fmt); +}; + +std::string Verbose::deviceModel(const KDeviceType dt, const int32 model, const int32 count, const Verbose::Presentation fmt) { try { - return internal_deviceModel(dt, model); + return internal_deviceModel(dt, model, count); } - catch (internal_not_found & e) + catch (internal_not_found e) { PRESENTATION_CHECK_RETURN(fmt, STG(FMT("[model='%d']") % (int)model), @@ -231,17 +244,17 @@ std::string Verbose::deviceModel(KDeviceType dt, int32 model, Verbose::Presentat } } -std::string Verbose::internal_deviceModel(KDeviceType dt, int32 model) +std::string Verbose::internal_deviceModel(const KDeviceType dt, const int32 model, const int32 count) { switch (dt) { case kdtE1: switch ((KE1DeviceModel)model) { - case kdmE1600: return "600"; - case kdmE1600E: return "600E"; + case kdmE1600: return (count > 34 || count == 0 ? "600" : "300"); + case kdmE1600E: return (count > 34 || count == 0 ? "600" : "300"); #if K3L_AT_LEAST(2,0,0) - case kdmE1600EX: return "600EX"; + case kdmE1600EX: return (count > 34 || count == 0 ? "600" : "300"); #endif } throw internal_not_found(); @@ -255,14 +268,38 @@ std::string Verbose::internal_deviceModel(KDeviceType dt, int32 model) #endif { #if K3L_AT_LEAST(1,6,0) - case kdmFXO80: return "80"; - case kdmFXOHI: return "HI"; + case kdmFXO80: + switch (count) + { + case 0: /* default */ + case 8: return "80"; + case 4: return "40"; + } + break; + + case kdmFXOHI: + switch (count) + { + case 0: /* default */ + case 8: return "80-HI"; + case 4: return "40-HI"; + } + break; + case kdmFXO160HI: return "160HI"; #if K3L_AT_LEAST(2,1,0) - case kdmFXO240HI: return "240HI"; + case kdmFXO240HI: return "240HI"; #endif #else - case kdmFXO80: return "80"; + case kdmFXO80: + switch (count) + { + case 0: /* default */ + case 8: return "80"; + case 4: return "40"; + } + break; + #endif } @@ -300,13 +337,13 @@ std::string Verbose::internal_deviceModel(KDeviceType dt, int32 model) switch ((KE1GWDeviceModel)model) { #if K3L_AT_LEAST(1,6,0) - case kdmE1GW640: return "640"; + case kdmE1GW640: return "640"; #if K3L_AT_LEAST(2,0,0) case kdmE1GW640EX: return "640EX"; #endif #else - case kdmE1600V: return "600V"; - case kdmE1600EV: return "600EV"; + case kdmE1600V: return (count > 34 || count == 0 ? "600V" : "300V" ); + case kdmE1600EV: return (count > 34 || count == 0 ? "600EV" : "600EV"); #endif } @@ -337,12 +374,12 @@ std::string Verbose::internal_deviceModel(KDeviceType dt, int32 model) switch ((KE1IPDeviceModel)model) { #if K3L_AT_LEAST(1,6,0) - case kdmE1IP: return "E1IP"; + case kdmE1IP: return "E1IP"; #if K3L_AT_LEAST(2,0,0) case kdmE1IPEX: return "E1IPEX"; #endif #else - case kdmE1600EG: return "600EG"; + case kdmE1600EG: return (count > 90 || count == 0 ? "600EG" : "300EG"); #endif } @@ -353,8 +390,8 @@ std::string Verbose::internal_deviceModel(KDeviceType dt, int32 model) case kdtE1Spx: switch ((KE1SpxDeviceModel)model) { - case kdmE1Spx: return "SPX"; - case kdm2E1Based: return "SPX-2E1"; + case kdmE1Spx: return "SPX"; + case kdm2E1Based: return "SPX-2E1"; #if K3L_AT_LEAST(2,0,0) case kdmE1SpxEX: return "SPXEX"; #endif @@ -367,7 +404,7 @@ std::string Verbose::internal_deviceModel(KDeviceType dt, int32 model) #if K3L_AT_LEAST(1,6,0) case kdmGWIP: return "GWIP"; #if K3L_AT_LEAST(2,0,0) - case kdmGWIPEX: return "GWIPEX"; + case kdmGWIPEX: return "GWIPEX"; #endif #else case kdmGW600G: return "600G"; @@ -382,9 +419,9 @@ std::string Verbose::internal_deviceModel(KDeviceType dt, int32 model) case kdtFXS: switch ((KFXSDeviceModel)model) { - case kdmFXS300: return "300"; + case kdmFXS300: return (count > 30 || count == 0 ? "300" : "150"); #if K3L_AT_LEAST(2,0,0) - case kdmFXS300EX: return "300EX"; + case kdmFXS300EX: return (count > 30 || count == 0 ? "300EX" : "150EX"); #endif } @@ -393,10 +430,10 @@ std::string Verbose::internal_deviceModel(KDeviceType dt, int32 model) case kdtFXSSpx: switch ((KFXSSpxDeviceModel)model) { - case kdmFXSSpx300: return "SPX"; - case kdmFXSSpx2E1Based: return "SPX-2E1"; + case kdmFXSSpx300: return (count > 30 || count == 0 ? "300-SPX" : "150-SPX"); + case kdmFXSSpx2E1Based: return "SPX-2E1"; #if K3L_AT_LEAST(2,0,0) - case kdmFXSSpx300EX: return "SPXEX"; + case kdmFXSSpx300EX: return (count > 30 || count == 0 ? "300-SPXEX" : "150-SPXEX"); #endif } @@ -405,9 +442,27 @@ std::string Verbose::internal_deviceModel(KDeviceType dt, int32 model) case kdtGSM: switch ((KGSMDeviceModel)model) { - case kdmGSM: return "40"; + case kdmGSM: + switch (count) + { + case 0: /* default */ + case 4: return "40"; + case 3: return "30"; + case 2: return "20"; + case 1: return "10"; + } + break; #if K3L_AT_LEAST(2,0,0) - case kdmGSMEX: return "40EX"; + case kdmGSMEX: + switch (count) + { + case 0: /* default */ + case 4: return "40EX"; + case 3: return "80EX"; + case 2: return "20EX"; + case 1: return "10EX"; + } + break; #endif } @@ -416,9 +471,27 @@ std::string Verbose::internal_deviceModel(KDeviceType dt, int32 model) case kdtGSMSpx: switch ((KGSMSpxDeviceModel)model) { - case kdmGSMSpx: return "SPX"; + case kdmGSMSpx: + switch (count) + { + case 0: /* default */ + case 4: return "40"; + case 3: return "30"; + case 2: return "20"; + case 1: return "10"; + } + break; #if K3L_AT_LEAST(2,0,0) - case kdmGSMSpxEX: return "SPXEX"; + case kdmGSMSpxEX: + switch (count) + { + case 0: /* default */ + case 4: return "40-SPXEX"; + case 3: return "80-SPXEX"; + case 2: return "20-SPXEX"; + case 1: return "10-SPXEX"; + } + break; #endif } @@ -444,8 +517,8 @@ std::string Verbose::internal_deviceModel(KDeviceType dt, int32 model) case kdtE1FXSSpx: switch ((KGSMSpxDeviceModel)model) { - case kdmE1FXSSpx: return "SPX"; - case kdmE1FXSSpxEX: return "SPXEX"; + case kdmE1FXSSpx: return "450-SPX"; + case kdmE1FXSSpxEX: return "450-SPXEX"; } throw internal_not_found(); @@ -476,7 +549,7 @@ std::string Verbose::internal_deviceModel(KDeviceType dt, int32 model) throw internal_not_found(); } -std::string Verbose::signaling(KSignaling sig, Verbose::Presentation fmt) +std::string Verbose::signaling(const KSignaling sig, const Verbose::Presentation fmt) { switch (sig) { @@ -523,7 +596,7 @@ std::string Verbose::signaling(KSignaling sig, Verbose::Presentation fmt) STG(FMT("Unknown signaling (%d)") % (int)sig)); } -std::string Verbose::systemObject(KSystemObject so, Verbose::Presentation fmt) +std::string Verbose::systemObject(const KSystemObject so, const Verbose::Presentation fmt) { switch (so) { @@ -544,7 +617,7 @@ std::string Verbose::systemObject(KSystemObject so, Verbose::Presentation fmt) STG(FMT("Unknown object (%d)") % (int)so)); } -std::string Verbose::mixerTone(KMixerTone mt, Verbose::Presentation fmt) +std::string Verbose::mixerTone(const KMixerTone mt, const Verbose::Presentation fmt) { switch (mt) { @@ -567,7 +640,7 @@ std::string Verbose::mixerTone(KMixerTone mt, Verbose::Presentation fmt) STG(FMT("Unknonwn tone (%d)") % (int)mt)); } -std::string Verbose::mixerSource(KMixerSource ms, Verbose::Presentation fmt) +std::string Verbose::mixerSource(const KMixerSource ms, const Verbose::Presentation fmt) { switch (ms) { @@ -588,7 +661,7 @@ std::string Verbose::mixerSource(KMixerSource ms, Verbose::Presentation fmt) STG(FMT("Unknonwn source (%d)") % (int)ms)); } -std::string Verbose::channelFeatures(int32 flags, Verbose::Presentation fmt) +std::string Verbose::channelFeatures(const int32 flags, const Verbose::Presentation fmt) { if (0x00 != flags) { @@ -603,9 +676,7 @@ std::string Verbose::channelFeatures(int32 flags, Verbose::Presentation fmt) if (kcfHighImpEvents & flags) strs.add(presentation(fmt, "HighImpEvents", "High Impedance Events")); #if K3L_AT_LEAST(1,6,0) if (kcfCallAnswerInfo & flags) strs.add(presentation(fmt, "CallAnswerInfo", "Call Answer Info")); -#if !K3L_AT_LEAST(2,2,0) if (kcfOutputVolume & flags) strs.add(presentation(fmt, "OutputVolume", "Output Volume")); -#endif if (kcfPlayerAGC & flags) strs.add(presentation(fmt, "PlayerAGC", "Player AGC")); #endif @@ -617,7 +688,7 @@ std::string Verbose::channelFeatures(int32 flags, Verbose::Presentation fmt) PRESENTATION_CHECK_RETURN(fmt, "", "No features"); } -std::string Verbose::seizeFail(KSeizeFail sf, Verbose::Presentation fmt) +std::string Verbose::seizeFail(const KSeizeFail sf, const Verbose::Presentation fmt) { switch (sf) { @@ -635,7 +706,7 @@ std::string Verbose::seizeFail(KSeizeFail sf, Verbose::Presentation fmt) } #if K3L_AT_LEAST(1,5,0) -std::string Verbose::internal_sipFailures(KSIP_Failures code, Verbose::Presentation fmt) +std::string Verbose::internal_sipFailures(const KSIP_Failures code, const Verbose::Presentation fmt) { switch (code) { @@ -691,13 +762,13 @@ std::string Verbose::internal_sipFailures(KSIP_Failures code, Verbose::Presentat throw internal_not_found(); } -std::string Verbose::sipFailures(KSIP_Failures code, Verbose::Presentation fmt) +std::string Verbose::sipFailures(const KSIP_Failures code, const Verbose::Presentation fmt) { try { return internal_sipFailures(code, fmt); } - catch (internal_not_found & e) + catch (internal_not_found e) { PRESENTATION_CHECK_RETURN(fmt, STG(FMT("[KSIP_Failures='%d']") % (int)code), @@ -708,7 +779,7 @@ std::string Verbose::sipFailures(KSIP_Failures code, Verbose::Presentation fmt) #endif #if K3L_AT_LEAST(1,5,1) -std::string Verbose::internal_isdnCause(KQ931Cause code, Verbose::Presentation fmt) +std::string Verbose::internal_isdnCause(const KQ931Cause code, const Verbose::Presentation fmt) { switch (code) { @@ -810,13 +881,13 @@ std::string Verbose::internal_isdnCause(KQ931Cause code, Verbose::Presentation f throw internal_not_found(); } -std::string Verbose::isdnCause(KQ931Cause code, Verbose::Presentation fmt) +std::string Verbose::isdnCause(const KQ931Cause code, const Verbose::Presentation fmt) { try { return internal_isdnCause(code); } - catch (internal_not_found & e) + catch (internal_not_found e) { return STG(FMT("[KQ931Cause='%d']") % (int)code); } @@ -824,7 +895,7 @@ std::string Verbose::isdnCause(KQ931Cause code, Verbose::Presentation fmt) #endif #if K3L_AT_LEAST(1,5,2) -std::string Verbose::isdnDebug(int32 flags, Verbose::Presentation fmt) +std::string Verbose::isdnDebug(const int32 flags, const Verbose::Presentation fmt) { if (0x00 != flags) { @@ -844,9 +915,9 @@ std::string Verbose::isdnDebug(int32 flags, Verbose::Presentation fmt) #endif #if K3L_AT_LEAST(2,0,0) -std::string Verbose::internal_signGroupB(KSignGroupB group, R2CountryType country, Verbose::Presentation fmt) +std::string Verbose::internal_signGroupB(const KSignGroupB group, const R2CountryType country, const Verbose::Presentation fmt) #else -std::string Verbose::internal_signGroupB(KSignGroupB group, Verbose::Presentation fmt) +std::string Verbose::internal_signGroupB(const KSignGroupB group, const Verbose::Presentation fmt) #endif { #if K3L_AT_LEAST(2,0,0) @@ -955,9 +1026,9 @@ std::string Verbose::internal_signGroupB(KSignGroupB group, Verbose::Presentatio } #if K3L_AT_LEAST(2,0,0) -std::string Verbose::signGroupB(KSignGroupB group, R2CountryType r2_country, Verbose::Presentation fmt) +std::string Verbose::signGroupB(const KSignGroupB group, const R2CountryType r2_country, const Verbose::Presentation fmt) #else -std::string Verbose::signGroupB(KSignGroupB group, Verbose::Presentation fmt) +std::string Verbose::signGroupB(const KSignGroupB group, const Verbose::Presentation fmt) #endif { try @@ -968,7 +1039,7 @@ std::string Verbose::signGroupB(KSignGroupB group, Verbose::Presentation fmt) return internal_signGroupB(group, fmt); #endif } - catch (internal_not_found & e) + catch (internal_not_found e) { PRESENTATION_CHECK_RETURN(fmt, STG(FMT("[KSignGroupB='%d']") % (int)group), @@ -977,9 +1048,9 @@ std::string Verbose::signGroupB(KSignGroupB group, Verbose::Presentation fmt) } #if K3L_AT_LEAST(2,0,0) -std::string Verbose::internal_signGroupII(KSignGroupII group, R2CountryType country, Verbose::Presentation fmt) +std::string Verbose::internal_signGroupII(const KSignGroupII group, const R2CountryType country, const Verbose::Presentation fmt) #else -std::string Verbose::internal_signGroupII(KSignGroupII group, Verbose::Presentation fmt) +std::string Verbose::internal_signGroupII(const KSignGroupII group, const Verbose::Presentation fmt) #endif { #if K3L_AT_LEAST(2,0,0) @@ -1085,9 +1156,9 @@ std::string Verbose::internal_signGroupII(KSignGroupII group, Verbose::Presentat } #if K3L_AT_LEAST(2,0,0) -std::string Verbose::signGroupII(KSignGroupII group, R2CountryType r2_country, Verbose::Presentation fmt) +std::string Verbose::signGroupII(const KSignGroupII group, const R2CountryType r2_country, const Verbose::Presentation fmt) #else -std::string Verbose::signGroupII(KSignGroupII group, Verbose::Presentation fmt) +std::string Verbose::signGroupII(const KSignGroupII group, const Verbose::Presentation fmt) #endif { try @@ -1098,7 +1169,7 @@ std::string Verbose::signGroupII(KSignGroupII group, Verbose::Presentation fmt) return internal_signGroupII(group); #endif } - catch (internal_not_found & e) + catch (internal_not_found e) { PRESENTATION_CHECK_RETURN(fmt, STG(FMT("[KSignGroupII='%d']") % (int)group), @@ -1107,9 +1178,9 @@ std::string Verbose::signGroupII(KSignGroupII group, Verbose::Presentation fmt) } #if K3L_AT_LEAST(2,0,0) -std::string Verbose::callFail(KSignaling sig, R2CountryType country, int32 info, Verbose::Presentation fmt) +std::string Verbose::callFail(const KSignaling sig, const R2CountryType country, const int32 info, const Verbose::Presentation fmt) #else -std::string Verbose::callFail(KSignaling sig, int32 info, Verbose::Presentation fmt) +std::string Verbose::callFail(const KSignaling sig, const int32 info, const Verbose::Presentation fmt) #endif { try @@ -1130,8 +1201,10 @@ std::string Verbose::callFail(KSignaling sig, int32 info, Verbose::Presentation #endif #if K3L_EXACT(2,1,0) case ksigISUP: +#if !K3L_AT_LEAST(2,2,0) case ksigFax: #endif +#endif #if K3L_AT_LEAST(1,6,0) case ksigCAS_EL7: case ksigE1LC: @@ -1181,7 +1254,7 @@ std::string Verbose::callFail(KSignaling sig, int32 info, Verbose::Presentation #endif } } - catch (internal_not_found & e) + catch (internal_not_found e) { /* this exception is used for breaking the control flow */ } @@ -1191,7 +1264,7 @@ std::string Verbose::callFail(KSignaling sig, int32 info, Verbose::Presentation STG(FMT("Unknown call fail code for '%s' (%d)") % signaling(sig, fmt) % (int)info)); } -std::string Verbose::channelFail(KSignaling sig, int32 code, Verbose::Presentation fmt) +std::string Verbose::channelFail(const KSignaling sig, const int32 code, const Verbose::Presentation fmt) { try { @@ -1202,7 +1275,9 @@ std::string Verbose::channelFail(KSignaling sig, int32 code, Verbose::Presentati case ksigSIP: #if K3L_EXACT(2,1,0) case ksigISUP: +#if !K3L_AT_LEAST(2,2,0) case ksigFax: +#endif #endif throw internal_not_found(); @@ -1248,7 +1323,7 @@ std::string Verbose::channelFail(KSignaling sig, int32 code, Verbose::Presentati #endif } } - catch (internal_not_found & e) + catch (internal_not_found e) { /* this exception is used for breaking the control flow */ } @@ -1258,7 +1333,7 @@ std::string Verbose::channelFail(KSignaling sig, int32 code, Verbose::Presentati STG(FMT("Unknown channel fail code for '%s' (%d)") % signaling(sig, fmt) % (int)code)); } -std::string Verbose::internalFail(KInternalFail inf, Verbose::Presentation fmt) +std::string Verbose::internalFail(const KInternalFail inf, const Verbose::Presentation fmt) { switch (inf) { @@ -1277,7 +1352,7 @@ std::string Verbose::internalFail(KInternalFail inf, Verbose::Presentation fmt) STG(FMT("Unknown internal failure (%d)") % (int)inf)); } -std::string Verbose::linkErrorCounter(KLinkErrorCounter ec, Verbose::Presentation fmt) +std::string Verbose::linkErrorCounter(const KLinkErrorCounter ec, const Verbose::Presentation fmt) { switch (ec) { @@ -1304,7 +1379,7 @@ std::string Verbose::linkErrorCounter(KLinkErrorCounter ec, Verbose::Presentatio STG(FMT("Unknown link error counter (%d)") % (int)ec)); } -std::string Verbose::callStatus(KCallStatus code, Verbose::Presentation fmt) +std::string Verbose::callStatus(const KCallStatus code, const Verbose::Presentation fmt) { switch (code) { @@ -1319,7 +1394,7 @@ std::string Verbose::callStatus(KCallStatus code, Verbose::Presentation fmt) STG(FMT("Unknown call status (%d)") % (int)code)); } -std::string Verbose::linkStatus(KSignaling sig, int32 code, Verbose::Presentation fmt) +std::string Verbose::linkStatus(const KSignaling sig, const int32 code, const Verbose::Presentation fmt, const bool simpleStatus) { switch (sig) { @@ -1340,7 +1415,9 @@ std::string Verbose::linkStatus(KSignaling sig, int32 code, Verbose::Presentatio #endif #if K3L_EXACT(2,1,0) - case ksigFax: +#if !K3L_AT_LEAST(2,2,0) + case ksigFax: +#endif return presentation(fmt, "[ksigFax]", "FAX"); #endif case ksigContinuousEM: @@ -1386,9 +1463,18 @@ std::string Verbose::linkStatus(KSignaling sig, int32 code, Verbose::Presentatio if (kesUnknownAlarm & code) strs.add(presentation(fmt, "UnknownAlarm", "Slip alarm")); if (kesE1Error & code) strs.add(presentation(fmt, "E1Error", "E1 error")); - PRESENTATION_CHECK_RETURN(fmt, - STG(FMT("kes{%s}") % strs.merge(",")), - strs.merge(", ")); + if (simpleStatus) + { + PRESENTATION_CHECK_RETURN(fmt, + STG(FMT("kes{%s}") % *(strs.list().begin())), + *(strs.list().begin())); + } + else + { + PRESENTATION_CHECK_RETURN(fmt, + STG(FMT("kes{%s}") % strs.merge(",")), + strs.merge(", ")); + } } } @@ -1397,7 +1483,7 @@ std::string Verbose::linkStatus(KSignaling sig, int32 code, Verbose::Presentatio STG(FMT("Unknown link status for '%s' (%d)") % signaling(sig) % (int)code)); } -std::string Verbose::channelStatus(KSignaling sig, int32 flags, Verbose::Presentation fmt) +std::string Verbose::channelStatus(const KSignaling sig, const int32 flags, const Verbose::Presentation fmt) { try { @@ -1413,8 +1499,10 @@ std::string Verbose::channelStatus(KSignaling sig, int32 flags, Verbose::Present #if K3L_EXACT(2,1,0) case ksigISUP: return presentation(fmt, "[ksigISUP]", "ISUP trunk"); +#if !K3L_AT_LEAST(2,2,0) case ksigFax: return presentation(fmt, "[ksigFax]", "FAX"); +#endif #endif case ksigAnalog: @@ -1532,7 +1620,7 @@ std::string Verbose::channelStatus(KSignaling sig, int32 flags, Verbose::Present } } } - catch (internal_not_found & e) + catch (internal_not_found e) { /* we use this exception to break the control flow */ } @@ -1542,7 +1630,7 @@ std::string Verbose::channelStatus(KSignaling sig, int32 flags, Verbose::Present STG(FMT("Unknown channel status for '%s' (%d)") % signaling(sig) % flags)); } -std::string Verbose::status(KLibraryStatus code, Verbose::Presentation fmt) +std::string Verbose::status(const KLibraryStatus code, const Verbose::Presentation fmt) { switch (code) { @@ -1569,7 +1657,7 @@ std::string Verbose::status(KLibraryStatus code, Verbose::Presentation fmt) STG(FMT("Unknown library status (%d)") % (int)code)); } -std::string Verbose::h100configIndex(KH100ConfigIndex code, Verbose::Presentation fmt) +std::string Verbose::h100configIndex(const KH100ConfigIndex code, const Verbose::Presentation fmt) { switch (code) { @@ -1584,7 +1672,7 @@ std::string Verbose::h100configIndex(KH100ConfigIndex code, Verbose::Presentatio case khciCTbusFreq07_04: return presentation(fmt, "khciCTbusFreq07_04", "CTBus Frequency 07 04"); // TODO: find better name case khciCTbusFreq11_08: return presentation(fmt, "khciCTbusFreq11_08", "CTBus Frequency 11 08"); // TODO: find better name case khciCTbusFreq15_12: return presentation(fmt, "khciCTbusFreq15_12", "CTBus Frequency 15 12"); // TODO: find better name - case khciMax: return presentation(fmt, "khciMax", "Max"); // TODO: find better name + case khciMax: return presentation(fmt, "khciMax", "Max"); // TODO: find better name case khciMasterDevId: return presentation(fmt, "khciMasterDevId", "Master Device Number"); case khciSecMasterDevId: return presentation(fmt, "khciSecMasterDevId", "Secondary Master Device Number"); case khciCtNetrefDevId: return presentation(fmt, "khciCtNetrefDevId", "CTBus Network Reference Device Number"); @@ -1599,7 +1687,7 @@ std::string Verbose::h100configIndex(KH100ConfigIndex code, Verbose::Presentatio } #if K3L_AT_LEAST(1,6,0) -std::string Verbose::callStartInfo(KCallStartInfo code, Verbose::Presentation fmt) +std::string Verbose::callStartInfo(const KCallStartInfo code, const Verbose::Presentation fmt) { switch (code) { @@ -1615,13 +1703,13 @@ std::string Verbose::callStartInfo(KCallStartInfo code, Verbose::Presentation fm STG(FMT("Unknown call answer info (%d)") % (int)code)); } -std::string Verbose::gsmCallCause(KGsmCallCause code, Verbose::Presentation fmt) +std::string Verbose::gsmCallCause(const KGsmCallCause code, const Verbose::Presentation fmt) { try { return internal_gsmCallCause(code, fmt); } - catch (internal_not_found & e) + catch (internal_not_found e) { PRESENTATION_CHECK_RETURN(fmt, STG(FMT("[KGsmCallCause='%d']") % (int)code), @@ -1629,7 +1717,7 @@ std::string Verbose::gsmCallCause(KGsmCallCause code, Verbose::Presentation fmt) } } -std::string Verbose::internal_gsmCallCause(KGsmCallCause code, Verbose::Presentation fmt) +std::string Verbose::internal_gsmCallCause(const KGsmCallCause code, const Verbose::Presentation fmt) { switch (code) { @@ -1686,13 +1774,13 @@ std::string Verbose::internal_gsmCallCause(KGsmCallCause code, Verbose::Presenta throw internal_not_found(); } -std::string Verbose::gsmMobileCause(KGsmMobileCause code, Verbose::Presentation fmt) +std::string Verbose::gsmMobileCause(const KGsmMobileCause code, const Verbose::Presentation fmt) { try { return internal_gsmMobileCause(code, fmt); } - catch (internal_not_found & e) + catch (internal_not_found e) { PRESENTATION_CHECK_RETURN(fmt, STG(FMT("[KGsmMobileCause='%d']") % (int)code), @@ -1700,7 +1788,7 @@ std::string Verbose::gsmMobileCause(KGsmMobileCause code, Verbose::Presentation } } -std::string Verbose::internal_gsmMobileCause(KGsmMobileCause code, Verbose::Presentation fmt) +std::string Verbose::internal_gsmMobileCause(const KGsmMobileCause code, const Verbose::Presentation fmt) { switch (code) { @@ -1792,13 +1880,13 @@ std::string Verbose::internal_gsmMobileCause(KGsmMobileCause code, Verbose::Pres throw internal_not_found(); } -std::string Verbose::gsmSmsCause(KGsmSmsCause code, Verbose::Presentation fmt) +std::string Verbose::gsmSmsCause(const KGsmSmsCause code, const Verbose::Presentation fmt) { try { return internal_gsmSmsCause(code, fmt); } - catch (internal_not_found & e) + catch (internal_not_found e) { PRESENTATION_CHECK_RETURN(fmt, STG(FMT("[KGsmSmsCause='%d']") % (int)code), @@ -1806,7 +1894,7 @@ std::string Verbose::gsmSmsCause(KGsmSmsCause code, Verbose::Presentation fmt) } } -std::string Verbose::internal_gsmSmsCause(KGsmSmsCause code, Verbose::Presentation fmt) +std::string Verbose::internal_gsmSmsCause(const KGsmSmsCause code, const Verbose::Presentation fmt) { switch (code) { @@ -1890,13 +1978,13 @@ std::string Verbose::internal_gsmSmsCause(KGsmSmsCause code, Verbose::Presentati throw internal_not_found(); } -std::string Verbose::q931ProgressIndication(KQ931ProgressIndication code, Verbose::Presentation fmt) +std::string Verbose::q931ProgressIndication(const KQ931ProgressIndication code, const Verbose::Presentation fmt) { try { return internal_q931ProgressIndication(code); } - catch (internal_not_found & e) + catch (internal_not_found e) { PRESENTATION_CHECK_RETURN(fmt, STG(FMT("[KQ931ProgressIndication='%d']") % (int)code), @@ -1904,7 +1992,7 @@ std::string Verbose::q931ProgressIndication(KQ931ProgressIndication code, Verbos } } -std::string Verbose::internal_q931ProgressIndication(KQ931ProgressIndication code, Verbose::Presentation fmt) +std::string Verbose::internal_q931ProgressIndication(const KQ931ProgressIndication code, const Verbose::Presentation fmt) { switch (code) { @@ -1924,7 +2012,7 @@ std::string Verbose::internal_q931ProgressIndication(KQ931ProgressIndication cod #if K3L_AT_LEAST(2,1,0) -std::string Verbose::faxResult(KFaxResult code, Verbose::Presentation fmt) +std::string Verbose::faxResult(const KFaxResult code, const Verbose::Presentation fmt) { switch (code) { @@ -1945,7 +2033,7 @@ std::string Verbose::faxResult(KFaxResult code, Verbose::Presentation fmt) STG(FMT("Unknown fax result (%d)") % (int)code)); } -std::string Verbose::faxFileErrorCause(KFaxFileErrorCause code, Verbose::Presentation fmt) +std::string Verbose::faxFileErrorCause(const KFaxFileErrorCause code, const Verbose::Presentation fmt) { switch (code) { @@ -1969,307 +2057,12 @@ std::string Verbose::faxFileErrorCause(KFaxFileErrorCause code, Verbose::Present #endif - /********/ -std::string Verbose::commandName(int32 code) -{ - switch ((kcommand)code) - { - case K_CM_SEIZE: return "CM_SEIZE"; - case K_CM_SYNC_SEIZE: return "CM_SYNC_SEIZE"; - case K_CM_DIAL_DTMF: return "CM_DIAL_DTMF"; -#if K3L_AT_LEAST(1,6,0) - case K_CM_SIP_REGISTER: return "CM_SIP_REGISTER"; -#endif - case K_CM_DISCONNECT: return "CM_DISCONNECT"; - case K_CM_CONNECT: return "CM_CONNECT"; - case K_CM_PRE_CONNECT: return "CM_PRE_CONNECT"; - case K_CM_CAS_CHANGE_LINE_STT: return "CM_CAS_CHANGE_LINE_STT"; - case K_CM_CAS_SEND_MFC: return "CM_CAS_SEND_MFC"; - case K_CM_SET_FORWARD_CHANNEL: return "CM_SET_FORWARD_CHANNEL"; - case K_CM_CAS_SET_MFC_DETECT_MODE: return "CM_CAS_SET_MFC_DETECT_MODE"; - case K_CM_DROP_COLLECT_CALL: return "CM_DROP_COLLECT_CALL"; - -#if K3L_AT_LEAST(1,5,0) - case K_CM_MAKE_CALL: return "CM_MAKE_CALL"; -#endif - -#if K3L_AT_LEAST(1,4,0) - case K_CM_RINGBACK: return "CM_RINGBACK"; -#endif - -#if K3L_AT_LEAST(1,5,1) - case K_CM_USER_INFORMATION: return "CM_USER_INFORMATION"; -#endif - -#if K3L_AT_LEAST(1,4,0) && !K3L_AT_LEAST(2,2,0) - case K_CM_VOIP_SEIZE: return "CM_VOIP_SEIZE"; - -#if !K3L_AT_LEAST(2,0,0) - /* internal commands */ - case K_CM_VOIP_START_DEBUG: return "CM_VOIP_START_DEBUG"; - case K_CM_VOIP_STOP_DEBUG: return "CM_VOIP_STOP_DEBUG"; - case K_CM_VOIP_DUMP_STAT: return "CM_VOIP_DUMP_STAT"; -#endif -#endif - -#if K3L_AT_LEAST(1,5,2) && !K3L_AT_LEAST(2,0,0) - /* internal command */ - case K_CM_ISDN_DEBUG: return "CM_ISDN_DEBUG"; -#endif - - case K_CM_LOCK_INCOMING: return "CM_LOCK_INCOMING"; - case K_CM_UNLOCK_INCOMING: return "CM_UNLOCK_INCOMING"; - case K_CM_LOCK_OUTGOING: return "CM_LOCK_OUTGOING"; - case K_CM_UNLOCK_OUTGOING: return "CM_UNLOCK_OUTGOING"; - - case K_CM_START_SEND_FAIL: return "CM_START_SEND_FAIL"; - case K_CM_STOP_SEND_FAIL: return "CM_STOP_SEND_FAIL"; - -#if K3L_AT_LEAST(1,5,3) - case K_CM_END_OF_NUMBER: return "CM_END_OF_NUMBER"; -#endif - -#if K3L_AT_LEAST(1,6,0) - case K_CM_SS_TRANSFER: return "CM_SS_TRANSFER"; - case K_CM_GET_SMS: return "CM_GET_SMS"; - case K_CM_PREPARE_SMS: return "CM_PREPARE_SMS"; - case K_CM_SEND_SMS: return "CM_SEND_SMS"; -#endif -#if K3L_HAS_MPTY_SUPPORT - case K_CM_HOLD_SWITCH: return "CM_HOLD_SWITCH"; - case K_CM_MPTY_CONF: return "CM_MPTY_CONF"; - case K_CM_MPTY_SPLIT: return "CM_MPTY_SPLIT"; -#endif - - case K_CM_ENABLE_DTMF_SUPPRESSION: return "CM_ENABLE_DTMF_SUPPRESSION"; - case K_CM_DISABLE_DTMF_SUPPRESSION: return "CM_DISABLE_DTMF_SUPPRESSION"; - case K_CM_ENABLE_AUDIO_EVENTS: return "CM_ENABLE_AUDIO_EVENTS"; - case K_CM_DISABLE_AUDIO_EVENTS: return "CM_DISABLE_AUDIO_EVENTS"; - case K_CM_ENABLE_CALL_PROGRESS: return "CM_ENABLE_CALL_PROGRESS"; - case K_CM_DISABLE_CALL_PROGRESS: return "CM_DISABLE_CALL_PROGRESS"; - case K_CM_FLASH: return "CM_FLASH"; - case K_CM_ENABLE_PULSE_DETECTION: return "CM_ENABLE_PULSE_DETECTION"; - case K_CM_DISABLE_PULSE_DETECTION: return "CM_DISABLE_PULSE_DETECTION"; - case K_CM_ENABLE_ECHO_CANCELLER: return "CM_ENABLE_ECHO_CANCELLER"; - case K_CM_DISABLE_ECHO_CANCELLER: return "CM_DISABLE_ECHO_CANCELLER"; - case K_CM_ENABLE_AGC: return "CM_ENABLE_AGC"; - case K_CM_DISABLE_AGC: return "CM_DISABLE_AGC"; - case K_CM_ENABLE_HIGH_IMP_EVENTS: return "CM_ENABLE_HIGH_IMP_EVENTS"; - case K_CM_DISABLE_HIGH_IMP_EVENTS: return "CM_DISABLE_HIGH_IMP_EVENTS"; - -#if K3L_AT_LEAST(1,6,0) - case K_CM_ENABLE_CALL_ANSWER_INFO: return "CM_ENABLE_CALL_ANSWER_INFO"; - case K_CM_DISABLE_CALL_ANSWER_INFO: return "CM_DISABLE_CALL_ANSWER_INFO"; -#endif - - case K_CM_RESET_LINK: return "CM_RESET_LINK"; - -#if K3L_AT_LEAST(1,6,0) - case K_CM_CLEAR_LINK_ERROR_COUNTER: return "CM_CLEAR_LINK_ERROR_COUNTER"; -#endif - - case K_CM_SEND_DTMF: return "CM_SEND_DTMF"; - case K_CM_STOP_AUDIO: return "CM_STOP_AUDIO"; - case K_CM_HARD_RESET: return "CM_HARD_RESET"; - - case K_CM_SEND_TO_CTBUS: return "CM_SEND_TO_CTBUS"; - case K_CM_RECV_FROM_CTBUS: return "CM_RECV_FROM_CTBUS"; - case K_CM_SETUP_H100: return "CM_SETUP_H100"; - - case K_CM_MIXER: return "CM_MIXER"; - case K_CM_CLEAR_MIXER: return "CM_CLEAR_MIXER"; - case K_CM_PLAY_FROM_FILE: return "CM_PLAY_FROM_FILE"; - case K_CM_RECORD_TO_FILE: return "CM_RECORD_TO_FILE"; - case K_CM_PLAY_FROM_STREAM: return "CM_PLAY_FROM_STREAM"; - case K_CM_STOP_PLAY: return "CM_STOP_PLAY"; - case K_CM_STOP_RECORD: return "CM_STOP_RECORD"; - case K_CM_PAUSE_PLAY: return "CM_PAUSE_PLAY"; - case K_CM_PAUSE_RECORD: return "CM_PAUSE_RECORD"; - case K_CM_INCREASE_VOLUME: return "CM_INCREASE_VOLUME"; - case K_CM_DECREASE_VOLUME: return "CM_DECREASE_VOLUME"; - case K_CM_LISTEN: return "CM_LISTEN"; - case K_CM_STOP_LISTEN: return "CM_STOP_LISTEN"; - case K_CM_PREPARE_FOR_LISTEN: return "CM_PREPARE_FOR_LISTEN"; - - case K_CM_PLAY_SOUND_CARD: return "CM_PLAY_SOUND_CARD"; - case K_CM_STOP_SOUND_CARD: return "CM_STOP_SOUND_CARD"; - - case K_CM_MIXER_CTBUS: return "CM_MIXER_CTBUS"; - case K_CM_PLAY_FROM_STREAM_EX: return "CM_PLAY_FROM_STREAM_EX"; - case K_CM_ENABLE_PLAYER_AGC: return "CM_ENABLE_PLAYER_AGC"; - case K_CM_DISABLE_PLAYER_AGC: return "CM_DISABLE_PLAYER_AGC"; - case K_CM_START_STREAM_BUFFER: return "CM_START_STREAM_BUFFER"; - case K_CM_ADD_STREAM_BUFFER: return "CM_ADD_STREAM_BUFFER"; - case K_CM_STOP_STREAM_BUFFER: return "CM_STOP_STREAM_BUFFER"; - case K_CM_SEND_BEEP: return "CM_SEND_BEEP"; - case K_CM_SEND_BEEP_CONF: return "CM_SEND_BEEP_CONF"; - case K_CM_ADD_TO_CONF: return "CM_ADD_TO_CONF"; - case K_CM_REMOVE_FROM_CONF: return "CM_REMOVE_FROM_CONF"; - case K_CM_RECORD_TO_FILE_EX: return "CM_RECORD_TO_FILE_EX"; - -#if K3L_AT_LEAST(1,5,4) - case K_CM_SET_VOLUME: return "CM_SET_VOLUME"; -#endif - case K_CM_SET_LINE_CONDITION: return "CM_SET_LINE_CONDITION"; - case K_CM_SEND_LINE_CONDITION: return "CM_SEND_LINE_CONDITION"; - case K_CM_SET_CALLER_CATEGORY: return "CM_SET_CALLER_CATEGORY"; - case K_CM_DIAL_MFC: return "CM_DIAL_MFC"; - - case K_CM_INTERNAL_PLAY: return "CM_INTERNAL_PLAY"; - case K_CM_RESUME_PLAY: return "CM_RESUME_PLAY"; - case K_CM_RESUME_RECORD: return "CM_RESUME_RECORD"; - case K_CM_INTERNAL_PLAY_EX: return "CM_INTERNAL_PLAY_EX"; -#if !K3L_AT_LEAST(2,0,0) - case K_CM_PING: return "CM_PING"; -#if K3L_AT_LEAST(1,6,0) - case K_CM_LOG_REQUEST: return "CM_LOG_REQUEST"; - case K_CM_LOG_CREATE_DISPATCHER: return "CM_LOG_CREATE_DISPATCHER"; - case K_CM_LOG_DESTROY_DISPATCHER: return "CM_LOG_DESTROY_DISPATCHER"; -#endif -#endif - -#if K3L_AT_LEAST(1,6,0) - case K_CM_START_CADENCE: return "CM_START_CADENCE"; - case K_CM_STOP_CADENCE: return "CM_STOP_CADENCE"; - case K_CM_CHECK_NEW_SMS: return "CM_CHECK_NEW_SMS"; - case K_CM_SEND_TO_MODEM: return "CM_SEND_TO_MODEM"; -#endif -#if K3L_AT_LEAST(2,1,0) - case K_CM_START_FAX_TX: return "CM_START_FAX_TX"; - case K_CM_STOP_FAX_TX: return "CM_STOP_FAX_TX"; - case K_CM_ADD_FAX_FILE: return "CM_ADD_FAX_FILE"; - case K_CM_ADD_FAX_PAGE_BREAK: return "CM_ADD_FAX_PAGE_BREAK"; - case K_CM_START_FAX_RX: return "CM_START_FAX_RX"; - case K_CM_STOP_FAX_RX: return "CM_STOP_FAX_RX"; - case K_CM_SIM_CARD_SELECT: return "CM_SIM_CARD_SELECT"; -#endif - -#if K3L_AT_LEAST(2,1,0) - case K_CM_NOTIFY_WATCHDOG: return "CM_NOTIFY_WATCHDOG"; - case K_CM_STOP_WATCHDOG: return "CM_STOP_WATCHDOG"; - case K_CM_WATCHDOG_COUNT: return "CM_WATCHDOG_COUNT"; - case K_CM_START_WATCHDOG: return "CM_START_WATCHDOG"; -#endif - - } - - return STG(FMT("[command='%d']") % code); -} - -std::string Verbose::eventName(int32 code) -{ - switch ((kevent)code) - { - case K_EV_CHANNEL_FREE: return "EV_CHANNEL_FREE"; - case K_EV_CONNECT: return "EV_CONNECT"; - case K_EV_DISCONNECT: return "EV_DISCONNECT"; - case K_EV_CALL_SUCCESS: return "EV_CALL_SUCCESS"; - case K_EV_CALL_FAIL: return "EV_CALL_FAIL"; - case K_EV_NO_ANSWER: return "EV_NO_ANSWER"; - case K_EV_BILLING_PULSE: return "EV_BILLING_PULSE"; - case K_EV_SEIZE_SUCCESS: return "EV_SEIZE_SUCCESS"; - case K_EV_SEIZE_FAIL: return "EV_SEIZE_FAIL"; - case K_EV_SEIZURE_START: return "EV_SEIZURE_START"; - case K_EV_CAS_LINE_STT_CHANGED: return "EV_CAS_LINE_STT_CHANGED"; - case K_EV_CAS_MFC_RECV: return "EV_CAS_MFC_RECV"; - -#if K3L_AT_LEAST(1,5,0) - case K_EV_NEW_CALL: return "EV_NEW_CALL"; -#endif - -#if K3L_AT_LEAST(1,5,1) - case K_EV_USER_INFORMATION: return "EV_USER_INFORMATION"; -#endif - -#if K3L_AT_LEAST(1,5,3) - case K_EV_DIALED_DIGIT: return "EV_DIALED_DIGIT"; -#endif - -#if K3L_AT_LEAST(1,6,0) - case K_EV_SIP_REGISTER_INFO: return "EV_SIP_REGISTER_INFO"; -#endif - -#if K3L_AT_LEAST(1,4,0) - case K_EV_CALL_HOLD_START: return "EV_CALL_HOLD_START"; - case K_EV_CALL_HOLD_STOP: return "EV_CALL_HOLD_STOP"; -#endif - -#if K3L_AT_LEAST(1,6,0) - case K_EV_SS_TRANSFER_FAIL: return "EV_SS_TRANSFER_FAIL"; - case K_EV_FLASH: return "EV_FLASH"; -#endif - - case K_EV_DTMF_DETECTED: return "EV_DTMF_DETECTED"; - case K_EV_DTMF_SEND_FINISH: return "EV_DTMF_SEND_FINISH"; - case K_EV_AUDIO_STATUS: return "EV_AUDIO_STATUS"; - case K_EV_CADENCE_RECOGNIZED: return "EV_CADENCE_RECOGNIZED"; - - case K_EV_END_OF_STREAM: return "EV_END_OF_STREAM"; - case K_EV_PULSE_DETECTED: return "EV_PULSE_DETECTED"; - -#if K3L_AT_LEAST(1,5,1) - case K_EV_POLARITY_REVERSAL: return "EV_POLARITY_REVERSAL"; -#endif - -#if K3L_AT_LEAST(1,6,0) - case K_EV_ISDN_PROGRESS_INDICATOR: return "EV_ISDN_PROGRESS_INDICATOR"; - case K_EV_CALL_ANSWER_INFO: return "EV_CALL_ANSWER_INFO"; - case K_EV_COLLECT_CALL: return "EV_COLLECT_CALL"; - case K_EV_SIP_DTMF_DETECTED: return "EV_SIP_DTMF_DETECTED"; - - case K_EV_RECV_FROM_MODEM: return "EV_RECV_FROM_MODEM"; - case K_EV_NEW_SMS: return "EV_NEW_SMS"; - case K_EV_SMS_INFO: return "EV_SMS_INFO"; - case K_EV_SMS_DATA: return "EV_SMS_DATA"; - case K_EV_SMS_SEND_RESULT: return "EV_SMS_SEND_RESULT"; - case K_EV_RING_DETECTED: return "EV_RING_DETECTED"; - case K_EV_PHYSICAL_LINK_DOWN: return "EV_PHYSICAL_LINK_DOWN"; - case K_EV_PHYSICAL_LINK_UP: return "EV_PHYSICAL_LINK_UP"; -#endif -#if K3L_HAS_MPTY_SUPPORT - case K_EV_CALL_MPTY_START: return "EV_CALL_MPTY_START"; - case K_EV_CALL_MPTY_STOP: return "EV_CALL_MPTY_STOP"; - case K_EV_GSM_COMMAND_STATUS: return "EV_GSM_COMMAND_STATUS"; -#endif -#if !K3L_AT_LEAST(2,0,0) - case K_EV_PONG: return "EV_PONG"; -#endif - case K_EV_CHANNEL_FAIL: return "EV_CHANNEL_FAIL"; - case K_EV_REFERENCE_FAIL: return "EV_REFERENCE_FAIL"; - case K_EV_INTERNAL_FAIL: return "EV_INTERNAL_FAIL"; - case K_EV_HARDWARE_FAIL: return "EV_HARDWARE_FAIL"; - case K_EV_LINK_STATUS: return "EV_LINK_STATUS"; - -#if K3L_AT_LEAST(1,4,0) - case K_EV_CLIENT_RECONNECT: return "EV_CLIENT_RECONNECT"; - case K_EV_VOIP_SEIZURE: return "EV_VOIP_SEIZURE"; -#endif - case K_EV_SEIZURE: return "EV_SEIZURE"; -#if K3L_AT_LEAST(2,1,0) - case K_EV_FAX_CHANNEL_FREE: return "EV_FAX_CHANNEL_FREE"; - case K_EV_FAX_FILE_SENT: return "EV_FAX_FILE_SENT"; - case K_EV_FAX_FILE_FAIL: return "EV_FAX_FILE_FAIL"; - /*case K_EV_FAX_MESSAGE_CONFIRMATION:return "EV_FAX_MESSAGE_CONFIRMATION";*/ - case K_EV_FAX_TX_TIMEOUT: return "EV_FAX_TX_TIMEOUT"; - case K_EV_FAX_PAGE_CONFIRMATION:return "EV_FAX_PAGE_CONFIRMATION"; - case K_EV_FAX_REMOTE_INFO: return "EV_FAX_REMOTE_INFO"; -#endif - -#if K3L_AT_LEAST(2,1,0) - case K_EV_WATCHDOG_COUNT: return "EV_WATCHDOG_COUNT"; -#endif - } - - return STG(FMT("[event='%d']") % code); -} - - #if K3L_AT_LEAST(2,0,0) -std::string Verbose::command(int32 dev, K3L_COMMAND *k3lcmd, R2CountryType r2_country, Verbose::Presentation fmt) +std::string Verbose::command(const int32 dev, const K3L_COMMAND * const k3lcmd, const R2CountryType r2_country, const Verbose::Presentation fmt) #else -std::string Verbose::command(int32 dev, K3L_COMMAND *k3lcmd, Verbose::Presentation fmt) +std::string Verbose::command(const int32 dev, const K3L_COMMAND * const k3lcmd, const Verbose::Presentation fmt) #endif { #if K3L_AT_LEAST(2,0,0) @@ -2280,106 +2073,107 @@ std::string Verbose::command(int32 dev, K3L_COMMAND *k3lcmd, Verbose::Presentati } #if K3L_AT_LEAST(2,0,0) -std::string Verbose::command(int32 cmd_code, int32 dev_idx, int32 obj_idx, const char * params, R2CountryType r2_country, Verbose::Presentation fmt) +std::string Verbose::command(const int32 cmd_code, const int32 dev_idx, const int32 obj_idx, const char * const params, const R2CountryType r2_country, const Verbose::Presentation fmt) #else -std::string Verbose::command(int32 cmd_code, int32 dev_idx, int32 obj_idx, const char * params, Verbose::Presentation fmt) +std::string Verbose::command(const int32 cmd_code, const int32 dev_idx, const int32 obj_idx, const char * const params, const Verbose::Presentation fmt) #endif { unsigned short int dev = (unsigned short int) dev_idx; unsigned short int obj = (unsigned short int) obj_idx; - kcommand code = (kcommand) cmd_code; + VerboseTraits::Command code = (VerboseTraits::Command) cmd_code; std::string buf, extra; switch (code) { - case K_CM_SEIZE: - case K_CM_SYNC_SEIZE: - //case K_CM_VOIP_SEIZE://deprecated - case K_CM_DIAL_MFC: - case K_CM_DIAL_DTMF: + case VerboseTraits::K_CM_SEIZE: + case VerboseTraits::K_CM_SYNC_SEIZE: + case VerboseTraits::K_CM_VOIP_SEIZE: + case VerboseTraits::K_CM_DIAL_MFC: + case VerboseTraits::K_CM_DIAL_DTMF: - case K_CM_CONNECT: - case K_CM_PRE_CONNECT: - case K_CM_DISCONNECT: - case K_CM_DROP_COLLECT_CALL: + case VerboseTraits::K_CM_CONNECT: + case VerboseTraits::K_CM_PRE_CONNECT: + case VerboseTraits::K_CM_DISCONNECT: + case VerboseTraits::K_CM_DROP_COLLECT_CALL: - case K_CM_START_SEND_FAIL: - case K_CM_STOP_SEND_FAIL: + case VerboseTraits::K_CM_START_SEND_FAIL: + case VerboseTraits::K_CM_STOP_SEND_FAIL: - case K_CM_ENABLE_DTMF_SUPPRESSION: - case K_CM_DISABLE_DTMF_SUPPRESSION: - case K_CM_ENABLE_AUDIO_EVENTS: - case K_CM_DISABLE_AUDIO_EVENTS: - case K_CM_ENABLE_CALL_PROGRESS: - case K_CM_DISABLE_CALL_PROGRESS: - case K_CM_ENABLE_PULSE_DETECTION: - case K_CM_DISABLE_PULSE_DETECTION: - case K_CM_ENABLE_ECHO_CANCELLER: - case K_CM_DISABLE_ECHO_CANCELLER: - case K_CM_ENABLE_AGC: - case K_CM_DISABLE_AGC: - case K_CM_ENABLE_HIGH_IMP_EVENTS: - case K_CM_DISABLE_HIGH_IMP_EVENTS: + case VerboseTraits::K_CM_ENABLE_DTMF_SUPPRESSION: + case VerboseTraits::K_CM_DISABLE_DTMF_SUPPRESSION: + case VerboseTraits::K_CM_ENABLE_AUDIO_EVENTS: + case VerboseTraits::K_CM_DISABLE_AUDIO_EVENTS: + case VerboseTraits::K_CM_ENABLE_CALL_PROGRESS: + case VerboseTraits::K_CM_DISABLE_CALL_PROGRESS: + case VerboseTraits::K_CM_ENABLE_PULSE_DETECTION: + case VerboseTraits::K_CM_DISABLE_PULSE_DETECTION: + case VerboseTraits::K_CM_ENABLE_ECHO_CANCELLER: + case VerboseTraits::K_CM_DISABLE_ECHO_CANCELLER: + case VerboseTraits::K_CM_ENABLE_AGC: + case VerboseTraits::K_CM_DISABLE_AGC: + case VerboseTraits::K_CM_ENABLE_HIGH_IMP_EVENTS: + case VerboseTraits::K_CM_DISABLE_HIGH_IMP_EVENTS: - case K_CM_FLASH: - case K_CM_RESET_LINK: - case K_CM_CLEAR_MIXER: + case VerboseTraits::K_CM_FLASH: + case VerboseTraits::K_CM_RESET_LINK: + case VerboseTraits::K_CM_CLEAR_MIXER: - case K_CM_LOCK_INCOMING: - case K_CM_UNLOCK_INCOMING: - case K_CM_LOCK_OUTGOING: - case K_CM_UNLOCK_OUTGOING: + case VerboseTraits::K_CM_LOCK_INCOMING: + case VerboseTraits::K_CM_UNLOCK_INCOMING: + case VerboseTraits::K_CM_LOCK_OUTGOING: + case VerboseTraits::K_CM_UNLOCK_OUTGOING: - case K_CM_INCREASE_VOLUME: - case K_CM_DECREASE_VOLUME: + case VerboseTraits::K_CM_INCREASE_VOLUME: + case VerboseTraits::K_CM_DECREASE_VOLUME: - case K_CM_STOP_RECORD: - case K_CM_PAUSE_RECORD: - case K_CM_RESUME_RECORD: + case VerboseTraits::K_CM_STOP_RECORD: + case VerboseTraits::K_CM_PAUSE_RECORD: + case VerboseTraits::K_CM_RESUME_RECORD: - case K_CM_STOP_LISTEN: + case VerboseTraits::K_CM_STOP_LISTEN: - case K_CM_PLAY_SOUND_CARD: - case K_CM_STOP_SOUND_CARD: - case K_CM_RINGBACK: + case VerboseTraits::K_CM_PLAY_SOUND_CARD: + case VerboseTraits::K_CM_STOP_SOUND_CARD: + case VerboseTraits::K_CM_RINGBACK: #if K3L_AT_LEAST(1,4,0) && !K3L_AT_LEAST(2,0,0) - case K_CM_VOIP_START_DEBUG: - case K_CM_VOIP_STOP_DEBUG: - case K_CM_VOIP_DUMP_STAT: + case VerboseTraits::K_CM_VOIP_START_DEBUG: + case VerboseTraits::K_CM_VOIP_STOP_DEBUG: + case VerboseTraits::K_CM_VOIP_DUMP_STAT: #endif #if K3L_AT_LEAST(1,5,3) - case K_CM_END_OF_NUMBER: + case VerboseTraits::K_CM_END_OF_NUMBER: #endif #if K3L_AT_LEAST(1,5,4) - case K_CM_SET_VOLUME: + case VerboseTraits::K_CM_SET_VOLUME: #endif #if K3L_AT_LEAST(1,6,0) - case K_CM_ENABLE_CALL_ANSWER_INFO: - case K_CM_DISABLE_CALL_ANSWER_INFO: + case VerboseTraits::K_CM_ENABLE_CALL_ANSWER_INFO: + case VerboseTraits::K_CM_DISABLE_CALL_ANSWER_INFO: - case K_CM_SS_TRANSFER: + case VerboseTraits::K_CM_SS_TRANSFER: - case K_CM_CHECK_NEW_SMS: - case K_CM_GET_SMS: - case K_CM_PREPARE_SMS: - case K_CM_SEND_SMS: + case VerboseTraits::K_CM_CHECK_NEW_SMS: + case VerboseTraits::K_CM_GET_SMS: + case VerboseTraits::K_CM_PREPARE_SMS: + case VerboseTraits::K_CM_SEND_SMS: - case K_CM_START_CADENCE: - case K_CM_STOP_CADENCE: - case K_CM_SEND_TO_MODEM: + case VerboseTraits::K_CM_START_CADENCE: + case VerboseTraits::K_CM_STOP_CADENCE: + case VerboseTraits::K_CM_SEND_TO_MODEM: #endif #if K3L_HAS_MPTY_SUPPORT - case K_CM_HOLD_SWITCH: - case K_CM_MPTY_CONF: - case K_CM_MPTY_SPLIT: + case VerboseTraits::K_CM_HOLD_SWITCH: + case VerboseTraits::K_CM_MPTY_CONF: + case VerboseTraits::K_CM_MPTY_SPLIT: #endif #if K3L_AT_LEAST(2,1,0) - case K_CM_SIM_CARD_SELECT: + case VerboseTraits::K_CM_SIM_CARD_SELECT: + case VerboseTraits::K_CM_CT_TRANSFER: #endif if (params != NULL) { @@ -2394,12 +2188,12 @@ std::string Verbose::command(int32 cmd_code, int32 dev_idx, int32 obj_idx, const return show(buf, commandName(code), Target(CHANNEL, dev, obj)); } - case K_CM_SEND_DTMF: /* ?? */ + case VerboseTraits::K_CM_SEND_DTMF: /* ?? */ return show(buf, commandName(code), Target(CHANNEL, dev, obj)); /****/ - case K_CM_STOP_AUDIO: + case VerboseTraits::K_CM_STOP_AUDIO: extra = "stop='"; switch ((params ? (int)(*params) : -1)) { @@ -2415,7 +2209,7 @@ std::string Verbose::command(int32 cmd_code, int32 dev_idx, int32 obj_idx, const /****/ #if K3L_AT_LEAST(1,5,2) && !K3L_AT_LEAST(2,0,0) - case K_CM_ISDN_DEBUG: + case VerboseTraits::K_CM_ISDN_DEBUG: extra = "flags='"; extra += isdnDebug((unsigned long)params); extra += "'"; @@ -2426,7 +2220,7 @@ std::string Verbose::command(int32 cmd_code, int32 dev_idx, int32 obj_idx, const /****/ #if K3L_AT_LEAST(1,5,1) - case K_CM_USER_INFORMATION: + case VerboseTraits::K_CM_USER_INFORMATION: #endif if (params != NULL) { @@ -2448,7 +2242,7 @@ std::string Verbose::command(int32 cmd_code, int32 dev_idx, int32 obj_idx, const - case K_CM_CAS_CHANGE_LINE_STT: + case VerboseTraits::K_CM_CAS_CHANGE_LINE_STT: { const char status = (params ? *params : 0x00); @@ -2462,7 +2256,7 @@ std::string Verbose::command(int32 cmd_code, int32 dev_idx, int32 obj_idx, const return show(buf, commandName(code), Target(CHANNEL, dev, obj), extra); } - case K_CM_CAS_SEND_MFC: + case VerboseTraits::K_CM_CAS_SEND_MFC: { char mfc = (params ? *params : 0xff); @@ -2471,7 +2265,7 @@ std::string Verbose::command(int32 cmd_code, int32 dev_idx, int32 obj_idx, const return show(buf, commandName(code), Target(CHANNEL, dev, obj), extra); } - case K_CM_CAS_SET_MFC_DETECT_MODE: + case VerboseTraits::K_CM_CAS_SET_MFC_DETECT_MODE: { int mode = (params ? *((int *)params) : -1); @@ -2480,7 +2274,7 @@ std::string Verbose::command(int32 cmd_code, int32 dev_idx, int32 obj_idx, const return show(buf, commandName(code), Target(CHANNEL, dev, obj), extra); } - case K_CM_SET_FORWARD_CHANNEL: + case VerboseTraits::K_CM_SET_FORWARD_CHANNEL: { int channel = (params ? *((int*) params) : -1); @@ -2490,7 +2284,7 @@ std::string Verbose::command(int32 cmd_code, int32 dev_idx, int32 obj_idx, const } #if K3L_AT_LEAST(1,5,0) - case K_CM_MAKE_CALL: + case VerboseTraits::K_CM_MAKE_CALL: extra = "options='"; extra += (params ? params : ""); extra += "'"; @@ -2498,8 +2292,8 @@ std::string Verbose::command(int32 cmd_code, int32 dev_idx, int32 obj_idx, const return show(buf, commandName(code), Target(CHANNEL, dev, obj), extra); #endif - case K_CM_MIXER: - case K_CM_MIXER_CTBUS: + case VerboseTraits::K_CM_MIXER: + case VerboseTraits::K_CM_MIXER_CTBUS: { if (params) { @@ -2537,29 +2331,29 @@ std::string Verbose::command(int32 cmd_code, int32 dev_idx, int32 obj_idx, const return show(buf, commandName(code), Target(MIXER, dev, obj), extra); }; - case K_CM_PLAY_FROM_FILE: + case VerboseTraits::K_CM_PLAY_FROM_FILE: extra = "file='"; extra += (params ? params : ""); extra += "'"; return show(buf, commandName(code), Target(PLAYER, dev, obj), extra); - case K_CM_RECORD_TO_FILE: + case VerboseTraits::K_CM_RECORD_TO_FILE: extra = "file='"; extra += (params ? params : ""); extra += "'"; return show(buf, commandName(code), Target(PLAYER, dev, obj), extra); - case K_CM_RECORD_TO_FILE_EX: + case VerboseTraits::K_CM_RECORD_TO_FILE_EX: extra = "params='"; extra += (params ? params : ""); extra += "'"; return show(buf, commandName(code), Target(PLAYER, dev, obj), extra); - case K_CM_PLAY_FROM_STREAM: - case K_CM_ADD_STREAM_BUFFER: + case VerboseTraits::K_CM_PLAY_FROM_STREAM: + case VerboseTraits::K_CM_ADD_STREAM_BUFFER: { struct buffer_param { @@ -2576,7 +2370,7 @@ std::string Verbose::command(int32 cmd_code, int32 dev_idx, int32 obj_idx, const return show(buf, commandName(code), Target(PLAYER, dev, obj), extra); } - case K_CM_PLAY_FROM_STREAM_EX: + case VerboseTraits::K_CM_PLAY_FROM_STREAM_EX: { struct buffer_param { @@ -2604,24 +2398,24 @@ std::string Verbose::command(int32 cmd_code, int32 dev_idx, int32 obj_idx, const return show(buf, commandName(code), Target(PLAYER, dev, obj), extra); } - case K_CM_STOP_PLAY: - case K_CM_PAUSE_PLAY: - case K_CM_RESUME_PLAY: + case VerboseTraits::K_CM_STOP_PLAY: + case VerboseTraits::K_CM_PAUSE_PLAY: + case VerboseTraits::K_CM_RESUME_PLAY: - case K_CM_START_STREAM_BUFFER: - case K_CM_STOP_STREAM_BUFFER: + case VerboseTraits::K_CM_START_STREAM_BUFFER: + case VerboseTraits::K_CM_STOP_STREAM_BUFFER: - case K_CM_ENABLE_PLAYER_AGC: - case K_CM_DISABLE_PLAYER_AGC: + case VerboseTraits::K_CM_ENABLE_PLAYER_AGC: + case VerboseTraits::K_CM_DISABLE_PLAYER_AGC: - case K_CM_SEND_BEEP: - case K_CM_SEND_BEEP_CONF: + case VerboseTraits::K_CM_SEND_BEEP: + case VerboseTraits::K_CM_SEND_BEEP_CONF: - case K_CM_INTERNAL_PLAY: - case K_CM_INTERNAL_PLAY_EX: + case VerboseTraits::K_CM_INTERNAL_PLAY: + case VerboseTraits::K_CM_INTERNAL_PLAY_EX: return show(buf, commandName(code), Target(PLAYER, dev, obj)); - case K_CM_ADD_TO_CONF: + case VerboseTraits::K_CM_ADD_TO_CONF: extra += "conference='"; extra += (params ? (int) (*params) : -1); extra += "'"; @@ -2631,8 +2425,8 @@ std::string Verbose::command(int32 cmd_code, int32 dev_idx, int32 obj_idx, const case CM_REMOVE_FROM_CONF: return show(buf, commandName(code), Target(MIXER, dev, obj)); - case K_CM_LISTEN: - case K_CM_PREPARE_FOR_LISTEN: + case VerboseTraits::K_CM_LISTEN: + case VerboseTraits::K_CM_PREPARE_FOR_LISTEN: { int msecs = (params ? *((int*)params) : -1); @@ -2641,8 +2435,8 @@ std::string Verbose::command(int32 cmd_code, int32 dev_idx, int32 obj_idx, const return show(buf, commandName(code), Target(PLAYER, dev, obj), extra); } - case K_CM_SEND_TO_CTBUS: - case K_CM_RECV_FROM_CTBUS: + case VerboseTraits::K_CM_SEND_TO_CTBUS: + case VerboseTraits::K_CM_RECV_FROM_CTBUS: { KCtbusCommand *p = (KCtbusCommand*)(params); @@ -2652,8 +2446,8 @@ std::string Verbose::command(int32 cmd_code, int32 dev_idx, int32 obj_idx, const return show(buf, commandName(code), Target(CHANNEL, dev, obj), extra); } - case K_CM_SET_LINE_CONDITION: - case K_CM_SEND_LINE_CONDITION: + case VerboseTraits::K_CM_SET_LINE_CONDITION: + case VerboseTraits::K_CM_SEND_LINE_CONDITION: extra = "condition='"; #if K3L_AT_LEAST(2,0,0) extra += signGroupB((KSignGroupB) *((int *) params), r2_country); @@ -2664,7 +2458,7 @@ std::string Verbose::command(int32 cmd_code, int32 dev_idx, int32 obj_idx, const return show(buf, commandName(code), Target(CHANNEL, dev, obj), extra); - case K_CM_SET_CALLER_CATEGORY: + case VerboseTraits::K_CM_SET_CALLER_CATEGORY: extra = "category='"; #if K3L_AT_LEAST(2,0,0) extra += signGroupII((KSignGroupII) *((int *) params), r2_country); @@ -2676,10 +2470,10 @@ std::string Verbose::command(int32 cmd_code, int32 dev_idx, int32 obj_idx, const return show(buf, commandName(code), Target(CHANNEL, dev, obj), extra); #if K3L_AT_LEAST(1,6,0) - case K_CM_CLEAR_LINK_ERROR_COUNTER: + case VerboseTraits::K_CM_CLEAR_LINK_ERROR_COUNTER: return show(buf, commandName(code), Target(LINK, dev, obj)); - case K_CM_SIP_REGISTER: + case VerboseTraits::K_CM_SIP_REGISTER: if (params != NULL) { extra += "param='"; @@ -2694,7 +2488,7 @@ std::string Verbose::command(int32 cmd_code, int32 dev_idx, int32 obj_idx, const } #endif - case K_CM_SETUP_H100: + case VerboseTraits::K_CM_SETUP_H100: extra += "option='"; extra += h100configIndex((KH100ConfigIndex)obj_idx); extra += "'value='"; @@ -2703,38 +2497,38 @@ std::string Verbose::command(int32 cmd_code, int32 dev_idx, int32 obj_idx, const return show(buf, commandName(code), Target(DEVICE, dev), extra); - case K_CM_HARD_RESET: + case VerboseTraits::K_CM_HARD_RESET: return show(buf, commandName(code), Target(LINK, dev, obj)); #if !K3L_AT_LEAST(2,0,0) /* como funciona? */ - case K_CM_LOG_REQUEST: - case K_CM_LOG_CREATE_DISPATCHER: - case K_CM_LOG_DESTROY_DISPATCHER: + case VerboseTraits::K_CM_LOG_REQUEST: + case VerboseTraits::K_CM_LOG_CREATE_DISPATCHER: + case VerboseTraits::K_CM_LOG_DESTROY_DISPATCHER: - case K_CM_PING: + case VerboseTraits::K_CM_PING: #endif return show(buf, commandName(code), Target(NONE)); #if K3L_AT_LEAST(2,1,0) - case K_CM_START_FAX_TX: - case K_CM_START_FAX_RX: - case K_CM_ADD_FAX_FILE: + case VerboseTraits::K_CM_START_FAX_TX: + case VerboseTraits::K_CM_START_FAX_RX: + case VerboseTraits::K_CM_ADD_FAX_FILE: extra = "params='"; extra += (params ? params : ""); extra += "'"; return show(buf, commandName(code), Target(CHANNEL, dev, obj), extra); - case K_CM_STOP_FAX_TX: - case K_CM_STOP_FAX_RX: - case K_CM_ADD_FAX_PAGE_BREAK: + case VerboseTraits::K_CM_STOP_FAX_TX: + case VerboseTraits::K_CM_STOP_FAX_RX: + case VerboseTraits::K_CM_ADD_FAX_PAGE_BREAK: return show(buf, commandName(code), Target(CHANNEL, dev, obj)); #endif #if K3L_AT_LEAST(2,1,0) - case K_CM_NOTIFY_WATCHDOG: - case K_CM_STOP_WATCHDOG: - case K_CM_START_WATCHDOG: + case VerboseTraits::K_CM_NOTIFY_WATCHDOG: + case VerboseTraits::K_CM_STOP_WATCHDOG: + case VerboseTraits::K_CM_START_WATCHDOG: return show(buf, commandName(code) , Target(DEVICE, obj)); - case K_CM_WATCHDOG_COUNT: + case VerboseTraits::K_CM_WATCHDOG_COUNT: return show(buf, commandName(code) , Target(NONE)); #endif @@ -2745,65 +2539,66 @@ std::string Verbose::command(int32 cmd_code, int32 dev_idx, int32 obj_idx, const } #if K3L_AT_LEAST(2,0,0) -std::string Verbose::event(KSignaling sig, int32 obj_idx, K3L_EVENT *ev, R2CountryType r2_country, Verbose::Presentation fmt) +std::string Verbose::event(const KSignaling sig, const int32 obj_idx, const K3L_EVENT * const ev, const R2CountryType r2_country, const Verbose::Presentation fmt) #else -std::string Verbose::event(KSignaling sig, int32 obj_idx, K3L_EVENT *ev, Verbose::Presentation fmt) +std::string Verbose::event(const KSignaling sig, const int32 obj_idx, const K3L_EVENT * const ev, const Verbose::Presentation fmt) #endif { unsigned short int dev = (unsigned short int) ev->DeviceId; unsigned short int obj = (unsigned short int) obj_idx; - kevent code = (kevent) ev->Code; + VerboseTraits::Event code = (VerboseTraits::Event) ev->Code; - std::string buf, extra; + std::string buf; + std::string extra; switch (code) { - case K_EV_CHANNEL_FREE: - case K_EV_SEIZE_SUCCESS: - case K_EV_CALL_SUCCESS: - case K_EV_NO_ANSWER: - case K_EV_CONNECT: - case K_EV_DTMF_SEND_FINISH: - case K_EV_SEIZURE_START: - case K_EV_BILLING_PULSE: - case K_EV_REFERENCE_FAIL: + case VerboseTraits::VerboseTraits::K_EV_CHANNEL_FREE: + case VerboseTraits::VerboseTraits::K_EV_SEIZE_SUCCESS: + case VerboseTraits::VerboseTraits::K_EV_CALL_SUCCESS: + case VerboseTraits::VerboseTraits::K_EV_NO_ANSWER: + case VerboseTraits::VerboseTraits::K_EV_CONNECT: + case VerboseTraits::VerboseTraits::K_EV_DTMF_SEND_FINISH: + case VerboseTraits::VerboseTraits::K_EV_SEIZURE_START: + case VerboseTraits::VerboseTraits::K_EV_BILLING_PULSE: + case VerboseTraits::VerboseTraits::K_EV_REFERENCE_FAIL: #if K3L_AT_LEAST(1,4,0) - case K_EV_CALL_HOLD_START: - case K_EV_CALL_HOLD_STOP: + case VerboseTraits::VerboseTraits::K_EV_CALL_HOLD_START: + case VerboseTraits::VerboseTraits::K_EV_CALL_HOLD_STOP: #endif #if K3L_AT_LEAST(1,5,0) - case K_EV_NEW_CALL: + case VerboseTraits::VerboseTraits::K_EV_NEW_CALL: #endif #if K3L_AT_LEAST(1,6,0) - case K_EV_FLASH: - case K_EV_POLARITY_REVERSAL: - case K_EV_COLLECT_CALL: - case K_EV_SS_TRANSFER_FAIL: - case K_EV_RING_DETECTED: + case VerboseTraits::VerboseTraits::K_EV_FLASH: + case VerboseTraits::VerboseTraits::K_EV_POLARITY_REVERSAL: + case VerboseTraits::VerboseTraits::K_EV_COLLECT_CALL: + case VerboseTraits::VerboseTraits::K_EV_RING_DETECTED: + case VerboseTraits::VerboseTraits::K_EV_SS_TRANSFER_FAIL: #endif #if K3L_HAS_MPTY_SUPPORT - case K_EV_CALL_MPTY_START: - case K_EV_CALL_MPTY_STOP: + case VerboseTraits::VerboseTraits::K_EV_CALL_MPTY_START: + case VerboseTraits::VerboseTraits::K_EV_CALL_MPTY_STOP: #endif break; #if K3L_AT_LEAST(1,6,0) - case K_EV_RECV_FROM_MODEM: - case K_EV_SMS_INFO: - case K_EV_SMS_DATA: + case VerboseTraits::VerboseTraits::K_EV_RECV_FROM_MODEM: + case VerboseTraits::VerboseTraits::K_EV_SMS_INFO: + case VerboseTraits::VerboseTraits::K_EV_SMS_DATA: +#endif extra = "data='"; extra += (ev->Params ? (const char *)(ev->Params) : ""); extra += "'"; return show(buf, eventName(code), Target(CHANNEL, dev, obj), extra); -#endif #if K3L_AT_LEAST(1,6,0) - case K_EV_SMS_SEND_RESULT: + case VerboseTraits::VerboseTraits::K_EV_SMS_SEND_RESULT: extra = "result='"; #if K3L_AT_LEAST(2,0,0) extra += gsmSmsCause((KGsmSmsCause)ev->AddInfo); @@ -2814,20 +2609,20 @@ std::string Verbose::event(KSignaling sig, int32 obj_idx, K3L_EVENT *ev, Verbose return show(buf, eventName(code), Target(CHANNEL, dev, obj), extra); #if K3L_HAS_MPTY_SUPPORT - case K_EV_GSM_COMMAND_STATUS: + case VerboseTraits::VerboseTraits::K_EV_GSM_COMMAND_STATUS: extra = "result='"; extra += gsmMobileCause((KGsmMobileCause)ev->AddInfo); extra += "'"; return show(buf, eventName(code), Target(CHANNEL, dev, obj), extra); #endif - case K_EV_CALL_ANSWER_INFO: + case VerboseTraits::VerboseTraits::K_EV_CALL_ANSWER_INFO: extra = "info='"; extra += callStartInfo((KCallStartInfo)ev->AddInfo); extra += "'"; return show(buf, eventName(code), Target(CHANNEL, dev, obj), extra); - case K_EV_NEW_SMS: + case VerboseTraits::VerboseTraits::K_EV_NEW_SMS: if (ev->AddInfo != 0) { extra = "messages='"; @@ -2840,7 +2635,7 @@ std::string Verbose::event(KSignaling sig, int32 obj_idx, K3L_EVENT *ev, Verbose return show(buf, eventName(code), Target(CHANNEL, dev, obj)); } - case K_EV_ISDN_PROGRESS_INDICATOR: + case VerboseTraits::VerboseTraits::K_EV_ISDN_PROGRESS_INDICATOR: if (ev->AddInfo != 0) { extra = "indication='"; @@ -2854,19 +2649,19 @@ std::string Verbose::event(KSignaling sig, int32 obj_idx, K3L_EVENT *ev, Verbose } #endif - case K_EV_CAS_LINE_STT_CHANGED: + case VerboseTraits::VerboseTraits::K_EV_CAS_LINE_STT_CHANGED: extra = STG(FMT("[a=%d,b=%d,c=%d,d=%d]") % ((ev->AddInfo & 0x8) >> 3) % ((ev->AddInfo & 0x4) >> 2) % ((ev->AddInfo & 0x2) >> 1) % (ev->AddInfo & 0x1)); return show(buf, eventName(code), Target(CHANNEL, dev, obj), extra); - case K_EV_CAS_MFC_RECV: + case VerboseTraits::VerboseTraits::K_EV_CAS_MFC_RECV: extra = STG(FMT("digit='%d'") % ev->AddInfo); return show(buf, eventName(code), Target(CHANNEL, dev, obj), extra); - case K_EV_CALL_FAIL: + case VerboseTraits::VerboseTraits::K_EV_CALL_FAIL: extra = "cause='"; #if K3L_AT_LEAST(2,0,0) extra += callFail(sig, r2_country, ev->AddInfo); @@ -2887,7 +2682,7 @@ std::string Verbose::event(KSignaling sig, int32 obj_idx, K3L_EVENT *ev, Verbose return show(buf, eventName(code), Target(CHANNEL, dev, obj), extra); - case K_EV_DISCONNECT: + case VerboseTraits::VerboseTraits::K_EV_DISCONNECT: switch (sig) { #if K3L_AT_LEAST(1,5,1) @@ -2921,16 +2716,16 @@ std::string Verbose::event(KSignaling sig, int32 obj_idx, K3L_EVENT *ev, Verbose break; #if K3L_AT_LEAST(1,6,0) - case K_EV_SIP_DTMF_DETECTED: + case VerboseTraits::VerboseTraits::K_EV_SIP_DTMF_DETECTED: #endif - case K_EV_DTMF_DETECTED: - case K_EV_PULSE_DETECTED: - case K_EV_DIALED_DIGIT: + case VerboseTraits::VerboseTraits::K_EV_DTMF_DETECTED: + case VerboseTraits::VerboseTraits::K_EV_PULSE_DETECTED: + case VerboseTraits::VerboseTraits::K_EV_DIALED_DIGIT: extra = STG(FMT("digit='%c'") % (char)ev->AddInfo); return show(buf, eventName(code), Target(CHANNEL, dev, obj), extra); - case K_EV_SEIZURE: + case VerboseTraits::VerboseTraits::K_EV_SEIZURE: { KIncomingSeizeParams *n = (KIncomingSeizeParams *) ( ((char*)ev) + sizeof(K3L_EVENT) ); @@ -2945,7 +2740,7 @@ std::string Verbose::event(KSignaling sig, int32 obj_idx, K3L_EVENT *ev, Verbose } #if K3L_AT_LEAST(1,4,0) - case K_EV_VOIP_SEIZURE: + case VerboseTraits::VerboseTraits::K_EV_VOIP_SEIZURE: { char *numB = ((char*)ev) + sizeof(K3L_EVENT); char *numA = numB + 61; @@ -2961,43 +2756,43 @@ std::string Verbose::event(KSignaling sig, int32 obj_idx, K3L_EVENT *ev, Verbose #endif - case K_EV_END_OF_STREAM: + case VerboseTraits::VerboseTraits::K_EV_END_OF_STREAM: return show(buf, eventName(code), Target(PLAYER, dev, obj)); - case K_EV_AUDIO_STATUS: + case VerboseTraits::VerboseTraits::K_EV_AUDIO_STATUS: extra = "tone='"; extra += mixerTone((KMixerTone)ev->AddInfo); extra += "'"; return show(buf, eventName(code), Target(CHANNEL, dev, obj), extra); - case K_EV_CADENCE_RECOGNIZED: + case VerboseTraits::VerboseTraits::K_EV_CADENCE_RECOGNIZED: extra = STG(FMT("cadence='%c'") % (char)(ev->AddInfo)); return show(buf, eventName(code), Target(CHANNEL, dev, obj), extra); - case K_EV_CHANNEL_FAIL: + case VerboseTraits::VerboseTraits::K_EV_CHANNEL_FAIL: extra = "reason='"; extra += channelFail(sig, ev->AddInfo); extra += "'"; return show(buf, eventName(code), Target(CHANNEL, dev, obj), extra); - case K_EV_SEIZE_FAIL: + case VerboseTraits::VerboseTraits::K_EV_SEIZE_FAIL: extra = "reason='"; extra += seizeFail((KSeizeFail) ev->AddInfo); extra += "'"; return show(buf, eventName(code), Target(CHANNEL, dev, obj), extra); - case K_EV_INTERNAL_FAIL: + case VerboseTraits::VerboseTraits::K_EV_INTERNAL_FAIL: extra = "reason='"; extra += internalFail((KInternalFail) ev->AddInfo); extra += "'"; return show(buf, eventName(code), Target(CHANNEL, dev, obj), extra); - case K_EV_HARDWARE_FAIL: + case VerboseTraits::VerboseTraits::K_EV_HARDWARE_FAIL: extra = "component='"; extra += systemObject((KSystemObject) ev->AddInfo); extra += "'"; @@ -3018,18 +2813,18 @@ std::string Verbose::event(KSignaling sig, int32 obj_idx, K3L_EVENT *ev, Verbose } - case K_EV_LINK_STATUS: + case VerboseTraits::VerboseTraits::K_EV_LINK_STATUS: // EV_LINK_STATUS has always zero in ObjectInfo (and AddInfo!) /* fall throught... */ #if K3L_AT_LEAST(1,6,0) - case K_EV_PHYSICAL_LINK_UP: - case K_EV_PHYSICAL_LINK_DOWN: + case VerboseTraits::VerboseTraits::K_EV_PHYSICAL_LINK_UP: + case VerboseTraits::VerboseTraits::K_EV_PHYSICAL_LINK_DOWN: return show(buf, eventName(code), Target(LINK, dev, obj)); #endif #if K3L_AT_LEAST(1,5,1) - case K_EV_USER_INFORMATION: + case VerboseTraits::VerboseTraits::K_EV_USER_INFORMATION: { KUserInformation *info = (KUserInformation *)(ev->Params); @@ -3044,7 +2839,7 @@ std::string Verbose::event(KSignaling sig, int32 obj_idx, K3L_EVENT *ev, Verbose #endif #if K3L_AT_LEAST(1,6,0) - case K_EV_SIP_REGISTER_INFO: + case VerboseTraits::VerboseTraits::K_EV_SIP_REGISTER_INFO: extra = "params='"; extra += (ev->Params ? (const char *) (ev->Params) : ""); extra += "',status='"; @@ -3055,28 +2850,28 @@ std::string Verbose::event(KSignaling sig, int32 obj_idx, K3L_EVENT *ev, Verbose #endif #if !K3L_AT_LEAST(2,0,0) - case K_EV_PONG: + case VerboseTraits::VerboseTraits::K_EV_PONG: #endif #if K3L_AT_LEAST(1,4,0) - case K_EV_CLIENT_RECONNECT: + case VerboseTraits::VerboseTraits::K_EV_CLIENT_RECONNECT: #endif return show(buf, eventName(code), Target(NONE)); #if K3L_AT_LEAST(2,1,0) - case K_EV_FAX_CHANNEL_FREE: + case VerboseTraits::VerboseTraits::K_EV_FAX_CHANNEL_FREE: extra = "status='"; extra += faxResult((KFaxResult)ev->AddInfo); extra += "'"; return show(buf, eventName(code), Target(CHANNEL, dev, obj), extra); - case K_EV_FAX_FILE_SENT: + case VerboseTraits::VerboseTraits::K_EV_FAX_FILE_SENT: extra = "filename='"; extra += (ev->Params ? (const char *) (ev->Params) : ""); extra += "'"; return show(buf, eventName(code), Target(CHANNEL, dev, obj), extra); - case K_EV_FAX_FILE_FAIL: + case VerboseTraits::VerboseTraits::K_EV_FAX_FILE_FAIL: extra = "cause='"; extra += faxFileErrorCause((KFaxFileErrorCause)ev->AddInfo); extra += "',filename='"; @@ -3084,22 +2879,29 @@ std::string Verbose::event(KSignaling sig, int32 obj_idx, K3L_EVENT *ev, Verbose extra += "'"; return show(buf, eventName(code), Target(CHANNEL, dev, obj), extra); - case K_EV_FAX_REMOTE_INFO: + case VerboseTraits::VerboseTraits::K_EV_FAX_REMOTE_INFO: extra = ((ev->Params && ev->ParamSize != 0) ? (const char *) ev->Params : ""); return show(buf, eventName(code), Target(CHANNEL, dev, obj), extra); - /*case K_EV_FAX_MESSAGE_CONFIRMATION:*/ - case K_EV_FAX_PAGE_CONFIRMATION: - case K_EV_FAX_TX_TIMEOUT: + case VerboseTraits::VerboseTraits::K_EV_FAX_PAGE_CONFIRMATION: + case VerboseTraits::VerboseTraits::K_EV_FAX_TX_TIMEOUT: return show(buf, eventName(code), Target(CHANNEL, dev, obj)); #endif #if K3L_AT_LEAST(2,1,0) - case K_EV_WATCHDOG_COUNT: + case VerboseTraits::VerboseTraits::K_EV_WATCHDOG_COUNT: extra = STG(FMT("count='%d'") % (char)ev->AddInfo); return show(buf , eventName(code), Target(NONE), extra); #endif +#if K3L_AT_LEAST(2,1,0) + case VerboseTraits::VerboseTraits::K_EV_CT_TRANSFER_FAIL: + extra = "cause='"; + extra += isdnCause((KQ931Cause)ev->AddInfo); + extra += "'"; + + return show(buf, eventName(code), Target(CHANNEL, dev, obj), extra); +#endif } // default handler... @@ -3117,7 +2919,7 @@ std::string Verbose::event(KSignaling sig, int32 obj_idx, K3L_EVENT *ev, Verbose /********************************************/ -std::string Verbose::show(std::string & buf, std::string name, Target tgt, std::string & extra) +std::string Verbose::show(std::string & buf, const std::string & name, const Target tgt, const std::string & extra) { if (tgt.type == NONE) { @@ -3134,7 +2936,7 @@ std::string Verbose::show(std::string & buf, std::string name, Target tgt, std:: return buf; } -std::string Verbose::show(std::string & buf, std::string name, Target tgt) +std::string Verbose::show(std::string & buf, const std::string & name, const Target tgt) { std::string tmp(""); @@ -3142,7 +2944,7 @@ std::string Verbose::show(std::string & buf, std::string name, Target tgt) return buf; } -void Verbose::generate(std::string &buf, std::string &name, Target tgt, std::string &extra) +void Verbose::generate(std::string & buf, const std::string & name, const Target tgt, const std::string & extra) { switch (tgt.type) { diff --git a/src/mod/endpoints/mod_khomp/commons/base/verbose.hpp b/src/mod/endpoints/mod_khomp/commons/base/verbose.hpp new file mode 100644 index 0000000000..a0ea290b7e --- /dev/null +++ b/src/mod/endpoints/mod_khomp/commons/base/verbose.hpp @@ -0,0 +1,303 @@ +/* + KHOMP generic endpoint/channel library. + Copyright (C) 2007-2009 Khomp Ind. & Com. + + The contents of this file are subject to the Mozilla Public License Version 1.1 + (the "License"); you may not use this file except in compliance with the + License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS IS" basis, + WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for + the specific language governing rights and limitations under the License. + + Alternatively, the contents of this file may be used under the terms of the + "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which + case the provisions of "LGPL License" are applicable instead of those above. + + If you wish to allow use of your version of this file only under the terms of + the LGPL License and not to allow others to use your version of this file under + the MPL, indicate your decision by deleting the provisions above and replace them + with the notice and other provisions required by the LGPL License. If you do not + delete the provisions above, a recipient may use your version of this file under + either the MPL or the LGPL License. + + The LGPL header follows below: + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#ifndef _VERBOSE_HPP_ +#define _VERBOSE_HPP_ + +#include +#include +#include + +#include + +// k3lApiMajorVersion +#ifndef CM_PING +# include +# include +#endif + +#include +#include +#include + +#include + +struct Verbose +{ + typedef enum + { + R2_COUNTRY_BRA = 1, + R2_COUNTRY_ARG = 2, + R2_COUNTRY_CHI = 3, + R2_COUNTRY_MEX = 4, + R2_COUNTRY_URY = 5, + R2_COUNTRY_VEN = 6 + } + R2CountryType; + + typedef enum + { + HUMAN, + EXACT + } + Presentation; + + /* dynamic (object) stuff */ + + Verbose(const K3LAPI & api) + : _api(api) {}; + +#if K3L_AT_LEAST(2,0,0) + std::string event(const int32, const K3L_EVENT * const, + const R2CountryType r2_country = R2_COUNTRY_BRA, + const Presentation fmt = HUMAN) const; +#else + std::string event(const int32, const K3L_EVENT * const, + const Presentation fmt = HUMAN) const; +#endif + + std::string channelStatus(const int32, const int32, const int32, + const Presentation fmt = HUMAN) const; + + /* end of dynamic (object) stuff */ + + protected: + const K3LAPI & _api; + + /* used internally */ + struct internal_not_found {}; + + public: + + /* static (class) stuff */ + + static std::string echoLocation(const KEchoLocation, const Presentation fmt = HUMAN); + static std::string echoCancellerConfig(const KEchoCancellerConfig, const Presentation fmt = HUMAN); + +#if K3L_AT_LEAST(2,0,0) + static std::string event(const KSignaling, const int32, const K3L_EVENT * const, + const R2CountryType = R2_COUNTRY_BRA, Presentation fmt = HUMAN); +#else + static std::string event(const KSignaling, const int32, const K3L_EVENT * const, + const Presentation fmt = HUMAN); +#endif + +#if K3L_AT_LEAST(2,0,0) + static std::string command(const int32, const K3L_COMMAND * const, + const R2CountryType = R2_COUNTRY_BRA, + const Presentation fmt = HUMAN); + + static std::string command(const int32, const int32, const int32, const char * const, + const R2CountryType = R2_COUNTRY_BRA, + const Presentation fmt = HUMAN); +#else + static std::string command(const int32, const K3L_COMMAND * const, + const Presentation fmt = HUMAN); + + static std::string command(const int32, const int32, const int32, const char * const, + const Presentation fmt = HUMAN); +#endif + + static std::string deviceName(const KDeviceType, const int32, const int32 count = 0, const Presentation fmt = HUMAN); + static std::string deviceName(const KDeviceType, const int32, const Presentation fmt); + + static std::string deviceType(const KDeviceType, const int32 count = 0, const Presentation fmt = HUMAN); + static std::string deviceType(const KDeviceType, const Presentation fmt); + + static std::string deviceModel(const KDeviceType, const int32, const int32 count = 0, const Presentation fmt = HUMAN); + static std::string deviceModel(const KDeviceType, const int32, const Presentation fmt); + + static std::string channelFeatures(const int32, const Presentation fmt = HUMAN); + static std::string signaling(const KSignaling, const Presentation fmt = HUMAN); + static std::string systemObject(const KSystemObject, const Presentation fmt = HUMAN); + static std::string mixerTone(const KMixerTone, const Presentation fmt = HUMAN); + static std::string mixerSource(const KMixerSource, const Presentation fmt = HUMAN); + + static std::string seizeFail(const KSeizeFail, const Presentation fmt = HUMAN); + +#if K3L_AT_LEAST(2,0,0) + static std::string callFail(const KSignaling, const R2CountryType, const int32, const Presentation fmt = HUMAN); +#else + static std::string callFail(const KSignaling, const int32, const Presentation fmt = HUMAN); +#endif + + static std::string channelFail(const KSignaling, const int32, const Presentation fmt = HUMAN); + static std::string internalFail(const KInternalFail, const Presentation fmt = HUMAN); + + static std::string linkErrorCounter(const KLinkErrorCounter, const Presentation fmt = HUMAN); + + static std::string linkStatus(const KSignaling, const int32, const Presentation fmt = HUMAN, const bool simpleStatus = false); + static std::string channelStatus(const KSignaling, const int32, const Presentation fmt = HUMAN); + static std::string callStatus(const KCallStatus, const Presentation fmt = HUMAN); + static std::string status(const KLibraryStatus, const Presentation fmt = HUMAN); + +#if K3L_AT_LEAST(2,0,0) + static std::string signGroupB(const KSignGroupB, const R2CountryType contry = R2_COUNTRY_BRA, + Presentation fmt = HUMAN); +#else + static std::string signGroupB(const KSignGroupB, const Presentation fmt = HUMAN); +#endif + +#if K3L_AT_LEAST(2,0,0) + static std::string signGroupII(const KSignGroupII, const R2CountryType contry = R2_COUNTRY_BRA, + Presentation fmt = HUMAN); +#else + static std::string signGroupII(const KSignGroupII, const Presentation fmt = HUMAN); +#endif + + static std::string h100configIndex(const KH100ConfigIndex, const Presentation fmt = HUMAN); + + static std::string eventName(const int32 value) + { + return VerboseTraits::eventName((VerboseTraits::Event)value); + }; + + static std::string commandName(const int32 value) + { + return VerboseTraits::commandName((VerboseTraits::Command)value); + }; + +#if K3L_AT_LEAST(1,5,0) + static std::string sipFailures(const KSIP_Failures, const Presentation fmt = HUMAN); +#endif + +#if K3L_AT_LEAST(1,5,1) + static std::string isdnCause(const KQ931Cause, const Presentation fmt = HUMAN); +#endif + +#if K3L_AT_LEAST(1,5,2) + static std::string isdnDebug(const int32, const Presentation fmt = HUMAN); +#endif + +#if K3L_AT_LEAST(1,6,0) + static std::string callStartInfo(const KCallStartInfo, const Presentation fmt = HUMAN); + + static std::string gsmCallCause(const KGsmCallCause, const Presentation fmt = HUMAN); + static std::string gsmMobileCause(const KGsmMobileCause, const Presentation fmt = HUMAN); + static std::string gsmSmsCause(const KGsmSmsCause, const Presentation fmt = HUMAN); + + static std::string q931ProgressIndication(const KQ931ProgressIndication, + Presentation fmt = HUMAN); +#endif + +#if K3L_AT_LEAST(2,1,0) + static std::string faxResult(const KFaxResult code, const Presentation fmt = HUMAN); + static std::string faxFileErrorCause(const KFaxFileErrorCause code, const Presentation fmt = HUMAN); +#endif + + /* end of static (class) stuff */ + + private: + static std::string internal_deviceType(const KDeviceType, const int32); + static std::string internal_deviceModel(const KDeviceType, const int32, const int32); + +#if K3L_AT_LEAST(1,5,0) + static std::string internal_sipFailures(const KSIP_Failures, const Presentation fmt = HUMAN); +#endif +#if K3L_AT_LEAST(1,5,1) + static std::string internal_isdnCause(const KQ931Cause, const Presentation fmt = HUMAN); +#endif + +#if K3L_AT_LEAST(2,0,0) + static std::string internal_signGroupB(const KSignGroupB, const R2CountryType contry, const Presentation fmt = HUMAN); + static std::string internal_signGroupII(const KSignGroupII, const R2CountryType contry, const Presentation fmt = HUMAN); +#else + static std::string internal_signGroupB(const KSignGroupB, const Presentation fmt = HUMAN); + static std::string internal_signGroupII(const KSignGroupII, const Presentation fmt = HUMAN); +#endif + +#if K3L_AT_LEAST(1,6,0) + static std::string internal_gsmCallCause(const KGsmCallCause, const Presentation fmt = HUMAN); + static std::string internal_gsmMobileCause(const KGsmMobileCause, const Presentation fmt = HUMAN); + static std::string internal_gsmSmsCause(const KGsmSmsCause, const Presentation fmt = HUMAN); + + static std::string internal_q931ProgressIndication(const KQ931ProgressIndication, const Presentation fmt = HUMAN); +#endif + + private: + enum Type + { + DEVICE, + CHANNEL, + PLAYER, + MIXER, + LINK, + NONE + }; + + struct Target + { + Target(Type _type) + : type(_type), device(-1), object(-1) + {}; + + Target(Type _type, int32 _device) + : type(_type), device(_device), object(-1) + {}; + + Target(Type _type, int32 _device, int32 _object) + : type(_type), device(_device), object(_object) + {}; + + const Type type; + const int32 device; + const int32 object; + }; + + static void generate(std::string &, const std::string &, const Target, const std::string &); + + static std::string show(std::string &, const std::string &, const Target, const std::string &); + static std::string show(std::string &, const std::string &, const Target); + + template < typename ReturnType > + static ReturnType presentation(const Presentation fmt, ReturnType str_exact, ReturnType str_human) + { + switch (fmt) + { + case HUMAN: return str_human; + case EXACT: return str_exact; + }; + + return str_exact; + } +}; + +#endif /* _VERBOSE_HPP_ */ diff --git a/src/mod/endpoints/mod_khomp/commons/config_options.cpp b/src/mod/endpoints/mod_khomp/commons/config_options.cpp deleted file mode 100644 index 5383855f65..0000000000 --- a/src/mod/endpoints/mod_khomp/commons/config_options.cpp +++ /dev/null @@ -1,710 +0,0 @@ -/* - KHOMP generic endpoint/channel library. - Copyright (C) 2007-2009 Khomp Ind. & Com. - - The contents of this file are subject to the Mozilla Public License Version 1.1 - (the "License"); you may not use this file except in compliance with the - License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ - - Software distributed under the License is distributed on an "AS IS" basis, - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for - the specific language governing rights and limitations under the License. - - Alternatively, the contents of this file may be used under the terms of the - "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which - case the provisions of "LGPL License" are applicable instead of those above. - - If you wish to allow use of your version of this file only under the terms of - the LGPL License and not to allow others to use your version of this file under - the MPL, indicate your decision by deleting the provisions above and replace them - with the notice and other provisions required by the LGPL License. If you do not - delete the provisions above, a recipient may use your version of this file under - either the MPL or the LGPL License. - - The LGPL header follows below: - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this library; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -*/ - -#include - -ConfigOption::ConfigOption(std::string name, const ConfigOption::StringType & value, const ConfigOption::StringType defvalue, string_allowed_type allowed, bool list_me) -: _my_name(name), _value_data(new StringData(const_cast(value), defvalue, allowed), true), - _list_me(list_me), _values(NULL), _loaded(false) -{}; - -ConfigOption::ConfigOption(std::string name, const ConfigOption::StringType & value, const ConfigOption::StringType defvalue, bool list_me) -: _my_name(name), _value_data(new StringData(const_cast(value), defvalue, string_allowed_type()), true), - _list_me(list_me), _values(NULL), _loaded(false) -{}; - -ConfigOption::ConfigOption(std::string name, const ConfigOption::SignedIntType & value, const ConfigOption::SignedIntType defvalue, - ConfigOption::SignedIntType min, ConfigOption::SignedIntType max, ConfigOption::SignedIntType step, bool list_me) -: _my_name(name), _value_data(new SignedIntData(const_cast(value), defvalue, Range(min, max, step)), true), - _list_me(list_me), _values(NULL), _loaded(false) -{}; - -ConfigOption::ConfigOption(std::string name, const ConfigOption::UnsignedIntType & value, const ConfigOption::UnsignedIntType defvalue, - ConfigOption::UnsignedIntType min, ConfigOption::UnsignedIntType max, ConfigOption::UnsignedIntType step, bool list_me) -: _my_name(name), _value_data(new UnsignedIntData(const_cast(value), defvalue, Range(min, max, step)), true), - _list_me(list_me), _values(NULL), _loaded(false) -{}; - -ConfigOption::ConfigOption(std::string name, const ConfigOption::BooleanType & value, const ConfigOption::BooleanType defvalue, bool list_me) -: _my_name(name), _value_data(new BooleanData(const_cast(value), defvalue), true), - _list_me(list_me), _values(NULL), _loaded(false) -{}; - -ConfigOption::ConfigOption(std::string name, ConfigOption::FunctionType fun, std::string defvalue, string_allowed_type allowed, bool list_me) -: _my_name(name), _value_data(new FunctionData(fun, defvalue, allowed), true), - _list_me(list_me), _values(NULL), _loaded(false) -{}; - -ConfigOption::ConfigOption(std::string name, ConfigOption::FunctionType fun, std::string defvalue, bool list_me) -: _my_name(name), _value_data(new FunctionData(fun, defvalue, string_allowed_type()), true), - _list_me(list_me), _values(NULL), _loaded(false) -{}; - -ConfigOption::ConfigOption(const ConfigOption & o) -: _my_name(o._my_name), _value_data(o._value_data), - _list_me(o._list_me), _values(o._values), _loaded(o._loaded) -{}; - -ConfigOption::~ConfigOption(void) -{ - if (_values) - { - for (unsigned int i = 0; _values[i] != NULL; i++) - delete _values[i]; - - delete[] _values; - _values = NULL; - } -}; - -void ConfigOption::set(ConfigOption::StringType value) -{ - switch (_value_data.which()) - { - case ID_STRING: - { - try - { - StringData & tmp = _value_data.get(); - - if (tmp.string_allowed.empty()) - { - tmp.string_val = value; - _loaded = true; - } - else - { - if (tmp.string_allowed.find(value) != tmp.string_allowed.end()) - { - tmp.string_val = value; - _loaded = true; - return; - } - - std::string allowed_string; - - for (string_allowed_type::iterator i = tmp.string_allowed.begin(); i != tmp.string_allowed.end(); i++) - { - allowed_string += " '"; - allowed_string += (*i); - allowed_string += "'"; - } - - throw ConfigProcessFailure(STG(FMT("value '%s' not allowed for option '%s' (allowed values:%s)") - % value % _my_name % allowed_string)); - } - break; - } - catch(ValueType::InvalidType & e) - { - throw; - } - } - - case ID_FUN: - { - try - { - FunctionData & tmp = _value_data.get(); - tmp.fun_val(value); - _loaded = true; - break; - } - catch(ValueType::InvalidType & e) - { - throw; - } - - } - - default: - { - throw ConfigProcessFailure(STG(FMT("option '%s' is not of type string, nor function defined") % _my_name)); - } - } -} - -void ConfigOption::set(ConfigOption::SignedIntType value) -{ - try - { - SignedIntData & tmp = _value_data.get(); - - if (value < tmp.sint_Range.minimum) - throw ConfigProcessFailure(STG(FMT("value '%d' out-of-Range for option '%s' (too low)") % value % _my_name)); - - if (value > tmp.sint_Range.maximum) - throw ConfigProcessFailure(STG(FMT("value '%d' out-of-Range for option '%s' (too high)") % value % _my_name)); - - if (((value - tmp.sint_Range.minimum) % tmp.sint_Range.step) != 0) - throw ConfigProcessFailure(STG(FMT("value '%d' out-of-Range for option '%s' (outside allowed step)") % value % _my_name)); - - tmp.sint_val = value; - _loaded = true; - } - catch(ValueType::InvalidType & e) - { - throw; - } -} - -void ConfigOption::set(ConfigOption::UnsignedIntType value) -{ - try - { - UnsignedIntData & tmp = _value_data.get(); - - if (value < tmp.uint_Range.minimum) - throw ConfigProcessFailure(STG(FMT("value '%d' out-of-Range for option '%s' (too low)") % value % _my_name)); - - if (value > tmp.uint_Range.maximum) - throw ConfigProcessFailure(STG(FMT("value '%d' out-of-Range for option '%s' (too high)") % value % _my_name)); - - if (((value - tmp.uint_Range.minimum) % tmp.uint_Range.step) != 0) - throw ConfigProcessFailure(STG(FMT("value '%d' out-of-Range for option '%s' (outside allowed step)") % value % _my_name)); - - tmp.uint_val = value; - _loaded = true; - } - catch(ValueType::InvalidType & e) - { - throw; - } -} - -void ConfigOption::set(ConfigOption::BooleanType value) -{ - try - { - BooleanData & tmp = _value_data.get(); - tmp.bool_val = value; - _loaded = true; - } - catch(ValueType::InvalidType & e) - { - throw; - } -} - -std::string & ConfigOption::name(void) { return _my_name; }; - -ConfigOption::value_id_type ConfigOption::type(void) -{ - return (value_id_type) _value_data.which(); -}; - -const char ** ConfigOption::values(void) -{ - if (_values != NULL) - return _values; - - switch ((value_id_type) _value_data.which()) - { - case ConfigOption::ID_BOOL: - { - _values = new const char*[3]; - - _values[0] = strdup("yes"); - _values[1] = strdup("no"); - _values[2] = NULL; - - return _values; - } - - case ConfigOption::ID_SINT: - { - try - { - SignedIntData & tmp = _value_data.get(); - - - unsigned int count = ((tmp.sint_Range.maximum - tmp.sint_Range.minimum) / tmp.sint_Range.step) + 1; - unsigned int index = 0; - - _values = new const char*[count + 1]; - - for (SignedIntType i = tmp.sint_Range.minimum; i <= tmp.sint_Range.maximum; i += tmp.sint_Range.step, index++) - _values[index] = strdup(STG(FMT("%d") % i).c_str()); - - _values[index] = NULL; - - return _values; - } - catch(ValueType::InvalidType & e) - { - throw; - } - } - - case ConfigOption::ID_UINT: - { - try - { - UnsignedIntData & tmp = _value_data.get(); - - unsigned int count = ((tmp.uint_Range.maximum - tmp.uint_Range.minimum) / tmp.uint_Range.step) + 1; - unsigned int index = 0; - - _values = new const char*[count + 1]; - - for (UnsignedIntType i = tmp.uint_Range.minimum; i <= tmp.uint_Range.maximum; i += tmp.uint_Range.step, index++) - _values[index] = strdup(STG(FMT("%d") % i).c_str()); - - _values[index] = NULL; - - return _values; - } - catch(ValueType::InvalidType & e) - { - throw; - } - } - - case ConfigOption::ID_STRING: - { - try - { - StringData & tmp = _value_data.get(); - - _values = new const char*[ tmp.string_allowed.size() + 1 ]; - - unsigned int index = 0; - - for (string_allowed_type::iterator i = tmp.string_allowed.begin(); i != tmp.string_allowed.end(); i++, index++) - _values[index] = strdup((*i).c_str()); - - _values[index] = NULL; - - return _values; - } - catch(ValueType::InvalidType & e) - { - throw; - } - } - - case ConfigOption::ID_FUN: - { - try - { - FunctionData & tmp = _value_data.get(); - - _values = new const char*[ tmp.fun_allowed.size() + 1 ]; - - unsigned int index = 0; - - for (string_allowed_type::iterator i = tmp.fun_allowed.begin(); i != tmp.fun_allowed.end(); i++, index++) - _values[index] = strdup((*i).c_str()); - - _values[index] = NULL; - return _values; - } - catch(ValueType::InvalidType & e) - { - throw; - } - - } - - default: - throw ConfigProcessFailure(STG(FMT("unknown type identifier '%d'") % _value_data.which())); - } -}; - -void ConfigOption::reset(void) -{ - _loaded = false; -}; - -void ConfigOption::commit(void) -{ - if (_loaded) - return; - - switch ((value_id_type) _value_data.which()) - { - case ConfigOption::ID_BOOL: - { - try - { - BooleanData & tmp = _value_data.get(); - tmp.bool_val = tmp.bool_default; - } - catch(ValueType::InvalidType & e) - { - throw; - } - - break; - } - - case ConfigOption::ID_SINT: - { - try - { - SignedIntData & tmp = _value_data.get(); - tmp.sint_val = tmp.sint_default; - } - catch(ValueType::InvalidType & e) - { - throw; - } - break; - } - - case ConfigOption::ID_UINT: - { - try - { - UnsignedIntData & tmp = _value_data.get(); - tmp.uint_val = tmp.uint_default; - } - catch(ValueType::InvalidType & e) - { - throw; - } - break; - } - - case ConfigOption::ID_STRING: - { - try - { - StringData & tmp = _value_data.get(); - tmp.string_val = tmp.string_default; - } - catch(ValueType::InvalidType & e) - { - throw; - } - break; - } - - case ConfigOption::ID_FUN: - { - try - { - FunctionData & tmp = _value_data.get(); - tmp.fun_val(tmp.fun_default); - } - catch(ValueType::InvalidType & e) - { - throw; - } - break; - } - - default: - throw ConfigProcessFailure(STG(FMT("unknown type identifier '%d'") % _value_data.which())); - } - - _loaded = true; -}; - -void ConfigOption::copy_from(ConfigOption & src) -{ - if (src._value_data.which() != _value_data.which()) - throw ConfigProcessFailure(STG(FMT("unable to copy options, source type differs from destination."))); - - if (!src._loaded) - return; - - switch ((value_id_type) _value_data.which()) - { - case ConfigOption::ID_BOOL: - { - try - { - BooleanData & stmp = src._value_data.get(); - BooleanData & dtmp = _value_data.get(); - /* do not copy references, but values.. */ - bool tmpval = stmp.bool_val; - dtmp.bool_val = tmpval; - } - catch(ValueType::InvalidType & e) - { - throw; - } - - break; - } - - case ConfigOption::ID_SINT: - { - try - { - SignedIntData & stmp = src._value_data.get(); - SignedIntData & dtmp = _value_data.get(); - /* do not copy references, but values.. */ - int tmpval = stmp.sint_val; - dtmp.sint_val = tmpval; - } - catch(ValueType::InvalidType & e) - { - throw; - } - - break; - } - - case ConfigOption::ID_UINT: - { - try - { - UnsignedIntData & stmp = src._value_data.get(); - UnsignedIntData & dtmp = _value_data.get(); - /* do not copy references, but values.. */ - unsigned int tmpval = stmp.uint_val; - dtmp.uint_val = tmpval; - } - catch(ValueType::InvalidType & e) - { - throw; - } - - - break; - } - - case ConfigOption::ID_STRING: - { - try - { - StringData & stmp = src._value_data.get(); - StringData & dtmp = _value_data.get(); - /* do not copy references, but values.. */ - std::string tmpval = stmp.string_val; - dtmp.string_val = tmpval; - } - catch(ValueType::InvalidType & e) - { - throw; - } - - break; - } - - case ConfigOption::ID_FUN: - { - /* TO IMPLEMENT (NEEDS ANOTHER METHOD ON FUNCTION FOR GETTING VALUE) */ - -// FunctionData & tmp = boost::get(_value_data); -// -// if (!tmp.loaded) -// { -// tmp.fun_val(tmp.fun_default); -// tmp.loaded = true; -// } - break; - } - - default: - throw ConfigProcessFailure(STG(FMT("unknown type identifier '%d'") % _value_data.which())); - } - - _loaded = true; -}; - -/*********************************/ - -bool ConfigOptions::add(ConfigOption option) -{ - //option_map_type::iterator iter2 = _map.begin(); - - //boost::tie(iter2, ok2) - std::pair ret = _map.insert(option_pair_type(option.name(), option)); - - return ret.second; -} - -bool ConfigOptions::synonym(std::string equiv_opt, std::string main_opt) -{ - //syn_option_map_type::iterator iter = _syn_map.begin(); - - //boost::tie(iter, ok) - std::pair ret = _syn_map.insert(syn_option_pair_type(equiv_opt, main_opt)); - - return ret.second; -} - -ConfigOptions::string_set ConfigOptions::options(void) -{ - string_set res; - - for (option_map_type::iterator i = _map.begin(); i != _map.end(); i++) - res.insert((*i).first); - - return res; -} - -void ConfigOptions::process(const char * name, const char * value) -{ - option_map_type::iterator iter = find_option(name); - - if (iter == _map.end()) - throw ConfigProcessFailure(STG(FMT("unknown option '%s'") % name)); - - try - { - switch ((*iter).second.type()) - { - case ConfigOption::ID_SINT: - set((*iter).first, Strings::toulong(value)); - return; - case ConfigOption::ID_UINT: - set((*iter).first, Strings::tolong(value)); - return; - case ConfigOption::ID_BOOL: - set((*iter).first, Strings::toboolean(value)); - return; - case ConfigOption::ID_STRING: - case ConfigOption::ID_FUN: - set((*iter).first, std::string(value)); - return; - default: - throw ConfigProcessFailure(STG(FMT("unknown type identifier '%d'") % (*iter).second.type())); - } - } - catch (Strings::invalid_value & e) - { - throw ConfigProcessFailure(STG(FMT("invalid value '%s' for option '%s'") % value % name)); - } -} - -const char ** ConfigOptions::values(const char * name) -{ - option_map_type::iterator iter = find_option(name); - - if (iter == _map.end()) - throw ConfigProcessFailure(STG(FMT("unknown option '%s'") % name)); - - return (*iter).second.values(); -} - -const char ** ConfigOptions::values(void) -{ - if (_values != NULL) - return _values; - - unsigned int count = 0; - - for (option_map_type::iterator i = _map.begin(); i != _map.end(); i++) - if ((*i).second.list_me()) - ++count; - - _values = new const char*[ count + 1 ]; - - unsigned int index = 0; - - for (option_map_type::iterator i = _map.begin(); i != _map.end(); i++) - { - if ((*i).second.list_me()) - { - _values[index] = strdup((*i).first.c_str()); - ++index; - } - } - - _values[index] = NULL; - - return _values; -} - -void ConfigOptions::reset(void) -{ - for (option_map_type::iterator i = _map.begin(); i != _map.end(); i++) - (*i).second.reset(); -} - -ConfigOptions::messages_type ConfigOptions::commit(void) -{ - messages_type msgs; - - for (option_map_type::iterator i = _map.begin(); i != _map.end(); i++) - { - try - { - (*i).second.commit(); - } - catch (ConfigProcessFailure & e) - { - msgs.push_back(e.msg); - } - } - - return msgs; -} - -bool ConfigOptions::loaded(std::string name) -{ - option_map_type::iterator iter = find_option(name); - - if (iter == _map.end()) - return false; - - return iter->second.loaded(); -} - -void ConfigOptions::copy_from(ConfigOptions & source, std::string name) -{ - option_map_type::iterator iter_src = source.find_option(name); - option_map_type::iterator iter_dst = find_option(name); - - if (iter_src == source._map.end()) - throw ConfigProcessFailure(STG(FMT("unknown option '%s' on source") % name)); - - if (iter_dst == _map.end()) - throw ConfigProcessFailure(STG(FMT("unknown option '%s' on destination") % name)); - - iter_dst->second.copy_from(iter_src->second); -} - -ConfigOptions::option_map_type::iterator ConfigOptions::find_option(std::string name) -{ - syn_option_map_type::iterator syn_iter = _syn_map.find(name); - - if (syn_iter != _syn_map.end()) - name = syn_iter->second; - - option_map_type::iterator iter = _map.find(name); - - return iter; -} diff --git a/src/mod/endpoints/mod_khomp/commons/config_options.hpp b/src/mod/endpoints/mod_khomp/commons/config_options.hpp deleted file mode 100644 index 3cfe2e1c78..0000000000 --- a/src/mod/endpoints/mod_khomp/commons/config_options.hpp +++ /dev/null @@ -1,286 +0,0 @@ -/* - KHOMP generic endpoint/channel library. - Copyright (C) 2007-2009 Khomp Ind. & Com. - - The contents of this file are subject to the Mozilla Public License Version 1.1 - (the "License"); you may not use this file except in compliance with the - License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ - - Software distributed under the License is distributed on an "AS IS" basis, - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for - the specific language governing rights and limitations under the License. - - Alternatively, the contents of this file may be used under the terms of the - "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which - case the provisions of "LGPL License" are applicable instead of those above. - - If you wish to allow use of your version of this file only under the terms of - the LGPL License and not to allow others to use your version of this file under - the MPL, indicate your decision by deleting the provisions above and replace them - with the notice and other provisions required by the LGPL License. If you do not - delete the provisions above, a recipient may use your version of this file under - either the MPL or the LGPL License. - - The LGPL header follows below: - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this library; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -*/ - -#include -#include -#include - -#include - -#include -#include -#include - -#ifndef _CONFIG_OPTIONS_HPP_ -#define _CONFIG_OPTIONS_HPP_ - -struct ConfigProcessFailure -{ - ConfigProcessFailure(std::string _msg): msg(_msg) {}; - std::string msg; -}; - -struct ConfigOption -{ - typedef int SignedIntType; - typedef unsigned int UnsignedIntType; - typedef bool BooleanType; - typedef std::string StringType; - - typedef Function::Function1 < void, std::string > FunctionType; - - typedef std::set < StringType > string_allowed_type; - - /* this should reflect 'variant.which()'! */ - typedef enum - { - ID_SINT = 0, - ID_UINT = 1, - ID_BOOL = 2, - ID_STRING = 3, - ID_FUN = 4, - } - value_id_type; - - template < typename number_type > - struct Range - { - Range(number_type _minimum, number_type _maximum, number_type _step) - : minimum(_minimum), maximum(_maximum), step(_step) {}; - - number_type minimum, maximum, step; - }; - - struct SignedIntData : public VariantBaseType < void > - { - SignedIntData(SignedIntType & _sint_val, SignedIntType _sint_default, Range< SignedIntType > _sint_Range) - : sint_val(_sint_val), sint_default(_sint_default), sint_Range(_sint_Range) {}; - - int which() - { - return ID_SINT; - } - - SignedIntType & sint_val; - SignedIntType sint_default; - Range sint_Range; - }; - - struct UnsignedIntData : public VariantBaseType < void > - { - UnsignedIntData(UnsignedIntType & _uint_val, UnsignedIntType _uint_default, Range< UnsignedIntType > _uint_Range) - : uint_val(_uint_val), uint_default(_uint_default), uint_Range(_uint_Range) {}; - - int which() - { - return ID_UINT; - } - - UnsignedIntType & uint_val; - UnsignedIntType uint_default; - Range uint_Range; - }; - - struct BooleanData : public VariantBaseType < void > - { - BooleanData(BooleanType & _bool_val, BooleanType _bool_default) - : bool_val(_bool_val), bool_default(_bool_default) {}; - - int which() - { - return ID_BOOL; - } - - BooleanType & bool_val; - BooleanType bool_default; - }; - - struct StringData : public VariantBaseType < void > - { - StringData(std::string & _string_val, std::string _string_default, string_allowed_type _string_allowed) - : string_val(_string_val), string_default(_string_default), string_allowed(_string_allowed) {}; - - int which() - { - return ID_STRING; - } - - std::string & string_val; - std::string string_default; - string_allowed_type string_allowed; - }; - - struct FunctionData : public VariantBaseType < void > - { - FunctionData(FunctionType _fun_val, std::string _fun_default, string_allowed_type _fun_allowed) - : fun_val(_fun_val), fun_default(_fun_default), fun_allowed(_fun_allowed) {}; - - int which() - { - return ID_FUN; - } - - FunctionType fun_val; - std::string fun_default; - string_allowed_type fun_allowed; - }; - - - typedef Variant < VariantBaseType < void > > ValueType; - - ConfigOption(std::string, const StringType &, const StringType, string_allowed_type allowed, bool list_me = true); - ConfigOption(std::string, const StringType &, const StringType = "", bool list_me = true); - ConfigOption(std::string, const SignedIntType &, const SignedIntType = 0, SignedIntType min = -INT_MAX, SignedIntType max = INT_MAX, SignedIntType step = 1, bool list_me = true); - ConfigOption(std::string, const UnsignedIntType &, const UnsignedIntType = 0, UnsignedIntType min = 0, UnsignedIntType max = UINT_MAX, UnsignedIntType step = 1, bool list_me = true); - ConfigOption(std::string, const BooleanType &, const BooleanType = false, bool list_me = true); - ConfigOption(std::string, FunctionType, std::string defvalue, string_allowed_type allowed, bool list_me = true); - ConfigOption(std::string, FunctionType, std::string defvalue = "", bool list_me = true); - - ConfigOption(const ConfigOption & o); - - ~ConfigOption(void); - - void set(StringType value); - - void set(SignedIntType value); - void set(UnsignedIntType value); - void set(BooleanType value); - - BooleanType get_bool(){ return _value_data.get().bool_val; } - std::string get_str(){ return _value_data.get().string_val; } - SignedIntType get_sint(){ return _value_data.get().sint_val; } - UnsignedIntType get_uint(){ return _value_data.get().uint_val; } - - std::string & name(void); - value_id_type type(void); - - const char ** values(void); - - void reset(void); - void commit(void); - - bool list_me(void) { return _list_me; }; - bool loaded(void) { return _loaded; }; - - void copy_from(ConfigOption &); - - protected: - std::string _my_name; - ValueType _value_data; - - bool _list_me; - const char ** _values; - bool _loaded; -}; - -struct ConfigOptions -{ - typedef std::vector < std::string > messages_type; - - ConfigOptions(void): _values(NULL) {}; - - typedef std::set < std::string > string_set; - - typedef std::map < std::string, ConfigOption > option_map_type; - typedef std::pair < std::string, ConfigOption > option_pair_type; - - typedef std::map < std::string, std::string > syn_option_map_type; - typedef std::pair < std::string, std::string > syn_option_pair_type; - - bool add(ConfigOption option); - - /* only valid in "process" (for backwards compatibility config files) */ - bool synonym(std::string, std::string); - - template - void set(std::string name, ValueType value) - { - option_map_type::iterator iter = _map.find(name); - - if (iter == _map.end()) - throw ConfigProcessFailure(STG(FMT("unknown option: %s") % name)); - - (*iter).second.set(value); - } - - std::string get(std::string name) - { - option_map_type::iterator iter = _map.find(name); - - if (iter == _map.end()) - throw ConfigProcessFailure(STG(FMT("unknown option: %s") % name)); - - switch((*iter).second.type()) - { - case ConfigOption::ID_BOOL: return (*iter).second.get_bool() ? "yes" : "no"; - case ConfigOption::ID_STRING: return (*iter).second.get_str(); - case ConfigOption::ID_UINT: return STG(FMT("%d") % (*iter).second.get_uint()); - case ConfigOption::ID_SINT: return STG(FMT("%d") % (*iter).second.get_sint()); - case ConfigOption::ID_FUN: return ""; - } - } - - string_set options(void); - - void process(const char *, const char *); /* process option from file */ - - void reset(void); /* reset loaded opts */ - messages_type commit(void); /* set defaults */ - - const char ** values(const char *); /* option value */ - const char ** values(void); /* values from options */ - - bool loaded(std::string); /* return if config was loaded */ - - void copy_from(ConfigOptions &, std::string); - - protected: - option_map_type::iterator find_option(std::string); - - protected: - option_map_type _map; - syn_option_map_type _syn_map; - - const char ** _values; -}; - -#endif /* _CONFIG_OPTIONS_HPP_ */ - diff --git a/src/mod/endpoints/mod_khomp/commons/configurator/configfile.cpp b/src/mod/endpoints/mod_khomp/commons/configurator/configfile.cpp deleted file mode 100644 index 6aa2e59201..0000000000 --- a/src/mod/endpoints/mod_khomp/commons/configurator/configfile.cpp +++ /dev/null @@ -1,241 +0,0 @@ -/* - KHOMP generic endpoint/channel library. - Copyright (C) 2007-2009 Khomp Ind. & Com. - - The contents of this file are subject to the Mozilla Public License Version 1.1 - (the "License"); you may not use this file except in compliance with the - License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ - - Software distributed under the License is distributed on an "AS IS" basis, - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for - the specific language governing rights and limitations under the License. - - Alternatively, the contents of this file may be used under the terms of the - "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which - case the provisions of "LGPL License" are applicable instead of those above. - - If you wish to allow use of your version of this file only under the terms of - the LGPL License and not to allow others to use your version of this file under - the MPL, indicate your decision by deleting the provisions above and replace them - with the notice and other provisions required by the LGPL License. If you do not - delete the provisions above, a recipient may use your version of this file under - either the MPL or the LGPL License. - - The LGPL header follows below: - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this library; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -*/ -#include - -#include - -#if _MSC_VER >= 1400 -#undef close -#endif - -void Configfile::ignore(std::string str) -{ - _ignores.insert(str); -}; - -bool Configfile::select(Section **ptr, std::string str) -{ - /* default section == this! */ - *ptr = this; - - /* always success by default */ - return true; -}; - -bool Configfile::adjust(Section * section, std::string & opt, std::string & val) -{ - return section->load(opt, val); -}; - -bool Configfile::deserialize(std::ifstream& fd) -{ - Section * section = NULL; - - /* default selection! */ - if (!select(§ion)) - { - _errors.push_back("default selection has failed!"); - return false; - } - - size_t count = 0; - - while (fd.good()) - { - std::string str; - - /* read one line! */ - std::getline(fd, str); - - size_t lst = str.size() - 1; - - if (str.size() >= 1 && str[lst] == '\r') //cuida das quebras de linha do tipo \r\n - { - str.erase(lst,1); - --lst; - } - - /* empty line! */ - if (str.size() == 0) - continue; - - /* comment! */ - if (str[0] == '#') - continue; - - ++count; - - if (str[0] == '[' && str[lst] == ']') - { - str.erase(0,1); --lst; - str.erase(lst,1); --lst; - - if (!select(§ion, str)) - { - _errors.push_back(STG(FMT("erroneous section '%s'") % str)); - - /* ignore this section */ - section = NULL; - continue; - } - } - else - { - std::string::size_type pos = str.find('='); - - if (pos == std::string::npos) - { - _errors.push_back(STG(FMT("erroneous separator '%s'") % str)); - continue; - }; - - if (section == NULL) - { - _errors.push_back(STG(FMT("no section for option '%s'") % str)); - continue; - } - - std::string opt(str.substr(0,pos)); - std::string val(str.substr(pos+1)); - - if (_ignores.find(opt) != _ignores.end()) - continue; - - if (val == "@") val = ""; - - if (adjust(section, opt, val)) - continue; - - _errors.push_back(STG(FMT("option '%s' does " - "not exist or '%s' is not a valid value (at section '%s')") - % opt % val % section->name())); - } - } - - // retorna 'true' se arquivo tinha alguma coisa valida. - return (count != 0); -} - -bool Configfile::obtain() -{ - std::ifstream fd(_filename.c_str()); - - if (!fd.is_open()) - { - _errors.push_back(STG(FMT("unable to open file '%s': %s") - % _filename % strerror(errno))); - return false; - }; - - if (!deserialize(fd)) - { - fd.close(); - return false; - } - - fd.close(); - return true; -}; - -void Configfile::recurse(std::ofstream& fd, Section * section) -{ - typedef Section::SectionMap::iterator section_iter; - typedef Section::OptionMap::iterator option_iter; - - for (option_iter i = section->option_begin(); i != section->option_end(); i++) - { - std::string res; - - if ((*i).second.store(res)) - { - if (res == "") res = "@"; - fd << (*i).first << "=" << res << std::endl; - } - } - - if (!section->recursive()) - return; - - for (section_iter j = section->section_begin(); j != section->section_end(); j++) - recurse(fd, (*j).second); -} - -bool Configfile::serialize(std::ofstream& fd) -{ - recurse(fd, this); - return true; -} - -bool Configfile::provide() -{ - std::string tmp(_filename); - tmp += ".new"; - - std::ofstream fd(tmp.c_str()); - - if (!fd.good()) - { - _errors.push_back(STG(FMT("unable to open file '%s': %s") - % tmp % strerror(errno))); - return false; - } - - if (!serialize(fd)) - { - fd.close(); - return false; - } - - fd.close(); - - if (rename(tmp.c_str(), _filename.c_str()) != 0) - { - _errors.push_back(STG(FMT("unable to replace config file '%s': %s") - % _filename % strerror(errno))); - return false; - } - - return true; -} - -#if _MSC_VER >= 1400 -#define close _close -#endif \ No newline at end of file diff --git a/src/mod/endpoints/mod_khomp/commons/configurator/option.cpp b/src/mod/endpoints/mod_khomp/commons/configurator/option.cpp deleted file mode 100644 index 083883e63f..0000000000 --- a/src/mod/endpoints/mod_khomp/commons/configurator/option.cpp +++ /dev/null @@ -1,185 +0,0 @@ -/* - KHOMP generic endpoint/channel library. - Copyright (C) 2007-2009 Khomp Ind. & Com. - - The contents of this file are subject to the Mozilla Public License Version 1.1 - (the "License"); you may not use this file except in compliance with the - License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ - - Software distributed under the License is distributed on an "AS IS" basis, - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for - the specific language governing rights and limitations under the License. - - Alternatively, the contents of this file may be used under the terms of the - "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which - case the provisions of "LGPL License" are applicable instead of those above. - - If you wish to allow use of your version of this file only under the terms of - the LGPL License and not to allow others to use your version of this file under - the MPL, indicate your decision by deleting the provisions above and replace them - with the notice and other provisions required by the LGPL License. If you do not - delete the provisions above, a recipient may use your version of this file under - either the MPL or the LGPL License. - - The LGPL header follows below: - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this library; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -*/ - -#include - -bool Option::equals(std::string & value) -{ - switch (_restriction.numeral()) - { - case Restriction::N_UNIQUE: - { - Restriction::Value my_value; - - if (!_restriction.get(Restriction::F_USER, my_value)) - return false; - - return (my_value == value); - } - case Restriction::N_MULTIPLE: - { - Restriction::Vector my_values; - - if (!_restriction.get(Restriction::F_USER, my_values)) - return false; - - for (Restriction::Vector::iterator i = my_values.begin(); i != my_values.end(); i++) - { - if ((*i) == value) - return true; - } - - return false; - } - } - - return false; -} - -bool Option::load(std::string & value) -{ - bool ret = _restriction.set(Restriction::F_FILE, value); - - if (ret) _modified = false; - - return ret; -} - -bool Option::change(std::string & value) -{ - bool ret = _restriction.set(Restriction::F_FILE, value); - - if (ret) _modified = true; - - return ret; -} - -bool Option::store(std::string & value) -{ - switch (_restriction.numeral()) - { - case Restriction::N_UNIQUE: - return _restriction.get(Restriction::F_FILE, value); - - case Restriction::N_MULTIPLE: - { - Restriction::Vector values; - - if (!_restriction.get(Restriction::F_FILE, values)) - return false; - - Strings::Merger strs; - - for (Restriction::Vector::iterator i = values.begin(); i != values.end(); i++) - strs.add(*i); - - value = strs.merge(","); - - return true; - } - - default: - return false; - } -} - -Option::Flags Option::set(const char * value) -{ - std::string str_value(value); - return set(str_value); -} - - -Option::Flags Option::set(Restriction::Value & value) -{ - Restriction::Value last_value, curr_value; - Flags flags; - - bool ret1 = _restriction.get(Restriction::F_USER, last_value); - - if (!_restriction.set(Restriction::F_USER, value)) - return flags; - - flags[F_ADJUSTED] = true; - - bool ret2 = _restriction.get(Restriction::F_USER, curr_value); - - if (!ret1 || (ret2 && (last_value != curr_value))) - { - flags[F_MODIFIED] = true; - _modified = true; - } - - return flags; -} - -Option::Flags Option::set(Restriction::Vector & values) -{ - Restriction::Vector last_values, curr_values; - Flags flags; - - bool ret1 = _restriction.get(Restriction::F_USER, last_values); - - if (!_restriction.set(Restriction::F_USER, values)) - return flags; - - flags[F_ADJUSTED] = true; - - bool ret2 = _restriction.get(Restriction::F_USER, curr_values); - - if (!ret1 || (ret2 && (last_values != curr_values))) - { - flags[F_MODIFIED] = true; - _modified = true; - } - - return flags; -} - -bool Option::get(Restriction::Value & value) -{ - return _restriction.get(Restriction::F_USER, value); -} - -bool Option::get(Restriction::Vector & values) -{ - return _restriction.get(Restriction::F_USER, values); -} diff --git a/src/mod/endpoints/mod_khomp/commons/configurator/restriction.cpp b/src/mod/endpoints/mod_khomp/commons/configurator/restriction.cpp deleted file mode 100644 index 9653a7c608..0000000000 --- a/src/mod/endpoints/mod_khomp/commons/configurator/restriction.cpp +++ /dev/null @@ -1,353 +0,0 @@ -/* - KHOMP generic endpoint/channel library. - Copyright (C) 2007-2009 Khomp Ind. & Com. - - The contents of this file are subject to the Mozilla Public License Version 1.1 - (the "License"); you may not use this file except in compliance with the - License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ - - Software distributed under the License is distributed on an "AS IS" basis, - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for - the specific language governing rights and limitations under the License. - - Alternatively, the contents of this file may be used under the terms of the - "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which - case the provisions of "LGPL License" are applicable instead of those above. - - If you wish to allow use of your version of this file only under the terms of - the LGPL License and not to allow others to use your version of this file under - the MPL, indicate your decision by deleting the provisions above and replace them - with the notice and other provisions required by the LGPL License. If you do not - delete the provisions above, a recipient may use your version of this file under - either the MPL or the LGPL License. - - The LGPL header follows below: - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this library; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -*/ - -#include -#include - -#include -#include - -#include - -/* internal helper! */ -bool Restriction::equalNumber(const double a, const double b) -{ - char tmp1[64]; - char tmp2[64]; - - snprintf(tmp1, sizeof(tmp1), "%.3f", a); - snprintf(tmp2, sizeof(tmp2), "%.3f", b); - - if (strncmp(tmp1, tmp2, sizeof(tmp1))) - return false; - - return true; -} - -/* process value to our internal representation */ - -bool Restriction::process(Restriction::Format fmt, - const Restriction::Value & value, Restriction::Value & final) -{ - switch (_bounds) - { - case B_RANGE: - { - if (_kind != K_NUMBER) - return false; - - std::string tmpvalue; - - Restriction::Value::const_iterator itr = value.begin(); - Restriction::Value::const_iterator end = value.end(); - - tmpvalue.reserve(value.size()); - - // f*cking dot/comma notation! - for (; itr != end; ++itr) - tmpvalue += ((*itr) != ',' ? (*itr) : '.'); - - try - { - double newvalue = Strings::todouble(tmpvalue); - - if (newvalue < _init && newvalue > _fini) - return false; - - double res = (newvalue - _init) / _step; - - if (!equalNumber(res, rint(res))) - return false; - - final = value; - return true; - } - catch (...) - { - return false; - } - } - - case B_LIST: - for (List::iterator i = _list.begin(); i != _list.end(); i++) - { - Value & tmp = (*i); - - if (tmp == value) - { - final = value; - return true; - } - } - return false; - - case B_MAPS: - switch (fmt) - { - case F_USER: - { - Map::iterator i = _map_from_usr.find(std::string(value)); - - if (i == _map_from_usr.end()) - return false; - - Value & tmp = (*i).second; - - final = tmp; - return true; - } - - case F_FILE: - { - Map::iterator i = _map_from_cfg.find(std::string(value)); - - if (i == _map_from_cfg.end()) - return false; - - final = value; - return true; - } - - default: - break; - } - return false; - - case B_FREE: - final = value; - return true; - - default: - break; - } - - return false; -} - -/* unprocess the value (outputs the external representation) */ - -bool Restriction::unprocess(Restriction::Format fmt, - const Restriction::Value & value, Restriction::Value & final) -{ - switch (_bounds) - { - case B_MAPS: - - switch (fmt) - { - case F_USER: - { - Map::iterator i = _map_from_cfg.find(std::string(value)); - - if (i == _map_from_cfg.end()) - return false; - - final = (*i).second; - return true; - } - default: - break; - } - - default: - final = value; - return true; - } -} - -/***************************** *****************************/ - -bool Restriction::get(Restriction::Format fmt, Restriction::Value & value) -{ - if (_numeral != N_UNIQUE) - return false; - - if (!unprocess(fmt, _value._unique, value)) - return false; - - return true; -} - -bool Restriction::get(Restriction::Format fmt, Restriction::Vector & values) -{ - if (_numeral != N_MULTIPLE) - return false; - - List & my_values = _value._multiple; - - for (List::iterator i = my_values.begin(); i != my_values.end(); i++) - { - Value & value = (*i); - Value final; - - if (!unprocess(fmt, value, final)) - return false; - - values.push_back(final); - }; - - return true; -} - -/***************************** *****************************/ - -bool Restriction::set(Restriction::Format fmt, Restriction::Value &value) -{ - switch (_numeral) - { - case N_UNIQUE: - { - Value final; - - if (!process(fmt, value, final)) - return false; - - _value._unique = final; - return true; - } - - case N_MULTIPLE: - { - if (value == "@" || value == "#" || value == "") - { - _value._multiple.clear(); - return true; - } - - Strings::vector_type values; - Strings::tokenize(value, values, ","); - - return set(fmt, values); - } - - default: - return false; - } -} - -bool Restriction::set(Restriction::Format fmt, Restriction::Vector & values) -{ - if (_numeral != N_MULTIPLE) - return false; - - if (values.empty()) - { - _value._multiple.clear(); - } - else - { - /* list needed to store temporary values */ - List finals; - - for (Vector::iterator i = values.begin(); i != values.end(); i++) - { - Value & value = (*i); - Value final; - - if (!process(fmt, value, final)) - return false; - - finals.push_back(final); - } - - List & lst = _value._multiple; - - /* need to clear values set before */ - lst.clear(); - - for (List::iterator i = finals.begin(); i != finals.end(); i++) - { - Value value = (*i); - lst.push_back(value); - } - }; - - return true; -} - -/***************************** *****************************/ - -void Restriction::allowed(Restriction::Vector &vals) -{ - switch (_bounds) - { - case B_FREE: - return; - - case B_LIST: - for (List::iterator i = _list.begin(); i != _list.end(); i++) - vals.push_back((*i)); - break; - - case B_MAPS: - for (Map::iterator i = _map_from_usr.begin(); i != _map_from_usr.end(); i++) - vals.push_back((*i).first); - break; - - case B_RANGE: - { - if (_kind != K_NUMBER) - return; - - // is there any fraction? - bool has_fraction = (!equalNumber(_init, rint(_init))) || (!equalNumber(_fini, rint(_fini))) || (!equalNumber(_step, rint(_step))); - - const char * format = (has_fraction ? "%.2f" : "%02.0f"); - - for (double i = _init; i <= _fini; i += _step) - { - char tmp[32]; - snprintf(tmp, sizeof(tmp), format, i); - vals.push_back(std::string(tmp)); - } - break; - } - - default: - break; - } -} - -void Restriction::init_class() -{ - _value._unique.clear(); - _value._multiple.clear(); -} diff --git a/src/mod/endpoints/mod_khomp/commons/configurator/restriction.hpp b/src/mod/endpoints/mod_khomp/commons/configurator/restriction.hpp deleted file mode 100644 index 0815ede3db..0000000000 --- a/src/mod/endpoints/mod_khomp/commons/configurator/restriction.hpp +++ /dev/null @@ -1,321 +0,0 @@ -/* - KHOMP generic endpoint/channel library. - Copyright (C) 2007-2009 Khomp Ind. & Com. - - The contents of this file are subject to the Mozilla Public License Version 1.1 - (the "License"); you may not use this file except in compliance with the - License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ - - Software distributed under the License is distributed on an "AS IS" basis, - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for - the specific language governing rights and limitations under the License. - - Alternatively, the contents of this file may be used under the terms of the - "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which - case the provisions of "LGPL License" are applicable instead of those above. - - If you wish to allow use of your version of this file only under the terms of - the LGPL License and not to allow others to use your version of this file under - the MPL, indicate your decision by deleting the provisions above and replace them - with the notice and other provisions required by the LGPL License. If you do not - delete the provisions above, a recipient may use your version of this file under - either the MPL or the LGPL License. - - The LGPL header follows below: - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this library; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -*/ - -#include - -#include -#include -#include -#include - -#ifndef _CONFIG_RESTRICTION_HPP_ -#define _CONFIG_RESTRICTION_HPP_ - -struct Restriction -{ - /* generic types */ - enum Format - { - F_USER, - F_FILE - }; - - enum Kind - { -// K_INTEGER, -// K_FLOAT, - K_STRING, - K_NUMBER // = K_INTEGER // compatibility - }; - - enum Bounds - { - B_FREE, - B_RANGE, - B_LIST, - B_MAPS - }; - - enum Numeral - { - N_UNIQUE, - N_MULTIPLE - }; - - typedef std::string Value; - - /* types used for data input */ - struct Pair - { - const char *pretty; - const char *value; - }; - - typedef std::pair < Value, Value > PairMap; - typedef std::list < PairMap > ListMap; - - /* types used internally */ - typedef std::map < Value, Value > Map; - typedef std::vector < Value > Vector; - - typedef std::list < Value > List; - typedef std::pair < Value, Value > MapPair; - - struct Generic - { - Value _unique; - List _multiple; - }; - - Restriction(Kind kind, Numeral num) - : _kind(kind), _bounds(B_FREE), _numeral(num), _unit(""), - _init(-1), _fini(-1), _step(-1) - { - init_class(); - } - -/* - Restriction(Kind kind, Numeral num, - int init, int fini, int step = 1) - : _kind(kind), _bounds(B_RANGE), _numeral(num), _unit(unit), - _iinit(init), _ifini(fini), _istep(step), - _finit(-1), _ffini(-1), _fstep(-1) - { - init_class(); - } - - Restriction(Kind kind, Numeral num, - const char *unit, int init, int fini, int step = 1) - : _kind(kind), _bounds(B_RANGE), _numeral(num), _unit(unit), - _iinit(init), _ifini(fini), _istep(step), - _finit(-1), _ffini(-1), _fstep(-1) - { - init_class(); - } - - Restriction(Kind kind, Numeral num, - std::string unit, int init, int fini, int step = 1) - : _kind(kind), _bounds(B_RANGE), _numeral(num), _unit(unit), - _iinit(init), _ifini(fini), _istep(step), - _finit(-1), _ffini(-1), _fstep(-1) - { - init_class(); - } - - Restriction(Kind kind, Numeral num, - float init, float fini, float step = 1) - : _kind(kind), _bounds(B_RANGE), _numeral(num), _unit(unit), - _iinit(-1), _ifini(-1), _istep(-1) - _finit(init), _ffini(fini), _fstep(step), - { - init_class(); - } - - Restriction(Kind kind, Numeral num, - const char *unit, float init, float fini, float step = 1.0) - : _kind(kind), _bounds(B_RANGE), _numeral(num), _unit(unit), - _iinit(-1), _ifini(-1), _istep(-1) - _finit(init), _ffini(fini), _fstep(step), - { - init_class(); - } - - Restriction(Kind kind, Numeral num, - std::string unit, float init, float fini, float step = 1.0) - : _kind(kind), _bounds(B_RANGE), _numeral(num), _unit(unit), - _iinit(-1), _ifini(-1), _istep(-1) - _finit(init), _ffini(fini), _fstep(step), - { - init_class(); - } -*/ - - Restriction(Kind kind, Numeral num, - double init, double fini, double step = 1) - : _kind(kind), _bounds(B_RANGE), _numeral(num), _unit(""), - _init(init), _fini(fini), _step(step) - { - init_class(); - } - - Restriction(Kind kind, Numeral num, - const char *unit, double init, double fini, double step = 1.0) - : _kind(kind), _bounds(B_RANGE), _numeral(num), _unit(unit), - _init(init), _fini(fini), _step(step) - { - init_class(); - } - - Restriction(Kind kind, Numeral num, - std::string unit, double init, double fini, double step = 1.0) - : _kind(kind), _bounds(B_RANGE), _numeral(num), _unit(unit), - _init(init), _fini(fini), _step(step) - { - init_class(); - } - - Restriction(Kind kind, Numeral num, - const char *first, ...) - : _kind(kind), _bounds(B_LIST), _numeral(num), _unit(""), - _init(-1), _fini(-1), _step(-1) - { - _list.push_back(std::string(first)); - - va_list ap; - va_start(ap, first); - - while (true) - { - const char *arg = va_arg(ap, const char *); - - if (arg == NULL) break; - - _list.push_back(std::string(arg)); - } - - init_class(); - } - - Restriction(Kind kind, const char *unit, Numeral num, - const char *first, ...) - : _kind(kind), _bounds(B_LIST), _numeral(num), _unit(unit), - _init(-1), _fini(-1), _step(-1) - { - _list.push_back(std::string(first)); - - va_list ap; - va_start(ap, first); - - while (true) - { - const char *arg = va_arg(ap, const char *); - - if (arg == NULL) break; - - _list.push_back(std::string(arg)); - } - - init_class(); - } - - Restriction(Kind kind, Numeral num, - const struct Pair first, ...) - : _kind(kind), _bounds(B_MAPS), _numeral(num), _unit(""), - _init(-1), _fini(-1), _step(-1) - { - _map_from_usr.insert(MapPair(Value(first.pretty), Value(first.value))); - _map_from_cfg.insert(MapPair(Value(first.value), Value(first.pretty))); - - va_list ap; - va_start(ap, first); - - while (true) - { - Pair arg = va_arg(ap, Pair); - - if (arg.pretty == NULL) break; - - _map_from_usr.insert(MapPair(Value(arg.pretty), Value(arg.value))); - _map_from_cfg.insert(MapPair(Value(arg.value), Value(arg.pretty))); - } - - init_class(); - } - - Restriction(Kind kind, Numeral num, List list) - : _kind(kind), _bounds(B_LIST), _numeral(num), _unit(""), - _init(-1), _fini(-1), _step(-1), _list(list) - { - init_class(); - } - - Restriction(Kind kind, Numeral num, ListMap map) - : _kind(kind), _bounds(B_MAPS), _numeral(num), _unit(""), - _init(-1), _fini(-1), _step(-1) - { - for (ListMap::iterator i = map.begin(); i != map.end(); i++) - { - _map_from_usr.insert(MapPair(Value((*i).first), Value((*i).second))); - _map_from_cfg.insert(MapPair(Value((*i).second), Value((*i).first))); - } - - init_class(); - } - - Kind kind() { return _kind; }; - Bounds bounds() { return _bounds; }; - Numeral numeral() { return _numeral; }; - - Value unit() { return _unit; }; - - bool set(Format, Vector &); - bool set(Format, Value &); - - bool get(Format, Vector &); - bool get(Format, Value &); - - void allowed(Vector &); - - private: - bool process(Format, const Value &, Value &); - bool unprocess(Format, const Value &, Value &); - void init_class(); - - bool equalNumber(const double, const double); - - protected: - Kind _kind; - Bounds _bounds; - Numeral _numeral; - - Value _unit; - - double _init, _fini, _step; - - Map _map_from_usr, - _map_from_cfg; - - List _list; - - Generic _value; -}; - -#endif /* _CONFIG_RESTRICTION_HPP_ */ diff --git a/src/mod/endpoints/mod_khomp/commons/configurator/section.hpp b/src/mod/endpoints/mod_khomp/commons/configurator/section.hpp deleted file mode 100644 index fdb782308a..0000000000 --- a/src/mod/endpoints/mod_khomp/commons/configurator/section.hpp +++ /dev/null @@ -1,226 +0,0 @@ -/* - KHOMP generic endpoint/channel library. - Copyright (C) 2007-2009 Khomp Ind. & Com. - - The contents of this file are subject to the Mozilla Public License Version 1.1 - (the "License"); you may not use this file except in compliance with the - License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ - - Software distributed under the License is distributed on an "AS IS" basis, - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for - the specific language governing rights and limitations under the License. - - Alternatively, the contents of this file may be used under the terms of the - "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which - case the provisions of "LGPL License" are applicable instead of those above. - - If you wish to allow use of your version of this file only under the terms of - the LGPL License and not to allow others to use your version of this file under - the MPL, indicate your decision by deleting the provisions above and replace them - with the notice and other provisions required by the LGPL License. If you do not - delete the provisions above, a recipient may use your version of this file under - either the MPL or the LGPL License. - - The LGPL header follows below: - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this library; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -*/ - -#include -#include -#include -#include -#include - -#include - -#ifndef _CONFIG_SECTION_HPP_ -#define _CONFIG_SECTION_HPP_ - -struct Section -{ - typedef std::map < std::string, Option > OptionMap; - typedef std::vector< Option * > OptionVector; - - typedef std::map < std::string, Section * > SectionMap; - typedef std::vector < Section * > SectionVector; - - struct not_found {}; /* exception */ - -// protected: - Section(std::string name, std::string desc, bool recursive = true) - : _name(name), _description(desc), _recursive(recursive) {}; - - void add(Option o) - { - _options.insert(std::pair(o.name(), o)); - }; - - void del(std::string name) - { - _options.erase(name); - }; - - void add(Section *s) - { - _sections.insert(std::pair(s->name(), s)); - }; - - public: - const std::string & name() { return _name; }; - const std::string & description() { return _description; }; - const bool & recursive() { return _recursive; }; - - OptionMap::iterator option_begin() { return _options.begin(); }; - OptionMap::iterator option_end() { return _options.end(); }; - - SectionMap::iterator section_begin() { return _sections.begin(); }; - SectionMap::iterator section_end() { return _sections.end(); }; - - /**/ - - Option * option_find(const char *, bool recurse = false); - Section * section_find(const char *, bool recurse = false); - - Option * option_find(std::string &, bool recurse = false); - Section * section_find(std::string &, bool recurse = false); - - /**/ - - void options(OptionVector &); - void sections(SectionVector &); - - /**/ - - template - bool search_and_apply(std::string &key, std::string &value, F f) - { - OptionMap::iterator i = _options.find(key); - - if (i != _options.end()) - return f((*i).second); - - if (!_recursive) - return false; - - return (find_if(_sections.begin(), _sections.end(), f) != _sections.end()); - } - - private: - struct key_value - { - key_value(std::string &k, std::string &v): _k(k), _v(v) {}; - std::string & _k, & _v; - }; - - struct load_section: protected key_value - { - load_section(std::string &k, std::string &v): key_value(k,v) {}; - - bool operator()(Option &o) { return o.load(_v); }; - bool operator()(SectionMap::value_type &v) { return v.second->load(_k,_v); }; - }; - - struct change_section: protected key_value - { - change_section(std::string &k, std::string &v): key_value(k,v) {}; - - bool operator()(Option &o) { return o.change(_v); }; - bool operator()(SectionMap::value_type &v) { return v.second->change(_k,_v); }; - }; - - struct store_section: protected key_value - { - store_section(std::string &k, std::string &v): key_value(k,v) {}; - - bool operator()(Option &o) { return o.store(_v); }; - bool operator()(SectionMap::value_type &v) { return v.second->store(_k,_v); }; - }; - - struct set_section: protected key_value - { - set_section(std::string &k, std::string &v): key_value(k,v) {}; - - bool operator()(Option &o) { return (o.set(_v))[Option::F_ADJUSTED]; }; - bool operator()(SectionMap::value_type &v) { return v.second->set(_k,_v); }; - }; - - struct get_section: protected key_value - { - get_section(std::string &k, std::string &v): key_value(k,v) {}; - - bool operator()(Option &o) { return o.get(_v); }; - bool operator()(SectionMap::value_type &v) { return v.second->get(_k,_v); }; - }; - - struct modified_section - { - bool operator()(OptionMap::value_type &v) { return v.second.modified(); }; - bool operator()(SectionMap::value_type &v) { return v.second->modified(); }; - }; - - public: - bool load(const char * key, std::string value) - { - std::string skey(key); - return search_and_apply(skey, value, load_section(skey, value)); - } - - bool load(std::string &key, std::string &value) - { - return search_and_apply(key, value, load_section(key, value)); - } - - bool change(std::string &key, std::string &value) - { - return search_and_apply(key, value, change_section(key, value)); - } - - bool store(std::string &key, std::string &value) - { - return search_and_apply(key, value, store_section(key, value)); - } - - bool set(std::string &key, std::string &value) - { - return search_and_apply(key, value, set_section(key, value)); - } - - bool get(std::string &key, std::string &value) - { - return search_and_apply(key, value, get_section(key, value)); - } - - bool modified() - { - return ((find_if(_options.begin(), _options.end(), modified_section()) != _options.end()) || - (find_if(_sections.begin(), _sections.end(), modified_section()) != _sections.end())); - } - - private: - Section() {}; - - protected: - std::string _name; - std::string _description; - - OptionMap _options; - SectionMap _sections; - - bool _recursive; -}; - -#endif /* _CONFIG_SECTION_HPP_ */ diff --git a/src/mod/endpoints/mod_khomp/commons/ringbuffer.cpp b/src/mod/endpoints/mod_khomp/commons/ringbuffer.cpp deleted file mode 100644 index 428bd29221..0000000000 --- a/src/mod/endpoints/mod_khomp/commons/ringbuffer.cpp +++ /dev/null @@ -1,575 +0,0 @@ -/* - KHOMP generic endpoint/channel library. - Copyright (C) 2007-2009 Khomp Ind. & Com. - - The contents of this file are subject to the Mozilla Public License Version 1.1 - (the "License"); you may not use this file except in compliance with the - License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ - - Software distributed under the License is distributed on an "AS IS" basis, - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for - the specific language governing rights and limitations under the License. - - Alternatively, the contents of this file may be used under the terms of the - "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which - case the provisions of "LGPL License" are applicable instead of those above. - - If you wish to allow use of your version of this file only under the terms of - the LGPL License and not to allow others to use your version of this file under - the MPL, indicate your decision by deleting the provisions above and replace them - with the notice and other provisions required by the LGPL License. If you do not - delete the provisions above, a recipient may use your version of this file under - either the MPL or the LGPL License. - - The LGPL header follows below: - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this library; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -*/ - -#include - -/********** BUFFER FUNCTIONS **********/ - -/* writes everything or nothing */ -bool Ringbuffer_traits::traits_provide(char * buffer, const char * value, unsigned int amount, bool skip_overwrite) -{ - /* avoid using different values */ - Buffer_table cache = _pointers; - - const unsigned int reader = cache.reader.complete; - const unsigned int writer = cache.writer.complete; - - const unsigned int dest = cache.writer.complete - 1; - - const bool reader_less = cache.reader.complete < cache.writer.complete; - - if (amount >= _size) - return false; - - bool ret = true; - - /* should we go around the buffer for writing? */ - if (((writer + amount) > _size) && (reader_less || !skip_overwrite)) - { - /* Documentation of the formula used in the 'if' below. - * - * [0|1|2|3|4|5|6|7] => size=8 - * | | - * reader | - * writer - * - * => writer has places [5,6,7,0,1] to write (5 places). - * - * => 8 - (4-2+1) = 8 - (2+1) = 8 - 3 = 5 - * - * > writer goes 1 up, amount goes 1 down. - * > reader goes 1 up, amount goes 1 up. - * > size goes 1 down, amount goes 1 down. - * - */ - - if ((_size - (writer - reader + 1)) <= amount) - { - if (skip_overwrite) - return false; - - do - { - Buffer_pointer extra(cache.reader); - extra.complete = (extra.complete + amount) % _size; - - if (update(cache.reader, extra)) - break; - } - while (true); - - ret = false; - } - - unsigned int wr1 = _size - writer + 1; /* writer is already 1 position after */ - unsigned int wr2 = amount - wr1; - -// fprintf(stderr, "%p> partial write: (%d/%d) %d/%d [%d/%d]\n", this, wr1, wr2, amount, _size, reader, writer); - - /* two partial writes (one at the end, another at the beginning) */ - memcpy((void *) &(buffer[dest]), (const void *) (value), _block * wr1); - memcpy((void *) (buffer), (const void *) &(value[wr1]), _block * wr2); - } - else - { - if (!reader_less && ((reader - writer) <= amount)) - { - if (skip_overwrite) - return false; - - do - { - Buffer_pointer extra(cache.reader); - extra.complete = (extra.complete + amount) % _size; - - if (update(cache.reader, extra)) - break; - } - while (true); - - ret = false; - } - -// fprintf(stderr, "%p> full write: a=%d/s=%d [r=%d/w=%d]\n", this, amount, _size, reader, writer); - - /* we are talking about buffers here, man! */ - memcpy((void *) &(buffer[dest]), (const void *) value, _block * amount); - } - - _pointers.writer.complete = ((dest + amount) % _size) + 1; - _pointers.writer.partial = 1; - -// fprintf(stderr, "%p> write end: %d [block=%d]\n", this, writer, _block); - - return ret; -} - -/* returns the number of itens that have been read */ -unsigned int Ringbuffer_traits::traits_consume(const char * buffer, char * value, unsigned int amount, bool atomic_mode) -{ - /* avoid using different values */ - Buffer_table cache = _pointers; - - const unsigned int writer = _pointers.writer.complete; - const unsigned int reader = _pointers.reader.complete; - - const bool writer_less = writer < reader; - - unsigned int total = 0; - - /* should we go around the buffer for reading? */ - if (writer_less && (reader + amount >= _size)) - { - total = std::min(_size - (reader - writer + 1), amount); - - if ((total == 0) || (atomic_mode && (total < amount))) - return 0; - - unsigned int rd1 = _size - reader; - unsigned int rd2 = total - rd1; - -// fprintf(stderr, "%p> partial read: (%d/%d) %d/%d [%d/%d]\n", this, rd1, rd2, total, _size, reader, writer); - - /* two partial consumes (one at the end, another at the beginning) */ - memcpy((void *) (value), (const void *) &(buffer[reader]), _block * rd1); - memcpy((void *) &(value[rd1]), (const void *) (buffer), _block * rd2); - } - else - { - total = std::min((!writer_less ? writer - (reader + 1) : amount), amount); - - if ((total == 0) || (atomic_mode && (total < amount))) - return 0; - -// fprintf(stderr, "%p> full read: %d/%d [%d/%d]\n", this, total, _size, reader, writer); - - /* we are talking about buffers here, man! */ - memcpy((void *) value, (const void *) &(buffer[reader]), _block * total); - } - - do - { - /* jump the reader forward */ - Buffer_pointer index((cache.reader.complete + total) % _size); - - if (update(cache.reader, index)) - break; - } - while (true); - -// fprintf(stderr, "%p> read end: %d [block=%d]\n", this, reader, _block); - - return total; -} - -/********** TWO-PHASE BUFFER FUNCTIONS ***********/ - -/* returns the number of itens that have been read */ -unsigned int Ringbuffer_traits::traits_consume_begins(const char * buffer, char * value, unsigned int amount, bool atomic_mode) -{ - Buffer_table cache = _pointers; - - /* avoid using different values */ - const unsigned int reader = cache.reader.complete; - const unsigned int writer = cache.writer.complete; - - const bool writer_less = writer < reader; - - unsigned int total = 0; - - /* should we go around the buffer for reading? */ - if (writer_less && (reader + amount >= _size)) - { - total = std::min(_size - (reader - writer + 1), amount); - - if ((total == 0) || (atomic_mode && (total < amount))) - return 0; - - unsigned int rd1 = _size - reader; - unsigned int rd2 = total - rd1; - -// fprintf(stderr, "%p> partial read: (%d/%d) %d/%d [%d/%d]\n", this, rd1, rd2, total, _size, reader, writer); - - /* two partial consumes (one at the end, another at the beginning) */ - memcpy((void *) (value), (const void *) &(buffer[reader]), _block * rd1); - memcpy((void *) &(value[rd1]), (const void *) (buffer), _block * rd2); - } - else - { - total = std::min((!writer_less ? writer - (reader + 1) : amount), amount); - - if ((total == 0) || (atomic_mode && (total < amount))) - return 0; - -// fprintf(stderr, "%p> full read: %d/%d [%d/%d]\n", this, total, _size, reader, writer); - - /* we are talking about buffers here, man! */ - memcpy((void *) value, (const void *) &(buffer[reader]), _block * total); - } - -// fprintf(stderr, "%p> read end: %d [%d]\n", this, _reader, _reader_partial); - - return total; -} - -bool Ringbuffer_traits::traits_consume_commit(unsigned int amount) -{ - /* avoid using different values */ - Buffer_table cache = _pointers; - - const unsigned int writer = cache.writer.complete; - const unsigned int reader = cache.reader.complete; - - const bool writer_less = writer < reader; - - unsigned int total = 0; - - /* should we go around the buffer for reading? */ - if (writer_less && (reader + amount >= _size)) - { - total = std::min(_size - (reader - writer + 1), amount); - - if (total < amount) - return false; - -// fprintf(stderr, "%p> partial read: (%d/%d) %d/%d [%d/%d]\n", this, rd1, rd2, total, _size, reader, writer); - } - else - { - total = std::min((!writer_less ? writer - (reader + 1) : amount), amount); - - if (total < amount) - return false; - -// fprintf(stderr, "%p> full read: %d/%d [%d/%d]\n", this, total, _size, reader, writer); - } - - do - { - /* jump the reader forward */ - Buffer_pointer index(cache.reader); - index.complete = (index.complete + total) % _size; - - if (update(cache.reader, index)) - break; - } - while (true); - -// fprintf(stderr, "%p> read end: %d [%d]\n", this, _reader, _reader_partial); - - return true; -} - -/********** PARTIAL BUFFER FUNCTIONS (bytes) ***********/ - -/* writes everything or nothing */ -bool Ringbuffer_traits::traits_provide_partial(char * buffer, const char * value, unsigned int amount) -{ - /* avoid using different values */ - Buffer_table cache = _pointers; - - const unsigned int reader = (cache.reader.complete * _block) + cache.reader.partial; - const unsigned int writer = ((cache.writer.complete - 1) * _block) + cache.writer.partial; - - const unsigned int size = _size * _block; - const unsigned int dest = writer - 1; - -// fprintf(stderr, "%p> provide partial: %d/%d [%d/%d]\n", this, reader, writer, amount, size); - - const bool reader_less = reader < writer; - - /* should we go around the buffer for writing? */ - if (reader_less && ((writer + amount) > size)) - { - /* Documentation of the formula used in the 'if' below. - * - * [0|1|2|3|4|5|6|7] => size=8 - * | | - * reader | - * writer - * - * => writer has places [5,6,7,0,1] to write (5 places). - * - * => 8 - (4-2+1) = 8 - (2+1) = 8 - 3 = 5 - * - * > writer goes 1 up, amount goes 1 down. - * > reader goes 1 up, amount goes 1 up. - * > size goes 1 down, amount goes 1 down. - * - */ - - if ((size - (writer - reader + 1)) <= amount) - return false; - - unsigned int wr1 = size - writer + 1; /* writer is already 1 position after */ - unsigned int wr2 = amount - wr1; - -// fprintf(stderr, "%p> p partial write: (%d/%d) %d/%d [%d/%d]\n", this, wr1, wr2, amount, size, reader, writer); - - /* two partial writes (one at the end, another at the beginning) */ - memcpy((void *) &(buffer[dest]), (const void *) (value), wr1); - memcpy((void *) (buffer), (const void *) &(value[wr1]), wr2); - } - else - { - if (!reader_less && ((reader - writer) <= amount)) - return false; - -// fprintf(stderr, "%p> p full write: %d/%d [r=%d/w=%d]\n", this, amount, size, reader, writer); - - /* we are talking about buffers here, man! */ - memcpy((void *) &(buffer[dest]), (const void *) value, amount); - } - - unsigned int new_writer = ((dest + amount) % size) + 1; - - /* update "full length position" */ - _pointers.writer.complete = (unsigned int)floor((double) new_writer / (double)_block)+1; - _pointers.writer.partial = (unsigned short)(new_writer % _block); - -// fprintf(stderr, "%p> p write end: %d [block=%d]\n", this, new_writer, _block); - - return true; -} - -/* returns the number of bytes that have been read */ -unsigned int Ringbuffer_traits::traits_consume_partial(const char * buffer, char * value, unsigned int amount) -{ - /* avoid using different values */ - Buffer_table cache = _pointers; - - const unsigned int writer = ((cache.writer.complete - 1) * _block) + cache.writer.partial; - const unsigned int reader = (cache.reader.complete * _block) + cache.reader.partial; - - const unsigned int size = _size * _block; - -// fprintf(stderr, "%p> consume partial: %d/%d [%d/%d]\n", this, reader, writer, amount, size); - - const bool writer_less = writer < reader; - - unsigned int total = 0; - - /* should we go around the buffer for reading? */ - if (writer_less && (reader + amount >= size)) - { - total = std::min(size - (reader - writer + 1), amount); - - if (total == 0) - return 0; - - unsigned int rd1 = size - reader; - unsigned int rd2 = total - rd1; - -// fprintf(stderr, "%p> p partial read: (%d/%d) %d/%d [%d/%d]\n", this, rd1, rd2, total, size, reader, writer); - - /* two partial consumes (one at the end, another at the beginning) */ - memcpy((void *) (value), (const void *) &(buffer[reader]), rd1); - memcpy((void *) &(value[rd1]), (const void *) (buffer), rd2); - } - else - { - total = std::min((writer_less ? amount : writer - (reader + 1)), amount); - - if (total == 0) - return 0; - -// fprintf(stderr, "%p> p full read: %d/%d [r=%d/w=%d]\n", this, total, size, reader, writer); - - /* we are talking about buffers here, man! */ - memcpy((void *) value, (const void *) &(buffer[reader]), total); - } - - do - { - unsigned int new_reader = (((cache.reader.complete * _block) + cache.reader.partial) + total) % size; - - /* jump the reader forward */ - Buffer_pointer index((unsigned int)floor((double)new_reader / (double)_block), - (unsigned short)(new_reader % _block)); - - if (update(cache.reader, index)) - { -// fprintf(stderr, "%p> p read end: %d [block=%d]\n", this, new_reader, _block); - break; - } - } - while (true); - - return total; -} - - - -/********** IO FUNCTIONS **********/ - -/* returns the number of items written to from buffer to stream */ -unsigned int Ringbuffer_traits::traits_put(const char * buffer, std::ostream &fd, unsigned int amount) -{ - /* avoid using different values */ - Buffer_table cache = _pointers; - - const unsigned int reader = cache.reader.complete; - const unsigned int writer = cache.writer.complete; - - const bool writer_less = writer < reader; - - unsigned int total = 0; - - /* should we go around the buffer for reading? */ - if (writer_less && (reader + amount >= _size)) - { - total = std::min(_size - (reader - writer + 1), amount); - - if (total == 0) - return 0; - - unsigned int rd1 = _size - reader; - unsigned int rd2 = total - rd1; - -// fprintf(stderr, "%p> partial read: (%d/%d) %d/%d [%d/%d]\n", this, rd1, rd2, total, _size, reader, writer); - - /* two partial consumes (one at the end, another at the beginning) */ - fd.write((const char *) &(buffer[reader]), _block * rd1); - fd.write((const char *) (buffer), _block * rd2); - } - else - { - total = std::min((!writer_less ? writer - (reader + 1) : amount), amount); - - if (total == 0) - return 0; - -// fprintf(stderr, "%p> full read: %d/%d [%d/%d]\n", this, total, _size, reader, writer); - - /* we are talking about buffers here, man! */ - fd.write((const char *) &(buffer[reader]), _block * total); - } - - do - { - /* jump the reader forward */ - Buffer_pointer index(cache.reader); - index.complete = (index.complete + total) % _size; - - if (update(cache.reader, index)) - break; - } - while (true); - - return total; -} - -/* returns number of items read from stream to buffer */ -unsigned int Ringbuffer_traits::traits_get(char * buffer, std::istream &fd, unsigned int amount) -{ - /* avoid using different values */ - Buffer_table cache = _pointers; - - const unsigned int reader = cache.reader.complete; - const unsigned int writer = cache.writer.complete; - - const unsigned int dest = writer - 1; - - const bool reader_less = reader < writer; - - unsigned int real_amount = 0; - - /* should we go around the buffer for writing? */ - if (reader_less && ((writer + amount) > _size)) - { - /* Documentation of the formula used in the 'if' below. - * - * [0|1|2|3|4|5|6|7] => size=8 - * | | - * reader | - * writer - * - * => writer has places [5,6,7,0,1] to write (5 places). - * - * => 8 - (4-2+1) = 8 - (2+1) = 8 - 3 = 5 - * - * > writer goes 1 up, amount goes 1 down. - * > reader goes 1 up, amount goes 1 up. - * > size goes 1 down, amount goes 1 down. - * - */ - - if ((_size - (writer - reader + 1)) <= amount) - return false; - - unsigned int wr1 = _size - writer + 1; /* writer is already 1 position after */ - unsigned int wr2 = amount - wr1; - -// fprintf(stderr, "%p> partial write: (%d/%d) %d/%d [%d/%d]\n", this, wr1, wr2, amount, _size, reader, writer); - - unsigned int char_amount = 0; - - /* one partial write on the buffer (at the end) */ - fd.read((char *) &(buffer[dest]), _block * wr1); - char_amount += fd.gcount(); - - if (fd.gcount() == (int)(_block * wr1)) - { - /* another partial write on the buffer (at the beginning) */ - fd.read((char *) (buffer), _block * wr2); - char_amount += fd.gcount(); - } - - real_amount = char_amount / _block; - } - else - { - if (!reader_less && ((reader - writer) <= amount)) - return false; - -// fprintf(stderr, "%p> full write: %d/%d [%d/%d]\n", this, amount, _size, reader, writer); - - /* we are talking about buffers here, man! */ - fd.read((char *) &(buffer[dest]), _block * amount); - - real_amount = fd.gcount() / _block; - } - - _pointers.writer.complete = ((dest + real_amount) % _size) + 1; - _pointers.writer.partial = 1; - - return real_amount; -} diff --git a/src/mod/endpoints/mod_khomp/commons/tools/generate-verbose-headers.sh b/src/mod/endpoints/mod_khomp/commons/tools/generate-verbose-headers.sh new file mode 100755 index 0000000000..7b9012baea --- /dev/null +++ b/src/mod/endpoints/mod_khomp/commons/tools/generate-verbose-headers.sh @@ -0,0 +1,183 @@ +#!/bin/sh + +cut_defines () +{ + cut -b9- | cut -f1 | cut -d' ' -f1 +} + +list_commands () +{ + egrep -h 'define.+CM_' "$@" | cut_defines +} + +list_events () +{ + # list and remove deprecations + egrep -h 'define.+EV_' "$@" | cut_defines | \ + grep -v 'EV_CALL_PROGRESS\|EV_FAX_MESSAGE_CONFIRMATION' +} + +make_enumeration_one_by_one () +{ + while read line + do + local size=$[50 - $(expr length "${line}")] + + echo -n " K_${line}" + + for ((i=0;i" + echo + echo "#include " + echo + echo "#include " + echo + echo "struct VerboseTraits" + echo "{" + make_enumeration "Command" list_commands "$@" || return 1 + echo + make_enumeration "Event" list_events "$@" || return 1 + echo + echo " static std::string eventName(const Event);" + echo " static std::string commandName(const Command);" + echo "};" + echo + echo "#endif /* _VERBOSE_TRAITS_H_ */" +} + +make_source () +{ + make_license + + echo "#include " + echo + + make_switch_case "Event" "event" list_events "$@" || return 1 + echo + make_switch_case "Command" "command" list_commands "$@" || return 1 +} + +make_run () +{ + local destdir="$1"; shift + + if [ ! -d "${destdir}" ] + then + echo "ERROR: First argument is not a directory!" + return 1 + fi + + make_header "$@" > "${destdir}/verbose_traits.hpp" + make_source "$@" > "${destdir}/verbose_traits.cpp" +} + +make_run "$@" diff --git a/src/mod/endpoints/mod_khomp/commons/verbose.hpp b/src/mod/endpoints/mod_khomp/commons/verbose.hpp deleted file mode 100644 index 4668ea6a9f..0000000000 --- a/src/mod/endpoints/mod_khomp/commons/verbose.hpp +++ /dev/null @@ -1,505 +0,0 @@ -/* - KHOMP generic endpoint/channel library. - Copyright (C) 2007-2009 Khomp Ind. & Com. - - The contents of this file are subject to the Mozilla Public License Version 1.1 - (the "License"); you may not use this file except in compliance with the - License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ - - Software distributed under the License is distributed on an "AS IS" basis, - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for - the specific language governing rights and limitations under the License. - - Alternatively, the contents of this file may be used under the terms of the - "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which - case the provisions of "LGPL License" are applicable instead of those above. - - If you wish to allow use of your version of this file only under the terms of - the LGPL License and not to allow others to use your version of this file under - the MPL, indicate your decision by deleting the provisions above and replace them - with the notice and other provisions required by the LGPL License. If you do not - delete the provisions above, a recipient may use your version of this file under - either the MPL or the LGPL License. - - The LGPL header follows below: - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this library; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -*/ - -#include -#include -#include - -#include - -// k3lApiMajorVersion -#ifndef CM_PING -# include -# include -#endif - -#include -#include -#include - -#ifndef _VERBOSE_HPP_ -#define _VERBOSE_HPP_ - -struct Verbose -{ - typedef enum - { - K_CM_SEIZE = CM_SEIZE, - K_CM_SYNC_SEIZE = CM_SYNC_SEIZE, -#if K3L_AT_LEAST(1,6,0) - K_CM_SIP_REGISTER = CM_SIP_REGISTER, -#endif - K_CM_DIAL_DTMF = CM_DIAL_DTMF, - K_CM_DISCONNECT = CM_DISCONNECT, - K_CM_CONNECT = CM_CONNECT, - K_CM_PRE_CONNECT = CM_PRE_CONNECT, - K_CM_CAS_CHANGE_LINE_STT = CM_CAS_CHANGE_LINE_STT, - K_CM_CAS_SEND_MFC = CM_CAS_SEND_MFC, - K_CM_SET_FORWARD_CHANNEL = CM_SET_FORWARD_CHANNEL, - K_CM_CAS_SET_MFC_DETECT_MODE = CM_CAS_SET_MFC_DETECT_MODE, - K_CM_DROP_COLLECT_CALL = CM_DROP_COLLECT_CALL, - K_CM_MAKE_CALL = CM_MAKE_CALL, - K_CM_RINGBACK = CM_RINGBACK, - K_CM_USER_INFORMATION = CM_USER_INFORMATION, -#if !K3L_AT_LEAST(2,2,0) - K_CM_VOIP_SEIZE = CM_VOIP_SEIZE, //deprecated -#endif - K_CM_LOCK_INCOMING = CM_LOCK_INCOMING, - K_CM_UNLOCK_INCOMING = CM_UNLOCK_INCOMING, - K_CM_LOCK_OUTGOING = CM_LOCK_OUTGOING, - K_CM_UNLOCK_OUTGOING = CM_UNLOCK_OUTGOING, - K_CM_START_SEND_FAIL = CM_START_SEND_FAIL, - K_CM_STOP_SEND_FAIL = CM_STOP_SEND_FAIL, - K_CM_END_OF_NUMBER = CM_END_OF_NUMBER, -#if K3L_AT_LEAST(1,6,0) - K_CM_SS_TRANSFER = CM_SS_TRANSFER, - K_CM_GET_SMS = CM_GET_SMS, - K_CM_PREPARE_SMS = CM_PREPARE_SMS, - K_CM_SEND_SMS = CM_SEND_SMS, -#endif -#if K3L_HAS_MPTY_SUPPORT - K_CM_HOLD_SWITCH = CM_HOLD_SWITCH, - K_CM_MPTY_CONF = CM_MPTY_CONF, - K_CM_MPTY_SPLIT = CM_MPTY_SPLIT, -#endif - K_CM_ENABLE_DTMF_SUPPRESSION = CM_ENABLE_DTMF_SUPPRESSION, - K_CM_DISABLE_DTMF_SUPPRESSION = CM_DISABLE_DTMF_SUPPRESSION, - K_CM_ENABLE_AUDIO_EVENTS = CM_ENABLE_AUDIO_EVENTS, - K_CM_DISABLE_AUDIO_EVENTS = CM_DISABLE_AUDIO_EVENTS, - K_CM_ENABLE_CALL_PROGRESS = CM_ENABLE_CALL_PROGRESS, - K_CM_DISABLE_CALL_PROGRESS = CM_DISABLE_CALL_PROGRESS, - K_CM_FLASH = CM_FLASH, - K_CM_ENABLE_PULSE_DETECTION = CM_ENABLE_PULSE_DETECTION, - K_CM_DISABLE_PULSE_DETECTION = CM_DISABLE_PULSE_DETECTION, - K_CM_ENABLE_ECHO_CANCELLER = CM_ENABLE_ECHO_CANCELLER, - K_CM_DISABLE_ECHO_CANCELLER = CM_DISABLE_ECHO_CANCELLER, - K_CM_ENABLE_AGC = CM_ENABLE_AGC, - K_CM_DISABLE_AGC = CM_DISABLE_AGC, - K_CM_ENABLE_HIGH_IMP_EVENTS = CM_ENABLE_HIGH_IMP_EVENTS, - K_CM_DISABLE_HIGH_IMP_EVENTS = CM_DISABLE_HIGH_IMP_EVENTS, -#if K3L_AT_LEAST(1,6,0) - K_CM_ENABLE_CALL_ANSWER_INFO = CM_ENABLE_CALL_ANSWER_INFO, - K_CM_DISABLE_CALL_ANSWER_INFO = CM_DISABLE_CALL_ANSWER_INFO, -#endif - K_CM_RESET_LINK = CM_RESET_LINK, -#if K3L_AT_LEAST(1,6,0) - K_CM_CLEAR_LINK_ERROR_COUNTER = CM_CLEAR_LINK_ERROR_COUNTER, -#endif - K_CM_SEND_DTMF = CM_SEND_DTMF, - K_CM_STOP_AUDIO = CM_STOP_AUDIO, - K_CM_HARD_RESET = CM_HARD_RESET, - K_CM_SEND_TO_CTBUS = CM_SEND_TO_CTBUS, - K_CM_RECV_FROM_CTBUS = CM_RECV_FROM_CTBUS, - K_CM_SETUP_H100 = CM_SETUP_H100, - K_CM_MIXER = CM_MIXER, - K_CM_CLEAR_MIXER = CM_CLEAR_MIXER, - K_CM_PLAY_FROM_FILE = CM_PLAY_FROM_FILE, - K_CM_RECORD_TO_FILE = CM_RECORD_TO_FILE, - K_CM_PLAY_FROM_STREAM = CM_PLAY_FROM_STREAM, - K_CM_INTERNAL_PLAY = CM_INTERNAL_PLAY, - K_CM_STOP_PLAY = CM_STOP_PLAY, - K_CM_STOP_RECORD = CM_STOP_RECORD, - K_CM_PAUSE_PLAY = CM_PAUSE_PLAY, - K_CM_PAUSE_RECORD = CM_PAUSE_RECORD, - K_CM_RESUME_PLAY = CM_RESUME_PLAY, - K_CM_RESUME_RECORD = CM_RESUME_RECORD, - K_CM_INCREASE_VOLUME = CM_INCREASE_VOLUME, - K_CM_DECREASE_VOLUME = CM_DECREASE_VOLUME, - K_CM_LISTEN = CM_LISTEN, - K_CM_STOP_LISTEN = CM_STOP_LISTEN, - K_CM_PREPARE_FOR_LISTEN = CM_PREPARE_FOR_LISTEN, - K_CM_PLAY_SOUND_CARD = CM_PLAY_SOUND_CARD, - K_CM_STOP_SOUND_CARD = CM_STOP_SOUND_CARD, - K_CM_MIXER_CTBUS = CM_MIXER_CTBUS, - K_CM_PLAY_FROM_STREAM_EX = CM_PLAY_FROM_STREAM_EX, - K_CM_INTERNAL_PLAY_EX = CM_INTERNAL_PLAY_EX, - K_CM_ENABLE_PLAYER_AGC = CM_ENABLE_PLAYER_AGC, - K_CM_DISABLE_PLAYER_AGC = CM_DISABLE_PLAYER_AGC, - K_CM_START_STREAM_BUFFER = CM_START_STREAM_BUFFER, - K_CM_ADD_STREAM_BUFFER = CM_ADD_STREAM_BUFFER, - K_CM_STOP_STREAM_BUFFER = CM_STOP_STREAM_BUFFER, - K_CM_SEND_BEEP = CM_SEND_BEEP, - K_CM_SEND_BEEP_CONF = CM_SEND_BEEP_CONF, - K_CM_ADD_TO_CONF = CM_ADD_TO_CONF, - K_CM_REMOVE_FROM_CONF = CM_REMOVE_FROM_CONF, - K_CM_RECORD_TO_FILE_EX = CM_RECORD_TO_FILE_EX, - K_CM_SET_VOLUME = CM_SET_VOLUME, - K_CM_SET_LINE_CONDITION = CM_SET_LINE_CONDITION, - K_CM_SEND_LINE_CONDITION = CM_SEND_LINE_CONDITION, - K_CM_SET_CALLER_CATEGORY = CM_SET_CALLER_CATEGORY, - K_CM_DIAL_MFC = CM_DIAL_MFC, -#if !K3L_AT_LEAST(2,0,0) - K_CM_VOIP_START_DEBUG = CM_VOIP_START_DEBUG, - K_CM_VOIP_STOP_DEBUG = CM_VOIP_STOP_DEBUG, - K_CM_VOIP_DUMP_STAT = CM_VOIP_DUMP_STAT, - K_CM_ISDN_DEBUG = CM_ISDN_DEBUG, - K_CM_PING = CM_PING, - K_CM_LOG_REQUEST = CM_LOG_REQUEST, - K_CM_LOG_CREATE_DISPATCHER = CM_LOG_CREATE_DISPATCHER, - K_CM_LOG_DESTROY_DISPATCHER = CM_LOG_DESTROY_DISPATCHER, -#endif -#if K3L_AT_LEAST(1,6,0) - K_CM_START_CADENCE = CM_START_CADENCE, - K_CM_STOP_CADENCE = CM_STOP_CADENCE, - K_CM_CHECK_NEW_SMS = CM_CHECK_NEW_SMS, - K_CM_SEND_TO_MODEM = CM_SEND_TO_MODEM, -#endif -#if K3L_AT_LEAST(2,1,0) - K_CM_START_FAX_TX = CM_START_FAX_TX, - K_CM_STOP_FAX_TX = CM_STOP_FAX_TX, - K_CM_ADD_FAX_FILE = CM_ADD_FAX_FILE, - K_CM_ADD_FAX_PAGE_BREAK = CM_ADD_FAX_PAGE_BREAK, - K_CM_START_FAX_RX = CM_START_FAX_RX, - K_CM_STOP_FAX_RX = CM_STOP_FAX_RX, - K_CM_SIM_CARD_SELECT = CM_SIM_CARD_SELECT, -#endif - -#if K3L_AT_LEAST(2,1,0) - K_CM_NOTIFY_WATCHDOG = CM_NOTIFY_WATCHDOG, - K_CM_STOP_WATCHDOG = CM_STOP_WATCHDOG, - K_CM_WATCHDOG_COUNT = CM_WATCHDOG_COUNT, - K_CM_START_WATCHDOG = CM_START_WATCHDOG, -#endif - - } - kcommand; - - typedef enum - { - K_EV_CHANNEL_FREE = EV_CHANNEL_FREE, - K_EV_CONNECT = EV_CONNECT, - K_EV_DISCONNECT = EV_DISCONNECT, - K_EV_CALL_SUCCESS = EV_CALL_SUCCESS, - K_EV_CALL_FAIL = EV_CALL_FAIL, - K_EV_NO_ANSWER = EV_NO_ANSWER, - K_EV_BILLING_PULSE = EV_BILLING_PULSE, - K_EV_SEIZE_SUCCESS = EV_SEIZE_SUCCESS, - K_EV_SEIZE_FAIL = EV_SEIZE_FAIL, - K_EV_SEIZURE_START = EV_SEIZURE_START, - K_EV_CAS_LINE_STT_CHANGED = EV_CAS_LINE_STT_CHANGED, - K_EV_CAS_MFC_RECV = EV_CAS_MFC_RECV, - K_EV_NEW_CALL = EV_NEW_CALL, - K_EV_USER_INFORMATION = EV_USER_INFORMATION, - K_EV_DIALED_DIGIT = EV_DIALED_DIGIT, -#if K3L_AT_LEAST(1,6,0) - K_EV_SIP_REGISTER_INFO = EV_SIP_REGISTER_INFO, - K_EV_RING_DETECTED = EV_RING_DETECTED, -#endif - K_EV_CALL_HOLD_START = EV_CALL_HOLD_START, - K_EV_CALL_HOLD_STOP = EV_CALL_HOLD_STOP, -#if K3L_AT_LEAST(1,6,0) - K_EV_SS_TRANSFER_FAIL = EV_SS_TRANSFER_FAIL, - K_EV_FLASH = EV_FLASH, -#endif - K_EV_DTMF_DETECTED = EV_DTMF_DETECTED, - K_EV_DTMF_SEND_FINISH = EV_DTMF_SEND_FINISH, - K_EV_AUDIO_STATUS = EV_AUDIO_STATUS, - K_EV_CADENCE_RECOGNIZED = EV_CADENCE_RECOGNIZED, - K_EV_END_OF_STREAM = EV_END_OF_STREAM, - K_EV_PULSE_DETECTED = EV_PULSE_DETECTED, - K_EV_POLARITY_REVERSAL = EV_POLARITY_REVERSAL, -#if K3L_AT_LEAST(1,6,0) - K_EV_ISDN_PROGRESS_INDICATOR = EV_ISDN_PROGRESS_INDICATOR, - K_EV_CALL_ANSWER_INFO = EV_CALL_ANSWER_INFO, - K_EV_COLLECT_CALL = EV_COLLECT_CALL, - K_EV_SIP_DTMF_DETECTED = EV_SIP_DTMF_DETECTED, - K_EV_RECV_FROM_MODEM = EV_RECV_FROM_MODEM, - K_EV_NEW_SMS = EV_NEW_SMS, - K_EV_SMS_INFO = EV_SMS_INFO, - K_EV_SMS_DATA = EV_SMS_DATA, - K_EV_SMS_SEND_RESULT = EV_SMS_SEND_RESULT, -#endif -#if K3L_HAS_MPTY_SUPPORT - K_EV_CALL_MPTY_START = EV_CALL_MPTY_START, - K_EV_CALL_MPTY_STOP = EV_CALL_MPTY_STOP, - K_EV_GSM_COMMAND_STATUS = EV_GSM_COMMAND_STATUS, -#endif - K_EV_CHANNEL_FAIL = EV_CHANNEL_FAIL, - K_EV_REFERENCE_FAIL = EV_REFERENCE_FAIL, - K_EV_INTERNAL_FAIL = EV_INTERNAL_FAIL, - K_EV_HARDWARE_FAIL = EV_HARDWARE_FAIL, - K_EV_LINK_STATUS = EV_LINK_STATUS, -#if K3L_AT_LEAST(1,6,0) - K_EV_PHYSICAL_LINK_UP = EV_PHYSICAL_LINK_UP, - K_EV_PHYSICAL_LINK_DOWN = EV_PHYSICAL_LINK_DOWN, -#endif - K_EV_CLIENT_RECONNECT = EV_CLIENT_RECONNECT, - K_EV_VOIP_SEIZURE = EV_VOIP_SEIZURE, - K_EV_SEIZURE = EV_SEIZURE, - -#if K3L_AT_LEAST(2,1,0) - K_EV_FAX_CHANNEL_FREE = EV_FAX_CHANNEL_FREE, - K_EV_FAX_FILE_SENT = EV_FAX_FILE_SENT, - K_EV_FAX_FILE_FAIL = EV_FAX_FILE_FAIL, - K_EV_FAX_MESSAGE_CONFIRMATION = EV_FAX_MESSAGE_CONFIRMATION, - K_EV_FAX_TX_TIMEOUT = EV_FAX_TX_TIMEOUT, - K_EV_FAX_PAGE_CONFIRMATION = EV_FAX_PAGE_CONFIRMATION, - K_EV_FAX_REMOTE_INFO = EV_FAX_REMOTE_INFO, -#endif - -#if K3L_AT_LEAST(2,1,0) - K_EV_WATCHDOG_COUNT = EV_WATCHDOG_COUNT, -#endif - -#if !K3L_AT_LEAST(2,0,0) - K_EV_PONG = EV_PONG, -#endif - } - kevent; - - typedef enum - { - R2_COUNTRY_ARG = 1, - R2_COUNTRY_BRA = 2, - R2_COUNTRY_CHI = 3, - R2_COUNTRY_MEX = 4, - R2_COUNTRY_URY = 5, - R2_COUNTRY_VEN = 6 - } - R2CountryType; - - typedef enum - { - HUMAN, - EXACT - } - Presentation; - - /* dynamic (object) stuff */ - - Verbose(K3LAPI & api): _api(api) {}; - -#if K3L_AT_LEAST(2,0,0) - std::string event(int32, K3L_EVENT*, R2CountryType r2_country = R2_COUNTRY_BRA, - Presentation fmt = HUMAN); -#else - std::string event(int32, K3L_EVENT*, Presentation fmt = HUMAN); -#endif - - std::string channelStatus(int32, int32, int32, Presentation fmt = HUMAN); - - /* end of dynamic (object) stuff */ - - protected: - K3LAPI & _api; - - /* used internally */ - struct internal_not_found {}; - - public: - - /* static (class) stuff */ - - static std::string echoLocation(KEchoLocation, Presentation fmt = HUMAN); - static std::string echoCancellerConfig(KEchoCancellerConfig, Presentation fmt = HUMAN); - -#if K3L_AT_LEAST(2,0,0) - static std::string event(KSignaling, int32, K3L_EVENT*, R2CountryType = R2_COUNTRY_BRA, - Presentation fmt = HUMAN); -#else - static std::string event(KSignaling, int32, K3L_EVENT*, Presentation fmt = HUMAN); -#endif - -#if K3L_AT_LEAST(2,0,0) - static std::string command(int32, K3L_COMMAND*, R2CountryType = R2_COUNTRY_BRA, - Presentation fmt = HUMAN); - static std::string command(int32, int32, int32, const char *, R2CountryType = R2_COUNTRY_BRA, - Presentation fmt = HUMAN); -#else - static std::string command(int32, K3L_COMMAND*, Presentation fmt = HUMAN); - static std::string command(int32, int32, int32, const char *, Presentation fmt = HUMAN); -#endif - - - static std::string deviceName(KDeviceType, int32, Presentation fmt = HUMAN); - - static std::string deviceType(KDeviceType, Presentation fmt = HUMAN); - static std::string deviceModel(KDeviceType, int32, Presentation fmt = HUMAN); - - static std::string channelFeatures(int32, Presentation fmt = HUMAN); - static std::string signaling(KSignaling, Presentation fmt = HUMAN); - static std::string systemObject(KSystemObject, Presentation fmt = HUMAN); - static std::string mixerTone(KMixerTone, Presentation fmt = HUMAN); - static std::string mixerSource(KMixerSource, Presentation fmt = HUMAN); - - static std::string seizeFail(KSeizeFail, Presentation fmt = HUMAN); - -#if K3L_AT_LEAST(2,0,0) - static std::string callFail(KSignaling, R2CountryType, int32, Presentation fmt = HUMAN); -#else - static std::string callFail(KSignaling, int32, Presentation fmt = HUMAN); -#endif - - static std::string channelFail(KSignaling, int32, Presentation fmt = HUMAN); - static std::string internalFail(KInternalFail, Presentation fmt = HUMAN); - - static std::string linkErrorCounter(KLinkErrorCounter, Presentation fmt = HUMAN); - - static std::string linkStatus(KSignaling, int32, Presentation fmt = HUMAN); - static std::string channelStatus(KSignaling, int32, Presentation fmt = HUMAN); - static std::string callStatus(KCallStatus, Presentation fmt = HUMAN); - static std::string status(KLibraryStatus, Presentation fmt = HUMAN); - -#if K3L_AT_LEAST(2,0,0) - static std::string signGroupB(KSignGroupB, R2CountryType contry = R2_COUNTRY_BRA, - Presentation fmt = HUMAN); -#else - static std::string signGroupB(KSignGroupB, Presentation fmt = HUMAN); -#endif - -#if K3L_AT_LEAST(2,0,0) - static std::string signGroupII(KSignGroupII, R2CountryType contry = R2_COUNTRY_BRA, - Presentation fmt = HUMAN); -#else - static std::string signGroupII(KSignGroupII, Presentation fmt = HUMAN); -#endif - - static std::string h100configIndex(KH100ConfigIndex, Presentation fmt = HUMAN); - - static std::string eventName(int32); - static std::string commandName(int32); - -#if K3L_AT_LEAST(1,5,0) - static std::string sipFailures(KSIP_Failures, Presentation fmt = HUMAN); -#endif - -#if K3L_AT_LEAST(1,5,1) - static std::string isdnCause(KQ931Cause, Presentation fmt = HUMAN); -#endif - -#if K3L_AT_LEAST(1,5,2) - static std::string isdnDebug(int32, Presentation fmt = HUMAN); -#endif - -#if K3L_AT_LEAST(1,6,0) - static std::string callStartInfo(KCallStartInfo, Presentation fmt = HUMAN); - - static std::string gsmCallCause(KGsmCallCause, Presentation fmt = HUMAN); - static std::string gsmMobileCause(KGsmMobileCause, Presentation fmt = HUMAN); - static std::string gsmSmsCause(KGsmSmsCause, Presentation fmt = HUMAN); - - static std::string q931ProgressIndication(KQ931ProgressIndication, - Presentation fmt = HUMAN); -#endif - -#if K3L_AT_LEAST(2,1,0) - static std::string faxResult(KFaxResult code, Presentation fmt = HUMAN); - static std::string faxFileErrorCause(KFaxFileErrorCause code, Presentation fmt = HUMAN); -#endif - - /* end of static (class) stuff */ - - private: - static std::string internal_deviceType(KDeviceType); - static std::string internal_deviceModel(KDeviceType, int32); - -#if K3L_AT_LEAST(1,5,0) - static std::string internal_sipFailures(KSIP_Failures, Presentation fmt = HUMAN); -#endif -#if K3L_AT_LEAST(1,5,1) - static std::string internal_isdnCause(KQ931Cause, Presentation fmt = HUMAN); -#endif - -#if K3L_AT_LEAST(2,0,0) - static std::string internal_signGroupB(KSignGroupB, R2CountryType contry, Presentation fmt = HUMAN); - static std::string internal_signGroupII(KSignGroupII, R2CountryType contry, Presentation fmt = HUMAN); -#else - static std::string internal_signGroupB(KSignGroupB, Presentation fmt = HUMAN); - static std::string internal_signGroupII(KSignGroupII, Presentation fmt = HUMAN); -#endif - -#if K3L_AT_LEAST(1,6,0) - static std::string internal_gsmCallCause(KGsmCallCause, Presentation fmt = HUMAN); - static std::string internal_gsmMobileCause(KGsmMobileCause, Presentation fmt = HUMAN); - static std::string internal_gsmSmsCause(KGsmSmsCause, Presentation fmt = HUMAN); - - static std::string internal_q931ProgressIndication(KQ931ProgressIndication, Presentation fmt = HUMAN); -#endif - - private: - enum Type - { - DEVICE, - CHANNEL, - PLAYER, - MIXER, - LINK, - NONE - }; - - struct Target - { - Target(Type _type) - : type(_type), device(-1), object(-1) - {}; - - Target(Type _type, int32 _device) - : type(_type), device(_device), object(-1) - {}; - - Target(Type _type, int32 _device, int32 _object) - : type(_type), device(_device), object(_object) - {}; - - Type type; - int32 device; - int32 object; - }; - - static void generate(std::string &, std::string &, Target, std::string &); - - static std::string show(std::string &, std::string, Target, std::string &); - static std::string show(std::string &, std::string, Target); - - template < typename ReturnType > - static ReturnType presentation(Presentation fmt, ReturnType str_exact, ReturnType str_human) - { - switch (fmt) - { - case HUMAN: return str_human; - case EXACT: return str_exact; - }; - - return str_exact; - } -}; - -#endif /* _VERBOSE_HPP_ */ diff --git a/src/mod/endpoints/mod_khomp/docs/Manual.html b/src/mod/endpoints/mod_khomp/docs/Manual.html index 863ef76847..c4745700b1 100644 --- a/src/mod/endpoints/mod_khomp/docs/Manual.html +++ b/src/mod/endpoints/mod_khomp/docs/Manual.html @@ -37,17 +37,22 @@
  • context-fxs: Contexto de entrada para placas FXS (o padrão é "khomp-DD-CC", onde "DD" será substituído, no momento da ligação, pelo número do dispositivo, "CC" pelo número do canal, e "SSSS" pelo número serial do dispositivo);
  • context-gsm-call (ou "context-gsm"): Contexto de entrada para ligações GSM (o padrão é "khomp-DD-CC", onde "DD" será substituído no momento da ligação pelo número do dispositivo, "CC" pelo número do canal, e "SSSS" pelo número serial do dispositivo);
  • context-gsm-sms: Contexto de entrada para SMSs (o padrão é "khomp-sms-DD-CC", onde "DD" será substituído pelo número de dispositivo, "CC" pelo número do canal, e "SSSS" pelo número serial do dispositivo); -
  • context-pr: Contexto de entrada para ligações em placas KPR (o padrão é "khomp-DD-CC", onde "DD" será substituído, no momento da ligação, pelo número do dispositivo, "CC" pelo número do canal); +
  • context-pr: Contexto de entrada para ligações em placas KPR (o padrão é "khomp-DD-CC", onde "DD" será substituído, no momento da ligação, pelo número do dispositivo, "CC" pelo número do canal); +
  • delay-ringback-co: Define o tempo de delay para ativar a geração de tom de controle de chamada (ringback) pelo Endpoint da Khomp quando há uma indicação de ringback, e não há áudio sendo enviado por quem indicou a situação de controle da chamada; +
  • delay-ringback-pbx: Define o tempo de delay para ativar a geração de controle de chamada (ringback) pelo Endpoint da Khomp quando há uma indicação de ringback, e o áudio de controle enviado não possui nenhum tom (ou seja, está em silêncio);
  • disconnect-delay: Define o tempo em milissegundos para realizar o processamento de um evento de desconexão, para ignorar situações onde outros equipamentos realizam o duplo atendimento para derrubar chamadas a cobrar; +
  • drop-collect-call: Ativa ("yes") ou desativa ("no") o derrubamento de chamadas à cobrar. Caso ativo, todas as chamadas à cobrar serão derrubadas não importando o que foi ajustado na variável KDropCollectCall (o valor padrão é "no");
  • echo-canceller: Ativa ("yes") ou desativa ("no") o cancelamento de eco automático pelo Endpoint; +
  • flash-to-digits: Define os dígitos para serem enviados quando o FLASH é detectado na FXS;
  • fxo-send-pre-audio: Quando ativada ("yes") libera canal de áudio sainte antes da conexão da chamada em placas KFXO (o valor padrão é "yes"); +
  • fxs-digit-timeout: Define o timeout, em segundos, entre dígitos na FXS;
  • fxs-global-orig: Número inicial para numeração seqüencial de ramais das placas KFXS que não estiverem listadas na seção <fxs-branches> (a numeração segue ordem crescente por número da placa e número do canal físico) (o padrão é "0");
  • fxs-co-dialtone: Seqüências de números, separados por vírgula, que disparam um tom contínuo (de central pública) em ramais FXS (ex: "0,99" faz com que, ao discar "0" ou "99", o usuário receba o tom de linha contínuo) (o padrão é vazio);
  • fxs-bina: Quando ativada ("yes"), ligações para ramais FXS enviarão os dígitos correspondentes ao telefone de origem em sinalização BINA DTMF (o valor padrão é "no"); +
  • ignore-letter-dtmfs: Define se o canal deve ignorar DTMFs incomuns detectados pela placa (A, B, C e D). Entretanto, se você necessita passar esses dígitos pela placa, você deve ajustar esta opção para "no" (o valor padrão é "yes");
  • input-volume: Define o volume de entrada das ligações, varia de -10 a +10 ;
  • kommuter-activation: Define se a ativação de dispositivos kommuter encontrados no sistema será feita de forma automática ("auto"), ou de forma manual ("manual") pelo usuário, através do comando "khomp kommuter on/off";
  • kommuter-timeout: Define o timeout (em segundos) com que os kommuters serão inicializados. Se chegarem a este timeout sem receberem notificação do channel, os dispositivos irão comutar para o estado "desligado". O valor mínimo é "0" , onde os links permanecerão sempre comutados no estado "ligado", e o valor máximo é "255"; -
  • language: Define idioma para ligações nas placas Khomp;
  • log-to-console: Define mensagens de log que devem ser impressas na console;
  • log-to-disk: Define mensagens de log que devem ser salvar em disco;
  • out-of-band-dtmfs: Ativa ("yes") ou desativa ("no") a supressão DTMF e o envio destes out-of-band; @@ -55,12 +60,9 @@
  • pulse-forwarding: Ativa ("yes") ou desativa ("no") a detecção de pulsos e a conversão dos mesmos em DTMFs;
  • r2-preconnect-wait: Define o tempo de espera do envio da sinalização de ringback, no protocolo R2/MFC, para iniciar o envio de áudio de silêncio. Apenas utilizado quando "r2-strict-behaviour" estiver ajustado para "no";
  • r2-strict-behaviour: Ativa ("yes") ou desativa ("no") o comportamento da sinalização R2/MFC conforme a norma define. O padrão é "no", e pode ser alterado para "yes" caso seja necessário receber/enviar dados precisos da sinalização do protocolo (condição de B, por exemplo); -
  • ringback-delay-co: Define o tempo de delay para ativar a geração de tom de controle de chamada (ringback) pelo Endpoint da Khomp quando há uma indicação de ringback, e não há áudio sendo enviado por quem indicou a situação de controle da chamada; -
  • ringback-delay-pbx: Define o tempo de delay para ativar a geração de controle de chamada (ringback) pelo Endpoint da Khomp quando há uma indicação de ringback, e o áudio de controle enviado não possui nenhum tom (ou seja, está em silêncio);
  • suppression-delay: Ativa ("yes") ou desativa ("no") o delay necessário para supressão DTMF. Se desativado ("no"), também desativa supressão de DTMFs;
  • trace: Define opções de depuração. Não deve ser utilizado em produção a não ser que estritamente necessário;
  • user-transfer-digits: Define uma seqüência de dígitos DTMF para iniciar a transferencia entre o FreeSWITCH® e um outro PABX (utilizando sinalização de usuário, como QSig ou FXO FLASH); -
  • flash-to-digits: Define os dígitos para serem enviados quando o FLASH é detectado na FXS;

  • @@ -117,15 +119,13 @@
    • context;
    • input-volume;
    • output-volume; -
    • accountcode;
    • calleridnum;
    • calleridname; -
    • mailbox;
    • flash-to-digits.

    Cada opção é separada uma da outra por um pipe "|" ou uma barra "/" e definidas após dois pontos ":", exemplo:

    -
     <param name="200" value="language:en|context:master-branch" />
    +
     <param name="200" value="input-volume:1|context:master-branch" />
     

    Para maiores informações sobre a sintaxe e exemplos, favor consultar o arquivo de configuração.


    diff --git a/src/mod/endpoints/mod_khomp/docs/Manual.pdf b/src/mod/endpoints/mod_khomp/docs/Manual.pdf index 935b299dbc821be862d801ecf934e5131acf1044..260ba542a5a1476b0bb0ecc9bc4b1ef9c313628a 100644 GIT binary patch delta 33248 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 KX(bho_te$ZUHv^Z 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 diff --git a/src/mod/endpoints/mod_khomp/docs/README.pdf b/src/mod/endpoints/mod_khomp/docs/README.pdf index 2b95cfaad4d41964e1155d28a906699c0227b1a1..13a5f5469a80ec0d20f7c85e60e193622eaee77a 100644 GIT binary patch delta 1303 zcmbQRPNILE#DsQEBLhPqFgG@CoX|Rfv2_Ad>jdW32`pPDuvYyQwlp*{urx6>)-^OV zwKO&`G&i!`F7uD|7&D{E_Q#BDUW_6uuV{L1a&)zJouE}3Y$F!myI|+9?M}>W8jSS@ zmI@GHXIETOl$w~!Rl!&r;+uclfM@UT@DDQ>HzuF#voE`SZHYu%QpRjX>o13Hc`Z9+ z7JE{!>))@ye<$YTNi^M1(46$%HmL3!OUobO30@sS8d>^0PT%IpmtUWE;*dh)+B3}p zSre4_o}`2pyw}a`J7scW`o-3>7efl_dpAxx-Mc9#&~n;G*OJWZ0`4ze?=L-jF-Lky z_o?#}Iuoo5CP$x3cAD^{aDrvm?Dd5l;Vj$lJwIH%?-|SNT0Wze!xJx0R(UkX*;3=s zzNFH-*)6-eAP{dan#PVJCmssC~1a~aQ`4K*FxHYNVmmH+FXn&A6SvCLgH-H7@7n+;E|Ppmll zY;EzyrmPKrU8Z+NulBcLeWI&;Vb8M1lXA~{e_MRH?=wSL&(h~N)@fG0pZ%`(+@93M z|M$!^eo|=_Kc^sKZdKTs3&}^zSym_{|5){5LT>y<0~YfeUmh=bR+laJJZ9zf%M&VQ z5d4{ks=w^L=F&&9Rr6baUCx+c%`Oj{p8B_^xdJy1cT!Mtk{BmkTUZ zodth6{aRR%D4Fgk_u2ipsDzCYf3wa^n-AaBQ_4T&?Y)0t%XF{pPV8(m*|gO!>O2ck z{e1dmQJ?jW`lHG;Bs9YdcLdp>ChvAjW1Cmu8u0l5CP} zXp)+oVqun)oMe$`VrrRYW@(vbl#-U1WM@NAMXa42S8+*VQAtHnY8scZrMZcj1(&L- ItG^o;0F6%t-v9sr delta 1245 zcmeBQCoutt+BppkObjedO^huYC$vsrY@NW=I)S-$0?XD3tW|%7EG#U{4b99gbuBDR zEQ~D8%ni27{$oAH%xJp(2_u^qqv*yfVHukoU9DXwY+5_}(Z(N4y;pbs+3v*5romWm zXrKTAc6P-jMX8CoTosJ9A@}oVJMh#!U;iOljr9=Y!{hh1nXX*6a@MW1OLD&+9a7!R zWw5t-)vI`Wd3MQ{%QU%8e7pH?-+8-vwv3AZSyBX#Xin)BXH%>`*S|a4|4HJ6LuOh{ z0#Y3=LN1d-5AWT+#ZoHOabu5OPG4G6efAD7GxKwwU7xCW=`Hf!-KcU-@0VU~-?Q5a z(IIthF)X(yMsIm)qsEdsk!9!79Y1Ha6u1_=uC?3qe6|0Eo8khk1r|kBvyROvUg73? zBYfRD_SS;$0_ux`MQbf=DreU+IqmpdH>G&H^VVIHWHp(mvRs`dmwlz-!qo_+Ei7&` z{8>%O&(J=yd9-i8NcepUMV zWM1If9o-Xux!z3DQ)h`k!k5wd;jOsoT-!%hiA%j)b;D8?xE?#NcI_4K|Av)%8V@c6 zH}BQjI5Ag$q08E*C!ev4DVTR(QrNiaj`uRliS2zolJ!%zo#C*Ue4E$jUgwcRUuWH# zl%VdAml1K~oBjUv?whyI`fzg6t;JTnRgE7e9^^VaL5(GS*Cf_WhNs0hT)t$GmLfXg z!HTFgjVC{s$)kx0}hw*DHVQ zIvbt7Sk*M4ty53f+-+_J*NJGi1r@$`C*_{^{iGcTo2pxJ@>y|`aPrP z_W93vD(9UO*Os}qyixS>mx#}@j9Q-A`?PFQjIZeM9OT{BEPdrp{@KSivAkJQLj058 z9^K`&V|mq%f-_(5_T_#1c|=j~$6-Ok+iNyRS36JLEieBt@B7PFY3Y(bJ}cUD9}f=H zaEj-!_sOyF`n15~$Kqsej@N>&5>H+}Y20tGxVyRh^IQWYa!=G3VS$ zuV>RQKb0vj_}}IJLuucG+m_EReQ>H3INQiDuWqkYt;Anu#vA+Vx3luGakDd;O&1hp z6Sg&1FaQCCJOwTgZER^|VQGOOW@&7RDQ00XJrQU`pdq@Hv4N!thM18BraBV~0}OR$ zrk2x>in3WV8ct^v13J(cU4@y25f(9XQw(*M7N*k!fkud8_|e?R*lc>G7@I|$frWXZ zp+QozNpiBGsY$AtiFvBAv5~ojfpJn&s#&VBoee=1v37P`#U+VFB^5=fX*=eSY81ud!5~UMf$-OTeM9zp*rfWfSv=fIOm5 z9#NP@6rnQZtzmGewV4IX1ZD=eg#8@^qSb{ZvLlQ|bjZK>w%q|Cu4&gREXX~mCLYwj z*m2tQxordJuy~ckvUpcmNF+3iyTAx0x#IQMMFVndk-(DfJ$LNc=fF}QjhASDkK2l> z9fHkx-rGB2D}N@UkYZW#fym; zoN{gc9`~5mBYNV@8g-vH_4!Yb#V7-PtmuT~t-Fm#JcKQGQbyV-w0Ekls~jg?liaQuOk$?n(f5AQ zi*W9`eUtbR59~_BcyPs#8LcXNo5xI^;z?H zXqhQQ&u~@W7|0mwEOtmi^U`borUIIFbP{ktoo>n5!My2GM9NVhXRr51Xo@PjNr7## zw<3;m#)m3pJEcLODr=Be5vKDJ=w;iwFG-iqN8m<;eTU8Can$wVN}8@8UJdj# zpfLXSOWv!P`qT^QOJqAOM~bwNV(c(G*D1QWNaZfTiCA0T+BqFzL@{2bBpum*YaHPA%>2Ia6A_jSFm8P zE%}2ZbSkxVwNu0$fVJuRT#cUmLq);0BgmAe`{c5$L3!Z`LoM)tU|XGZAw2Cy6*SCN zdAP#*;xM5y6%1M%LYHyS_Kwr4cO2gRCFtl_a_^6Jnm|{~`Ekxy40l{9=;9?Eiea}T zq_%8)&qsmdeu!*IcxW5C&wWaq+cv!oS!i^}ZS1EZ>n{$$MOH^{65>(a z!p856wm%U3PPQ1?VH*>tNAqS2OW5iryNhaPuV(91o>~X5A4>T}W7g<45TgA1Xs-)O zXLEG;&~-cjN9^LanE1*vO08h%hmxBH8BUR3Zv%%oWH=@z$L zqZE~moE)M?E>>?#M=fp7hmn=I`g5Pf$-^kCsVTZ+B5)Kzlt0diU8fx}2kVW#2wlXPGMrP}^2i^=jT85LZ` zMe0X!mUL%vXjBBPKEcVrJ4MO;?bP`(bIY4|7zC${#M!B|Tb_5Ap18N67Il$wq2s_N zj$07~8}^uc$yRmwaoBj@q zb+S{$ISR}J*X@&GsENtRRJeCGU^1}p+}cU<8b0NEzY3Q7>E+J($F^Q%{G`&e`@L7F zZiaR!YDgc_l!5y~Xxys+Q1e^&{wboZ;haXq#)jx`h4A~omq~*qXnRM!?5oMZ73~F> zmv>W1Ibgzl!?i1UNZOHt#*BvbnScElKD13f{C6Yx@g&dRt@=J~`i<{l|QG6!teKI&C|89P@_OO8Uv96!{;sbWt zWH?TFCojyz_-AQaE?w>Ory3|!eG*%BWf`@;QIpi4%B23WtqFcVld0C7U~)%PMGJbq zZzg@3qSn;tCF*d9oBh+n=uAjYcc5WlIdD13-FHySgAN^{gBa7R**;1zMV!o@bA2Jm zX4?$!jtxZ*MWSTZ45hQVedqK%4zqtM@k^8OqZ*mEtAjS)#goX40qYgcEVf~_*zY}A z9FzSnEC*R>iKg~0NiKxKQsQkG8mdijzVl3N)fJW2I!&IG(a!WDXL&tdy6l6i?Dm5~ zWmF0t981u%de*7m2b~a;#bZ=2-79eee5yV0wCwV{3^0Sp6R;GLhlhP88PpUT&GF=xkbUGEVw5yK)N(0_o$L4f}>0tSP^&HvZI z5pekL&eH5RXJ+-gGqj(91hggb@X%s{ue^JXm9`k delta 2426 zcmajhc{~%09|v$s!!*j3BRN8BvD=pW$Pv~YO(B&z8fwlx&RU3wnB^#Pl_TT`b9S(D zmSb|?giWp}%2A%@c|HIA`s4Tc=lgoSU!Olde|}3JiIhDOq21$$!%(m@XcP(=PK%;( zN6`*M(GD_bJo(ikSS%I;*T5px;1~o3gTTTy;I(E9p522~ttyeO<()=3+WN`oq8#Cx zT$;*BzeYP~ynYc#lP`yVLK@k+=}@HT$%+(fj>uJ+sE)jYqqpH zh)Y`#+X!eXCe?RxD@1|`2QhQ$RMJFkTkcYir9@=PRv=2CrL4doQ#P1N%H-`SN4Q@- ztd?hmyfl#56Bhz#%o2+jXV_lo^Dm?;9!jD`3wyX74?(`Ui|TJsO>Kcz8NC#!wQb-z z!A(WLxNrtT>E; zEBXDS5vjQHR29f%H}2jVUzg%HTRe5`p}`x#fQbj)W^V5%MS4D%&ICg^BTO*9=2LF? z6f4a|U`*TocD+ams-q{$ertpp4Y}$Jp%e6b?9R2)D%4Z^GtEw~ZX6~b);>G+!NO#V zEAAGzJ(xgF8(YHOAy~x;)5%Sd!uCjifB2-2ySqpds8rJYQvT#eqfVS>sowvOB>XIbLsvr}<_d zcu^)cWCZ2oAWB3y?Bct7lFLQERb&Fatc1Nj$uIK+3GX1%n<|g#_qp=!>ggHLDyGkA zmNv;7MB0kK)Iu(+X)f4{bqW zZ|-|K_jmU3HcOY(*K#2`4pRD|QaLZOc-f9meP;?4EHt-}(LYYwK&XnFr`%Tc+>=r) z2aguFWdWKABF8-fB8i|){e+%iNl}~r3^}V$3-J%HWFDJl!8>47uVD(o`@7kOzt(mB zUYa5%)RVLsZxc!RCZHtvSetpWly7_^p{EBD2Y%u1(WNgl&XU0A7>pC&Wkm!9R%isy=R-^IY-Nv_z52~=auE{N`1E{W9`#@{f z&}6q8?i{`4x|UG3NBVTM1ubg^^|UW2wZ%4#9iVHzXv0dI^p1O%w?aQpEx(>D=wUtk zHAtKJ*m%Zy=E~%LLDXfsz3+~H{+H-7SC)!=SI2Dj#`qL8oY zeg;uTUkLASCQlAAJzb@GHBW|~Gd!kFX>Gzo~5I^oIIY{6V^tdtnGk8pB zfNJV{gejBOd4xJ&kG|tNRcHMG+HZRLu6v>wc-c@$)!Zapy3BvjS3yzYnwX@ue+b9a zhOsc?>T@TmjvSPbUeblXX0GUSDBK*9zeE>5l&D|$`B80BV;%zrp*nnPTP*-2s`m*# zkC5DIMZ zv!^;JcUK0)I^S79uz0`8`feh9<#T+pcHrqRWwjmEUSw2kA^!vS^pKAwLPO#{bHFom_R5( z|J0pk5kUFbyf=)}DXm!P5R1*CyRXnYN#(blRBtMlY(t$|W%mfAXA=X7r`T1$4j4Fn z@p6=VJ69eJmOrzYQc2(rT|}QQBy{ESadL$5d#5Bk#Fq`I1&qwOzzJz4MAP+s)q;T$ zf4zfwU1E+Y-ne_zP^kSzI(|b&ZS2^&(TK_|{n5}Cu$Pp8B!#$!jV=!7nlCS!1{8xD z-s>dBT*~?e5ZpB1ST|hpFE@FWSAVQBujIXK@Wr!lX154MCW(WB6WpTag zO=RpnSnBbl26ArA;X_tnLC+1vXN^U_9-oH*N-j*xWT9$Ox+D5zWADzUfzsAI)*)clm_MiOi%uu!{zV+0jL&NM zAq;wW+;a?1k{R(JDYe*~vN7?~j=q9d$A`jLgcVBWte)-Jm0UMq>hk6pB6_sO|>J#ch zX*t_wz^U4s+IsJ_K9XEu%?7JFsyiLJeAvrl&m9>T{3K-Oj|_@x-?QRG!rF#xhR2-S>Y}c;8<5Alf^G8qP4D3Hk%lyEDFu=OFpThis step is carried out in a semi-automated way using the khompwizard program, a wizard that configures the basic parameters of the system boards. This wizard initializes the configuration files using information from the user when they are needed, initializing the standard settings to default values.

    Typically, this program runs automatically after installation of the system. However, you may need to run it manually if an update is being performed, or if new cards were added to the system after installing new drivers.


    -If you need to set advanced parameters of the board and/or signaling, the program k3lconfig allows you to access all the available settings for each installed card. For more information about this program, check the
    k3lconfig User's Guide. For solving synchronization issues, check the Troubleshooting section for manual configuration of the boards. +If you need to set advanced parameters of the board and/or signaling, the program k3lconfig allows you to access all the available settings for each installed card. For more information about this program, check the k3lconfig User's Guide. For solving synchronization issues, check the Troubleshooting section for manual configuration of the boards.

    Endpoint Configuration

    @@ -39,16 +39,21 @@ If you need to set advanced parameters of the board and/or signaling, the progra
  • context-gsm-call (or context-gsm): Context of entry for GSM boards (the default is "khomp-CC-DD", where "DD" will be replaced at the time of connection by the device number, "CC" by channel number, and "SSSS" by the device serial number);
  • context-gsm-sms: Context for incoming SMSs (the default is "khomp-sms-CC-DD", where "DD" will be replaced by the number of device, "CC" by channel number and "SSSS" by the device's serial number);
  • context-pr: Context for incoming connections on boards KPR (default is "khomp-CC-DD", where "DD" will be replaced at the time of connection by the device number, "CC "by channel number); +
  • delay-ringback-co: Sets the delay to enable the generation of call control tone (ringback) by the Endpoint Khomp when there is an ringback indication from signaling and there is no audio being sent by the channel which indicated the situation (local option); +
  • delay-ringback-pbx: Sets the delay to enable the generation of call control tone (ringback) by the Endpoint Khomp when there is an ringback indication, and the audio has no tone (silence) (local option);
  • disconnect-delay: Sets the time in milliseconds to perform processing a disconnect event, to ignore situations where other equipment performing the double service to overthrow collect calls (local option); +
  • drop-collect-call: Enables/Disables the action of dropping collect calls. If enabled, all collect calls will be dropped no matter what KDropCollectCall is set to (the default value is "no");
  • echo-canceller (former 'echocanceller): Active ("yes") or disables ("no") echo cancellation automatic Endpoint (local option); +
  • flash-to-digits: Defines the digits to be sent when the FLASH is detected on FXS channels;
  • fxo-send-pre-audio: When enabled ("yes") releases audio channel before the outgoing call connection boards KFXO (the default value is "yes"); +
  • fxs-digit-timeout: Defines the timeout, in seconds, between digits of a FXS board's extension;
  • fxs-global-orig: Start number for sequencial branch numbering in FXS cards that are not listed in the [fxs-branches] section (the numbering follows ascending order from board number and physical channel number) (default is "0");
  • fxs-co-dialtone: Sequences of numbers, separated by commas, which fires a continuous tone (of central office) in FXS branches (eg: "0,99" means that, when you dial "0" or "99", the user will hear a continuous dial tone) (default is empty);
  • fxs-bina: When enabled ("yes"), calls to FXS lines will send digits corresponding to the source phone identification using BINA DTMF signaling (the default value is "no") (local option); +
  • ignore-letter-dtmfs: Defines if the channel should ignore some uncommon DTMF digits detected by the board (A, B, C and D). However, if you need to pass those digits througth the board, you may need to set this option to 'no' (the default value is "yes");
  • input-volume: Sets the volume gain for incoming audio (entering the board), from -10 to +10 (local option);
  • kommuter-activation: Sets whether to activate devices kommuter found in the system will be done automatically ("auto") by the channel, or manually ("manual") by the user through the command "khomp kommuter on/off"
  • kommuter-timeout: Sets the timeout (in seconds) for initializing the kommuter devices. If this timeout is reached without receiving notification of the channel, the devices will switch back to "off" condition. The minimum value is "0", where the links will always remain switched "on", and the maximum is "255"; -
  • language: Set language to Khomp channel calls (local option);
  • log-to-console: Set log messages to be printed on the console;
  • log-to-disk (old "log"): Set log messages to be saved to disk;
  • out-of-band-DTMF (former dtmfsuppression): Activate ("yes") or disables ("no") the removal and DTMF sending these out-of-band (local option); @@ -56,12 +61,9 @@ If you need to set advanced parameters of the board and/or signaling, the progra
  • pulse-forwarding (former 'pulsedetection): Active ("yes") or disables ("no") for the detection of pulses and converting them into DTMF (local option);
  • r2-preconnect-wait (former 'r2preconnectwait): Sets the timeout sending the ringback signaling, protocol R2/MFC to start sending audio silence. Only used when "r2-strict-Behavior" is set to "no" (local option);
  • r2-strict-Behaviour: Enable ("yes") or disables ("no") the behavior of signaling R2/MFC as the standard sets. The default is "no", and can be changed to "yes" if needed to receive / send data precise signaling protocol (condition B, for example) (local option); -
  • ringback-delay-co: Sets the delay to enable the generation of call control tone (ringback) by the Endpoint Khomp when there is an ringback indication from signaling and there is no audio being sent by the channel which indicated the situation (local option); -
  • ringback-delay-pbx: Sets the delay to enable the generation of call control tone (ringback) by the Endpoint Khomp when there is an ringback indication, and the audio has no tone (silence) (local option);
  • suppression-delay (former suppressiondelay): Activate ("yes") or disables ("no") the delay necessary to suppress DTMF. If disabled ("no"), also disables suppression of DTMF (local option);
  • trace: Set debugging options. Should not be used in production unless absolutely necessary; -
  • user-transfer-digits: Defines a sequence of DTMF digits to initiate the transfer between FreeSWITCH® and another PBX (using user signaling, like QSig or FXO FLASH). -
  • flash-to-digits: Defines the digits to be sent when the FLASH is detected on FXS channels.. +
  • user-transfer-digits: Defines a sequence of DTMF digits to initiate the transfer between FreeSWITCH® and another PBX (using user signaling, like QSig or FXO FLASH);

  • @@ -121,15 +123,13 @@ For details, please refer to the configuration file for examples.
    • context;
    • input-volume;
    • output-volume; -
    • accountcode;
    • calleridnum;
    • calleridname; -
    • mailbox;
    • flash-to-digits.

    Each option is separated from each other by a pipe "|" or a slash "/" and defined after the colon ":". Example:

    -
    <param name="200" value="language:en|context:master-branch" />
    +
    <param name="200" value="input-volume:1|context:master-branch" />
     

    For more information on the syntax and examples, please refer to the configuration file.

    For more information visit the configuration file 'khomp.conf.xml'. diff --git a/src/mod/endpoints/mod_khomp/docs/User_Guide.pdf b/src/mod/endpoints/mod_khomp/docs/User_Guide.pdf index 832596bdb255ccbd3bc03c675d3afe7a590008b7..e0c33e1c74e1c6f9588831d2b52013482fd13437 100644 GIT binary patch delta 36916 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

    WkXLuEr$VImcWjue|Mhk`fO|V~kNo!_IfS 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 + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mod/endpoints/mod_khomp/examples/transfer.xml b/src/mod/endpoints/mod_khomp/examples/transfer.xml new file mode 100644 index 0000000000..5c66633574 --- /dev/null +++ b/src/mod/endpoints/mod_khomp/examples/transfer.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mod/endpoints/mod_khomp/include/applications.h b/src/mod/endpoints/mod_khomp/include/applications.h index 75f55ec5ca..21b66b2b0a 100644 --- a/src/mod/endpoints/mod_khomp/include/applications.h +++ b/src/mod/endpoints/mod_khomp/include/applications.h @@ -268,7 +268,7 @@ struct Transfer if (!(_call->_flags.check(Kflags::XFER_DIALING))) { _call->_flags.set(Kflags::XFER_DIALING); - _idx_xfer_dial = Board::board(_pvt->target().device)->_timers.add(Opt::_transferdigittimeout, &userXferTimer, _pvt, TM_VAL_CALL); + _idx_xfer_dial = Board::board(_pvt->target().device)->_timers.add(Opt::_options._transferdigittimeout(), &userXferTimer, _pvt, TM_VAL_CALL); } else { @@ -280,7 +280,7 @@ struct Transfer } } - catch (K3LAPI::invalid_device & err) + catch (K3LAPITraits::invalid_device & err) { LOG(ERROR, PVT_FMT(_pvt->target(), "Unable to get device: %d!") % err.device); } @@ -506,7 +506,7 @@ struct Transfer if (!(_call->_flags.check(Kflags::XFER_DIALING) || _call->_flags.check(Kflags::XFER_QSIG_DIALING))) { _call->_flags.set(Kflags::XFER_DIALING); - _idx_xfer_dial = Board::board(_pvt->target().device)->_timers.add(Opt::_transferdigittimeout, &userXferTimer, _pvt, TM_VAL_CALL); + _idx_xfer_dial = Board::board(_pvt->target().device)->_timers.add(Opt::_options._transferdigittimeout(), &userXferTimer, _pvt, TM_VAL_CALL); } else { @@ -530,7 +530,7 @@ struct Transfer } } - catch (K3LAPI::invalid_device & err) + catch (K3LAPITraits::invalid_device & err) { LOG(ERROR, PVT_FMT(_pvt->target(), "Unable to get device: %d!") % err.device); } @@ -735,6 +735,9 @@ struct Transfer }; /*************************** SMS **********************************************/ +#define ESL_SMS_RECEIVED "khomp::sms_received" +#define ESL_SMS_SENT "khomp::sms_sent" + struct SMS : public Application { typedef std::list< switch_core_session_t *> OwnersList; @@ -889,6 +892,78 @@ struct SMS : public Application bool _conf; }; + static struct _SMSEvent : public ESL + { + + _SMSEvent() : ESL("khomp::sms") + { + if(_events) + { + _events->push_back(ESL_SMS_RECEIVED); + _events->push_back(ESL_SMS_SENT); + } + } + + ~_SMSEvent() + { + if(_events) + { + //Remove two from vector + _events->pop_back(); + _events->pop_back(); + } + } + + bool operator()(Board::KhompPvt * pvt, ReceiveData & data) + { + switch_event_t *event = create(ESL_SMS_RECEIVED); + + if(!event) + { + LOG(ERROR, "Cannot create SMS ESL"); + return false; + } + + add(event, pvt->target()); + add(event, "Type", data._type); + add(event, "From", data._from); + add(event, "Date", data._date); + add(event, "Size", data._size); + add(event, "Coding", data._coding); + add(event, "Serial", data._serial); + add(event, "Id", data._id); + add(event, "Page", data._page); + add(event, "Pages", data._pages); + add(event, "Sc_date", data._sc_date); + add(event, "Status", data._status); + add(event, "Body", data._body); + + return fire(&event); + } + + bool operator()(Board::KhompPvt * pvt, SendData & data) + { + switch_event_t *event = create(ESL_SMS_SENT); + + if(!event) + { + LOG(ERROR, "Cannot create SMS ESL"); + return false; + } + + add(event, pvt->target()); + add(event, "Dest", data._dest); + add(event, "Body", data._body); + add(event, "Confirmation?", (data._conf ? "Yes" : "No")); + + + return fire(&event); + } + + + + } SMSEvent; + struct Request { /* "empty" constructor */ diff --git a/src/mod/endpoints/mod_khomp/include/cli.h b/src/mod/endpoints/mod_khomp/include/cli.h index 214e2aa2d5..bb251bb16b 100644 --- a/src/mod/endpoints/mod_khomp/include/cli.h +++ b/src/mod/endpoints/mod_khomp/include/cli.h @@ -99,12 +99,52 @@ struct Command std::string usage; /* usage of the command, a help */ }; +struct CommandXMLOutput : public Command +{ + void createRoot(const char *name) + { + root = switch_xml_new(name); + } + + void insertXML(switch_xml_t xml) + { + switch_xml_insert(xml,root,0); + } + + void clearRoot() + { + if(root) + { + switch_xml_free(root); + root = NULL; + } + } + + void printXMLOutput(switch_stream_handle_t *stream) + { + K::Logger::Logg2(C_CLI,stream,switch_xml_toxml(root,SWITCH_FALSE)); + } + + CommandXMLOutput() : root(NULL) {}; + + switch_xml_t root; /* for commands that ouput as xml */ +}; + struct Cli { /* Useful definitions --------------------------------------------------- */ typedef switch_status_t (APIFunc)(const char*, switch_core_session_t*, switch_stream_handle_t*); typedef std::vector Commands; + /* Define the output types form commands */ + typedef enum + { + VERBOSE = 1, + CONCISE, + DETAILED, + XML + } OutputType; + /* register our commands, but you must create the command function */ static void registerCommands(APIFunc func,switch_loadable_module_interface_t **mod_int); @@ -145,27 +185,31 @@ struct Cli /* The Commands --------------------------------------------------------- */ /* khomp summary */ - static struct _KhompSummary : public Command + static struct _KhompSummary : public CommandXMLOutput { _KhompSummary(bool on_cli_term = true): - _on_cli_term(on_cli_term) + CommandXMLOutput(), + _on_cli_term(on_cli_term), + xdevs(NULL) { complete_name = "summary"; options.push_back("verbose"); options.push_back("concise"); + options.push_back("xml"); brief = "Print system info."; usage = \ "Prints detailed info about the system like API version and \n" \ "boards characteristics like DSPs version.\n\n" \ -"Usage: khomp summary [concise]"; +"Usage: khomp summary [concise|verbose|xml]"; _commands.push_back(this); }; bool execute(int argc, char *argv[]); - bool _on_cli_term; /* indicates if message is sent to fs_cli */ + bool _on_cli_term; /* indicates if message is sent to fs_cli */ + switch_xml_t xdevs; /* support xml needed to help the interation */ } KhompSummary; /* khomp show calls */ @@ -239,21 +283,22 @@ struct Cli } KhompChannelsUnblock; /* khomp show statistics */ - static struct _KhompShowStatistics : public Command + static struct _KhompShowStatistics : public CommandXMLOutput { - _KhompShowStatistics() + _KhompShowStatistics() : CommandXMLOutput(), xdevs(NULL) { complete_name = "show statistics"; options.push_back("verbose"); options.push_back("detailed"); + options.push_back("xml"); brief = "Shows statistics of the channels."; usage = \ "Shows statistics of the channels, like number of calls incoming \n" \ "and outgoing, status, status time.\n\n" \ -"Usage: khomp show statistics [{verbose [ []]} | \n" \ +"Usage: khomp show statistics [{{verbose|xml} [ []]} | \n" \ " {detailed }]\n" \ "\tboard -- Number of the board (start from 0).\n" \ "\tchannel -- Number of the channel (start from 0).\n" \ @@ -274,20 +319,22 @@ struct Cli bool execute(int argc, char *argv[]); /* support functions */ - void cliStatistics(unsigned int device); - void cliDetailedStatistics(unsigned int device, unsigned int channel); + void cliStatistics(unsigned int device, OutputType output_type); + void cliDetailedStatistics(unsigned int device, unsigned int channel, OutputType output_type); + switch_xml_t xdevs; /* support xml needed to help the interation */ } KhompShowStatistics; /* khomp show channels */ - static struct _KhompShowChannels: public Command + static struct _KhompShowChannels: public CommandXMLOutput { - _KhompShowChannels() + _KhompShowChannels() : CommandXMLOutput(), xdev(NULL) { complete_name = "show channels"; options.push_back("verbose"); options.push_back("concise"); + options.push_back("xml"); brief = "Show all channels status."; usage = \ @@ -295,34 +342,40 @@ struct Cli "khomp API point of view.\n\n" \ "Usage: \n" \ "khomp show channels [{ []} | \n" \ - "{{concise|verbose} [ []]}]\n" \ + "{{concise|verbose|xml} [ []]}]\n" \ "\tboard -- Number of the board (start from 0).\n" \ "e.g. khomp show channels - List status of all channels of all boards.\n" \ "e.g. khomp show channels concise 0 - List status of all channels of \n" \ -" board 0 in a concise way."; +" board 0 in a concise way.\n" \ +"e.g. khomp show channels xml 0 - List status of all channels of \n" \ +" board 0 in a xml structure."; _commands.push_back(this); }; /* support function for _KhompShowChannels */ - void showChannel(unsigned int device, bool concise, unsigned int channel); - void showChannels(unsigned int device, bool concise); + void showChannel(unsigned int device, unsigned int channel, OutputType output_type = Cli::VERBOSE); + void showChannels(unsigned int device, OutputType output_type = Cli::VERBOSE); bool execute(int argc, char *argv[]); + switch_xml_t xdev; /* support xml needed to help the interation */ + } KhompShowChannels; /* khomp show links */ - static struct _KhompShowLinks: public Command + static struct _KhompShowLinks: public CommandXMLOutput { - _KhompShowLinks() + _KhompShowLinks() : CommandXMLOutput(), xdev(NULL) { complete_name = "show links"; options.push_back("verbose"); options.push_back("concise"); + options.push_back("xml"); options.push_back("errors"); options.push_back("errors verbose"); options.push_back("errors concise"); + options.push_back("errors xml"); brief = "Show E1 link(s) status/errors counters in a concise \n" \ "way or not."; @@ -332,8 +385,9 @@ struct Cli "status/the error counters of each link on the board. It prints in \n" \ "a concise way for parsing facilities.\n\n" \ "Usage: \n" \ -"khomp show links [[errors] [{} | {{concise|verbose} []}]]\n" \ +"khomp show links [[errors] [{} | {{concise|verbose|xml} []}]]\n"\ "e.g. khomp show links - Show all links of all boards.\n" \ +"e.g. khomp show links xml - Show all links of all boards in xml.\n" \ "e.g. khomp show links errors - Show error counters of all links of \n" \ " all boards.\n" \ "e.g. khomp show links errors 0 - Show error counters of all links of \n" \ @@ -343,10 +397,12 @@ struct Cli }; /* support function for _KhompShowLinks */ - void showLinks(unsigned int device, bool concise); - void showErrors(unsigned int device, bool concise); + void showLinks(unsigned int device, OutputType output_type = Cli::VERBOSE); + void showErrors(unsigned int device, OutputType output_type = Cli::VERBOSE); + std::string getLinkStatus(int dev, int obj, Verbose::Presentation fmt); bool execute(int argc, char *argv[]); + switch_xml_t xdev; /* support xml needed to help the interation */ } KhompShowLinks; /* khomp clear links */ @@ -653,24 +709,41 @@ struct Cli { complete_name = "get"; + options.push_back("dialplan"); options.push_back("echo-canceller"); + options.push_back("auto-gain-control"); options.push_back("out-of-band-dtmfs"); + options.push_back("suppression-delay"); options.push_back("auto-fax-adjustment"); + options.push_back("fax-adjustment-timeout"); options.push_back("pulse-forwarding"); options.push_back("r2-strict-behaviour"); options.push_back("r2-preconnect-wait"); - options.push_back("native-bridge"); - options.push_back("suppression-delay"); - options.push_back("context-fxo"); - options.push_back("context-fxo-alt"); - options.push_back("context-fxs"); - options.push_back("context-fxs-alt"); - options.push_back("context-gsm-call"); - options.push_back("context-gsm-call-alt"); - options.push_back("context-gsm-sms"); options.push_back("context-digital"); + options.push_back("context-fxs"); + options.push_back("context-fxo"); + options.push_back("context-gsm-call"); + options.push_back("context-gsm-sms"); + options.push_back("context-pr"); + options.push_back("log-to-console"); + options.push_back("log-to-disk"); + options.push_back("trace"); options.push_back("output-volume"); options.push_back("input-volume"); + options.push_back("fxs-global-orig"); + options.push_back("fxs-co-dialtone"); + options.push_back("fxs-bina"); + options.push_back("disconnect-delay"); + options.push_back("delay-ringback-co"); + options.push_back("delay-ringback-pbx"); + options.push_back("ignore-letter-dtmfs"); + options.push_back("fxo-send-pre-audio"); + options.push_back("fxs-digit-timeout"); + options.push_back("drop-collect-call"); + options.push_back("kommuter-activation"); + options.push_back("kommuter-timeout"); + options.push_back("user-transfer-digits"); + options.push_back("flash-to-digits"); brief = "Get configuration options in the Khomp channel."; @@ -678,36 +751,37 @@ struct Cli "Usage: khomp get