diff --git a/build/modules.conf.in b/build/modules.conf.in index 3f77b125b5..f7b36831cc 100644 --- a/build/modules.conf.in +++ b/build/modules.conf.in @@ -99,6 +99,7 @@ event_handlers/mod_cdr_sqlite #event_handlers/mod_event_multicast event_handlers/mod_event_socket #event_handlers/mod_event_zmq +#event_handlers/mod_format_cdr #event_handlers/mod_json_cdr #event_handlers/mod_radius_cdr #event_handlers/mod_rayo diff --git a/conf/vanilla/autoload_configs/format_cdr.conf.xml b/conf/vanilla/autoload_configs/format_cdr.conf.xml new file mode 100644 index 0000000000..227bcb4722 --- /dev/null +++ b/conf/vanilla/autoload_configs/format_cdr.conf.xml @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/configure.in b/configure.in index eb845c3282..278243b6d4 100644 --- a/configure.in +++ b/configure.in @@ -420,9 +420,9 @@ if test "$PG_CONFIG" != "no"; then POSTGRESQL_CXXFLAGS="`$PG_CONFIG --cppflags` -I`$PG_CONFIG --includedir`" POSTGRESQL_LDFLAGS="`$PG_CONFIG --ldflags|sed 's/ -Wl,--as-needed//g'` -L`$PG_CONFIG --libdir` -lpq" POSTGRESQL_VERSION=`$PG_CONFIG --version | sed -e 's#PostgreSQL ##'` - POSTGRESQL_MAJOR_VERSION=`$PG_CONFIG --version | sed -re 's#PostgreSQL ([0-9]+).[0-9]+.[0-9]+#\1#'` - POSTGRESQL_MINOR_VERSION=`$PG_CONFIG --version | sed -re 's#PostgreSQL [0-9]+.([0-9]+).[0-9]+#\1#'` - POSTGRESQL_PATCH_VERSION=`$PG_CONFIG --version | sed -re 's#PostgreSQL [0-9]+.[0-9]+.([0-9]+)#\1#'` + POSTGRESQL_MAJOR_VERSION=`$PG_CONFIG --version | sed -e 's/devel//' | sed -re 's#PostgreSQL ([0-9]+).[0-9]+.?[0-9]+?#\1#'` + POSTGRESQL_MINOR_VERSION=`$PG_CONFIG --version | sed -e 's/devel//' | sed -re 's#PostgreSQL [0-9]+.([0-9]+).?[0-9]+?#\1#'` + POSTGRESQL_PATCH_VERSION=`$PG_CONFIG --version | sed -e 's/devel//' | sed -re 's#PostgreSQL [0-9]+.[0-9]+.?([0-9]+)?#\1#'` AC_DEFINE([SWITCH_HAVE_PGSQL], [1], [Define to 1 if PostgreSQL libraries are available]) AC_DEFINE_UNQUOTED([POSTGRESQL_VERSION], "${POSTGRESQL_VERSION}", [Specifies the version of PostgreSQL we are linking against]) AC_DEFINE_UNQUOTED([POSTGRESQL_MAJOR_VERSION], ${POSTGRESQL_MAJOR_VERSION}, [Specifies the version of PostgreSQL we are linking against]) diff --git a/debian/control-modules b/debian/control-modules index 679082187c..61f0b33a80 100644 --- a/debian/control-modules +++ b/debian/control-modules @@ -229,7 +229,7 @@ Description: Voicemail detection Module: applications/mod_voicemail Description: Voicemail This module provides a voicemail system. -Depends: mail-transport-agent +Depends: ssmtp | mail-transport-agent Module: applications/mod_voicemail_ivr Description: Voicemail IVR diff --git a/docs/phrase/phrase_en.xml b/docs/phrase/phrase_en.xml index 15e80f8882..a37dd5e3cc 100644 --- a/docs/phrase/phrase_en.xml +++ b/docs/phrase/phrase_en.xml @@ -198,8 +198,10 @@ + + @@ -218,13 +220,34 @@ + + + + + + + + + + + + + + + + + + + + + @@ -232,10 +255,14 @@ + + + + @@ -260,6 +287,7 @@ + @@ -388,7 +416,7 @@ - + @@ -443,7 +471,7 @@ - + @@ -507,6 +535,7 @@ + @@ -598,12 +627,16 @@ + + + + diff --git a/libs/esl/php/Makefile b/libs/esl/php/Makefile index dce8fd4bd1..97674f85be 100644 --- a/libs/esl/php/Makefile +++ b/libs/esl/php/Makefile @@ -17,6 +17,7 @@ all: ESL.so esl_wrap.cpp: swig -module ESL -php5 -c++ -DMULTIPLICITY -I../src/include -o esl_wrap.cpp ../ESL.i + sed -e 's/ char \*type_name;/ const char \*type_name;/' -i esl_wrap.cpp esl_wrap.o: esl_wrap.cpp $(CXX) $(CXX_CFLAGS) $(CXXFLAGS) $(LOCAL_CFLAGS) $(WRAP_GCC_WARNING_SILENCE) -c esl_wrap.cpp -o esl_wrap.o diff --git a/libs/esl/php/esl_wrap.cpp b/libs/esl/php/esl_wrap.cpp index 8c91f25452..0389cc2151 100644 --- a/libs/esl/php/esl_wrap.cpp +++ b/libs/esl/php/esl_wrap.cpp @@ -857,7 +857,7 @@ SWIG_ZTS_ConvertResourcePtr(zval *z, swig_type_info *ty, int flags TSRMLS_DC) { swig_object_wrapper *value; void *p; int type; - char *type_name; + const char *type_name; value = (swig_object_wrapper *) zend_list_find(z->value.lval, &type); if ( flags && SWIG_POINTER_DISOWN ) { diff --git a/libs/esl/src/include/cc.h b/libs/esl/src/include/cc.h index 965aa9cbac..d2635f3b1c 100644 --- a/libs/esl/src/include/cc.h +++ b/libs/esl/src/include/cc.h @@ -1,4 +1,4 @@ -const char *cc = ".========================================================================================================.\n| ____ _____ ____ _ ____ _ _ _____ |\n| / ___|___ _ __ ___ ___ |_ _|__ / ___| |_ _ ___ / ___|___ _ __ ( ) |___ / |\n| | | / _ \\| '_ ` _ \\ / _ \\ | |/ _ \\ | | | | | | |/ _ \\ | / _ \\| '_ \\ |/| | |_ \\ |\n| | |__| (_) | | | | | | __/ | | (_) | | |___| | |_| | __/ |__| (_) | | | | | |___) | |\n| \\____\\___/|_| |_| |_|\\___| |_|\\___/ \\____|_|\\__,_|\\___|\\____\\___/|_| |_| |_|____/ |\n| |\n| ____ _ _ _ _ ____ _ |\n| / ___| |__ (_) ___ __ _ __ _ ___ | | | / ___| / \\ |\n| | | | '_ \\| |/ __/ _` |/ _` |/ _ \\ | | | \\___ \\ / _ \\ |\n| | |___| | | | | (_| (_| | (_| | (_) | | |_| |___) / ___ \\ |\n| \\____|_| |_|_|\\___\\__,_|\\__, |\\___( ) \\___/|____/_/ \\_\\ |\n| |___/ |/ |\n| _ _ __ _ _ ___ _ _ ____ ___ _ _____ |\n| / \\ _ _ __ _ _ _ ___| |_ / /_ | |_| |__ ( _ )| |_| |__ |___ \\ / _ \\/ |___ / |\n| / _ \\| | | |/ _` | | | / __| __| | '_ \\| __| '_ \\ _____ / _ \\| __| '_ \\ __) | | | | | |_ \\ |\n| / ___ \\ |_| | (_| | |_| \\__ \\ |_ | (_) | |_| | | | |_____| | (_) | |_| | | | / __/| |_| | |___) | |\n| /_/ \\_\\__,_|\\__, |\\__,_|___/\\__| \\___/ \\__|_| |_| \\___/ \\__|_| |_| |_____|\\___/|_|____/ |\n| |___/ |\n| _ |\n| __ ____ ____ __ ___| |_ _ ___ ___ ___ _ __ ___ ___ _ __ ___ |\n| \\ \\ /\\ / /\\ \\ /\\ / /\\ \\ /\\ / / / __| | | | |/ _ \\/ __/ _ \\| '_ \\ / __/ _ \\| '_ ` _ \\ |\n| \\ V V / \\ V V / \\ V V / _ | (__| | |_| | __/ (_| (_) | | | | _ | (_| (_) | | | | | | |\n| \\_/\\_/ \\_/\\_/ \\_/\\_/ (_) \\___|_|\\__,_|\\___|\\___\\___/|_| |_| (_) \\___\\___/|_| |_| |_| |\n| |\n.========================================================================================================.\n"; +const char *cc = ".=======================================================================================================.\n| ____ _ ____ |\n| / ___| |_ _ ___ / ___|___ _ __ |\n| | | | | | | |/ _ \\ | / _ \\| '_ \\ |\n| | |___| | |_| | __/ |__| (_) | | | | |\n| \\____|_|\\__,_|\\___|\\____\\___/|_| |_| |\n| |\n| _____ _ _ ____ __ |\n| |_ _|__| | ___ _ __ | |__ ___ _ __ _ _ / ___|___ _ __ / _| ___ _ __ ___ _ __ ___ ___ |\n| | |/ _ \\ |/ _ \\ '_ \\| '_ \\ / _ \\| '_ \\| | | | | | / _ \\| '_ \\| |_ / _ \\ '__/ _ \\ '_ \\ / __/ _ \\ |\n| | | __/ | __/ |_) | | | | (_) | | | | |_| | | |__| (_) | | | | _| __/ | | __/ | | | (_| __/ |\n| |_|\\___|_|\\___| .__/|_| |_|\\___/|_| |_|\\__, | \\____\\___/|_| |_|_| \\___|_| \\___|_| |_|\\___\\___| |\n| |_| |___/ |\n| _____ _ _ |\n| | ____|_ _____ _ __ _ _ / \\ _ _ __ _ _ _ ___| |_ |\n| | _| \\ \\ / / _ \\ '__| | | | / _ \\| | | |/ _` | | | / __| __| |\n| | |___ \\ V / __/ | | |_| | / ___ \\ |_| | (_| | |_| \\__ \\ |_ |\n| |_____| \\_/ \\___|_| \\__, | /_/ \\_\\__,_|\\__, |\\__,_|___/\\__| |\n| |___/ |___/ |\n| ____ _ ____ |\n| __ ____ ____ __ / ___| |_ _ ___ / ___|___ _ __ ___ ___ _ __ ___ |\n| \\ \\ /\\ / /\\ \\ /\\ / /\\ \\ /\\ / / | | | | | | |/ _ \\ | / _ \\| '_ \\ / __/ _ \\| '_ ` _ \\ |\n| \\ V V / \\ V V / \\ V V / _ | |___| | |_| | __/ |__| (_) | | | | _ | (_| (_) | | | | | | |\n| \\_/\\_/ \\_/\\_/ \\_/\\_/ (_) \\____|_|\\__,_|\\___|\\____\\___/|_| |_| (_) \\___\\___/|_| |_| |_| |\n| |\n.=======================================================================================================.\n"; const char *cc_s = ".===============================================================.\n| _ |\n| ___| |_ _ ___ ___ ___ _ __ ___ ___ _ __ ___ |\n| / __| | | | |/ _ \\/ __/ _ \\| '_ \\ / __/ _ \\| '_ ` _ \\ |\n| | (__| | |_| | __/ (_| (_) | | | | _ | (_| (_) | | | | | | |\n| \\___|_|\\__,_|\\___|\\___\\___/|_| |_| (_) \\___\\___/|_| |_| |_| |\n| |\n.===============================================================.\n"; diff --git a/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.c b/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.c index cb0d80ff20..471afe080c 100644 --- a/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.c +++ b/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.c @@ -1913,6 +1913,12 @@ static int on_ring(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event ftdm_set_string(caller_data->dnis.digits, (char *)pevent->ring.callednum); ftdm_set_string(caller_data->rdnis.digits, (char *)pevent->ring.redirectingnum); + caller_data->cid_num.type = pevent->ring.callingplan >> 4; + caller_data->cid_num.plan = pevent->ring.callingplan & 0x0F; + + caller_data->dnis.type = pevent->ring.calledplan >> 4; + caller_data->dnis.plan = pevent->ring.calledplan & 0x0F; + if (!ftdm_strlen_zero((char *)pevent->ring.callingname)) { ftdm_set_string(caller_data->cid_name, (char *)pevent->ring.callingname); } else { diff --git a/libs/sofia-sip/.update b/libs/sofia-sip/.update index 76ab95f85f..36fa387d65 100644 --- a/libs/sofia-sip/.update +++ b/libs/sofia-sip/.update @@ -1 +1 @@ -Tue Sep 17 06:24:17 CDT 2013 +Tue Oct 8 12:10:32 CDT 2013 diff --git a/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_parse.c b/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_parse.c index 4c48dfc133..7877100978 100644 --- a/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_parse.c +++ b/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_parse.c @@ -1589,7 +1589,7 @@ static void parse_media_attr(sdp_parser_t *p, char *r, sdp_media_t *m, if (p->pr_mode_manual) ; - else if (su_casematch(name, "inactive")) { + else if (m->m_port == 0 || su_casematch(name, "inactive")) { m->m_mode = sdp_inactive; return; } diff --git a/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_print.c b/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_print.c index 537e9fe606..70a5b23b72 100644 --- a/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_print.c +++ b/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_print.c @@ -640,14 +640,16 @@ static void print_media(sdp_printer_t *p, print_key(p, m->m_key); for (rm = m->m_rtpmaps; rm; rm = rm->rm_next) { - if (!rm->rm_predef || p->pr_all_rtpmaps) - sdp_printf(p, "a=rtpmap:%u %s/%lu%s%s" CRLF, - rm->rm_pt, rm->rm_encoding, rm->rm_rate, - rm->rm_params ? "/" : "", - rm->rm_params ? rm->rm_params : ""); - if (rm->rm_fmtp) - sdp_printf(p, "a=fmtp:%u %s" CRLF, - rm->rm_pt, rm->rm_fmtp); + if (rm->rm_encoding && *rm->rm_encoding && (!rm->rm_predef || p->pr_all_rtpmaps)) { + sdp_printf(p, "a=rtpmap:%u %s/%lu%s%s" CRLF, + rm->rm_pt, rm->rm_encoding, rm->rm_rate, + rm->rm_params ? "/" : "", + rm->rm_params ? rm->rm_params : ""); + } + if (rm->rm_fmtp) { + sdp_printf(p, "a=fmtp:%u %s" CRLF, + rm->rm_pt, rm->rm_fmtp); + } } if (!p->pr_mode_manual && !m->m_rejected && diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/sip_feature.c b/libs/sofia-sip/libsofia-sip-ua/sip/sip_feature.c index b2940526b3..e203964a82 100644 --- a/libs/sofia-sip/libsofia-sip-ua/sip/sip_feature.c +++ b/libs/sofia-sip/libsofia-sip-ua/sip/sip_feature.c @@ -116,7 +116,7 @@ static int sip_allow_update(msg_common_t *h, k->k_bitmap = 0; } else { - sip_method_t method = sip_method_code(name); + int method = (int)sip_method_code(name); if (method >= 0 && method < 32) k->k_bitmap |= 1 << method; @@ -130,14 +130,16 @@ int sip_is_allowed(sip_allow_t const *allow, sip_method_t method, char const *name) { - if (method < sip_method_unknown || !allow) + int meth = method; + + if (meth < sip_method_unknown || !allow) return 0; - if (sip_method_unknown < method && method < 32) + if (sip_method_unknown < meth && meth < 32) /* Well-known method */ - return (allow->k_bitmap & (1 << method)) != 0; + return (allow->k_bitmap & (1 << meth)) != 0; - if (method == sip_method_unknown && + if (meth == sip_method_unknown && (allow->k_bitmap & (1 << sip_method_unknown)) == 0) return 0; diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/sip_util.c b/libs/sofia-sip/libsofia-sip-ua/sip/sip_util.c index cf470075a2..a2880df520 100644 --- a/libs/sofia-sip/libsofia-sip-ua/sip/sip_util.c +++ b/libs/sofia-sip/libsofia-sip-ua/sip/sip_util.c @@ -672,7 +672,7 @@ static void sip_fragment_clear_chain(sip_header_t *h) { void const *next; - for (h = h; h; h = h->sh_succ) { + for (; h; h = h->sh_succ) { next = (char *)h->sh_data + h->sh_len; sip_fragment_clear(h->sh_common); diff --git a/libs/sofia-sip/libsofia-sip-ua/tport/tport.c b/libs/sofia-sip/libsofia-sip-ua/tport/tport.c index 50050e2289..ccffb5e007 100644 --- a/libs/sofia-sip/libsofia-sip-ua/tport/tport.c +++ b/libs/sofia-sip/libsofia-sip-ua/tport/tport.c @@ -3322,7 +3322,8 @@ tport_t *tport_tsend(tport_t *self, self = primary->pri_primary; } else if (tport_is_secondary(self) && tport_is_clear_to_send(self)) { - self = self; + /* self = self; */ + ; } /* * Try to find an already open connection to the destination, diff --git a/libs/sofia-sip/libsofia-sip-ua/tport/ws.c b/libs/sofia-sip/libsofia-sip-ua/tport/ws.c index 6039aea826..a8d056c895 100644 --- a/libs/sofia-sip/libsofia-sip-ua/tport/ws.c +++ b/libs/sofia-sip/libsofia-sip-ua/tport/ws.c @@ -223,6 +223,7 @@ int ws_handshake(wsh_t *wsh) char key[256] = ""; char version[5] = ""; char proto[256] = ""; + char proto_buf[384] = ""; char uri[256] = ""; char input[256] = ""; unsigned char output[SHA1_HASH_SIZE] = ""; @@ -242,7 +243,7 @@ int ws_handshake(wsh_t *wsh) } } - if (bytes > sizeof(wsh->buffer)) { + if (bytes > sizeof(wsh->buffer) -1) { goto err; } @@ -273,14 +274,18 @@ int ws_handshake(wsh_t *wsh) sha1_digest(output, input); b64encode((unsigned char *)output, SHA1_HASH_SIZE, (unsigned char *)b64, sizeof(b64)); + if (*proto) { + snprintf(proto_buf, sizeof(proto_buf), "Sec-WebSocket-Protocol: %s\r\n", proto); + } + snprintf(respond, sizeof(respond), "HTTP/1.1 101 Switching Protocols\r\n" "Upgrade: websocket\r\n" "Connection: Upgrade\r\n" "Sec-WebSocket-Accept: %s\r\n" - "Sec-WebSocket-Protocol: %s\r\n\r\n", + "%s\r\n", b64, - proto); + proto_buf); ws_raw_write(wsh, respond, strlen(respond)); @@ -319,7 +324,7 @@ ssize_t ws_raw_read(wsh_t *wsh, void *data, size_t bytes) #endif } while (r == -1 && SSL_get_error(wsh->ssl, r) == SSL_ERROR_WANT_READ && x < 100); - return r; + goto end; } do { @@ -336,6 +341,12 @@ ssize_t ws_raw_read(wsh_t *wsh, void *data, size_t bytes) r = -1; } + end: + + if (r > 0) { + *((char *)data + r) = '\0'; + } + return r; } @@ -530,7 +541,7 @@ ssize_t ws_close(wsh_t *wsh, int16_t reason) restore_socket(wsh->sock); - if (wsh->close_sock) { + if (wsh->close_sock && wsh->sock != ws_sock_invalid) { close(wsh->sock); } @@ -559,7 +570,11 @@ ssize_t ws_read_frame(wsh_t *wsh, ws_opcode_t *oc, uint8_t **data) return ws_close(wsh, WS_PROTO_ERR); } - if ((wsh->datalen = ws_raw_read(wsh, wsh->buffer, 9)) < need) { + if ((wsh->datalen = ws_raw_read(wsh, wsh->buffer, 9)) < 0) { + return ws_close(wsh, WS_PROTO_ERR); + } + + if (wsh->datalen < need) { if ((wsh->datalen += ws_raw_read(wsh, wsh->buffer + wsh->datalen, 9 - wsh->datalen)) < need) { /* too small - protocol err */ return ws_close(wsh, WS_PROTO_ERR); diff --git a/libs/sofia-sip/libsofia-sip-ua/tport/ws.h b/libs/sofia-sip/libsofia-sip-ua/tport/ws.h index ac383e9c8b..11e6b93068 100644 --- a/libs/sofia-sip/libsofia-sip-ua/tport/ws.h +++ b/libs/sofia-sip/libsofia-sip-ua/tport/ws.h @@ -13,6 +13,7 @@ #include #else #pragma warning(disable:4996) +#include #endif #include #include @@ -26,14 +27,7 @@ #include #ifdef _MSC_VER -#ifdef _WIN64 -#define WS_SSIZE_T __int64 -#elif _MSC_VER >= 1400 -#define WS_SSIZE_T __int32 __w64 -#else -#define WS_SSIZE_T __int32 -#endif -typedef WS_SSIZE_T ssize_t +typedef intptr_t ssize_t; #endif diff --git a/libs/spandsp/src/fax.c b/libs/spandsp/src/fax.c index 3a08d49218..8d8b3b25bc 100644 --- a/libs/spandsp/src/fax.c +++ b/libs/spandsp/src/fax.c @@ -163,7 +163,8 @@ SPAN_DECLARE_NONSTD(int) fax_rx(fax_state_t *s, int16_t *amp, int len) #endif for (i = 0; i < len; i++) amp[i] = dc_restore(&s->modems.dc_restore, amp[i]); - s->modems.rx_handler(s->modems.rx_user_data, amp, len); + if (s->modems.rx_handler) + s->modems.rx_handler(s->modems.rx_user_data, amp, len); t30_timer_update(&s->t30, len); return 0; } @@ -197,26 +198,6 @@ SPAN_DECLARE_NONSTD(int) fax_rx_fillin(fax_state_t *s, int len) } /*- End of function --------------------------------------------------------*/ -static int set_next_tx_type(fax_state_t *s) -{ - fax_modems_state_t *t; - - t = &s->modems; - if (t->next_tx_handler) - { - fax_modems_set_tx_handler(t, t->next_tx_handler, t->next_tx_user_data); - t->next_tx_handler = NULL; - return 0; - } - /* If there is nothing else to change to, so use zero length silence */ - silence_gen_alter(&t->silence_gen, 0); - fax_modems_set_tx_handler(t, (span_tx_handler_t) &silence_gen, &t->silence_gen); - fax_modems_set_next_tx_handler(t, (span_tx_handler_t) NULL, NULL); - t->transmit = false; - return -1; -} -/*- End of function --------------------------------------------------------*/ - SPAN_DECLARE_NONSTD(int) fax_tx(fax_state_t *s, int16_t *amp, int max_len) { int len; @@ -226,41 +207,30 @@ SPAN_DECLARE_NONSTD(int) fax_tx(fax_state_t *s, int16_t *amp, int max_len) required_len = max_len; #endif len = 0; - if (s->modems.transmit) + while (s->modems.transmit && (len += s->modems.tx_handler(s->modems.tx_user_data, &[len], max_len - len)) < max_len) { - while ((len += s->modems.tx_handler(s->modems.tx_user_data, amp + len, max_len - len)) < max_len) - { - /* Allow for a change of tx handler within a block */ - if (set_next_tx_type(s) && s->modems.current_tx_type != T30_MODEM_NONE && s->modems.current_tx_type != T30_MODEM_DONE) - t30_front_end_status(&s->t30, T30_FRONT_END_SEND_STEP_COMPLETE); - if (!s->modems.transmit) - { - if (s->modems.transmit_on_idle) - { - /* Pad to the requested length with silence */ - memset(amp + len, 0, (max_len - len)*sizeof(int16_t)); - len = max_len; - } - break; - } - } + /* Allow for a change of tx handler within a block */ + if (fax_modems_set_next_tx_type(&s->modems) && s->modems.current_tx_type != T30_MODEM_NONE && s->modems.current_tx_type != T30_MODEM_DONE) + t30_front_end_status(&s->t30, T30_FRONT_END_SEND_STEP_COMPLETE); + /*endif*/ } - else + /*endwhile*/ + if (s->modems.transmit_on_idle) { - if (s->modems.transmit_on_idle) - { - /* Pad to the requested length with silence */ - memset(amp, 0, max_len*sizeof(int16_t)); - len = max_len; - } + /* Pad to the requested length with silence */ + memset(&[len], 0, (max_len - len)*sizeof(int16_t)); + len = max_len; } + /*endif*/ #if defined(LOG_FAX_AUDIO) if (s->modems.audio_tx_log >= 0) { if (len < required_len) - memset(amp + len, 0, (required_len - len)*sizeof(int16_t)); + memset(&[len], 0, (required_len - len)*sizeof(int16_t)); + /*endif*/ write(s->modems.audio_tx_log, amp, required_len*sizeof(int16_t)); } + /*endif*/ #endif return len; } @@ -285,7 +255,6 @@ static void fax_set_rx_type(void *user_data, int type, int bit_rate, int short_t { case T30_MODEM_V21: fax_modems_start_slow_modem(t, FAX_MODEM_V21_RX); - fax_modems_set_rx_handler(t, (span_rx_handler_t) &fsk_rx, &t->v21_rx, (span_rx_fillin_handler_t) &fsk_rx_fillin, &t->v21_rx); break; case T30_MODEM_V17: fax_modems_start_fast_modem(t, FAX_MODEM_V17_RX, bit_rate, short_train, use_hdlc); @@ -316,6 +285,7 @@ static void fax_set_tx_type(void *user_data, int type, int bit_rate, int short_t span_log(&s->logging, SPAN_LOG_FLOW, "Set tx type %d\n", type); if (t->current_tx_type == type) return; + switch (type) { case T30_MODEM_PAUSE: diff --git a/libs/spandsp/src/fax_modems.c b/libs/spandsp/src/fax_modems.c index 413a464330..e298f4d70a 100644 --- a/libs/spandsp/src/fax_modems.c +++ b/libs/spandsp/src/fax_modems.c @@ -101,6 +101,50 @@ #define HDLC_FRAMING_OK_THRESHOLD 5 +SPAN_DECLARE(const char *) fax_modem_to_str(int modem) +{ + switch (modem) + { + case FAX_MODEM_NONE: + return "None"; + case FAX_MODEM_FLUSH: + return "Flush"; + case FAX_MODEM_SILENCE_TX: + return "Silence Tx"; + case FAX_MODEM_SILENCE_RX: + return "Silence Rx"; + case FAX_MODEM_CED_TONE_TX: + return "CED Tx"; + case FAX_MODEM_CNG_TONE_TX: + return "CNG Tx"; + case FAX_MODEM_NOCNG_TONE_TX: + return "No CNG Tx"; + case FAX_MODEM_CED_TONE_RX: + return "CED Rx"; + case FAX_MODEM_CNG_TONE_RX: + return "CNG Rx"; + case FAX_MODEM_V21_TX: + return "V.21 Tx"; + case FAX_MODEM_V17_TX: + return "V.17 Tx"; + case FAX_MODEM_V27TER_TX: + return "V.27ter Tx"; + case FAX_MODEM_V29_TX: + return "V.29 Tx"; + case FAX_MODEM_V21_RX: + return "V.21 Rx"; + case FAX_MODEM_V17_RX: + return "V.17 Rx"; + case FAX_MODEM_V27TER_RX: + return "V.27ter Rx"; + case FAX_MODEM_V29_RX: + return "V.29 Rx"; + } + /*endswitch*/ + return "???"; +} +/*- End of function --------------------------------------------------------*/ + static void fax_modems_hdlc_accept(void *user_data, const uint8_t *msg, int len, int ok) { fax_modems_state_t *s; @@ -489,6 +533,23 @@ SPAN_DECLARE(void) fax_modems_set_next_tx_handler(fax_modems_state_t *s, span_tx } /*- End of function --------------------------------------------------------*/ +SPAN_DECLARE(int) fax_modems_set_next_tx_type(fax_modems_state_t *s) +{ + if (s->next_tx_handler) + { + fax_modems_set_tx_handler(s, s->next_tx_handler, s->next_tx_user_data); + fax_modems_set_next_tx_handler(s, (span_tx_handler_t) NULL, NULL); + return 0; + } + /* There is nothing else to change to, so use zero length silence */ + silence_gen_alter(&s->silence_gen, 0); + fax_modems_set_tx_handler(s, (span_tx_handler_t) &silence_gen, &s->silence_gen); + fax_modems_set_next_tx_handler(s, (span_tx_handler_t) NULL, NULL); + s->transmit = false; + return -1; +} +/*- End of function --------------------------------------------------------*/ + SPAN_DECLARE(void) fax_modems_set_tep_mode(fax_modems_state_t *s, int use_tep) { s->use_tep = use_tep; diff --git a/libs/spandsp/src/make_at_dictionary.c b/libs/spandsp/src/make_at_dictionary.c index 7f05dd9b14..3a881af992 100644 --- a/libs/spandsp/src/make_at_dictionary.c +++ b/libs/spandsp/src/make_at_dictionary.c @@ -24,10 +24,6 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - #include #include #include diff --git a/libs/spandsp/src/make_cielab_luts.c b/libs/spandsp/src/make_cielab_luts.c index 5fca6c7236..b143817d85 100644 --- a/libs/spandsp/src/make_cielab_luts.c +++ b/libs/spandsp/src/make_cielab_luts.c @@ -25,22 +25,13 @@ /*! \file */ -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - #include #include #include #include #include #include -#if defined(HAVE_TGMATH_H) -#include -#endif -#if defined(HAVE_MATH_H) #include -#endif typedef struct { diff --git a/libs/spandsp/src/make_math_fixed_tables.c b/libs/spandsp/src/make_math_fixed_tables.c index 64b33ca328..075cb15bd2 100644 --- a/libs/spandsp/src/make_math_fixed_tables.c +++ b/libs/spandsp/src/make_math_fixed_tables.c @@ -24,10 +24,6 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - #include #include #include diff --git a/libs/spandsp/src/make_modem_filter.c b/libs/spandsp/src/make_modem_filter.c index b0faed4a02..bd9427e24f 100644 --- a/libs/spandsp/src/make_modem_filter.c +++ b/libs/spandsp/src/make_modem_filter.c @@ -24,10 +24,6 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - #include #include #include @@ -35,22 +31,20 @@ #include #include #include -#if defined(HAVE_TGMATH_H) -#include -#endif -#if defined(HAVE_MATH_H) #include -#endif #if defined(HAVE_STDBOOL_H) #include #else #include "spandsp/stdbool.h" #endif -#include "floating_fudge.h" #if defined(__sunos) || defined(__solaris) || defined(__sun) #include #endif +#if defined (_MSC_VER) + #define __inline__ __inline +#endif + #include "spandsp/telephony.h" #include "spandsp/complex.h" #include "filter_tools.h" diff --git a/libs/spandsp/src/make_t43_gray_code_tables.c b/libs/spandsp/src/make_t43_gray_code_tables.c index c44adc27bb..90117c5d83 100644 --- a/libs/spandsp/src/make_t43_gray_code_tables.c +++ b/libs/spandsp/src/make_t43_gray_code_tables.c @@ -24,10 +24,6 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - #include #include #include @@ -41,12 +37,13 @@ int main(int argc, char *argv[]) int j; int gray; int new_gray; - int restore = 0; + int restore; printf("static const int16_t gray_code[4096] =\n{\n"); for (i = 0; i < 4096; i++) { gray = i & 0x800; + restore = i; for (j = 10; j >= 0; j--) { if (((i >> (j + 1)) & 1) ^ ((i >> j) & 1)) diff --git a/libs/spandsp/src/msvc/spandsp.h b/libs/spandsp/src/msvc/spandsp.h index b98aa66aa4..fb7b1431b1 100644 --- a/libs/spandsp/src/msvc/spandsp.h +++ b/libs/spandsp/src/msvc/spandsp.h @@ -36,9 +36,10 @@ #define SPANDSP_USE_EXPORT_CAPABILITY 1 -#undef SPANDSP_SUPPORT_T42 #undef SPANDSP_SUPPORT_T43 +#undef SPANDSP_SUPPORT_V32BIS #undef SPANDSP_SUPPORT_V34 +#undef SPANDSP_SUPPORT_TIFF_FX #include #include diff --git a/libs/spandsp/src/spandsp/bit_operations.h b/libs/spandsp/src/spandsp/bit_operations.h index 2deca2828a..311408123e 100644 --- a/libs/spandsp/src/spandsp/bit_operations.h +++ b/libs/spandsp/src/spandsp/bit_operations.h @@ -42,7 +42,7 @@ extern "C" /*! \brief Find the bit position of the highest set bit in a word \param bits The word to be searched \return The bit number of the highest set bit, or -1 if the word is zero. */ -static __inline__ int top_bit(unsigned int bits) +static __inline__ int top_bit(uint32_t bits) { #if defined(SPANDSP_USE_86_ASM) int res; @@ -141,7 +141,7 @@ static __inline__ int top_bit(unsigned int bits) /*! \brief Find the bit position of the lowest set bit in a word \param bits The word to be searched \return The bit number of the lowest set bit, or -1 if the word is zero. */ -static __inline__ int bottom_bit(unsigned int bits) +static __inline__ int bottom_bit(uint32_t bits) { int res; diff --git a/libs/spandsp/src/spandsp/fax_modems.h b/libs/spandsp/src/spandsp/fax_modems.h index 3c76022575..2ffb7be7c5 100644 --- a/libs/spandsp/src/spandsp/fax_modems.h +++ b/libs/spandsp/src/spandsp/fax_modems.h @@ -59,6 +59,12 @@ extern "C" { #endif +/*! Convert a FAX modem type to a short text description. + \brief Convert a FAX modem type to a short text description. + \param modem The modem code. + \return A pointer to the description. */ +SPAN_DECLARE(const char *) fax_modem_to_str(int modem); + /* N.B. the following are currently a work in progress */ SPAN_DECLARE_NONSTD(int) fax_modems_v17_v21_rx(void *user_data, const int16_t amp[], int len); SPAN_DECLARE_NONSTD(int) fax_modems_v27ter_v21_rx(void *user_data, const int16_t amp[], int len); @@ -93,6 +99,8 @@ SPAN_DECLARE(void) fax_modems_set_tx_handler(fax_modems_state_t *s, span_tx_hand SPAN_DECLARE(void) fax_modems_set_next_tx_handler(fax_modems_state_t *s, span_tx_handler_t handler, void *user_data); +SPAN_DECLARE(int) fax_modems_set_next_tx_type(fax_modems_state_t *s); + SPAN_DECLARE(int) fax_modems_restart(fax_modems_state_t *s); /*! Get a pointer to the logging context associated with a FAX modems context. diff --git a/libs/spandsp/src/spandsp/t30_logging.h b/libs/spandsp/src/spandsp/t30_logging.h index 2dc9bb321c..7122b1c6eb 100644 --- a/libs/spandsp/src/spandsp/t30_logging.h +++ b/libs/spandsp/src/spandsp/t30_logging.h @@ -53,6 +53,12 @@ SPAN_DECLARE(void) t30_decode_dis_dtc_dcs(t30_state_t *s, const uint8_t *dis, in \return A pointer to the description. */ SPAN_DECLARE(const char *) t30_completion_code_to_str(int result); +/*! Convert a T.30 modem type to a short text description. + \brief Convert a T.30 modem type to a short text description. + \param modem The modem code. + \return A pointer to the description. */ +SPAN_DECLARE(const char *) t30_modem_to_str(int modem); + #if defined(__cplusplus) } #endif diff --git a/libs/spandsp/src/t30.c b/libs/spandsp/src/t30.c index 7defb47d15..de71d91067 100644 --- a/libs/spandsp/src/t30.c +++ b/libs/spandsp/src/t30.c @@ -421,7 +421,7 @@ static const struct { 7200, T30_MODEM_V29, T30_SUPPORT_V29, (DISBIT4 | DISBIT3)}, { 4800, T30_MODEM_V27TER, T30_SUPPORT_V27TER, DISBIT4}, { 2400, T30_MODEM_V27TER, T30_SUPPORT_V27TER, 0}, - { 0, 0, 0, 0} + { 0, 0, 0, 0} }; static void queue_phase(t30_state_t *s, int phase); @@ -437,6 +437,7 @@ static void decode_20digit_msg(t30_state_t *s, char *msg, const uint8_t *pkt, in static void decode_url_msg(t30_state_t *s, char *msg, const uint8_t *pkt, int len); static int decode_nsf_nss_nsc(t30_state_t *s, uint8_t *msg[], const uint8_t *pkt, int len); static void set_min_scan_time(t30_state_t *s); +static int build_dcs(t30_state_t *s); static void timer_t2_start(t30_state_t *s); static void timer_t2a_start(t30_state_t *s); static void timer_t2b_start(t30_state_t *s); @@ -470,6 +471,27 @@ static int find_fallback_entry(int dcs_code) } /*- End of function --------------------------------------------------------*/ +static int step_fallback_entry(t30_state_t *s) +{ + while (fallback_sequence[++s->current_fallback].bit_rate) + { + if ((fallback_sequence[s->current_fallback].which & s->current_permitted_modems)) + break; + } + if (fallback_sequence[s->current_fallback].bit_rate == 0) + { + /* Reset the fallback sequence */ + s->current_fallback = 0; + return -1; + } + /* We need to update the minimum scan time, in case we are in non-ECM mode. */ + set_min_scan_time(s); + /* Now we need to rebuild the DCS message we will send. */ + build_dcs(s); + return s->current_fallback; +} +/*- End of function --------------------------------------------------------*/ + static int terminate_operation_in_progress(t30_state_t *s) { /* Make sure any FAX in progress is tidied up. If the tidying up has @@ -2242,23 +2264,6 @@ static int analyze_rx_dcs(t30_state_t *s, const uint8_t *msg, int len) } /*- End of function --------------------------------------------------------*/ -static int step_fallback_entry(t30_state_t *s) -{ - while (fallback_sequence[++s->current_fallback].which) - { - if ((fallback_sequence[s->current_fallback].which & s->current_permitted_modems)) - break; - } - if (fallback_sequence[s->current_fallback].which == 0) - return -1; - /* We need to update the minimum scan time, in case we are in non-ECM mode. */ - set_min_scan_time(s); - /* Now we need to rebuild the DCS message we will send. */ - build_dcs(s); - return s->current_fallback; -} -/*- End of function --------------------------------------------------------*/ - static void send_dcn(t30_state_t *s) { queue_phase(s, T30_PHASE_D_TX); @@ -2710,6 +2715,13 @@ static int process_rx_dis_dtc(t30_state_t *s, const uint8_t *msg, int len) send_dcn(s); return -1; } + /* Start document transmission */ + span_log(&s->logging, + SPAN_LOG_FLOW, + "Put document with modem (%d) %s at %dbps\n", + fallback_sequence[s->current_fallback].modem_type, + t30_modem_to_str(fallback_sequence[s->current_fallback].modem_type), + fallback_sequence[s->current_fallback].bit_rate); s->retries = 0; send_dcs_sequence(s, true); return 0; @@ -2773,9 +2785,10 @@ static int process_rx_dcs(t30_state_t *s, const uint8_t *msg, int len) /* Start document reception */ span_log(&s->logging, SPAN_LOG_FLOW, - "Get document at %dbps, modem %d\n", - fallback_sequence[s->current_fallback].bit_rate, - fallback_sequence[s->current_fallback].modem_type); + "Get document with modem (%d) %s at %dbps\n", + fallback_sequence[s->current_fallback].modem_type, + t30_modem_to_str(fallback_sequence[s->current_fallback].modem_type), + fallback_sequence[s->current_fallback].bit_rate); if (s->rx_file[0] == '\0') { span_log(&s->logging, SPAN_LOG_FLOW, "No document to receive\n"); @@ -3439,7 +3452,6 @@ static void process_state_d_post_tcf(t30_state_t *s, const uint8_t *msg, int len if (step_fallback_entry(s) < 0) { /* We have fallen back as far as we can go. Give up. */ - s->current_fallback = 0; t30_set_status(s, T30_ERR_CANNOT_TRAIN); send_dcn(s); break; @@ -4091,7 +4103,6 @@ static void process_state_ii_q(t30_state_t *s, const uint8_t *msg, int len) if (step_fallback_entry(s) < 0) { /* We have fallen back as far as we can go. Give up. */ - s->current_fallback = 0; t30_set_status(s, T30_ERR_CANNOT_TRAIN); send_dcn(s); break; @@ -4152,7 +4163,6 @@ static void process_state_ii_q(t30_state_t *s, const uint8_t *msg, int len) if (step_fallback_entry(s) < 0) { /* We have fallen back as far as we can go. Give up. */ - s->current_fallback = 0; t30_set_status(s, T30_ERR_CANNOT_TRAIN); send_dcn(s); break; @@ -4186,7 +4196,6 @@ static void process_state_ii_q(t30_state_t *s, const uint8_t *msg, int len) if (step_fallback_entry(s) < 0) { /* We have fallen back as far as we can go. Give up. */ - s->current_fallback = 0; t30_set_status(s, T30_ERR_CANNOT_TRAIN); send_dcn(s); break; diff --git a/libs/spandsp/src/t30_logging.c b/libs/spandsp/src/t30_logging.c index a3dea97b2e..51739999d1 100644 --- a/libs/spandsp/src/t30_logging.c +++ b/libs/spandsp/src/t30_logging.c @@ -246,6 +246,36 @@ SPAN_DECLARE(const char *) t30_completion_code_to_str(int result) } /*- End of function --------------------------------------------------------*/ +SPAN_DECLARE(const char *) t30_modem_to_str(int modem) +{ + switch (modem) + { + case T30_MODEM_NONE: + return "None"; + case T30_MODEM_PAUSE: + return "Pause"; + case T30_MODEM_CED: + return "CED"; + case T30_MODEM_CNG: + return "CNG"; + case T30_MODEM_V21: + return "V.21"; + case T30_MODEM_V27TER: + return "V.27ter"; + case T30_MODEM_V29: + return "V.29"; + case T30_MODEM_V17: + return "V.17"; + case T30_MODEM_V34HDX: + return "V.34HDX"; + case T30_MODEM_DONE: + return "Done"; + } + /*endswitch*/ + return "???"; +} +/*- End of function --------------------------------------------------------*/ + SPAN_DECLARE(const char *) t30_frametype(uint8_t x) { switch (x) diff --git a/libs/spandsp/src/t31.c b/libs/spandsp/src/t31.c index 79ba8f5286..76aa7e56ab 100644 --- a/libs/spandsp/src/t31.c +++ b/libs/spandsp/src/t31.c @@ -2830,7 +2830,8 @@ SPAN_DECLARE_NONSTD(int) t31_rx(t31_state_t *s, int16_t amp[], int len) } /*endif*/ - s->audio.modems.rx_handler(s->audio.modems.rx_user_data, amp, len); + if (s->audio.modems.rx_handler) + s->audio.modems.rx_handler(s->audio.modems.rx_user_data, amp, len); return 0; } /*- End of function --------------------------------------------------------*/ @@ -2861,23 +2862,6 @@ SPAN_DECLARE_NONSTD(int) t31_rx_fillin(t31_state_t *s, int len) } /*- End of function --------------------------------------------------------*/ -static int set_next_tx_type(t31_state_t *s) -{ - if (s->audio.next_tx_handler) - { - fax_modems_set_tx_handler(&s->audio.modems, s->audio.next_tx_handler, s->audio.next_tx_user_data); - fax_modems_set_next_tx_handler(&s->audio.modems, (span_tx_handler_t) NULL, NULL); - return 0; - } - /*endif*/ - /* There is nothing else to change to, so use zero length silence */ - silence_gen_alter(&s->audio.modems.silence_gen, 0); - fax_modems_set_tx_handler(&s->audio.modems, (span_tx_handler_t) &silence_gen, &s->audio.modems.silence_gen); - fax_modems_set_next_tx_handler(&s->audio.modems, (span_tx_handler_t) NULL, NULL); - return -1; -} -/*- End of function --------------------------------------------------------*/ - SPAN_DECLARE_NONSTD(int) t31_tx(t31_state_t *s, int16_t amp[], int max_len) { int len; @@ -2888,8 +2872,8 @@ SPAN_DECLARE_NONSTD(int) t31_tx(t31_state_t *s, int16_t amp[], int max_len) if ((len = s->audio.modems.tx_handler(s->audio.modems.tx_user_data, amp, max_len)) < max_len) { /* Allow for one change of tx handler within a block */ - set_next_tx_type(s); - if ((len += s->audio.modems.tx_handler(s->audio.modems.tx_user_data, amp + len, max_len - len)) < max_len) + fax_modems_set_next_tx_type(&s->audio.modems); + if ((len += s->audio.modems.tx_handler(s->audio.modems.tx_user_data, &[len], max_len - len)) < max_len) front_end_status(s, T30_FRONT_END_SEND_STEP_COMPLETE); /*endif*/ } @@ -2899,7 +2883,7 @@ SPAN_DECLARE_NONSTD(int) t31_tx(t31_state_t *s, int16_t amp[], int max_len) if (s->audio.modems.transmit_on_idle) { /* Pad to the requested length with silence */ - memset(amp + len, 0, (max_len - len)*sizeof(int16_t)); + memset(&[len], 0, (max_len - len)*sizeof(int16_t)); len = max_len; } /*endif*/ diff --git a/libs/spandsp/src/t38_gateway.c b/libs/spandsp/src/t38_gateway.c index 77225cc63f..c41df87c75 100644 --- a/libs/spandsp/src/t38_gateway.c +++ b/libs/spandsp/src/t38_gateway.c @@ -2061,7 +2061,8 @@ SPAN_DECLARE_NONSTD(int) t38_gateway_rx(t38_gateway_state_t *s, int16_t amp[], i for (i = 0; i < len; i++) amp[i] = dc_restore(&s->audio.modems.dc_restore, amp[i]); /*endfor*/ - s->audio.modems.rx_handler(s->audio.modems.rx_user_data, amp, len); + if (s->audio.modems.rx_handler) + s->audio.modems.rx_handler(s->audio.modems.rx_user_data, amp, len); return 0; } /*- End of function --------------------------------------------------------*/ @@ -2102,12 +2103,13 @@ SPAN_DECLARE_NONSTD(int) t38_gateway_tx(t38_gateway_state_t *s, int16_t amp[], i required_len = max_len; #endif + len = 0; if ((len = s->audio.modems.tx_handler(s->audio.modems.tx_user_data, amp, max_len)) < max_len) { if (set_next_tx_type(s)) { /* Give the new handler a chance to file the remaining buffer space */ - len += s->audio.modems.tx_handler(s->audio.modems.tx_user_data, amp + len, max_len - len); + len += s->audio.modems.tx_handler(s->audio.modems.tx_user_data, &[len], max_len - len); if (len < max_len) { silence_gen_set(&s->audio.modems.silence_gen, 0); @@ -2121,7 +2123,7 @@ SPAN_DECLARE_NONSTD(int) t38_gateway_tx(t38_gateway_state_t *s, int16_t amp[], i if (s->audio.modems.transmit_on_idle) { /* Pad to the requested length with silence */ - memset(amp + len, 0, (max_len - len)*sizeof(int16_t)); + memset(&[len], 0, (max_len - len)*sizeof(int16_t)); len = max_len; } /*endif*/ @@ -2129,7 +2131,7 @@ SPAN_DECLARE_NONSTD(int) t38_gateway_tx(t38_gateway_state_t *s, int16_t amp[], i if (s->audio.modems.audio_tx_log >= 0) { if (len < required_len) - memset(amp + len, 0, (required_len - len)*sizeof(int16_t)); + memset(&[len], 0, (required_len - len)*sizeof(int16_t)); /*endif*/ write(s->audio.modems.audio_tx_log, amp, required_len*sizeof(int16_t)); } diff --git a/libs/spandsp/tests/super_tone_tx_tests.c b/libs/spandsp/tests/super_tone_tx_tests.c index 561b333c36..9f32ea6c78 100644 --- a/libs/spandsp/tests/super_tone_tx_tests.c +++ b/libs/spandsp/tests/super_tone_tx_tests.c @@ -41,7 +41,6 @@ #include #include #include -#include #include #if defined(HAVE_LIBXML_XMLMEMORY_H) diff --git a/src/fs_encode.c b/src/fs_encode.c index 83b5484e5e..417ff7dc2f 100644 --- a/src/fs_encode.c +++ b/src/fs_encode.c @@ -129,7 +129,8 @@ int main(int argc, char *argv[]) } switch_loadable_module_init(SWITCH_FALSE); - + switch_loadable_module_load_module("", "CORE_PCM_MODULE", SWITCH_TRUE, &err); + for (i = 0; i < extra_modules_count; i++) { if (switch_loadable_module_load_module((char *) SWITCH_GLOBAL_dirs.mod_dir, (char *) extra_modules[i], SWITCH_TRUE, &err) != SWITCH_STATUS_SUCCESS) { fprintf(stderr, "Cannot init %s [%s]\n", extra_modules[i], err); diff --git a/src/include/cc.h b/src/include/cc.h index 965aa9cbac..d2635f3b1c 100644 --- a/src/include/cc.h +++ b/src/include/cc.h @@ -1,4 +1,4 @@ -const char *cc = ".========================================================================================================.\n| ____ _____ ____ _ ____ _ _ _____ |\n| / ___|___ _ __ ___ ___ |_ _|__ / ___| |_ _ ___ / ___|___ _ __ ( ) |___ / |\n| | | / _ \\| '_ ` _ \\ / _ \\ | |/ _ \\ | | | | | | |/ _ \\ | / _ \\| '_ \\ |/| | |_ \\ |\n| | |__| (_) | | | | | | __/ | | (_) | | |___| | |_| | __/ |__| (_) | | | | | |___) | |\n| \\____\\___/|_| |_| |_|\\___| |_|\\___/ \\____|_|\\__,_|\\___|\\____\\___/|_| |_| |_|____/ |\n| |\n| ____ _ _ _ _ ____ _ |\n| / ___| |__ (_) ___ __ _ __ _ ___ | | | / ___| / \\ |\n| | | | '_ \\| |/ __/ _` |/ _` |/ _ \\ | | | \\___ \\ / _ \\ |\n| | |___| | | | | (_| (_| | (_| | (_) | | |_| |___) / ___ \\ |\n| \\____|_| |_|_|\\___\\__,_|\\__, |\\___( ) \\___/|____/_/ \\_\\ |\n| |___/ |/ |\n| _ _ __ _ _ ___ _ _ ____ ___ _ _____ |\n| / \\ _ _ __ _ _ _ ___| |_ / /_ | |_| |__ ( _ )| |_| |__ |___ \\ / _ \\/ |___ / |\n| / _ \\| | | |/ _` | | | / __| __| | '_ \\| __| '_ \\ _____ / _ \\| __| '_ \\ __) | | | | | |_ \\ |\n| / ___ \\ |_| | (_| | |_| \\__ \\ |_ | (_) | |_| | | | |_____| | (_) | |_| | | | / __/| |_| | |___) | |\n| /_/ \\_\\__,_|\\__, |\\__,_|___/\\__| \\___/ \\__|_| |_| \\___/ \\__|_| |_| |_____|\\___/|_|____/ |\n| |___/ |\n| _ |\n| __ ____ ____ __ ___| |_ _ ___ ___ ___ _ __ ___ ___ _ __ ___ |\n| \\ \\ /\\ / /\\ \\ /\\ / /\\ \\ /\\ / / / __| | | | |/ _ \\/ __/ _ \\| '_ \\ / __/ _ \\| '_ ` _ \\ |\n| \\ V V / \\ V V / \\ V V / _ | (__| | |_| | __/ (_| (_) | | | | _ | (_| (_) | | | | | | |\n| \\_/\\_/ \\_/\\_/ \\_/\\_/ (_) \\___|_|\\__,_|\\___|\\___\\___/|_| |_| (_) \\___\\___/|_| |_| |_| |\n| |\n.========================================================================================================.\n"; +const char *cc = ".=======================================================================================================.\n| ____ _ ____ |\n| / ___| |_ _ ___ / ___|___ _ __ |\n| | | | | | | |/ _ \\ | / _ \\| '_ \\ |\n| | |___| | |_| | __/ |__| (_) | | | | |\n| \\____|_|\\__,_|\\___|\\____\\___/|_| |_| |\n| |\n| _____ _ _ ____ __ |\n| |_ _|__| | ___ _ __ | |__ ___ _ __ _ _ / ___|___ _ __ / _| ___ _ __ ___ _ __ ___ ___ |\n| | |/ _ \\ |/ _ \\ '_ \\| '_ \\ / _ \\| '_ \\| | | | | | / _ \\| '_ \\| |_ / _ \\ '__/ _ \\ '_ \\ / __/ _ \\ |\n| | | __/ | __/ |_) | | | | (_) | | | | |_| | | |__| (_) | | | | _| __/ | | __/ | | | (_| __/ |\n| |_|\\___|_|\\___| .__/|_| |_|\\___/|_| |_|\\__, | \\____\\___/|_| |_|_| \\___|_| \\___|_| |_|\\___\\___| |\n| |_| |___/ |\n| _____ _ _ |\n| | ____|_ _____ _ __ _ _ / \\ _ _ __ _ _ _ ___| |_ |\n| | _| \\ \\ / / _ \\ '__| | | | / _ \\| | | |/ _` | | | / __| __| |\n| | |___ \\ V / __/ | | |_| | / ___ \\ |_| | (_| | |_| \\__ \\ |_ |\n| |_____| \\_/ \\___|_| \\__, | /_/ \\_\\__,_|\\__, |\\__,_|___/\\__| |\n| |___/ |___/ |\n| ____ _ ____ |\n| __ ____ ____ __ / ___| |_ _ ___ / ___|___ _ __ ___ ___ _ __ ___ |\n| \\ \\ /\\ / /\\ \\ /\\ / /\\ \\ /\\ / / | | | | | | |/ _ \\ | / _ \\| '_ \\ / __/ _ \\| '_ ` _ \\ |\n| \\ V V / \\ V V / \\ V V / _ | |___| | |_| | __/ |__| (_) | | | | _ | (_| (_) | | | | | | |\n| \\_/\\_/ \\_/\\_/ \\_/\\_/ (_) \\____|_|\\__,_|\\___|\\____\\___/|_| |_| (_) \\___\\___/|_| |_| |_| |\n| |\n.=======================================================================================================.\n"; const char *cc_s = ".===============================================================.\n| _ |\n| ___| |_ _ ___ ___ ___ _ __ ___ ___ _ __ ___ |\n| / __| | | | |/ _ \\/ __/ _ \\| '_ \\ / __/ _ \\| '_ ` _ \\ |\n| | (__| | |_| | __/ (_| (_) | | | | _ | (_| (_) | | | | | | |\n| \\___|_|\\__,_|\\___|\\___\\___/|_| |_| (_) \\___\\___/|_| |_| |_| |\n| |\n.===============================================================.\n"; diff --git a/src/include/private/switch_core_pvt.h b/src/include/private/switch_core_pvt.h index fffd51abac..f6d3474386 100644 --- a/src/include/private/switch_core_pvt.h +++ b/src/include/private/switch_core_pvt.h @@ -290,10 +290,14 @@ struct switch_session_manager { switch_queue_t *thread_queue; switch_thread_t *manager_thread; switch_mutex_t *mutex; + switch_thread_cond_t *cond; + switch_mutex_t *cond_mutex; + switch_mutex_t *cond2_mutex; int ready; int running; int busy; int popping; + int starting; }; extern struct switch_session_manager session_manager; diff --git a/src/include/switch_core.h b/src/include/switch_core.h index 8f02987281..064ab56324 100644 --- a/src/include/switch_core.h +++ b/src/include/switch_core.h @@ -1751,7 +1751,7 @@ SWITCH_DECLARE(void) switch_core_db_test_reactive(switch_core_db_t *db, char *te SWITCH_DECLARE(switch_status_t) switch_core_perform_file_open(const char *file, const char *func, int line, _In_ switch_file_handle_t *fh, _In_opt_z_ const char *file_path, - _In_ uint8_t channels, + _In_ uint32_t channels, _In_ uint32_t rate, _In_ unsigned int flags, _In_opt_ switch_memory_pool_t *pool); /*! diff --git a/src/include/switch_module_interfaces.h b/src/include/switch_module_interfaces.h index b4ea5a4bc8..b6f4f11554 100644 --- a/src/include/switch_module_interfaces.h +++ b/src/include/switch_module_interfaces.h @@ -310,7 +310,7 @@ struct switch_file_handle { /*! the current native samplerate */ uint32_t native_rate; /*! the number of channels */ - uint8_t channels; + uint32_t channels; /*! integer representation of the format */ unsigned int format; /*! integer representation of the sections */ @@ -353,6 +353,8 @@ struct switch_file_handle { const char *prefix; int max_samples; switch_event_t *params; + uint32_t cur_channels; + uint32_t cur_samplerate; }; /*! \brief Abstract interface to an asr module */ diff --git a/src/include/switch_types.h b/src/include/switch_types.h index 9c86e56ae9..27a88dcc73 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -1041,7 +1041,9 @@ typedef enum { SWITCH_STATUS_FOUND, SWITCH_STATUS_CONTINUE, SWITCH_STATUS_TERM, - SWITCH_STATUS_NOT_INITALIZED + SWITCH_STATUS_NOT_INITALIZED, + SWITCH_STATUS_XBREAK = 35, + SWITCH_STATUS_WINBREAK = 730035 } switch_status_t; @@ -1615,7 +1617,8 @@ typedef enum { SWITCH_FILE_BUFFER_DONE = (1 << 14), SWITCH_FILE_WRITE_APPEND = (1 << 15), SWITCH_FILE_WRITE_OVER = (1 << 16), - SWITCH_FILE_NOMUX = (1 << 17) + SWITCH_FILE_NOMUX = (1 << 17), + SWITCH_FILE_BREAK_ON_CHANGE = (1 << 18) } switch_file_flag_enum_t; typedef uint32_t switch_file_flag_t; diff --git a/src/mod/applications/mod_callcenter/mod_callcenter.c b/src/mod/applications/mod_callcenter/mod_callcenter.c index 4e9e852aa9..3286cea05a 100644 --- a/src/mod/applications/mod_callcenter/mod_callcenter.c +++ b/src/mod/applications/mod_callcenter/mod_callcenter.c @@ -24,6 +24,7 @@ * Contributor(s): * * Marc Olivier Chouinard + * Emmanuel Schmidbauer * * * mod_callcenter.c -- Call Center Module @@ -1452,9 +1453,12 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa switch_channel_process_export(member_channel, NULL, ovars, "cc_export_vars"); t_agent_called = local_epoch_time_now(NULL); - dialstr = switch_mprintf("%s", h->originate_string); + + dialstr = switch_channel_expand_variables(member_channel, h->originate_string); status = switch_ivr_originate(NULL, &agent_session, &cause, dialstr, 60, NULL, cid_name ? cid_name : h->member_cid_name, h->member_cid_number, NULL, ovars, SOF_NONE, NULL); - switch_safe_free(dialstr); + if (dialstr != h->originate_string) { + switch_safe_free(dialstr); + } switch_safe_free(cid_name); switch_event_destroy(&ovars); diff --git a/src/mod/applications/mod_commands/mod_commands.c b/src/mod/applications/mod_commands/mod_commands.c index 2b7804dd31..97ec23f9c9 100644 --- a/src/mod/applications/mod_commands/mod_commands.c +++ b/src/mod/applications/mod_commands/mod_commands.c @@ -1329,6 +1329,8 @@ SWITCH_STANDARD_API(stun_function) switch_port_t port = 0; switch_memory_pool_t *pool = NULL; char *error = ""; + char *argv[3] = { 0 }; + char *mycmd = NULL; ip = ip_buf; @@ -1337,9 +1339,15 @@ SWITCH_STANDARD_API(stun_function) return SWITCH_STATUS_SUCCESS; } - stun_ip = strdup(cmd); + mycmd = strdup(cmd); + switch_split(mycmd, ' ', argv); + + stun_ip = argv[0]; + switch_assert(stun_ip); + port = argv[1] ? atoi(argv[1]) : 0; + if ((p = strchr(stun_ip, ':'))) { int iport; *p++ = '\0'; @@ -1374,7 +1382,7 @@ SWITCH_STANDARD_API(stun_function) } switch_core_destroy_memory_pool(&pool); - free(stun_ip); + switch_safe_free(mycmd); return SWITCH_STATUS_SUCCESS; } @@ -4608,7 +4616,6 @@ SWITCH_STANDARD_API(show_function) char *command = NULL, *as = NULL; switch_core_flag_t cflags = switch_core_flags(); switch_status_t status = SWITCH_STATUS_SUCCESS; - const char *hostname = switch_core_get_switchname(); int html = 0; char *nl = "\n"; stream_format format = { 0 }; @@ -4661,33 +4668,33 @@ SWITCH_STANDARD_API(show_function) if (end_of(command) == 's') { end_of(command) = '\0'; } - sprintf(sql, "select type, name, ikey from interfaces where hostname='%s' and type = '%s' order by type,name", hostname, command); + sprintf(sql, "select type, name, ikey from interfaces where hostname='%s' and type = '%s' order by type,name", switch_core_get_hostname(), command); } else if (!strncasecmp(command, "module", 6)) { if (argv[1] && strcasecmp(argv[1], "as")) { sprintf(sql, "select distinct type, name, ikey, filename from interfaces where hostname='%s' and ikey = '%s' order by type,name", - hostname, argv[1]); + switch_core_get_hostname(), argv[1]); } else { - sprintf(sql, "select distinct type, name, ikey, filename from interfaces where hostname='%s' order by type,name", hostname); + sprintf(sql, "select distinct type, name, ikey, filename from interfaces where hostname='%s' order by type,name", switch_core_get_hostname()); } } else if (!strcasecmp(command, "interfaces")) { - sprintf(sql, "select type, name, ikey from interfaces where hostname='%s' order by type,name", hostname); + sprintf(sql, "select type, name, ikey from interfaces where hostname='%s' order by type,name", switch_core_get_hostname()); } else if (!strcasecmp(command, "interface_types")) { - sprintf(sql, "select type,count(type) as total from interfaces where hostname='%s' group by type order by type", hostname); + sprintf(sql, "select type,count(type) as total from interfaces where hostname='%s' group by type order by type", switch_core_get_switchname()); } else if (!strcasecmp(command, "tasks")) { - sprintf(sql, "select * from %s where hostname='%s'", command, hostname); + sprintf(sql, "select * from %s where hostname='%s'", command, switch_core_get_hostname()); } else if (!strcasecmp(command, "application") || !strcasecmp(command, "api")) { if (argv[1] && strcasecmp(argv[1], "as")) { sprintf(sql, "select name, description, syntax, ikey from interfaces where hostname='%s' and type = '%s' and description != '' and name = '%s' order by type,name", - hostname, command, argv[1]); + switch_core_get_hostname(), command, argv[1]); } else { - sprintf(sql, "select name, description, syntax, ikey from interfaces where hostname='%s' and type = '%s' and description != '' order by type,name", hostname, command); + sprintf(sql, "select name, description, syntax, ikey from interfaces where hostname='%s' and type = '%s' and description != '' order by type,name", switch_core_get_hostname(), command); } /* moved refreshable webpage show commands i.e. show calls|registrations|channels||detailed_calls|bridged_calls|detailed_bridged_calls */ } else if (!strcasecmp(command, "aliases")) { - sprintf(sql, "select * from aliases where hostname='%s' order by alias", hostname); + sprintf(sql, "select * from aliases where hostname='%s' order by alias", switch_core_get_switchname()); } else if (!strcasecmp(command, "complete")) { - sprintf(sql, "select * from complete where hostname='%s' order by a1,a2,a3,a4,a5,a6,a7,a8,a9,a10", hostname); + sprintf(sql, "select * from complete where hostname='%s' order by a1,a2,a3,a4,a5,a6,a7,a8,a9,a10", switch_core_get_switchname()); } else if (!strncasecmp(command, "help", 4)) { char *cmdname = NULL; @@ -4697,9 +4704,9 @@ SWITCH_STANDARD_API(show_function) *cmdname++ = '\0'; switch_snprintfv(sql, sizeof(sql), "select name, syntax, description, ikey from interfaces where hostname='%s' and type = 'api' and name = '%q' order by name", - hostname, cmdname); + switch_core_get_hostname(), cmdname); } else { - switch_snprintfv(sql, sizeof(sql), "select name, syntax, description, ikey from interfaces where hostname='%q' and type = 'api' order by name", hostname); + switch_snprintfv(sql, sizeof(sql), "select name, syntax, description, ikey from interfaces where hostname='%q' and type = 'api' order by name", switch_core_get_hostname()); } } else if (!strcasecmp(command, "nat_map")) { switch_snprintf(sql, sizeof(sql) - 1, @@ -4707,7 +4714,7 @@ SWITCH_STANDARD_API(show_function) " CASE proto " " WHEN 0 THEN 'udp' " " WHEN 1 THEN 'tcp' " - " ELSE 'unknown' " " END AS proto, " " proto AS proto_num, " " sticky " " FROM nat where hostname='%s' ORDER BY port, proto", hostname); + " ELSE 'unknown' " " END AS proto, " " proto AS proto_num, " " sticky " " FROM nat where hostname='%s' ORDER BY port, proto", switch_core_get_hostname()); } else { /* from here on refreshable commands: calls|registrations|channels||detailed_calls|bridged_calls|detailed_bridged_calls */ if (holder.format->api) { @@ -4726,18 +4733,18 @@ SWITCH_STANDARD_API(show_function) } if (!strcasecmp(command, "calls")) { - sprintf(sql, "select * from basic_calls where hostname='%s' order by call_created_epoch", hostname); + sprintf(sql, "select * from basic_calls where hostname='%s' order by call_created_epoch", switch_core_get_switchname()); if (argv[1] && !strcasecmp(argv[1], "count")) { - sprintf(sql, "select count(*) from basic_calls where hostname='%s'", hostname); + sprintf(sql, "select count(*) from basic_calls where hostname='%s'", switch_core_get_switchname()); holder.justcount = 1; if (argv[3] && !strcasecmp(argv[2], "as")) { as = argv[3]; } } } else if (!strcasecmp(command, "registrations")) { - sprintf(sql, "select * from registrations where hostname='%s'", hostname); + sprintf(sql, "select * from registrations where hostname='%s'", switch_core_get_switchname()); if (argv[1] && !strcasecmp(argv[1], "count")) { - sprintf(sql, "select count(*) from registrations where hostname='%s'", hostname); + sprintf(sql, "select count(*) from registrations where hostname='%s'", switch_core_get_switchname()); holder.justcount = 1; if (argv[3] && !strcasecmp(argv[2], "as")) { as = argv[3]; @@ -4754,39 +4761,39 @@ SWITCH_STANDARD_API(show_function) if (strchr(argv[2], '%')) { sprintf(sql, "select * from channels where hostname='%s' and uuid like '%s' or name like '%s' or cid_name like '%s' or cid_num like '%s' or presence_data like '%s' order by created_epoch", - hostname, argv[2], argv[2], argv[2], argv[2], argv[2]); + switch_core_get_switchname(), argv[2], argv[2], argv[2], argv[2], argv[2]); } else { sprintf(sql, "select * from channels where hostname='%s' and uuid like '%%%s%%' or name like '%%%s%%' or cid_name like '%%%s%%' or cid_num like '%%%s%%' or presence_data like '%%%s%%' order by created_epoch", - hostname, argv[2], argv[2], argv[2], argv[2], argv[2]); + switch_core_get_switchname(), argv[2], argv[2], argv[2], argv[2], argv[2]); } if (argv[4] && !strcasecmp(argv[3], "as")) { as = argv[4]; } } else { - sprintf(sql, "select * from channels where hostname='%s' order by created_epoch", hostname); + sprintf(sql, "select * from channels where hostname='%s' order by created_epoch", switch_core_get_switchname()); } } else if (!strcasecmp(command, "channels")) { - sprintf(sql, "select * from channels where hostname='%s' order by created_epoch", hostname); + sprintf(sql, "select * from channels where hostname='%s' order by created_epoch", switch_core_get_switchname()); if (argv[1] && !strcasecmp(argv[1], "count")) { - sprintf(sql, "select count(*) from channels where hostname='%s'", hostname); + sprintf(sql, "select count(*) from channels where hostname='%s'", switch_core_get_switchname()); holder.justcount = 1; if (argv[3] && !strcasecmp(argv[2], "as")) { as = argv[3]; } } } else if (!strcasecmp(command, "detailed_calls")) { - sprintf(sql, "select * from detailed_calls where hostname='%s' order by created_epoch", hostname); + sprintf(sql, "select * from detailed_calls where hostname='%s' order by created_epoch", switch_core_get_switchname()); if (argv[2] && !strcasecmp(argv[1], "as")) { as = argv[2]; } } else if (!strcasecmp(command, "bridged_calls")) { - sprintf(sql, "select * from basic_calls where b_uuid is not null and hostname='%s' order by created_epoch", hostname); + sprintf(sql, "select * from basic_calls where b_uuid is not null and hostname='%s' order by created_epoch", switch_core_get_switchname()); if (argv[2] && !strcasecmp(argv[1], "as")) { as = argv[2]; } } else if (!strcasecmp(command, "detailed_bridged_calls")) { - sprintf(sql, "select * from detailed_calls where b_uuid is not null and hostname='%s' order by created_epoch", hostname); + sprintf(sql, "select * from detailed_calls where b_uuid is not null and hostname='%s' order by created_epoch", switch_core_get_switchname()); if (argv[2] && !strcasecmp(argv[1], "as")) { as = argv[2]; } diff --git a/src/mod/applications/mod_conference/mod_conference.c b/src/mod/applications/mod_conference/mod_conference.c index 111e4ef917..db38e5c7eb 100644 --- a/src/mod/applications/mod_conference/mod_conference.c +++ b/src/mod/applications/mod_conference/mod_conference.c @@ -286,6 +286,17 @@ struct vid_helper { int up; }; +struct conference_obj; + +/* Record Node */ +typedef struct conference_record { + struct conference_obj *conference; + char *path; + switch_memory_pool_t *pool; + switch_bool_t autorec; + struct conference_record *next; +} conference_record_t; + /* Conference Object */ typedef struct conference_obj { char *name; @@ -352,7 +363,7 @@ typedef struct conference_obj { int pin_retries; int broadcast_chat_messages; int comfort_noise_level; - int is_recording; + int auto_recording; int record_count; int video_running; int ivr_dtmf_timeout; @@ -385,6 +396,7 @@ typedef struct conference_obj { cdr_event_mode_t cdr_event_mode; struct vid_helper vh[2]; struct vid_helper mh; + conference_record_t *rec_node_head; } conference_obj_t; /* Relationship with another member */ @@ -421,6 +433,7 @@ struct conference_member { switch_codec_t write_codec; char *rec_path; switch_time_t rec_time; + conference_record_t *rec; uint8_t *frame; uint8_t *last_frame; uint32_t frame_size; @@ -455,13 +468,6 @@ struct conference_member { switch_thread_t *input_thread; }; -/* Record Node */ -typedef struct conference_record { - conference_obj_t *conference; - char *path; - switch_memory_pool_t *pool; -} conference_record_t; - typedef enum { CONF_API_SUB_ARGS_SPLIT, CONF_API_SUB_MEMBER_TARGET, @@ -529,7 +535,7 @@ static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_c static switch_status_t chat_send(switch_event_t *message_event); -static void launch_conference_record_thread(conference_obj_t *conference, char *path); +static void launch_conference_record_thread(conference_obj_t *conference, char *path, switch_bool_t autorec); static int launch_conference_video_bridge_thread(conference_member_t *member_a, conference_member_t *member_b); typedef switch_status_t (*conf_api_args_cmd_t) (conference_obj_t *, switch_stream_handle_t *, int, char **); @@ -547,7 +553,6 @@ static switch_status_t conference_add_event_member_data(conference_member_t *mem static switch_status_t conf_api_sub_floor(conference_member_t *member, switch_stream_handle_t *stream, void *data); static switch_status_t conf_api_sub_vid_floor(conference_member_t *member, switch_stream_handle_t *stream, void *data); static switch_status_t conf_api_sub_clear_vid_floor(conference_obj_t *conference, switch_stream_handle_t *stream, void *data); -static switch_status_t conf_api_sub_enforce_floor(conference_member_t *member, switch_stream_handle_t *stream, void *data); #define lock_member(_member) switch_mutex_lock(_member->write_mutex); switch_mutex_lock(_member->read_mutex) @@ -1217,7 +1222,7 @@ static conference_member_t *conference_member_get(conference_obj_t *conference, } /* stop the specified recording */ -static switch_status_t conference_record_stop(conference_obj_t *conference, char *path) +static switch_status_t conference_record_stop(conference_obj_t *conference, switch_stream_handle_t *stream, char *path) { conference_member_t *member = NULL; int count = 0; @@ -1226,10 +1231,21 @@ static switch_status_t conference_record_stop(conference_obj_t *conference, char switch_mutex_lock(conference->member_mutex); for (member = conference->members; member; member = member->next) { if (switch_test_flag(member, MFLAG_NOCHANNEL) && (!path || !strcmp(path, member->rec_path))) { + if (member->rec && member->rec->autorec) { + stream->write_function(stream, "Stopped AUTO recording file %s (Auto Recording Now Disabled)\n", member->rec_path); + conference->auto_record = 0; + } else { + stream->write_function(stream, "Stopped recording file %s\n", member->rec_path); + } + switch_clear_flag_locked(member, MFLAG_RUNNING); count++; + } } + + conference->record_count -= count; + switch_mutex_unlock(conference->member_mutex); return count; } @@ -2067,7 +2083,7 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v globals.threads++; switch_mutex_unlock(globals.hash_mutex); - conference->is_recording = 0; + conference->auto_recording = 0; conference->record_count = 0; @@ -2169,15 +2185,15 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v } /* Start recording if there's more than one participant. */ - if (conference->auto_record && !conference->is_recording && conference->count > 1) { - conference->is_recording = 1; + if (conference->auto_record && !conference->auto_recording && conference->count > 1) { + conference->auto_recording++; conference->record_count++; imember = conference->members; if (imember) { switch_channel_t *channel = switch_core_session_get_channel(imember->session); char *rfile = switch_channel_expand_variables(channel, conference->auto_record); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Auto recording file: %s\n", rfile); - launch_conference_record_thread(conference, rfile); + launch_conference_record_thread(conference, rfile, SWITCH_TRUE); if (rfile != conference->auto_record) { conference->record_filename = switch_core_strdup(conference->pool, rfile); switch_safe_free(rfile); @@ -2607,13 +2623,6 @@ static void conference_loop_fn_vid_floor_force(conference_member_t *member, call conf_api_sub_vid_floor(member, NULL, "force"); } -static void conference_loop_fn_enforce_floor(conference_member_t *member, caller_control_action_t *action) -{ - if (member == NULL) return; - - conf_api_sub_enforce_floor(member, NULL, NULL); -} - static void conference_loop_fn_mute_toggle(conference_member_t *member, caller_control_action_t *action) { if (member == NULL) @@ -3185,7 +3194,7 @@ static void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, v if (switch_core_session_read_lock(session) != SWITCH_STATUS_SUCCESS) { - return NULL; + goto end; } switch_assert(member != NULL); @@ -3482,10 +3491,12 @@ static void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, v switch_resample_destroy(&member->read_resampler); - switch_clear_flag_locked(member, MFLAG_ITHREAD); - switch_core_session_rwunlock(session); + end: + + switch_clear_flag_locked(member, MFLAG_ITHREAD); + return NULL; } @@ -3583,7 +3594,9 @@ static void launch_conference_loop_input(conference_member_t *member, switch_mem switch_threadattr_create(&thd_attr, pool); switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE); switch_set_flag_locked(member, MFLAG_ITHREAD); - switch_thread_create(&member->input_thread, thd_attr, conference_loop_input, member, pool); + if (switch_thread_create(&member->input_thread, thd_attr, conference_loop_input, member, pool) != SWITCH_STATUS_SUCCESS) { + switch_clear_flag_locked(member, MFLAG_ITHREAD); + } } /* marshall frames from the conference (or file or tts output) to the call leg */ @@ -3919,6 +3932,7 @@ static void conference_loop_output(conference_member_t *member) switch_clear_flag_locked(member, MFLAG_RUNNING); + /* Wait for the input thread to end */ if (member->input_thread) { switch_thread_join(&st, member->input_thread); } @@ -3932,11 +3946,6 @@ static void conference_loop_output(conference_member_t *member) if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { member->conference->bridge_hangup_cause = switch_channel_get_cause(channel); } - - /* Wait for the input thread to end */ - while (switch_test_flag(member, MFLAG_ITHREAD)) { - switch_cond_next(); - } } /* Sub-Routine called by a record entity inside a conference */ @@ -3945,7 +3954,7 @@ static void *SWITCH_THREAD_FUNC conference_record_thread_run(switch_thread_t *th int16_t *data_buf; switch_file_handle_t fh = { 0 }; conference_member_t smember = { 0 }, *member; - conference_record_t *rec = (conference_record_t *) obj; + conference_record_t *rp, *last = NULL, *rec = (conference_record_t *) obj; conference_obj_t *conference = rec->conference; uint32_t samples = switch_samples_per_packet(conference->rate, conference->interval); uint32_t mux_used; @@ -3983,7 +3992,7 @@ static void *SWITCH_THREAD_FUNC conference_record_thread_run(switch_thread_t *th fh.samplerate = conference->rate; member->id = next_member_id(); member->pool = rec->pool; - + member->rec = rec; member->frame_size = SWITCH_RECOMMENDED_BUFFER_SIZE; member->frame = switch_core_alloc(member->pool, member->frame_size); member->mux_frame = switch_core_alloc(member->pool, member->frame_size); @@ -4126,8 +4135,6 @@ static void *SWITCH_THREAD_FUNC conference_record_thread_run(switch_thread_t *th switch_mutex_unlock(member->audio_out_mutex); } - conference->is_recording = 0; - switch_safe_free(data_buf); switch_core_timer_destroy(&timer); conference_del_member(conference, member); @@ -4146,6 +4153,23 @@ static void *SWITCH_THREAD_FUNC conference_record_thread_run(switch_thread_t *th switch_event_fire(&event); } + if (rec->autorec && conference->auto_recording) { + conference->auto_recording--; + } + + switch_mutex_lock(conference->flag_mutex); + for (rp = conference->rec_node_head; rp; rp = rp->next) { + if (rec == rp) { + if (last) { + last->next = rp->next; + } else { + conference->rec_node_head = rp->next; + } + } + } + switch_mutex_unlock(conference->flag_mutex); + + if (rec->pool) { switch_memory_pool_t *pool = rec->pool; rec = NULL; @@ -5390,26 +5414,6 @@ static switch_status_t conf_api_sub_vid_floor(conference_member_t *member, switc return SWITCH_STATUS_SUCCESS; } -static switch_status_t conf_api_sub_enforce_floor(conference_member_t *member, switch_stream_handle_t *stream, void *data) -{ - if (member == NULL) - return SWITCH_STATUS_GENERR; - - switch_mutex_lock(member->conference->mutex); - - if (member->conference->floor_holder != member) { - conference_set_floor_holder(member->conference, member); - - if (stream != NULL) { - stream->write_function(stream, "OK floor %u\n", member->id); - } - } - - switch_mutex_unlock(member->conference->mutex); - - return SWITCH_STATUS_SUCCESS; -} - static switch_xml_t add_x_tag(switch_xml_t x_member, const char *name, const char *value, int off) { switch_size_t dlen; @@ -6278,11 +6282,20 @@ static switch_status_t conf_api_sub_transfer(conference_obj_t *conference, switc static switch_status_t conf_api_sub_check_record(conference_obj_t *conference, switch_stream_handle_t *stream, int arc, char **argv) { - if (conference->is_recording) { - stream->write_function(stream, "Record file %s\n", conference->record_filename); - } else { + conference_record_t *rec; + int x = 0; + + switch_mutex_lock(conference->flag_mutex); + for (rec = conference->rec_node_head; rec; rec = rec->next) { + stream->write_function(stream, "Record file %s%s%s\n", rec->path, rec->autorec ? " " : "", rec->autorec ? "(Auto)" : ""); + x++; + } + + if (!x) { stream->write_function(stream, "Conference is not being recorded.\n"); } + switch_mutex_unlock(conference->flag_mutex); + return SWITCH_STATUS_SUCCESS; } @@ -6291,19 +6304,20 @@ static switch_status_t conf_api_sub_record(conference_obj_t *conference, switch_ switch_assert(conference != NULL); switch_assert(stream != NULL); - if (argc <= 2) + if (argc <= 2) { return SWITCH_STATUS_GENERR; + } stream->write_function(stream, "Record file %s\n", argv[2]); conference->record_filename = switch_core_strdup(conference->pool, argv[2]); conference->record_count++; - launch_conference_record_thread(conference, argv[2]); + launch_conference_record_thread(conference, argv[2], SWITCH_FALSE); return SWITCH_STATUS_SUCCESS; } static switch_status_t conf_api_sub_norecord(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv) { - int all; + int all, before = conference->record_count, ttl = 0; switch_event_t *event; switch_assert(conference != NULL); @@ -6313,15 +6327,10 @@ static switch_status_t conf_api_sub_norecord(conference_obj_t *conference, switc return SWITCH_STATUS_GENERR; all = (strcasecmp(argv[2], "all") == 0); - stream->write_function(stream, "Stop recording file %s\n", argv[2]); - if (!conference_record_stop(conference, all ? NULL : argv[2]) && !all) { + + if (!conference_record_stop(conference, stream, all ? NULL : argv[2]) && !all) { stream->write_function(stream, "non-existant recording '%s'\n", argv[2]); } else { - if (all) { - conference->record_count = 0; - } else { - conference->record_count--; - } if (test_eflag(conference, EFLAG_RECORD) && switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) { conference_add_event_data(conference, event); @@ -6332,6 +6341,9 @@ static switch_status_t conf_api_sub_norecord(conference_obj_t *conference, switc } } + ttl = before - conference->record_count; + stream->write_function(stream, "Stopped recording %d file%s\n", ttl, ttl == 1 ? "" : "s"); + return SWITCH_STATUS_SUCCESS; } @@ -6383,6 +6395,13 @@ static switch_status_t conf_api_sub_recording(conference_obj_t *conference, swit switch_assert(conference != NULL); switch_assert(stream != NULL); + if (argc > 2 && argc <= 3) { + if (strcasecmp(argv[2], "stop") == 0 || strcasecmp(argv[2], "check") == 0) { + argv[3] = "all"; + argc++; + } + } + if (argc <= 3) { /* It means that old syntax is used */ return conf_api_sub_record(conference,stream,argc,argv); @@ -6604,8 +6623,7 @@ static api_command_t conf_api_sub_commands[] = { {"set", (void_fn_t) & conf_api_sub_set, CONF_API_SUB_ARGS_SPLIT, "set", " "}, {"floor", (void_fn_t) & conf_api_sub_floor, CONF_API_SUB_MEMBER_TARGET, "floor", ""}, {"vid-floor", (void_fn_t) & conf_api_sub_vid_floor, CONF_API_SUB_MEMBER_TARGET, "vid-floor", " [force]"}, - {"clear-vid-floor", (void_fn_t) & conf_api_sub_clear_vid_floor, CONF_API_SUB_ARGS_AS_ONE, "clear-vid-floor", ""}, - {"enforce_floor", (void_fn_t) & conf_api_sub_enforce_floor, CONF_API_SUB_MEMBER_TARGET, "enforce_floor", ""}, + {"clear-vid-floor", (void_fn_t) & conf_api_sub_clear_vid_floor, CONF_API_SUB_ARGS_AS_ONE, "clear-vid-floor", ""} }; #define CONFFUNCAPISIZE (sizeof(conf_api_sub_commands)/sizeof(conf_api_sub_commands[0])) @@ -8117,9 +8135,7 @@ static int launch_conference_video_bridge_thread(conference_member_t *member_a, } - - -static void launch_conference_record_thread(conference_obj_t *conference, char *path) +static void launch_conference_record_thread(conference_obj_t *conference, char *path, switch_bool_t autorec) { switch_thread_t *thread; switch_threadattr_t *thd_attr = NULL; @@ -8138,11 +8154,15 @@ static void launch_conference_record_thread(conference_obj_t *conference, char * return; } - conference->is_recording = 1; - rec->conference = conference; rec->path = switch_core_strdup(pool, path); rec->pool = pool; + rec->autorec = autorec; + + switch_mutex_lock(conference->flag_mutex); + rec->next = conference->rec_node_head; + conference->rec_node_head = rec; + switch_mutex_unlock(conference->flag_mutex); switch_threadattr_create(&thd_attr, rec->pool); switch_threadattr_detach_set(thd_attr, 1); @@ -9189,8 +9209,7 @@ static struct _mapping control_mappings[] = { {"execute_application", conference_loop_fn_exec_app}, {"floor", conference_loop_fn_floor_toggle}, {"vid-floor", conference_loop_fn_vid_floor_toggle}, - {"vid-floor-force", conference_loop_fn_vid_floor_force}, - {"enforce_floor", conference_loop_fn_enforce_floor}, + {"vid-floor-force", conference_loop_fn_vid_floor_force} }; #define MAPPING_LEN (sizeof(control_mappings)/sizeof(control_mappings[0])) diff --git a/src/mod/applications/mod_dptools/mod_dptools.c b/src/mod/applications/mod_dptools/mod_dptools.c index a05f880a4a..5fe2c57e5b 100755 --- a/src/mod/applications/mod_dptools/mod_dptools.c +++ b/src/mod/applications/mod_dptools/mod_dptools.c @@ -283,10 +283,17 @@ SWITCH_STANDARD_APP(clear_digit_action_function) { //switch_channel_t *channel = switch_core_session_get_channel(session); switch_ivr_dmachine_t *dmachine; - char *realm = switch_core_session_strdup(session, data); + char *realm = NULL; char *target_str; switch_digit_action_target_t target = DIGIT_TARGET_SELF; + if (zstr(realm)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "clear_digit_action called with no args"); + return; + } + + realm = switch_core_session_strdup(session, data); + if ((target_str = strchr(realm, ','))) { *target_str++ = '\0'; target = str2target(target_str); @@ -2538,8 +2545,8 @@ SWITCH_STANDARD_APP(play_and_get_digits_function) switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Transfer on failure = [%s].\n", transfer_on_failure); } - if (min_digits <= 1) { - min_digits = 1; + if (min_digits <= 0) { + min_digits = 0; } if (max_digits < min_digits) { @@ -4509,8 +4516,8 @@ static switch_status_t next_file(switch_file_handle_t *handle) } handle->samples = context->fh.samples; - //handle->samplerate = context->fh.samplerate; - //handle->channels = context->fh.channels; + handle->cur_samplerate = context->fh.samplerate; + handle->cur_channels = context->fh.channels; handle->format = context->fh.format; handle->sections = context->fh.sections; handle->seekable = context->fh.seekable; @@ -4518,6 +4525,7 @@ static switch_status_t next_file(switch_file_handle_t *handle) handle->interval = context->fh.interval; handle->max_samples = 0; + if (switch_test_flag((&context->fh), SWITCH_FILE_NATIVE)) { switch_set_flag(handle, SWITCH_FILE_NATIVE); } else { @@ -4602,13 +4610,19 @@ static switch_status_t file_string_file_read(switch_file_handle_t *handle, void if ((status = next_file(handle)) != SWITCH_STATUS_SUCCESS) { return status; } - *len = llen; - status = switch_core_file_read(&context->fh, data, len); + if (switch_test_flag(handle, SWITCH_FILE_BREAK_ON_CHANGE)) { + *len = 0; + status = SWITCH_STATUS_BREAK; + } else { + *len = llen; + status = switch_core_file_read(&context->fh, data, len); + } } return status; } + static switch_status_t file_string_file_write(switch_file_handle_t *handle, void *data, size_t *len) { file_string_context_t *context = handle->private_info; @@ -4627,10 +4641,101 @@ static switch_status_t file_string_file_write(switch_file_handle_t *handle, void return status; } +static switch_status_t file_url_file_seek(switch_file_handle_t *handle, unsigned int *cur_sample, int64_t samples, int whence) +{ + switch_file_handle_t *fh = handle->private_info; + return switch_core_file_seek(fh, cur_sample, samples, whence); +} + +static switch_status_t file_url_file_close(switch_file_handle_t *handle) +{ + switch_file_handle_t *fh = handle->private_info; + if (switch_test_flag(fh, SWITCH_FILE_OPEN)) { + switch_core_file_close(fh); + } + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t file_url_file_read(switch_file_handle_t *handle, void *data, size_t *len) +{ + switch_file_handle_t *fh = handle->private_info; + return switch_core_file_read(fh, data, len); +} + +static switch_status_t file_url_file_open(switch_file_handle_t *handle, const char *path) +{ + switch_file_handle_t *fh = switch_core_alloc(handle->memory_pool, sizeof(*fh)); + switch_status_t status; + char *url_host; + char *url_path; + + if (zstr(path)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "NULL path\n"); + return SWITCH_STATUS_FALSE; + } + + /* parse and check host */ + url_host = switch_core_strdup(handle->memory_pool, path); + if (!(url_path = strchr(url_host, '/'))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "missing path\n"); + return SWITCH_STATUS_FALSE; + } + *url_path = '\0'; + /* TODO allow this host */ + if (!zstr(url_host) && strcasecmp(url_host, "localhost")) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "not localhost\n"); + return SWITCH_STATUS_FALSE; + } + + /* decode and check path */ + url_path++; + if (zstr(url_path)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "empty path\n"); + return SWITCH_STATUS_FALSE; + } + if (strstr(url_path, "%2f") || strstr(url_path, "%2F")) { + /* don't allow %2f or %2F encoding (/) */ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "encoded slash is not allowed\n"); + return SWITCH_STATUS_FALSE; + } + url_path = switch_core_sprintf(handle->memory_pool, "/%s", url_path); + switch_url_decode(url_path); + + /* TODO convert to native file separators? */ + + handle->private_info = fh; + status = switch_core_file_open(fh, url_path, handle->channels, handle->samplerate, handle->flags, NULL); + if (status == SWITCH_STATUS_SUCCESS) { + handle->samples = fh->samples; + handle->cur_samplerate = fh->samplerate; + handle->cur_channels = fh->channels; + handle->format = fh->format; + handle->sections = fh->sections; + handle->seekable = fh->seekable; + handle->speed = fh->speed; + handle->interval = fh->interval; + handle->max_samples = 0; + + if (switch_test_flag(fh, SWITCH_FILE_NATIVE)) { + switch_set_flag(handle, SWITCH_FILE_NATIVE); + } else { + switch_clear_flag(handle, SWITCH_FILE_NATIVE); + } + } + return status; +} + +static switch_status_t file_url_file_write(switch_file_handle_t *handle, void *data, size_t *len) +{ + switch_file_handle_t *fh = handle->private_info; + return switch_core_file_write(fh, data, len); +} /* Registration */ static char *file_string_supported_formats[SWITCH_MAX_CODECS] = { 0 }; +static char *file_url_supported_formats[SWITCH_MAX_CODECS] = { 0 }; /* /FILE STRING INTERFACE */ @@ -5498,6 +5603,17 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_dptools_load) file_interface->file_write = file_string_file_write; file_interface->file_seek = file_string_file_seek; + file_url_supported_formats[0] = "file"; + + file_interface = (switch_file_interface_t *) switch_loadable_module_create_interface(*module_interface, SWITCH_FILE_INTERFACE); + file_interface->interface_name = modname; + file_interface->extens = file_url_supported_formats; + file_interface->file_open = file_url_file_open; + file_interface->file_close = file_url_file_close; + file_interface->file_read = file_url_file_read; + file_interface->file_write = file_url_file_write; + file_interface->file_seek = file_url_file_seek; + error_endpoint_interface = (switch_endpoint_interface_t *) switch_loadable_module_create_interface(*module_interface, SWITCH_ENDPOINT_INTERFACE); error_endpoint_interface->interface_name = "error"; @@ -5652,7 +5768,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_dptools_load) SAF_SUPPORT_NOMEDIA); SWITCH_ADD_APP(app_interface, "unbind_meta_app", "Unbind a key from an application", "Unbind a key from an application", dtmf_unbind_function, UNBIND_SYNTAX, SAF_SUPPORT_NOMEDIA); - SWITCH_ADD_APP(app_interface, "block_dfmf", "Block DTMF", "Block DTMF", dtmf_block_function, "", SAF_SUPPORT_NOMEDIA); + SWITCH_ADD_APP(app_interface, "block_dtmf", "Block DTMF", "Block DTMF", dtmf_block_function, "", SAF_SUPPORT_NOMEDIA); SWITCH_ADD_APP(app_interface, "unblock_dtmf", "Stop blocking DTMF", "Stop blocking DTMF", dtmf_unblock_function, "", SAF_SUPPORT_NOMEDIA); SWITCH_ADD_APP(app_interface, "intercept", "intercept", "intercept", intercept_function, INTERCEPT_SYNTAX, SAF_NONE); SWITCH_ADD_APP(app_interface, "eavesdrop", "eavesdrop on a uuid", "eavesdrop on a uuid", eavesdrop_function, eavesdrop_SYNTAX, SAF_MEDIA_TAP); diff --git a/src/mod/applications/mod_fifo/mod_fifo.c b/src/mod/applications/mod_fifo/mod_fifo.c index 1affefa3e4..886930f096 100644 --- a/src/mod/applications/mod_fifo/mod_fifo.c +++ b/src/mod/applications/mod_fifo/mod_fifo.c @@ -1366,7 +1366,11 @@ static void *SWITCH_THREAD_FUNC ringall_thread_run(switch_thread_t *thread, void if (!switch_event_get_header(ovars, "origination_caller_id_name")) { if ((caller_id_name = switch_event_get_header(pop, "caller-caller-id-name"))) { if (!zstr(node->outbound_name)) { - switch_event_add_header(ovars, SWITCH_STACK_BOTTOM, "origination_caller_id_name", "(%s) %s", node->outbound_name, caller_id_name); + if ( node->outbound_name[0] == '=' ) { + switch_event_add_header(ovars, SWITCH_STACK_BOTTOM, "origination_caller_id_name", "%s", node->outbound_name + 1); + } else { + switch_event_add_header(ovars, SWITCH_STACK_BOTTOM, "origination_caller_id_name", "(%s) %s", node->outbound_name, caller_id_name); + } } else { switch_event_add_header_string(ovars, SWITCH_STACK_BOTTOM, "origination_caller_id_name", caller_id_name); } diff --git a/src/mod/applications/mod_sonar/mod_sonar.c b/src/mod/applications/mod_sonar/mod_sonar.c index 4453deea90..446319b2a8 100644 --- a/src/mod/applications/mod_sonar/mod_sonar.c +++ b/src/mod/applications/mod_sonar/mod_sonar.c @@ -24,6 +24,7 @@ * Contributor(s): * * William King + * Seven Du * * mod_sonar.c -- Sonar ping timer * @@ -40,6 +41,14 @@ #include +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +#ifndef MAX +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#endif + /* Prototypes */ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_sonar_shutdown); SWITCH_MODULE_RUNTIME_FUNCTION(mod_sonar_runtime); @@ -50,18 +59,38 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_sonar_load); */ SWITCH_MODULE_DEFINITION(mod_sonar, mod_sonar_load, mod_sonar_shutdown, NULL); -switch_time_t start, end, diff; + +struct sonar_ping_helper_s { + switch_time_t start, end, diff; + int samples[1024]; + int received; + int sum, min, max; +}; + +typedef struct sonar_ping_helper_s sonar_ping_helper_t; switch_bool_t sonar_ping_callback(switch_core_session_t *session, const char *app, const char *app_data){ - - if ( end ) { + switch_channel_t *channel = switch_core_session_get_channel(session); + sonar_ping_helper_t *ph = switch_channel_get_private(channel, "__sonar_ping__"); + int diff; + + if (!ph) return SWITCH_TRUE; + + if ( ph->end ) { return SWITCH_TRUE; } - - end = switch_time_now(); - diff = end - start; - start = 0; + + ph->end = switch_time_now(); + diff = ph->end - ph->start; + + ph->start = 0; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Sonar ping took %ld milliseconds\n", (long)diff / 1000); + + diff /= 1000; + ph->sum += diff; + ph->max = MAX(ph->max, diff); + ph->min = MIN(ph->min, diff); + ph->samples[ph->received++] = diff; return SWITCH_TRUE; } @@ -70,15 +99,31 @@ SWITCH_STANDARD_APP(sonar_app) { switch_channel_t *channel = switch_core_session_get_channel(session); char *tone = "%(500,0,1004)"; - int loops = atoi(data); - - if ( ! loops ) { + const char *arg = (char *) data; + int loops; + int lost = 0; + int x; + int avg = 0, sdev = 0, mdev = 0; + int sum2; + switch_event_t *event; + sonar_ping_helper_t ph = { 0 }; + + if (zstr(arg)) { loops = 5; + } else { + loops = atoi(data); + } + + if (loops < 0) { + loops = 5; + } else if (loops > 1024) { + loops = 1024; } switch_channel_answer(channel); switch_ivr_sleep(session, 1000, SWITCH_FALSE, NULL); - + switch_channel_set_private(channel, "__sonar_ping__", &ph); + switch_ivr_tone_detect_session(session, "ping", "1004", "r", 0, @@ -86,18 +131,81 @@ SWITCH_STANDARD_APP(sonar_app) switch_ivr_sleep(session, 1000, SWITCH_FALSE, NULL); - for( int x = 0; x < loops; x++ ) { - end = 0; - start = switch_time_now(); + ph.min = 999999; + for( x = 0; x < loops; x++ ) { + ph.end = 0; + ph.start = switch_time_now(); switch_ivr_gentones(session, tone, 1, NULL); switch_ivr_sleep(session, 2000, SWITCH_FALSE, NULL); - if ( start ) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Lost sonar ping\n"); + if ( ph.start ) { + lost++; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Lost sonar ping\n"); } } switch_ivr_sleep(session, 1000, SWITCH_FALSE, NULL); switch_ivr_stop_tone_detect_session(session); + + if (loops == lost) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Too bad, we lost all!\n"); + return; + } + + if (ph.received + lost != loops) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Race happend %d + %d != %d\n", ph.received, lost, loops); + } + + if (ph.received > 0) avg = ph.sum / ph.received; + + sum2 = 0; + for(x = 0; x < ph.received; x++) { + sum2 += abs(ph.samples[x] - avg); + } + + if (ph.received > 0) { + mdev = sum2 / ph.received; + } + + + sum2 = 0; + for(x = 0; x < ph.received; x++) { + sum2 += (ph.samples[x] - avg) * (ph.samples[x] - avg); + } + + if (ph.received > 1) { + sdev = sqrt(sum2 / (ph.received - 1)); + } + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, + "Sonar Ping (in ms): min:%d max:%d avg:%d sdev:%d mdev:%d sent:%d recv: %d lost:%d lost/send:%2.2f%%\n", + ph.min, ph.max, avg, sdev, mdev, loops, ph.received, lost, lost * 1.0 / loops); + + if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, "sonar::ping") == SWITCH_STATUS_SUCCESS) { + const char *verbose_event; + + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "ping_min", "%d", ph.min); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "ping_max", "%d", ph.max); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "ping_avg", "%d", avg); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "ping_sdev", "%d", sdev); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "ping_mdev", "%d", mdev); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "ping_sent", "%d", loops); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "ping_recv", "%d", ph.received); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "ping_lost", "%d", lost); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "lost_rate", "%2.2f%%", lost * 1.0 / loops); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "destination_number", + switch_channel_get_variable(channel, "ping_destination_number")); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "sonar_ping_ref", + switch_channel_get_variable(channel, "sonar_ping_ref")); + + verbose_event = switch_channel_get_variable(channel, "sonar_channel_event"); + + if (verbose_event && switch_true(verbose_event)) { + switch_channel_event_set_data(channel, event); + } + + switch_event_fire(&event); + } + } /* Macro expands to: switch_status_t mod_sonar_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool) */ diff --git a/src/mod/applications/mod_spandsp/mod_spandsp_modem.c b/src/mod/applications/mod_spandsp/mod_spandsp_modem.c index 3a84a451de..7c43577427 100644 --- a/src/mod/applications/mod_spandsp/mod_spandsp_modem.c +++ b/src/mod/applications/mod_spandsp/mod_spandsp_modem.c @@ -239,7 +239,6 @@ switch_status_t modem_init(modem_t *modem, modem_control_handler_t control_handl modem->stty = ttyname(modem->slave); #else #ifdef WIN32 - modem->slot = 4 + globals.NEXT_ID++; /* need work here we start at COM4 for now*/ snprintf(modem->devlink, sizeof(modem->devlink), "COM%d", modem->slot); modem->master = CreateFile(modem->devlink, @@ -884,6 +883,7 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi if (outbound_profile) { caller_profile = switch_caller_profile_clone(*new_session, outbound_profile); caller_profile->source = switch_core_strdup(caller_profile->pool, "mod_spandsp"); + caller_profile->destination_number = switch_core_strdup(caller_profile->pool, number); switch_channel_set_caller_profile(channel, caller_profile); tech_pvt->caller_profile = caller_profile; } else { diff --git a/src/mod/applications/mod_voicemail/mod_voicemail.c b/src/mod/applications/mod_voicemail/mod_voicemail.c index a87e849001..07d4d2fe95 100644 --- a/src/mod/applications/mod_voicemail/mod_voicemail.c +++ b/src/mod/applications/mod_voicemail/mod_voicemail.c @@ -3078,16 +3078,24 @@ static switch_status_t deliver_vm(vm_profile_t *profile, vm_cc_num = switch_separate_string(vm_cc_dup, ',', vm_cc_list, (sizeof(vm_cc_list) / sizeof(vm_cc_list[0]))); for (vm_cc_i=0; vm_cc_i + + + + + diff --git a/src/mod/endpoints/mod_skinny/mod_skinny.c b/src/mod/endpoints/mod_skinny/mod_skinny.c index e329affb5c..cc94f1129f 100644 --- a/src/mod/endpoints/mod_skinny/mod_skinny.c +++ b/src/mod/endpoints/mod_skinny/mod_skinny.c @@ -173,6 +173,7 @@ switch_status_t skinny_profile_dump(const skinny_profile_t *profile, switch_stre stream->write_function(stream, "Ext-Redial \t%s\n", profile->ext_redial); stream->write_function(stream, "Ext-MeetMe \t%s\n", profile->ext_meetme); stream->write_function(stream, "Ext-PickUp \t%s\n", profile->ext_pickup); + stream->write_function(stream, "Ext-CFwdAll \t%s\n", profile->ext_cfwdall); stream->write_function(stream, "%s\n", line); return SWITCH_STATUS_SUCCESS; @@ -1939,6 +1940,10 @@ switch_status_t skinny_profile_set(skinny_profile_t *profile, const char *var, c if (!profile->ext_pickup || strcmp(val, profile->ext_pickup)) { profile->ext_pickup = switch_core_strdup(profile->pool, val); } + } else if (!strcasecmp(var, "ext-cfwdall")) { + if (!profile->ext_cfwdall || strcmp(val, profile->ext_cfwdall)) { + profile->ext_cfwdall = switch_core_strdup(profile->pool, val); + } } else { return SWITCH_STATUS_FALSE; } @@ -2039,6 +2044,10 @@ static switch_status_t load_skinny_config(void) skinny_profile_set(profile, "ext-pickup", "pickup"); } + if (!profile->ext_cfwdall) { + skinny_profile_set(profile, "ext-pickup", "cfwdall"); + } + if (profile->port == 0) { profile->port = 2000; } diff --git a/src/mod/endpoints/mod_skinny/mod_skinny.h b/src/mod/endpoints/mod_skinny/mod_skinny.h index df876d0894..b252dd7e4a 100644 --- a/src/mod/endpoints/mod_skinny/mod_skinny.h +++ b/src/mod/endpoints/mod_skinny/mod_skinny.h @@ -59,6 +59,11 @@ "[%s:%d @ %s:%d] " _fmt, skinny_undef_str(listener->device_name), listener->device_instance, skinny_undef_str(listener->remote_ip), \ listener->remote_port, __VA_ARGS__) +#define skinny_log_l_ffl_msg(listener, file, func, line, level, _fmt) switch_log_printf( \ + SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, level, \ + "[%s:%d @ %s:%d] " _fmt, skinny_undef_str(listener->device_name), listener->device_instance, skinny_undef_str(listener->remote_ip), \ + listener->remote_port) + #define skinny_log_ls(listener, session, level, _fmt, ...) switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), level, \ "[%s:%d @ %s:%d] " _fmt, skinny_undef_str(listener->device_name), listener->device_instance, skinny_undef_str(listener->remote_ip), \ listener->remote_port, __VA_ARGS__) @@ -125,6 +130,7 @@ struct skinny_profile { char *ext_redial; char *ext_meetme; char *ext_pickup; + char *ext_cfwdall; /* db */ char *dbname; char *odbc_dsn; @@ -194,6 +200,7 @@ struct listener { char *ext_redial; char *ext_meetme; char *ext_pickup; + char *ext_cfwdall; }; typedef struct listener listener_t; diff --git a/src/mod/endpoints/mod_skinny/skinny_api.c b/src/mod/endpoints/mod_skinny/skinny_api.c index db9338b000..f4c9560352 100644 --- a/src/mod/endpoints/mod_skinny/skinny_api.c +++ b/src/mod/endpoints/mod_skinny/skinny_api.c @@ -235,6 +235,7 @@ static switch_status_t skinny_api_list_settings(const char *line, const char *cu switch_console_push_match(&my_matches, "ext-redial"); switch_console_push_match(&my_matches, "ext-meetme"); switch_console_push_match(&my_matches, "ext-pickup"); + switch_console_push_match(&my_matches, "ext-cfwdall"); if (my_matches) { *matches = my_matches; @@ -384,6 +385,50 @@ static switch_status_t skinny_api_cmd_profile_device_send_call_state_message(con return SWITCH_STATUS_SUCCESS; } +static switch_status_t skinny_api_cmd_profile_device_send_forward_stat_message(const char *profile_name, const char *device_name, const char *number, switch_stream_handle_t *stream) +{ + skinny_profile_t *profile; + + if ((profile = skinny_find_profile(profile_name))) { + listener_t *listener = NULL; + skinny_profile_find_listener_by_device_name(profile, device_name, &listener); + if(listener) { + + send_forward_stat(listener, number); + + stream->write_function(stream, "+OK\n"); + } else { + stream->write_function(stream, "Listener not found!\n"); + } + } else { + stream->write_function(stream, "Profile not found!\n"); + } + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t skinny_api_cmd_profile_device_send_display_prompt_status_message(const char *profile_name, const char *device_name, const char *display, switch_stream_handle_t *stream) +{ + skinny_profile_t *profile; + + if ((profile = skinny_find_profile(profile_name))) { + listener_t *listener = NULL; + skinny_profile_find_listener_by_device_name(profile, device_name, &listener); + if(listener) { + + send_display_prompt_status(listener, 0, display, 0, 0); + + stream->write_function(stream, "+OK\n"); + } else { + stream->write_function(stream, "Listener not found!\n"); + } + } else { + stream->write_function(stream, "Profile not found!\n"); + } + + return SWITCH_STATUS_SUCCESS; +} + static switch_status_t skinny_api_cmd_profile_device_send_reset_message(const char *profile_name, const char *device_name, const char *reset_type, switch_stream_handle_t *stream) { skinny_profile_t *profile; @@ -497,6 +542,8 @@ SWITCH_STANDARD_API(skinny_function) "skinny profile device send SetLampMessage \n" "skinny profile device send SetSpeakerModeMessage \n" "skinny profile device send CallStateMessage \n" + "skinny profile device send ForwardStatMessage \n" + "skinny profile device send DisplayPromptStatus \n" "skinny profile device send [ =;... ] \n" "skinny profile set \n" "--------------------------------------------------------------------------------\n"; @@ -560,6 +607,21 @@ SWITCH_STANDARD_API(skinny_function) status = skinny_api_cmd_profile_device_send_call_state_message(argv[1], argv[3], argv[6], argv[7], argv[8], stream); } break; + case FORWARD_STAT_MESSAGE: + if (argc == 7) { + /* ForwardStatMessage */ + status = skinny_api_cmd_profile_device_send_forward_stat_message(argv[1], argv[3], argv[6], stream); + } else if (argc == 6) { + /* ForwardStatMessage */ + status = skinny_api_cmd_profile_device_send_forward_stat_message(argv[1], argv[3], NULL, stream); + } + break; + case DISPLAY_PROMPT_STATUS_MESSAGE: + if (argc == 7) { + /* DisplayPromptStatus */ + status = skinny_api_cmd_profile_device_send_display_prompt_status_message(argv[1], argv[3], argv[6], stream); + } + break; case RESET_MESSAGE: if (argc == 7) { /* ResetMessage */ @@ -610,6 +672,8 @@ switch_status_t skinny_api_register(switch_loadable_module_interface_t **module_ switch_console_set_complete("add skinny profile ::skinny::list_profiles device ::skinny::list_devices send SetLampMessage ::skinny::list_stimuli ::skinny::list_stimulus_instances ::skinny::list_stimulus_modes"); switch_console_set_complete("add skinny profile ::skinny::list_profiles device ::skinny::list_devices send SetSpeakerModeMessage ::skinny::list_speaker_modes"); switch_console_set_complete("add skinny profile ::skinny::list_profiles device ::skinny::list_devices send CallStateMessage ::skinny::list_call_states ::skinny::list_line_instances ::skinny::list_call_ids"); + switch_console_set_complete("add skinny profile ::skinny::list_profiles device ::skinny::list_devices send ForwardStatMessage"); + switch_console_set_complete("add skinny profile ::skinny::list_profiles device ::skinny::list_devices send DisplayPromptStatusMessage"); switch_console_set_complete("add skinny profile ::skinny::list_profiles device ::skinny::list_devices send UserToDeviceDataMessage"); switch_console_set_complete("add skinny profile ::skinny::list_profiles device ::skinny::list_devices send UserToDeviceDataVersion1Message"); switch_console_set_complete("add skinny profile ::skinny::list_profiles set ::skinny::list_settings"); diff --git a/src/mod/endpoints/mod_skinny/skinny_protocol.c b/src/mod/endpoints/mod_skinny/skinny_protocol.c index ce756da34a..5498e5ebee 100644 --- a/src/mod/endpoints/mod_skinny/skinny_protocol.c +++ b/src/mod/endpoints/mod_skinny/skinny_protocol.c @@ -592,6 +592,38 @@ switch_status_t perform_send_set_ringer(listener_t *listener, return skinny_send_reply_quiet(listener, message, SWITCH_TRUE); } +switch_status_t perform_send_forward_stat(listener_t *listener, + const char *file, const char *func, int line, + const char *number) +{ + skinny_message_t *message; + + skinny_create_message(message, FORWARD_STAT_MESSAGE, forward_stat); + + if ( number && number[0] ) + { + message->data.forward_stat.active_forward = 1; + message->data.forward_stat.line_instance = 1; + message->data.forward_stat.forward_all_active = 1; + message->data.forward_stat.forward_busy_active = 1; + message->data.forward_stat.forward_noanswer_active = 1; + + strncpy(message->data.forward_stat.forward_all_number, number, sizeof(message->data.forward_stat.forward_all_number)); + strncpy(message->data.forward_stat.forward_busy_number, number, sizeof(message->data.forward_stat.forward_all_number)); + strncpy(message->data.forward_stat.forward_noanswer_number, number, sizeof(message->data.forward_stat.forward_all_number)); + skinny_log_l_ffl(listener, file, func, line, SWITCH_LOG_DEBUG, + "Sending ForwardStat with Number (%s)\n", number); + } + else + { + skinny_log_l_ffl_msg(listener, file, func, line, SWITCH_LOG_DEBUG, + "Sending ForwardStat with No Number (Inactive)\n"); + } + + + return skinny_send_reply_quiet(listener, message, SWITCH_TRUE); +} + switch_status_t perform_send_set_lamp(listener_t *listener, const char *file, const char *func, int line, uint32_t stimulus, diff --git a/src/mod/endpoints/mod_skinny/skinny_protocol.h b/src/mod/endpoints/mod_skinny/skinny_protocol.h index 43b2502e81..8a5178302e 100644 --- a/src/mod/endpoints/mod_skinny/skinny_protocol.h +++ b/src/mod/endpoints/mod_skinny/skinny_protocol.h @@ -1019,6 +1019,11 @@ switch_status_t perform_send_set_ringer(listener_t *listener, uint32_t call_id); #define send_set_ringer(listener, ...) perform_send_set_ringer(listener, __FILE__, __SWITCH_FUNC__, __LINE__, __VA_ARGS__) +switch_status_t perform_send_forward_stat(listener_t *listener, + const char *file, const char *func, int line, + const char *forward_to); +#define send_forward_stat(listener, ...) perform_send_forward_stat(listener, __FILE__, __SWITCH_FUNC__, __LINE__, __VA_ARGS__) + switch_status_t perform_send_set_lamp(listener_t *listener, const char *file, const char *func, int line, uint32_t stimulus, diff --git a/src/mod/endpoints/mod_skinny/skinny_server.c b/src/mod/endpoints/mod_skinny/skinny_server.c index 1dbf66b7b2..76486633ba 100644 --- a/src/mod/endpoints/mod_skinny/skinny_server.c +++ b/src/mod/endpoints/mod_skinny/skinny_server.c @@ -592,7 +592,6 @@ int skinny_ring_lines_callback(void *pArg, int argc, char **argv, char **columnN device_name, device_instance, &listener); if(listener && helper->tech_pvt->session && helper->remote_session) { switch_channel_t *channel = switch_core_session_get_channel(helper->tech_pvt->session); - switch_channel_t *remchannel = switch_core_session_get_channel(helper->remote_session); switch_channel_set_state(channel, CS_ROUTING); helper->lines_count++; switch_channel_set_variable(channel, "effective_callee_id_number", value); @@ -632,7 +631,7 @@ int skinny_ring_lines_callback(void *pArg, int argc, char **argv, char **columnN skinny_session_send_call_info(helper->tech_pvt->session, listener, line_instance); send_set_lamp(listener, SKINNY_BUTTON_LINE, line_instance, SKINNY_LAMP_BLINK); send_set_ringer(listener, SKINNY_RING_INSIDE, SKINNY_RING_FOREVER, 0, helper->tech_pvt->call_id); - switch_channel_ring_ready(remchannel); + switch_channel_ring_ready(channel); } return 0; } @@ -1097,6 +1096,10 @@ switch_status_t skinny_handle_register(listener_t *listener, skinny_message_t *r if (!listener->ext_pickup || strcmp(value,listener->ext_pickup)) { listener->ext_pickup = switch_core_strdup(profile->pool, value); } + } else if (!strcasecmp(name, "ext-cfwdall")) { + if (!listener->ext_cfwdall || strcmp(value,listener->ext_cfwdall)) { + listener->ext_cfwdall = switch_core_strdup(profile->pool, value); + } } } } @@ -1256,7 +1259,7 @@ switch_status_t skinny_handle_keypad_button_message(listener_t *listener, skinny digit = '*'; } else if (request->data.keypad_button.button == 15) { digit = '#'; - } else if (request->data.keypad_button.button >= 0 && request->data.keypad_button.button <= 9) { + } else if (request->data.keypad_button.button <= 9) { /* unsigned, so guaranteed to be >= 0 */ digit = '0' + request->data.keypad_button.button; } else { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "UNKNOW DTMF RECEIVED ON CALL %d [%d]\n", tech_pvt->call_id, request->data.keypad_button.button); @@ -2001,6 +2004,11 @@ switch_status_t skinny_handle_soft_key_event_message(listener_t *listener, skinn skinny_session_process_dest(session, listener, line_instance, empty_null2(listener->ext_pickup, listener->profile->ext_pickup), '\0', 0); break; + case SOFTKEY_CFWDALL: + skinny_create_incoming_session(listener, &line_instance, &session); + skinny_session_process_dest(session, listener, line_instance, + empty_null2(listener->ext_cfwdall, listener->profile->ext_cfwdall), '\0', 0); + break; default: switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unknown SoftKeyEvent type: %d.\n", request->data.soft_key_event.event); diff --git a/src/mod/endpoints/mod_skinny/skinny_tables.c b/src/mod/endpoints/mod_skinny/skinny_tables.c index ea29918cbb..9c053d6b58 100644 --- a/src/mod/endpoints/mod_skinny/skinny_tables.c +++ b/src/mod/endpoints/mod_skinny/skinny_tables.c @@ -212,6 +212,7 @@ SKINNY_DECLARE_STR2ID(skinny_str2ring_mode, SKINNY_RING_MODES, -1) {SKINNY_BUTTON_LAST_NUMBER_REDIAL, "LastNumberRedial"}, {SKINNY_BUTTON_SPEED_DIAL, "SpeedDial"}, {SKINNY_BUTTON_HOLD, "Hold"}, + {SKINNY_BUTTON_FORWARDALL, "ForwardAll"}, {SKINNY_BUTTON_TRANSFER, "Transfer"}, {SKINNY_BUTTON_LINE, "Line"}, {SKINNY_BUTTON_VOICEMAIL, "Voicemail"}, diff --git a/src/mod/endpoints/mod_skinny/skinny_tables.h b/src/mod/endpoints/mod_skinny/skinny_tables.h index 647837f212..4fea984756 100644 --- a/src/mod/endpoints/mod_skinny/skinny_tables.h +++ b/src/mod/endpoints/mod_skinny/skinny_tables.h @@ -165,13 +165,14 @@ enum skinny_button_definition { SKINNY_BUTTON_SPEED_DIAL = 0x02, SKINNY_BUTTON_HOLD = 0x03, SKINNY_BUTTON_TRANSFER = 0x04, + SKINNY_BUTTON_FORWARDALL = 0x05, SKINNY_BUTTON_LINE = 0x09, SKINNY_BUTTON_VOICEMAIL = 0x0F, SKINNY_BUTTON_PRIVACY = 0x13, SKINNY_BUTTON_SERVICE_URL = 0x14, SKINNY_BUTTON_UNDEFINED = 0xFF, }; -extern struct skinny_table SKINNY_BUTTONS[11]; +extern struct skinny_table SKINNY_BUTTONS[12]; const char *skinny_button2str(uint32_t id); uint32_t skinny_str2button(const char *str); #define SKINNY_PUSH_STIMULI SKINNY_DECLARE_PUSH_MATCH(SKINNY_BUTTONS) diff --git a/src/mod/endpoints/mod_sofia/conf/sofia.conf.xml b/src/mod/endpoints/mod_sofia/conf/sofia.conf.xml index 411ea3e44e..1b64f63bc7 100644 --- a/src/mod/endpoints/mod_sofia/conf/sofia.conf.xml +++ b/src/mod/endpoints/mod_sofia/conf/sofia.conf.xml @@ -64,6 +64,10 @@ + diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index 2bc0476da7..a4c8913ee5 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -1,4 +1,4 @@ -/* +/* * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application * Copyright (C) 2005-2012, Anthony Minessale II * @@ -22,7 +22,7 @@ * the Initial Developer. All Rights Reserved. * * Contributor(s): - * + * * Anthony Minessale II * Ken Rice * Paul D. Tinsley @@ -65,8 +65,8 @@ static switch_status_t sofia_kill_channel(switch_core_session_t *session, int si /* BODY OF THE MODULE */ /*************************************************************************************************************************************************************/ -/* - State methods they get called when the state changes to the specific state +/* + State methods they get called when the state changes to the specific state returning SWITCH_STATUS_SUCCESS tells the core to execute the standard state method next so if you fully implement the state you can return SWITCH_STATUS_FALSE to skip it. */ @@ -375,7 +375,7 @@ switch_status_t sofia_on_destroy(switch_core_session_t *session) switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s SOFIA DESTROY\n", switch_channel_get_name(channel)); if (tech_pvt) { - + if (tech_pvt->respond_phrase) { switch_yield(100000); } @@ -402,7 +402,7 @@ switch_status_t sofia_on_destroy(switch_core_session_t *session) sofia_profile_destroy(tech_pvt->profile); } } - + return SWITCH_STATUS_SUCCESS; } @@ -552,18 +552,18 @@ switch_status_t sofia_on_hangup(switch_core_session_t *session) case 401: case 407: { - const char *to_host = switch_channel_get_variable(channel, "sip_challenge_realm"); + const char *to_host = switch_channel_get_variable(channel, "sip_challenge_realm"); if (zstr(to_host)) { - to_host = switch_channel_get_variable(channel, "sip_to_host"); + to_host = switch_channel_get_variable(channel, "sip_to_host"); } - + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Challenging call\n"); - sofia_reg_auth_challenge(tech_pvt->profile, tech_pvt->nh, NULL, REG_INVITE, to_host, 0, 0); + sofia_reg_auth_challenge(tech_pvt->profile, tech_pvt->nh, NULL, REG_INVITE, to_host, 0, 0); *reason = '\0'; } break; - + case 484: { const char *to = switch_channel_get_variable(channel, "sip_to_uri"); @@ -575,13 +575,13 @@ switch_status_t sofia_on_hangup(switch_core_session_t *session) if ((p = strstr(to_uri, ":5060"))) { *p = '\0'; } - + tech_pvt->respond_dest = to_uri; - + } switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Overlap Dial with %d %s\n", sip_cause, phrase); - + } break; @@ -590,7 +590,7 @@ switch_status_t sofia_on_hangup(switch_core_session_t *session) } } - + if (tech_pvt->respond_dest && !sofia_test_pflag(tech_pvt->profile, PFLAG_MANUAL_REDIRECT)) { added_headers = sofia_glue_get_extra_headers(channel, SOFIA_SIP_HEADER_PREFIX); } @@ -611,12 +611,12 @@ switch_status_t sofia_on_hangup(switch_core_session_t *session) nua_respond(tech_pvt->nh, sip_cause, phrase, TAG_IF(!zstr(reason), SIPTAG_REASON_STR(reason)), - TAG_IF(cid, SIPTAG_HEADER_STR(cid)), - TAG_IF(!zstr(bye_headers), SIPTAG_HEADER_STR(bye_headers)), - TAG_IF(!zstr(resp_headers), SIPTAG_HEADER_STR(resp_headers)), - TAG_IF(!zstr(added_headers), SIPTAG_HEADER_STR(added_headers)), + TAG_IF(cid, SIPTAG_HEADER_STR(cid)), + TAG_IF(!zstr(bye_headers), SIPTAG_HEADER_STR(bye_headers)), + TAG_IF(!zstr(resp_headers), SIPTAG_HEADER_STR(resp_headers)), + TAG_IF(!zstr(added_headers), SIPTAG_HEADER_STR(added_headers)), TAG_IF(tech_pvt->respond_dest, SIPTAG_CONTACT_STR(tech_pvt->respond_dest)), - TAG_IF(!zstr(max_forwards), SIPTAG_MAX_FORWARDS_STR(max_forwards)), + TAG_IF(!zstr(max_forwards), SIPTAG_MAX_FORWARDS_STR(max_forwards)), TAG_END()); switch_safe_free(resp_headers); @@ -663,7 +663,7 @@ static switch_status_t sofia_answer_channel(switch_core_session_t *session) int is_3pcc = 0; char *sticky = NULL; const char *call_info = switch_channel_get_variable(channel, "presence_call_info_full"); - + if (switch_channel_test_flag(channel, CF_CONFERENCE)) { tech_pvt->reply_contact = switch_core_session_sprintf(session, "%s;isfocus", tech_pvt->reply_contact); } @@ -671,7 +671,7 @@ static switch_status_t sofia_answer_channel(switch_core_session_t *session) //switch_core_media_set_local_sdp if(sofia_test_flag(tech_pvt, TFLAG_3PCC_INVITE)) { // SNARK: complete hack to get final ack sent when a 3pcc invite has been passed from the other leg in bypass_media mode. - // This code handles the pass_indication sent after the 3pcc ack is received by the other leg in the is_3pcc && is_proxy case below. + // This code handles the pass_indication sent after the 3pcc ack is received by the other leg in the is_3pcc && is_proxy case below. // Is there a better place to hang this...? b_sdp = switch_channel_get_variable(channel, SWITCH_B_SDP_VARIABLE); switch_core_media_set_local_sdp(session, b_sdp, SWITCH_TRUE); @@ -818,7 +818,7 @@ static switch_status_t sofia_answer_channel(switch_core_session_t *session) if (sofia_media_activate_rtp(tech_pvt) != SWITCH_STATUS_SUCCESS) { switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); } - + if (tech_pvt->nh) { if (tech_pvt->mparams.local_sdp_str) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Local SDP %s:\n%s\n", switch_channel_get_name(channel), @@ -853,14 +853,14 @@ static switch_status_t sofia_answer_channel(switch_core_session_t *session) if (switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE) && tech_pvt->mparams.early_sdp) { char *a, *b; - + /* start at the s= line to avoid some devices who update the o= between messages */ a = strstr(tech_pvt->mparams.early_sdp, "s="); b = strstr(tech_pvt->mparams.local_sdp_str, "s="); if (!a || !b || strcmp(a, b)) { - /* The SIP RFC for SOA forbids sending a 183 with one sdp then a 200 with another but it won't do us much good unless + /* The SIP RFC for SOA forbids sending a 183 with one sdp then a 200 with another but it won't do us much good unless we do so in this case we will abandon the SOA rules and go rogue. */ sofia_clear_flag(tech_pvt, TFLAG_ENABLE_SOA); @@ -873,7 +873,7 @@ static switch_status_t sofia_answer_channel(switch_core_session_t *session) tech_pvt->session_refresher = nua_no_refresher; } - + if (sofia_use_soa(tech_pvt)) { nua_respond(tech_pvt->nh, SIP_200_OK, @@ -928,7 +928,7 @@ static switch_status_t sofia_read_video_frame(switch_core_session_t *session, sw #if 0 while (!(tech_pvt->video_read_codec.implementation && switch_core_media_ready(tech_pvt->session, SWITCH_MEDIA_TYPE_VIDEO) && !switch_channel_test_flag(channel, CF_REQ_MEDIA))) { switch_ivr_parse_all_messages(tech_pvt->session); - + if (--sanity && switch_channel_ready(channel)) { switch_yield(10000); } else { @@ -1110,7 +1110,7 @@ static switch_status_t sofia_send_dtmf(switch_core_session_t *session, const swi dtmf_type = tech_pvt->mparams.dtmf_type; /* We only can send INFO when we have no media */ - if (!switch_core_media_ready(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO) || + if (!switch_core_media_ready(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO) || !switch_channel_media_ready(tech_pvt->channel) || switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE)) { dtmf_type = DTMF_INFO; } @@ -1187,7 +1187,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi break; case SWITCH_MESSAGE_INDICATE_BRIDGE: switch_channel_set_variable(channel, SOFIA_REPLACES_HEADER, NULL); - + if (switch_true(switch_channel_get_variable(channel, "sip_auto_simplify"))) { sofia_set_flag(tech_pvt, TFLAG_SIMPLIFY); } @@ -1269,8 +1269,8 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi } - if (((var = switch_channel_get_variable(channel, SOFIA_SECURE_MEDIA_VARIABLE)) || - (var = switch_channel_get_variable(channel, "rtp_secure_media"))) && + if (((var = switch_channel_get_variable(channel, SOFIA_SECURE_MEDIA_VARIABLE)) || + (var = switch_channel_get_variable(channel, "rtp_secure_media"))) && (switch_true(var) || !strcasecmp(var, SWITCH_RTP_CRYPTO_KEY_32) || !strcasecmp(var, SWITCH_RTP_CRYPTO_KEY_80))) { switch_channel_set_flag(tech_pvt->channel, CF_SECURE); } @@ -1306,10 +1306,10 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi if (!zstr(msg->string_arg)) { pl = msg->string_arg; } - + nua_info(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("application/media_control+xml"), SIPTAG_PAYLOAD_STR(pl), TAG_END()); } - + } break; case SWITCH_MESSAGE_INDICATE_BROADCAST: @@ -1353,9 +1353,9 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi if(zstr(tech_pvt->mparams.local_sdp_str)) { sofia_set_flag(tech_pvt, TFLAG_3PCC_INVITE); } - + sofia_set_flag_locked(tech_pvt, TFLAG_SENT_UPDATE); - + if (!switch_channel_test_flag(channel, CF_PROXY_MEDIA)) { switch_channel_set_flag(channel, CF_REQ_MEDIA); } @@ -1416,7 +1416,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi switch_channel_set_variable(channel, "sip_require_timer", "false"); sofia_glue_do_invite(session); } else { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "%s Request to send IMAGE on channel with not t38 options.\n", + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "%s Request to send IMAGE on channel with not t38 options.\n", switch_channel_get_name(channel)); } } @@ -1477,9 +1477,9 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi } if (!switch_channel_test_flag(channel, CF_ANSWERED) && switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Operation not permitted on an inbound non-answered call leg!\n"); - } else { + } else { nua_notify(tech_pvt->nh, NUTAG_NEWSUB(1), NUTAG_SUBSTATE(nua_substate_active), SIPTAG_SUBSCRIPTION_STATE_STR("active"), SIPTAG_EVENT_STR(event), TAG_END()); } @@ -1546,23 +1546,23 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi "fs_send_unspported_info is deprecated in favor of correctly spelled fs_send_unsupported_info\n"); ok = 1; } - + if (switch_true(switch_channel_get_variable(channel, "fs_send_unsupported_info"))) { ok = 1; } - + if (ok) { char *headers = sofia_glue_get_extra_headers(channel, SOFIA_SIP_INFO_HEADER_PREFIX); const char *pl = NULL; - + if (!zstr(msg->string_array_arg[2])) { pl = msg->string_array_arg[2]; } - + nua_info(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR(ct), TAG_IF(!zstr(headers), SIPTAG_HEADER_STR(headers)), - TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)), + TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)), TAG_IF(pl, SIPTAG_PAYLOAD_STR(pl)), TAG_END()); @@ -1621,21 +1621,29 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi break; case SWITCH_MESSAGE_INDICATE_DISPLAY: { - const char *name = msg->string_array_arg[0], *number = msg->string_array_arg[1]; - const char *call_info = switch_channel_get_variable(channel, "presence_call_info_full"); - + const char *name = NULL, *number = NULL; + const char *call_info = NULL; + + if (!sofia_test_pflag(tech_pvt->profile, PFLAG_SEND_DISPLAY_UPDATE)) { + goto end_lock; + } + + name = msg->string_array_arg[0]; + number = msg->string_array_arg[1]; + call_info = switch_channel_get_variable(channel, "presence_call_info_full"); + if (!zstr(name)) { char message[256] = ""; const char *ua = switch_channel_get_variable(tech_pvt->channel, "sip_user_agent"); switch_event_t *event; - + check_decode(name, tech_pvt->session); if (zstr(number)) { number = tech_pvt->caller_profile->destination_number; } - + switch_ivr_eavesdrop_update_display(session, name, number); if (!sofia_test_flag(tech_pvt, TFLAG_UPDATING_DISPLAY) && switch_channel_test_flag(channel, CF_ANSWERED)) { @@ -1660,7 +1668,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi TAG_IF(!zstr_buf(message), SIPTAG_HEADER_STR(message)), TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)), TAG_END()); } else if (ua && switch_stristr("snom", ua)) { - const char *ver_str = NULL; + const char *ver_str = NULL; int version = 0; ver_str = switch_stristr( "/", ua); @@ -1744,7 +1752,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi tech_pvt->last_sent_callee_id_name = switch_core_session_strdup(tech_pvt->session, name); tech_pvt->last_sent_callee_id_number = switch_core_session_strdup(tech_pvt->session, number); - + if (switch_event_create(&event, SWITCH_EVENT_CALL_UPDATE) == SWITCH_STATUS_SUCCESS) { const char *uuid = switch_channel_get_partner_uuid(channel); @@ -1784,7 +1792,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi if (!zstr(msg->string_arg)) { char message[256] = ""; const char *ua = switch_channel_get_variable(tech_pvt->channel, "sip_user_agent"); - + if (ua && switch_stristr("snom", ua)) { snprintf(message, sizeof(message), "From:\r\nTo: \"%s\" %s\r\n", msg->string_arg, tech_pvt->caller_profile->destination_number); nua_info(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("message/sipfrag"), @@ -1853,9 +1861,9 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi } switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Redirecting to %s\n", dest); - + tech_pvt->respond_dest = dest; - + if (argc > 1) { tech_pvt->respond_code = 300; tech_pvt->respond_phrase = "Multiple Choices"; @@ -1997,7 +2005,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi /* Regain lock on sofia */ switch_mutex_lock(tech_pvt->sofia_mutex); - + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "3PCC-PROXY, Done waiting for ACK\n"); sofia_clear_flag(tech_pvt, TFLAG_3PCC); sofia_clear_flag(tech_pvt, TFLAG_3PCC_HAS_ACK); @@ -2102,7 +2110,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi } } } else { - if (sofia_test_flag(tech_pvt, TFLAG_LATE_NEGOTIATION) || + if (sofia_test_flag(tech_pvt, TFLAG_LATE_NEGOTIATION) || switch_core_media_codec_chosen(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO) != SWITCH_STATUS_SUCCESS) { sofia_clear_flag_locked(tech_pvt, TFLAG_LATE_NEGOTIATION); if (switch_channel_direction(tech_pvt->channel) == SWITCH_CALL_DIRECTION_INBOUND) { @@ -2150,11 +2158,11 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi char *cid = NULL; cid = generate_pai_str(tech_pvt); - + if (switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE) && tech_pvt->mparams.early_sdp && strcmp(tech_pvt->mparams.early_sdp, tech_pvt->mparams.local_sdp_str)) { - /* The SIP RFC for SOA forbids sending a 183 with one sdp then a 200 with another but it won't do us much good unless + /* The SIP RFC for SOA forbids sending a 183 with one sdp then a 200 with another but it won't do us much good unless we do so in this case we will abandon the SOA rules and go rogue. */ sofia_clear_flag(tech_pvt, TFLAG_ENABLE_SOA); @@ -2202,7 +2210,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi case SWITCH_MESSAGE_INDICATE_UDPTL_MODE: { switch_t38_options_t *t38_options = switch_channel_get_private(channel, "t38_options"); - + if (!t38_options) { nua_respond(tech_pvt->nh, SIP_488_NOT_ACCEPTABLE, TAG_END()); } @@ -3082,7 +3090,7 @@ static switch_status_t cmd_profile(char **argv, int argc, switch_stream_handle_t goto done; } - + if (!strcasecmp(argv[1], "recover")) { if (argv[2] && !strcasecmp(argv[2], "flush")) { sofia_glue_profile_recover(profile, SWITCH_TRUE); @@ -3199,16 +3207,16 @@ static switch_status_t cmd_profile(char **argv, int argc, switch_stream_handle_t goto done; } - if (!strcasecmp(argv[1], "capture")) { - if (argc > 2) { - int value = switch_true(argv[2]); - nua_set_params(profile->nua, TPTAG_CAPT(value ? mod_sofia_globals.capture_server : NULL), TAG_END()); - stream->write_function(stream, "%s sip capturing on %s", value ? "Enabled" : "Disabled", profile->name); - } else { - stream->write_function(stream, "Usage: sofia profile capture \n"); - } - goto done; - } + if (!strcasecmp(argv[1], "capture")) { + if (argc > 2) { + int value = switch_true(argv[2]); + nua_set_params(profile->nua, TPTAG_CAPT(value ? mod_sofia_globals.capture_server : NULL), TAG_END()); + stream->write_function(stream, "%s sip capturing on %s", value ? "Enabled" : "Disabled", profile->name); + } else { + stream->write_function(stream, "Usage: sofia profile capture \n"); + } + goto done; + } if (!strcasecmp(argv[1], "watchdog")) { if (argc > 2) { @@ -3224,7 +3232,7 @@ static switch_status_t cmd_profile(char **argv, int argc, switch_stream_handle_t if (!strcasecmp(argv[1], "gwlist")) { int up = 1; - + if (argc > 2) { if (!strcasecmp(argv[2], "down")) { up = 0; @@ -3250,13 +3258,13 @@ static int contact_callback(void *pArg, int argc, char **argv, char **columnName { struct cb_helper *cb = (struct cb_helper *) pArg; char *contact; - + cb->row_process++; - + if (!zstr(argv[0]) && (contact = sofia_glue_get_url_from_contact(argv[0], 1))) { if (cb->dedup) { char *tmp = switch_mprintf("%ssofia/%s/sip:%s", argv[2], argv[1], sofia_glue_strip_proto(contact)); - + if (!strstr((char *)cb->stream->data, tmp)) { cb->stream->write_function(cb->stream, "%s,", tmp); } @@ -3463,17 +3471,17 @@ SWITCH_STANDARD_API(sofia_username_of_function) return SWITCH_STATUS_SUCCESS; } -static void select_from_profile(sofia_profile_t *profile, +static void select_from_profile(sofia_profile_t *profile, const char *user, const char *domain, const char *concat, - const char *exclude_contact, + const char *exclude_contact, switch_stream_handle_t *stream, switch_bool_t dedup) { struct cb_helper cb; char *sql; - + cb.row_process = 0; cb.profile = profile; @@ -3552,7 +3560,7 @@ SWITCH_STANDARD_API(sofia_contact_function) if (!zstr(profile_name)) { profile = sofia_glue_find_profile(profile_name); } - + if (!profile && !zstr(domain)) { profile = sofia_glue_find_profile(domain); } @@ -3571,32 +3579,32 @@ SWITCH_STANDARD_API(sofia_contact_function) if (!zstr(profile->domain_name) && !zstr(profile_name) && !strcmp(profile_name, profile->name)) { domain = profile->domain_name; } - + select_from_profile(profile, user, domain, concat, exclude_contact, &mystream, SWITCH_FALSE); sofia_glue_release_profile(profile); - + } else if (!zstr(domain)) { switch_mutex_lock(mod_sofia_globals.hash_mutex); if (mod_sofia_globals.profile_hash) { switch_hash_index_t *hi; const void *var; void *val; - + for (hi = switch_hash_first(NULL, mod_sofia_globals.profile_hash); hi; hi = switch_hash_next(hi)) { switch_hash_this(hi, &var, NULL, &val); if ((profile = (sofia_profile_t *) val) && !strcmp((char *)var, profile->name)) { - select_from_profile(profile, user, domain, concat, exclude_contact, &mystream, SWITCH_TRUE); + select_from_profile(profile, user, domain, concat, exclude_contact, &mystream, SWITCH_TRUE); profile = NULL; } } } switch_mutex_unlock(mod_sofia_globals.hash_mutex); - } - + } + reply = (char *) mystream.data; end: - + if (zstr(reply)) { reply = "error/user_not_registered"; } else if (end_of(reply) == ',') { @@ -3606,7 +3614,7 @@ SWITCH_STANDARD_API(sofia_contact_function) stream->write_function(stream, "%s", reply); reply = NULL; - switch_safe_free(mystream.data); + switch_safe_free(mystream.data); switch_safe_free(data); switch_safe_free(dup_domain); @@ -3933,12 +3941,12 @@ SWITCH_STANDARD_API(sofia_function) mod_sofia_globals.debug_presence = 10; stream->write_function(stream, "+OK Debugging presence\n"); } - + if (strstr(argv[2], "sla")) { mod_sofia_globals.debug_sla = 10; stream->write_function(stream, "+OK Debugging sla\n"); } - + if (strstr(argv[2], "none")) { stream->write_function(stream, "+OK Debugging nothing\n"); mod_sofia_globals.debug_presence = 0; @@ -3946,13 +3954,13 @@ SWITCH_STANDARD_API(sofia_function) } } - stream->write_function(stream, "+OK Debugging summary: presence: %s sla: %s\n", + stream->write_function(stream, "+OK Debugging summary: presence: %s sla: %s\n", mod_sofia_globals.debug_presence ? "on" : "off", mod_sofia_globals.debug_sla ? "on" : "off"); - + goto done; } - + if (!strcasecmp(argv[1], "siptrace")) { if (argc > 2) { ston = switch_true(argv[2]); @@ -3966,10 +3974,10 @@ SWITCH_STANDARD_API(sofia_function) } if (!strcasecmp(argv[1], "capture")) { - if (argc > 2) { - cton = switch_true(argv[2]); - } - } + if (argc > 2) { + cton = switch_true(argv[2]); + } + } if (!strcasecmp(argv[1], "watchdog")) { if (argc > 2) { @@ -3993,7 +4001,7 @@ SWITCH_STANDARD_API(sofia_function) } else { stream->write_function(stream, "-ERR Usage: siptrace |capture |watchdog |debug gateway_name = switch_core_session_strdup(nsession, gateway_ptr->name); switch_channel_set_variable(nchannel, "sip_gateway_name", gateway_ptr->name); @@ -4217,7 +4225,7 @@ static switch_call_cause_t sofia_outgoing_channel(switch_core_session_t *session dest_to = NULL; } } - + if (params) { tech_pvt->invite_contact = switch_core_session_sprintf(nsession, "%s;%s", gateway_ptr->register_contact, params); tech_pvt->dest = switch_core_session_sprintf(nsession, "%s;%s", tech_pvt->dest, params); @@ -4228,10 +4236,10 @@ static switch_call_cause_t sofia_outgoing_channel(switch_core_session_t *session gateway_ptr->ob_calls++; if (!zstr(gateway_ptr->from_domain) && !switch_channel_get_variable(nchannel, "sip_invite_domain")) { - + if (!strcasecmp(gateway_ptr->from_domain, "auto-aleg-full")) { const char *sip_full_from = switch_channel_get_variable(o_channel, "sip_full_from"); - + if (!zstr(sip_full_from)) { switch_channel_set_variable(nchannel, "sip_force_full_from", sip_full_from); } @@ -4309,7 +4317,7 @@ static switch_call_cause_t sofia_outgoing_channel(switch_core_session_t *session } } else { host++; - + if (!strchr(host, '.') || switch_true(switch_event_get_header(var_event, "sip_gethostbyname"))) { struct sockaddr_in sa; struct hostent *he = gethostbyname(host); @@ -4318,7 +4326,7 @@ static switch_call_cause_t sofia_outgoing_channel(switch_core_session_t *session if (he) { memcpy(&sa.sin_addr, he->h_addr, sizeof(struct in_addr)); ip = inet_ntoa(sa.sin_addr); - + tmp = switch_string_replace(dest, host, ip); //host = switch_core_session_strdup(nsession, ip); //dest = switch_core_session_strdup(nsession, tmp); @@ -4339,7 +4347,7 @@ static switch_call_cause_t sofia_outgoing_channel(switch_core_session_t *session 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; } @@ -4351,7 +4359,7 @@ static switch_call_cause_t sofia_outgoing_channel(switch_core_session_t *session if (!zstr(remote_host)) { switch_split_user_domain(remote_host, NULL, &tech_pvt->mparams.remote_ip); } - } + } if (zstr(tech_pvt->mparams.remote_ip)) { switch_split_user_domain(switch_core_session_strdup(nsession, tech_pvt->dest), NULL, &tech_pvt->mparams.remote_ip); @@ -4373,7 +4381,7 @@ static switch_call_cause_t sofia_outgoing_channel(switch_core_session_t *session switch_channel_set_variable(nchannel, "rtp_secure_media", SWITCH_RTP_CRYPTO_KEY_80); } - if ((hval = switch_event_get_header(var_event, SOFIA_SECURE_MEDIA_VARIABLE)) || + if ((hval = switch_event_get_header(var_event, SOFIA_SECURE_MEDIA_VARIABLE)) || (hval = switch_event_get_header(var_event, "rtp_secure_media"))) { switch_channel_set_variable(nchannel, "rtp_secure_media", hval); @@ -4384,7 +4392,7 @@ static switch_call_cause_t sofia_outgoing_channel(switch_core_session_t *session switch_channel_set_variable(nchannel, "media_webrtc", "true"); switch_core_session_set_ice(nsession); } - + sofia_glue_attach_private(nsession, profile, tech_pvt, dest); @@ -4518,7 +4526,7 @@ static switch_call_cause_t sofia_outgoing_channel(switch_core_session_t *session } if (switch_core_session_compare(session, nsession)) { - /* It's another sofia channel! so lets cache what they use as a pt for telephone event so + /* It's another sofia channel! so lets cache what they use as a pt for telephone event so we can keep it the same */ private_object_t *ctech_pvt; @@ -4680,19 +4688,19 @@ static int notify_callback(void *pArg, int argc, char **argv, char **columnNames dst = sofia_glue_get_destination((char *) contact); - + if (dst->route_uri) { route_uri = sofia_glue_strip_uri(dst->route_uri); } nh = nua_handle(profile->nua, NULL, NUTAG_URL(dst->contact), SIPTAG_FROM_STR(id), SIPTAG_TO_STR(id), SIPTAG_CONTACT_STR(profile->url), TAG_END()); - + nua_handle_bind(nh, &mod_sofia_globals.destroy_private); nua_notify(nh, NUTAG_NEWSUB(1), SIPTAG_SUBSCRIPTION_STATE_STR("terminated;reason=noresource"), TAG_IF(dst->route_uri, NUTAG_PROXY(route_uri)), TAG_IF(dst->route, SIPTAG_ROUTE_STR(dst->route)), SIPTAG_EVENT_STR(es), SIPTAG_CONTENT_TYPE_STR(ct), TAG_IF(!zstr(body), SIPTAG_PAYLOAD_STR(body)), TAG_END()); - + switch_safe_free(route_uri); sofia_glue_free_destination(dst); @@ -4809,32 +4817,32 @@ static void general_event_handler(switch_event_t *event) char *route_uri = NULL; dst = sofia_glue_get_destination((char *) to_uri); - + if (dst->route_uri) { route_uri = sofia_glue_strip_uri(dst->route_uri); } - - + + nh = nua_handle(profile->nua, NULL, - NUTAG_URL(to_uri), + NUTAG_URL(to_uri), SIPTAG_FROM_STR(from_uri), SIPTAG_TO_STR(to_uri), SIPTAG_CONTACT_STR(profile->url), TAG_END()); nua_handle_bind(nh, &mod_sofia_globals.destroy_private); - + nua_notify(nh, NUTAG_NEWSUB(1), SIPTAG_SUBSCRIPTION_STATE_STR("terminated;reason=noresource"), TAG_IF(dst->route_uri, NUTAG_PROXY(dst->route_uri)), TAG_IF(dst->route, SIPTAG_ROUTE_STR(dst->route)), SIPTAG_EVENT_STR(es), TAG_IF(ct, SIPTAG_CONTENT_TYPE_STR(ct)), TAG_IF(!zstr(body), SIPTAG_PAYLOAD_STR(body)), TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)), TAG_END()); - + switch_safe_free(route_uri); sofia_glue_free_destination(dst); - + sofia_glue_release_profile(profile); } @@ -4891,7 +4899,7 @@ static void general_event_handler(switch_event_t *event) const char *user = switch_event_get_header(event, "user"); const char *host = switch_event_get_header(event, "host"); const char *call_id = switch_event_get_header(event, "call-id"); - const char *csta_event = switch_event_get_header(event, "csta-event"); + const char *csta_event = switch_event_get_header(event, "Feature-Event"); char *ct = "application/x-as-feature-event+xml"; @@ -4948,8 +4956,19 @@ static void general_event_handler(switch_event_t *event) ct = switch_mprintf("multipart/mixed; boundary=\"%s\"", boundary_string); } else { + char *fwd_type = NULL; + char *header_name = NULL; + + if ((header_name = switch_event_get_header(event, "forward_immediate"))) { + fwd_type = "forwardImmediate"; + } else if ((header_name = switch_event_get_header(event, "forward_busy"))) { + fwd_type = "forwardBusy"; + } else if ((header_name = switch_event_get_header(event, "forward_no_answer"))) { + fwd_type = "forwardNoAns"; + } + // this will need some work to handle the different types of forwarding events - write_csta_xml_chunk(event, stream, csta_event, NULL); + write_csta_xml_chunk(event, stream, csta_event, fwd_type); } } @@ -4998,7 +5017,7 @@ static void general_event_handler(switch_event_t *event) char *contact, *p; switch_console_callback_match_t *list = NULL; switch_console_callback_match_node_t *m; - + if (!(list = sofia_reg_find_reg_url_multi(profile, user, host))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't find registered user %s@%s\n", user, host); return; @@ -5150,7 +5169,7 @@ static void general_event_handler(switch_event_t *event) if (!strcmp(cond, "network-external-address-change") && mod_sofia_globals.auto_restart) { const char *old_ip4 = switch_event_get_header_nil(event, "network-external-address-previous-v4"); const char *new_ip4 = switch_event_get_header_nil(event, "network-external-address-change-v4"); - + switch_mutex_lock(mod_sofia_globals.hash_mutex); if (mod_sofia_globals.profile_hash && !zstr(old_ip4) && !zstr(new_ip4)) { for (hi = switch_hash_first(NULL, mod_sofia_globals.profile_hash); hi; hi = switch_hash_next(hi)) { @@ -5168,7 +5187,7 @@ static void general_event_handler(switch_event_t *event) } } switch_mutex_unlock(mod_sofia_globals.hash_mutex); - sofia_glue_restart_all_profiles(); + sofia_glue_restart_all_profiles(); } else if (!strcmp(cond, "network-address-change") && mod_sofia_globals.auto_restart) { const char *old_ip4 = switch_event_get_header_nil(event, "network-address-previous-v4"); const char *new_ip4 = switch_event_get_header_nil(event, "network-address-change-v4"); @@ -5248,30 +5267,35 @@ void write_csta_xml_chunk(switch_event_t *event, switch_stream_handle_t stream, stream.write_function(&stream, " %s\n", dndstatus); } } else if(!strcmp(csta_event, "ForwardingEvent")) { - const char *fwdstatus = switch_event_get_header(event, "forwardStatus"); + const char *fwdstatus = NULL; const char *fwdto = NULL; const char *ringcount = NULL; - if (strcmp("forwardImmediate", fwdtype)) { - fwdto = switch_event_get_header(event, "forward_immediate"); - } else if (strcmp("forwardBusy", fwdtype)) { - fwdto = switch_event_get_header(event, "forward_busy"); - } else if (strcmp("fowardNoAns", fwdtype)) { - fwdto = switch_event_get_header(event, "forward_no_answer"); - ringcount = switch_event_get_header(event, "ringCount"); - } + if (fwdtype && !zstr(fwdtype)) { + if (!strcmp("forwardImmediate", fwdtype)) { + fwdto = switch_event_get_header(event, "forward_immediate"); + fwdstatus = switch_event_get_header(event, "forward_immediate_enabled"); + } else if (!strcmp("forwardBusy", fwdtype)) { + fwdto = switch_event_get_header(event, "forward_busy"); + fwdstatus = switch_event_get_header(event, "forward_busy_enabled"); + } else if (!strcmp("forwardNoAns", fwdtype)) { + fwdto = switch_event_get_header(event, "forward_no_answer"); + fwdstatus = switch_event_get_header(event, "forward_no_answer_enabled"); + ringcount = switch_event_get_header(event, "ringCount"); + } - if (fwdtype) { - stream.write_function(&stream, " %s\n", fwdtype); - } - if (fwdstatus) { - stream.write_function(&stream, " %s\n", fwdstatus); - } - if (fwdto) { - stream.write_function(&stream, " %s\n", fwdto); - } - if (ringcount) { - stream.write_function(&stream, " %s\n", ringcount); + if (fwdtype) { + stream.write_function(&stream, " %s\n", fwdtype); + } + if (fwdstatus) { + stream.write_function(&stream, " %s\n", fwdstatus); + } + if (fwdto) { + stream.write_function(&stream, " %s\n", fwdto); + } + if (ringcount) { + stream.write_function(&stream, " %s\n", ringcount); + } } } @@ -5403,7 +5427,7 @@ SWITCH_STANDARD_APP(sofia_sla_function) } switch_channel_answer(channel); - + if ((bargee_session = switch_core_session_locate((char *)data))) { if (bargee_session == session) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "BARGE: %s (cannot barge on myself)\n", (char *) data); @@ -5415,12 +5439,12 @@ SWITCH_STANDARD_APP(sofia_sla_function) switch_channel_set_flag(tech_pvt->channel, CF_SLA_BARGE); switch_ivr_transfer_variable(bargee_session, session, SWITCH_SIGNAL_BOND_VARIABLE); } - + if (switch_core_session_check_interface(session, sofia_endpoint_interface)) { tech_pvt = switch_core_session_get_private(session); switch_channel_set_flag(tech_pvt->channel, CF_SLA_BARGING); } - + switch_channel_set_variable(channel, "sip_barging_uuid", (char *)data); } @@ -5428,7 +5452,7 @@ SWITCH_STANDARD_APP(sofia_sla_function) } switch_channel_execute_on(channel, "execute_on_sip_barge"); - + switch_ivr_eavesdrop_session(session, data, NULL, ED_MUX_READ | ED_MUX_WRITE | ED_COPY_DISPLAY); } @@ -5482,12 +5506,12 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_sofia_load) /* start one message thread */ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Starting initial message thread.\n"); sofia_msg_thread_start(0); - + if (sofia_init() != SWITCH_STATUS_SUCCESS) { return SWITCH_STATUS_GENERR; } - + if (config_sofia(SOFIA_CONFIG_LOAD, NULL) != SWITCH_STATUS_SUCCESS) { mod_sofia_globals.running = 0; return SWITCH_STATUS_GENERR; @@ -5573,7 +5597,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_sofia_load) management_interface->relative_oid = "1001"; management_interface->management_function = sofia_manage; - SWITCH_ADD_APP(app_interface, "sofia_sla", "private sofia sla function", + SWITCH_ADD_APP(app_interface, "sofia_sla", "private sofia sla function", "private sofia sla function", sofia_sla_function, "", SAF_NONE); @@ -5597,7 +5621,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_sofia_load) switch_console_set_complete("add sofia profile"); switch_console_set_complete("add sofia profile restart all"); - + switch_console_set_complete("add sofia profile ::sofia::list_profiles start"); switch_console_set_complete("add sofia profile ::sofia::list_profiles stop wait"); switch_console_set_complete("add sofia profile ::sofia::list_profiles rescan"); @@ -5709,4 +5733,3 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_sofia_shutdown) * For VIM: * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: */ - diff --git a/src/mod/endpoints/mod_sofia/sofia_presence.c b/src/mod/endpoints/mod_sofia/sofia_presence.c index 27e9c6d669..11228355bf 100644 --- a/src/mod/endpoints/mod_sofia/sofia_presence.c +++ b/src/mod/endpoints/mod_sofia/sofia_presence.c @@ -1,4 +1,4 @@ -/* +/* * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application * Copyright (C) 2005-2012, Anthony Minessale II * @@ -22,14 +22,14 @@ * the Initial Developer. All Rights Reserved. * * Contributor(s): - * + * * Anthony Minessale II * Ken Rice * Paul D. Tinsley * Bret McDanel * Raymond Chandler * William King - * Emmanuel Schmidbauer + * Emmanuel Schmidbauer * * sofia_presence.c -- SOFIA SIP Endpoint (presence code) * @@ -98,7 +98,7 @@ struct presence_helper { }; switch_status_t sofia_presence_chat_send(switch_event_t *message_event) - + { char *prof = NULL, *user = NULL, *host = NULL; sofia_profile_t *profile = NULL; @@ -119,7 +119,7 @@ switch_status_t sofia_presence_chat_send(switch_event_t *message_event) char *p = NULL; char *remote_host = NULL; const char *proto; - const char *from; + const char *from; const char *to; //const char *subject; const char *body; @@ -179,14 +179,14 @@ switch_status_t sofia_presence_chat_send(switch_event_t *message_event) if (!prof) { prof = switch_event_get_header(message_event, "sip_profile"); } - + if (!strncasecmp(user, "sip:", 4)) { to_uri = user; } if ((host = strchr(user, '@'))) { if (!to_uri) { - *host++ = '\0'; + *host++ = '\0'; } else { host++; } @@ -228,12 +228,12 @@ switch_status_t sofia_presence_chat_send(switch_event_t *message_event) } } - + if (!strcasecmp(proto, SOFIA_CHAT_PROTO)) { from = from_full; } else { char *fp, *p = NULL; - + fp = strdup(from); switch_assert(fp); @@ -291,7 +291,7 @@ switch_status_t sofia_presence_chat_send(switch_event_t *message_event) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memory Error!\n"); break; } - + /* sofia_glue is running sofia_overcome_sip_uri_weakness we do not, not sure if it matters */ if (dst->route_uri) { @@ -331,7 +331,7 @@ switch_status_t sofia_presence_chat_send(switch_event_t *message_event) if (dup_dest && (p = strstr(dup_dest, ";fs_"))) { *p = '\0'; } - + /* if this cries, add contact here too, change the 1 to 0 and omit the safe_free */ //printf("DEBUG To: [%s] From: [%s] Contact: [%s] RURI [%s] ip [%s] port [%s]\n", to, from, contact, dst->route_uri, network_ip, network_port); @@ -346,17 +346,17 @@ switch_status_t sofia_presence_chat_send(switch_event_t *message_event) TAG_END()); nua_handle_bind(msg_nh, &mod_sofia_globals.destroy_private); - + switch_snprintf(header, sizeof(header), "X-FS-Sending-Message: %s", switch_core_get_uuid()); switch_uuid_str(uuid_str, sizeof(uuid_str)); - + if (is_blocking) { switch_mutex_lock(profile->flag_mutex); switch_core_hash_insert(profile->chat_hash, uuid_str, &mstatus); switch_mutex_unlock(profile->flag_mutex); } - + nua_message(msg_nh, TAG_IF(dst->route_uri, NUTAG_PROXY(dst->route_uri)), TAG_IF(route_uri, NUTAG_PROXY(route_uri)), @@ -371,7 +371,7 @@ switch_status_t sofia_presence_chat_send(switch_event_t *message_event) SIPTAG_HEADER_STR(header), TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)), TAG_END()); - + if (is_blocking) { sanity = 200; @@ -379,7 +379,7 @@ switch_status_t sofia_presence_chat_send(switch_event_t *message_event) while(!mstatus && --sanity && !msg_nh->nh_destroyed) { switch_yield(100000); } - + if (!(mstatus > 199 && mstatus < 300)) { status = SWITCH_STATUS_FALSE; } @@ -394,7 +394,7 @@ switch_status_t sofia_presence_chat_send(switch_event_t *message_event) sofia_glue_free_destination(dst); switch_safe_free(dup_dest); switch_safe_free(remote_host); - } + } end: @@ -425,23 +425,23 @@ void sofia_presence_cancel(void) if (!mod_sofia_globals.profile_hash) { return; } - + if (list_profiles_full(NULL, NULL, &matches, SWITCH_FALSE) == SWITCH_STATUS_SUCCESS) { switch_console_callback_match_node_t *m; - + for (m = matches->head; m; m = m->next) { if ((profile = sofia_glue_find_profile(m->val))) { if (profile->pres_type == PRES_TYPE_FULL) { helper.profile = profile; helper.event = NULL; - + sql = switch_mprintf("select proto,sip_user,sip_host,sub_to_user,sub_to_host,event,contact,call_id,full_from," "full_via,expires,user_agent,accept,profile_name,network_ip" ",-1,'unavailable','unavailable' from sip_subscriptions where " "event='presence' and hostname='%q' and profile_name='%q'", mod_sofia_globals.hostname, profile->name); - + r = sofia_glue_execute_sql_callback(profile, profile->dbh_mutex, sql, sofia_presence_sub_callback, &helper); switch_safe_free(sql); @@ -453,7 +453,7 @@ void sofia_presence_cancel(void) sofia_glue_release_profile(profile); } } - + switch_console_free_matches(&matches); } @@ -528,16 +528,16 @@ static void actual_sofia_presence_mwi_event_handler(switch_event_t *event) if ((pname = switch_event_get_header(event, "sofia-profile"))) { profile = sofia_glue_find_profile(pname); } - + if (!profile) { if (!host || !(profile = sofia_glue_find_profile(host))) { char *sql; char buf[512] = ""; switch_console_callback_match_t *matches; - sql = switch_mprintf("select profile_name from sip_registrations where hostname='%q' and (sip_host='%s' or mwi_host='%s')", + sql = switch_mprintf("select profile_name from sip_registrations where hostname='%q' and (sip_host='%s' or mwi_host='%s')", mod_sofia_globals.hostname, host, host); - + if (list_profiles_full(NULL, NULL, &matches, SWITCH_FALSE) == SWITCH_STATUS_SUCCESS) { switch_console_callback_match_node_t *m; @@ -597,7 +597,7 @@ static void actual_sofia_presence_mwi_event_handler(switch_event_t *event) "full_via,expires,user_agent,accept,profile_name,network_ip" ",'%q',full_to,network_ip,network_port from sip_subscriptions " "where hostname='%q' and event='message-summary' " - "and sub_to_user='%q' and (sub_to_host='%q' or presence_hosts like '%%%q%%')", + "and sub_to_user='%q' and (sub_to_host='%q' or presence_hosts like '%%%q%%')", stream.data, mod_sofia_globals.hostname, user, host, host); } else if (sub_call_id) { sql = switch_mprintf("select proto,sip_user,sip_host,sub_to_user,sub_to_host,event,contact,call_id,full_from," @@ -618,11 +618,11 @@ static void actual_sofia_presence_mwi_event_handler(switch_event_t *event) if (for_everyone) { sql = switch_mprintf("select sip_user,sip_host,contact,profile_name,network_ip,'%q',call_id " - "from sip_registrations where hostname='%q' and mwi_user='%q' and mwi_host='%q'", + "from sip_registrations where hostname='%q' and mwi_user='%q' and mwi_host='%q'", stream.data, mod_sofia_globals.hostname, user, host); } else if (call_id) { sql = switch_mprintf("select sip_user,sip_host,contact,profile_name,network_ip,'%q',call_id " - "from sip_registrations where hostname='%q' and call_id='%q'", + "from sip_registrations where hostname='%q' and call_id='%q'", stream.data, mod_sofia_globals.hostname, call_id); } @@ -654,7 +654,7 @@ static int sofia_presence_dialog_callback(void *pArg, int argc, char **argv, cha } if (mod_sofia_globals.debug_presence > 0) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "CHECK DIALOG state[%s] status[%s] rpid[%s] pres[%s] uuid[%s]\n", + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "CHECK DIALOG state[%s] status[%s] rpid[%s] pres[%s] uuid[%s]\n", argv[0], argv[1], argv[2], argv[3], argv[4]); } @@ -683,7 +683,7 @@ static void do_normal_probe(switch_event_t *event) sofia_profile_t *profile; //DUMP_EVENT(event); - + if (!proto || strcasecmp(proto, SOFIA_CHAT_PROTO) != 0) { return; } @@ -703,10 +703,10 @@ static void do_normal_probe(switch_event_t *event) if (probe_euser && probe_host && (profile = sofia_glue_find_profile(probe_host))) { sql = switch_mprintf("select state,status,rpid,presence_id,uuid from sip_dialogs " "where hostname='%q' and profile_name='%q' and call_info_state != 'seized' and " - "((sip_from_user='%q' and sip_from_host='%q') or presence_id='%q@%q') order by rcd desc", + "((sip_from_user='%q' and sip_from_host='%q') or presence_id='%q@%q') order by rcd desc", mod_sofia_globals.hostname, profile->name, probe_euser, probe_host, probe_euser, probe_host); - - + + sofia_glue_execute_sql_callback(profile, profile->dbh_mutex, sql, sofia_presence_dialog_callback, &dh); h.profile = profile; @@ -736,7 +736,7 @@ static void do_normal_probe(switch_event_t *event) "sip_dialogs.presence_id = sip_registrations.sip_user %q '@' %q sip_registrations.sub_host " "or (sip_dialogs.sip_from_user = sip_registrations.sip_user " "and sip_dialogs.sip_from_host = sip_registrations.sip_host)) " - + "left join sip_presence on " "sip_presence.hostname=sip_registrations.hostname and " "(sip_registrations.sip_user=sip_presence.sip_user and sip_registrations.orig_server_host=sip_presence.sip_host and " @@ -748,11 +748,11 @@ static void do_normal_probe(switch_event_t *event) dh.status, dh.rpid, switch_str_nil(sub_call_id), switch_sql_concat(), switch_sql_concat(), mod_sofia_globals.hostname, profile->name, probe_euser, probe_host, probe_euser, probe_host, probe_host); - - + + switch_assert(sql); - + if (mod_sofia_globals.debug_presence > 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s START_PRESENCE_PROBE_SQL\n", profile->name); } @@ -762,19 +762,19 @@ static void do_normal_probe(switch_event_t *event) } sofia_glue_execute_sql_callback(profile, profile->dbh_mutex, sql, sofia_presence_resub_callback, &h); - switch_safe_free(sql); + switch_safe_free(sql); if (!h.rowcount) { h.noreg++; - + /* find ones with presence_id defined that are not registred */ sql = switch_mprintf("select sip_from_user, sip_from_host, 'Registered', '', '', " "uuid, state, direction, " "sip_to_user, sip_to_host," "'%q','%q',presence_id, '','','' " - + "from sip_dialogs " - + "where call_info_state != 'seized' and hostname='%q' and profile_name='%q' and (presence_id='%q@%q' or " "(sip_from_user='%q' and (sip_from_host='%q' or sip_to_host='%q')))", mod_sofia_globals.hostname, profile->name, @@ -790,7 +790,7 @@ static void do_normal_probe(switch_event_t *event) sofia_glue_execute_sql_callback(profile, profile->dbh_mutex, sql, sofia_presence_resub_callback, &h); switch_safe_free(sql); - + if (mod_sofia_globals.debug_presence > 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s END_PRESENCE_PROBE_SQL\n\n", profile->name); } @@ -804,13 +804,13 @@ static void do_normal_probe(switch_event_t *event) switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, "from", "%s@%s", probe_euser, probe_host); switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "status", "Unregistered"); switch_event_fire(&sevent); - } + } } sofia_glue_release_profile(profile); } - + switch_safe_free(probe_user); } @@ -935,7 +935,7 @@ static void send_conference_data(sofia_profile_t *profile, switch_event_t *event const char *body = switch_event_get_body(event); const char *type = "application/conference-info+xml"; const char *final = switch_event_get_header(event, "final"); - + if (!event_str) { event_str = "conference"; } @@ -962,36 +962,36 @@ static void send_conference_data(sofia_profile_t *profile, switch_event_t *event if (call_id) { if (switch_true(final)) { - sql = switch_mprintf("update sip_subscriptions set expires=%ld where " - "hostname='%q' and profile_name='%q' and sub_to_user='%q' and sub_to_host='%q' and event='%q' " - "and call_id = '%q' ", - (long)0, - mod_sofia_globals.hostname, profile->name, - from_user, from_host, event_str, call_id); + sql = switch_mprintf("update sip_subscriptions set expires=%ld where " + "hostname='%q' and profile_name='%q' and sub_to_user='%q' and sub_to_host='%q' and event='%q' " + "and call_id = '%q' ", + (long)0, + mod_sofia_globals.hostname, profile->name, + from_user, from_host, event_str, call_id); - sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE); + sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE); } sql = switch_mprintf("select full_to, full_from, contact %q ';_;isfocus', expires, call_id, event, network_ip, network_port, " "'%q' as ct,'%q' as pt " " from sip_subscriptions where " "hostname='%q' and profile_name='%q' and sub_to_user='%q' and sub_to_host='%q' and event='%q' " - "and call_id = '%q' ", + "and call_id = '%q' ", switch_sql_concat(), type, switch_str_nil(body), mod_sofia_globals.hostname, profile->name, from_user, from_host, event_str, call_id); } else { - if (switch_true(final)) { - sql = switch_mprintf("update sip_subscriptions set expires=%ld where " - "hostname='%q' and profile_name='%q' and sub_to_user='%q' and sub_to_host='%q' and event='%q'", - (long)0, - mod_sofia_globals.hostname, profile->name, - from_user, from_host, event_str); + if (switch_true(final)) { + sql = switch_mprintf("update sip_subscriptions set expires=%ld where " + "hostname='%q' and profile_name='%q' and sub_to_user='%q' and sub_to_host='%q' and event='%q'", + (long)0, + mod_sofia_globals.hostname, profile->name, + from_user, from_host, event_str); - sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE); - } + sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE); + } sql = switch_mprintf("select full_to, full_from, contact %q ';_;isfocus', expires, call_id, event, network_ip, network_port, " "'%q' as ct,'%q' as pt " @@ -1014,7 +1014,7 @@ static void send_conference_data(sofia_profile_t *profile, switch_event_t *event "and call_id = '%q' ", mod_sofia_globals.hostname, profile->name, from_user, from_host, event_str, call_id); - + } else { sql = switch_mprintf("delete from sip_subscriptions where " "hostname='%q' and profile_name='%q' and sub_to_user='%q' and sub_to_host='%q' and event='%q'", @@ -1045,7 +1045,7 @@ static void conference_data_event_handler(switch_event_t *event) if ((pname = switch_event_get_header(event, "sofia-profile"))) { profile = sofia_glue_find_profile(pname); } - + if (host && !profile) { profile = sofia_glue_find_profile(host); } @@ -1055,17 +1055,17 @@ static void conference_data_event_handler(switch_event_t *event) sofia_glue_release_profile(profile); } else { switch_console_callback_match_t *matches; - + if (list_profiles_full(NULL, NULL, &matches, SWITCH_FALSE) == SWITCH_STATUS_SUCCESS) { switch_console_callback_match_node_t *m; - + for (m = matches->head; m; m = m->next) { if ((profile = sofia_glue_find_profile(m->val))) { send_conference_data(profile, event); sofia_glue_release_profile(profile); } } - + switch_console_free_matches(&matches); } } @@ -1091,7 +1091,7 @@ static switch_event_t *actual_sofia_presence_event_handler(switch_event_t *event char *call_info_state = switch_event_get_header(event, "presence-call-info-state"); const char *uuid = switch_event_get_header(event, "unique-id"); switch_console_callback_match_t *matches = NULL; - struct presence_helper helper = { 0 }; + struct presence_helper helper = { 0 }; int hup = 0; switch_event_t *s_event = NULL; @@ -1135,25 +1135,25 @@ static switch_event_t *actual_sofia_presence_event_handler(switch_event_t *event if ((profile = sofia_glue_find_profile(m->val))) { if (profile->pres_type != PRES_TYPE_FULL) { - + if (!mod_sofia_globals.profile_hash) { switch_console_free_matches(&matches); goto done; } - + if (from) { - + sql = switch_mprintf("update sip_subscriptions set version=version+1 where hostname='%q' and profile_name='%q' and " "sip_subscriptions.event='presence' and sip_subscriptions.full_from like '%%%q%%'", mod_sofia_globals.hostname, profile->name, from); - + if (mod_sofia_globals.debug_presence > 1) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "PRES SQL %s\n", sql); } - + sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE); - - + + sql = switch_mprintf("select sip_subscriptions.proto,sip_subscriptions.sip_user,sip_subscriptions.sip_host," "sip_subscriptions.sub_to_user,sip_subscriptions.sub_to_host,sip_subscriptions.event," "sip_subscriptions.contact,sip_subscriptions.call_id,sip_subscriptions.full_from," @@ -1173,13 +1173,13 @@ static switch_event_t *actual_sofia_presence_event_handler(switch_event_t *event sql = switch_mprintf("update sip_subscriptions set version=version+1 where hostname='%q' and profile_name='%q' and " "sip_subscriptions.event='presence'", mod_sofia_globals.hostname, profile->name); - + if (mod_sofia_globals.debug_presence > 1) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "PRES SQL %s\n", sql); } - + sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE); - + sql = switch_mprintf("select sip_subscriptions.proto,sip_subscriptions.sip_user,sip_subscriptions.sip_host," "sip_subscriptions.sub_to_user,sip_subscriptions.sub_to_host,sip_subscriptions.event," "sip_subscriptions.contact,sip_subscriptions.call_id,sip_subscriptions.full_from," @@ -1196,9 +1196,9 @@ static switch_event_t *actual_sofia_presence_event_handler(switch_event_t *event "sip_subscriptions.event='presence'", switch_str_nil(status), switch_str_nil(rpid), mod_sofia_globals.hostname, profile->name); } - + switch_assert(sql != NULL); - + if (mod_sofia_globals.debug_presence > 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "%s is passive, skipping\n", (char *) profile->name); @@ -1216,7 +1216,7 @@ static switch_event_t *actual_sofia_presence_event_handler(switch_event_t *event } switch_console_free_matches(&matches); } - + switch_safe_free(sql); goto done; } @@ -1258,10 +1258,10 @@ static switch_event_t *actual_sofia_presence_event_handler(switch_event_t *event { char *probe_type = switch_event_get_header(event, "probe-type"); - if (!probe_type || strcasecmp(probe_type, "dialog")) { + if (!probe_type || strcasecmp(probe_type, "dialog")) { /* NORMAL PROBE */ do_normal_probe(event); - } else { + } else { /* DIALOG PROBE */ do_dialog_probe(event); } @@ -1270,7 +1270,7 @@ static switch_event_t *actual_sofia_presence_event_handler(switch_event_t *event default: break; - } + } if (!mod_sofia_globals.profile_hash) { goto done; @@ -1299,8 +1299,8 @@ static switch_event_t *actual_sofia_presence_event_handler(switch_event_t *event switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "CHECK CALL_INFO [%s]\n", switch_str_nil(call_info)); } - if (call_info) { - + if (call_info) { + if (uuid) { sql = switch_mprintf("update sip_dialogs set call_info='%q',call_info_state='%q' where " "hostname='%q' and profile_name='%q' and uuid='%q'", @@ -1308,25 +1308,25 @@ static switch_event_t *actual_sofia_presence_event_handler(switch_event_t *event } else { sql = switch_mprintf("update sip_dialogs set call_info='%q', call_info_state='%q' where hostname='%q' and profile_name='%q' and " "((sip_dialogs.sip_from_user='%q' and sip_dialogs.sip_from_host='%q') or presence_id='%q@%q') and call_info='%q'", - + call_info, call_info_state, mod_sofia_globals.hostname, profile->name, euser, host, euser, host, call_info); - + } - + if (mod_sofia_globals.debug_sla > 1) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "STATE SQL %s\n", sql); } sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE); - + if (mod_sofia_globals.debug_sla > 1) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "PROCESS PRESENCE EVENT\n"); } - + sync_sla(profile, euser, host, SWITCH_TRUE, SWITCH_TRUE, call_id); } - + if (!strcmp(proto, "dp")) { sql = switch_mprintf("update sip_presence set rpid='%q',status='%q' where hostname='%q' and profile_name='%q' and " "sip_user='%q' and sip_host='%q'", @@ -1336,20 +1336,20 @@ static switch_event_t *actual_sofia_presence_event_handler(switch_event_t *event } if (zstr(uuid)) { - + sql = switch_mprintf("select state,status,rpid,presence_id,uuid from sip_dialogs " "where call_info_state != 'seized' and hostname='%q' and profile_name='%q' and " - "((sip_from_user='%q' and sip_from_host='%q') or presence_id='%q@%q') order by rcd desc", + "((sip_from_user='%q' and sip_from_host='%q') or presence_id='%q@%q') order by rcd desc", mod_sofia_globals.hostname, profile->name, euser, host, euser, host); } else { sql = switch_mprintf("select state,status,rpid,presence_id,uuid from sip_dialogs " "where uuid != '%q' and call_info_state != 'seized' and hostname='%q' and profile_name='%q' and " - "((sip_from_user='%q' and sip_from_host='%q') or presence_id='%q@%q') order by rcd desc", + "((sip_from_user='%q' and sip_from_host='%q') or presence_id='%q@%q') order by rcd desc", uuid, mod_sofia_globals.hostname, profile->name, euser, host, euser, host); } sofia_glue_execute_sql_callback(profile, profile->dbh_mutex, sql, sofia_presence_dialog_callback, &dh); - + if (mod_sofia_globals.debug_presence > 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "CHECK SQL: %s@%s [%s]\nhits: %d\n", euser, host, sql, dh.hits); } @@ -1366,29 +1366,29 @@ static switch_event_t *actual_sofia_presence_event_handler(switch_event_t *event if (rpid) { rpid = sofia_presence_translate_rpid(rpid, status); } - + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Answer-State", "early"); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "status", status); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Channel-State", status); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Channel-Call-State", "EARLY"); - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "astate", "early"); - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "answer-state", "early"); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "astate", "early"); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "answer-state", "early"); } else { status = "CS_EXECUTE"; if (rpid) { rpid = sofia_presence_translate_rpid(rpid, status); } - + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Answer-State", "answered"); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "status", status); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Channel-State", status); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Channel-Call-State", "ACTIVE"); - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "astate", "confirmed"); - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "answer-state", "confirmed"); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "astate", "confirmed"); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "answer-state", "confirmed"); } } - + if (zstr(call_id) && (dh.hits && presence_source && (!strcasecmp(presence_source, "register") || switch_stristr("register", status)))) { goto done; @@ -1401,11 +1401,11 @@ static switch_event_t *actual_sofia_presence_event_handler(switch_event_t *event "and sip_subscriptions.proto='%q' and (event='%q' or event='%q') and sub_to_user='%q' and " "(sub_to_host='%q' or sub_to_host='%q' or sub_to_host='%q' or " "presence_hosts like '%%%q%%') and " - "(sip_subscriptions.profile_name = '%q' or presence_hosts like '%%%q%%')", + "(sip_subscriptions.profile_name = '%q' or presence_hosts like '%%%q%%')", mod_sofia_globals.hostname, profile->name, proto, event_type, alt_event_type, euser, host, profile->sipip, profile->extsipip ? profile->extsipip : "N/A", host, profile->name, host); - + if (mod_sofia_globals.debug_presence > 1) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "PRES SQL %s\n", sql); @@ -1414,7 +1414,7 @@ static switch_event_t *actual_sofia_presence_event_handler(switch_event_t *event sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE); - + sql = switch_mprintf("select distinct sip_subscriptions.proto,sip_subscriptions.sip_user,sip_subscriptions.sip_host," "sip_subscriptions.sub_to_user,sip_subscriptions.sub_to_host,sip_subscriptions.event," "sip_subscriptions.contact,sip_subscriptions.call_id,sip_subscriptions.full_from," @@ -1427,23 +1427,23 @@ static switch_event_t *actual_sofia_presence_event_handler(switch_event_t *event "left join sip_presence on " "(sip_subscriptions.sub_to_user=sip_presence.sip_user and sip_subscriptions.sub_to_host=sip_presence.sip_host and " "sip_subscriptions.profile_name=sip_presence.profile_name and sip_subscriptions.hostname=sip_presence.hostname) " - + "where sip_subscriptions.hostname='%q' and sip_subscriptions.profile_name='%q' and " "sip_subscriptions.event != 'line-seize' and " "sip_subscriptions.proto='%q' and " "(event='%q' or event='%q') and sub_to_user='%q' " "and (sub_to_host='%q' or sub_to_host='%q' or sub_to_host='%q' or presence_hosts like '%%%q%%') ", - - + + switch_str_nil(status), switch_str_nil(rpid), host, dh.status,dh.rpid,dh.presence_id, mod_sofia_globals.hostname, profile->name, proto, - event_type, alt_event_type, euser, host, profile->sipip, + event_type, alt_event_type, euser, host, profile->sipip, profile->extsipip ? profile->extsipip : "N/A", host); } else { sql = switch_mprintf("update sip_subscriptions set version=version+1 where sip_subscriptions.event != 'line-seize' and " "sip_subscriptions.call_id='%q'", call_id); - + if (mod_sofia_globals.debug_presence > 1) { @@ -1465,23 +1465,23 @@ static switch_event_t *actual_sofia_presence_event_handler(switch_event_t *event "left join sip_presence on " "(sip_subscriptions.sub_to_user=sip_presence.sip_user and sip_subscriptions.sub_to_host=sip_presence.sip_host and " "sip_subscriptions.profile_name=sip_presence.profile_name and sip_subscriptions.hostname=sip_presence.hostname) " - + "where sip_subscriptions.hostname='%q' and sip_subscriptions.profile_name='%q' and " "sip_subscriptions.event != 'line-seize' and " "sip_subscriptions.call_id='%q'", - + switch_str_nil(status), switch_str_nil(rpid), host, dh.status,dh.rpid,dh.presence_id, mod_sofia_globals.hostname, profile->name, call_id); } - + helper.hup = hup; helper.calls_up = dh.hits; helper.profile = profile; helper.event = event; SWITCH_STANDARD_STREAM(helper.stream); switch_assert(helper.stream.data); - + if (mod_sofia_globals.debug_presence > 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s START_PRESENCE_SQL (%s)\n", event->event_id == SWITCH_EVENT_PRESENCE_IN ? "IN" : "OUT", profile->name); @@ -1501,14 +1501,14 @@ static switch_event_t *actual_sofia_presence_event_handler(switch_event_t *event sofia_glue_execute_sql_callback(profile, profile->dbh_mutex, sql, sofia_presence_sub_callback, &helper); switch_safe_free(sql); - + if (mod_sofia_globals.debug_presence > 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s END_PRESENCE_SQL (%s)\n", event->event_id == SWITCH_EVENT_PRESENCE_IN ? "IN" : "OUT", profile->name); } #if 0 - if (hup && dh.hits < 1) { + if (hup && dh.hits < 1) { /* so many phones get confused when whe hangup we have to reprobe to get them all to reset to absolute states so the lights stay correct */ if (switch_event_create(&s_event, SWITCH_EVENT_PRESENCE_PROBE) == SWITCH_STATUS_SUCCESS) { switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO); @@ -1520,13 +1520,13 @@ static switch_event_t *actual_sofia_presence_event_handler(switch_event_t *event sofia_event_fire(profile, &s_event); } } -#endif - +#endif + if (!zstr((char *) helper.stream.data)) { char *this_sql = (char *) helper.stream.data; char *next = NULL; char *last = NULL; - + do { if ((next = strchr(this_sql, ';'))) { *next++ = '\0'; @@ -1534,7 +1534,7 @@ static switch_event_t *actual_sofia_presence_event_handler(switch_event_t *event *next++ = '\0'; } } - + if (!zstr(this_sql) && (!last || strcmp(last, this_sql))) { sofia_glue_execute_sql(profile, &this_sql, SWITCH_FALSE); last = this_sql; @@ -1544,7 +1544,7 @@ static switch_event_t *actual_sofia_presence_event_handler(switch_event_t *event } switch_safe_free(helper.stream.data); helper.stream.data = NULL; - + sofia_glue_release_profile(profile); } } @@ -2017,7 +2017,7 @@ static int sofia_dialog_probe_callback(void *pArg, int argc, char **argv, char * else if (proto && !strcasecmp(proto, "conf")) { local_user = to_user; local_user_param = switch_mprintf(";proto=%s", proto); - if (skip_proto) { + if (skip_proto) { buf_to_free = switch_mprintf("sip:%s@%s", to_user, host); } else { buf_to_free = switch_mprintf("sip:conf+%s@%s", to_user, host); @@ -2082,9 +2082,9 @@ static int sofia_dialog_probe_callback(void *pArg, int argc, char **argv, char * #define send_presence_notify(_a,_b,_c,_d,_e,_f,_g,_h,_i,_j,_k,_l) \ _send_presence_notify(_a,_b,_c,_d,_e,_f,_g,_h,_i,_j,_k,_l,__FILE__, __SWITCH_FUNC__, __LINE__) -static void _send_presence_notify(sofia_profile_t *profile, - const char *full_to, - const char *full_from, +static void _send_presence_notify(sofia_profile_t *profile, + const char *full_to, + const char *full_from, const char *o_contact, const char *expires, const char *call_id, @@ -2122,7 +2122,9 @@ static void _send_presence_notify(sofia_profile_t *profile, cparams += 3; } - path = sofia_glue_get_path_from_contact((char *) o_contact); + if (!switch_stristr("fs_nat=yes", o_contact)) { + path = sofia_glue_get_path_from_contact((char *) o_contact); + } tmp = (char *)o_contact; o_contact_dup = sofia_glue_get_url_from_contact(tmp, 1); @@ -2141,10 +2143,10 @@ static void _send_presence_notify(sofia_profile_t *profile, our_contact = our_contact_dup; } - + if (!zstr(remote_ip) && sofia_glue_check_nat(profile, remote_ip)) { char *ptr = NULL; - + if ((ptr = sofia_glue_find_parameter(o_contact, "transport="))) { sofia_transport_t transport = sofia_glue_str2transport(ptr); @@ -2168,22 +2170,22 @@ static void _send_presence_notify(sofia_profile_t *profile, } else { contact_str = our_contact; } - - + + if ((to_uri = sofia_glue_get_url_from_contact((char *)full_to, 1))) { char *p; - + if ((p = strstr(to_uri, "sip:"))) { char *q; - + p += 4; if ((q = strchr(p, '@'))) { *q++ = '\0'; - + if ((dcs = switch_string_replace(contact_str, "mod_sofia", p))) { contact_str = dcs; } - + } } @@ -2198,7 +2200,7 @@ static void _send_presence_notify(sofia_profile_t *profile, } else { contact = strdup(o_contact); } - + if (dst->route_uri) { route_uri = sofia_glue_strip_uri(dst->route_uri); } else { @@ -2209,7 +2211,7 @@ static void _send_presence_notify(sofia_profile_t *profile, if (expires) { long ltmp = atol(expires); - + if (ltmp > 0) { exptime = (ltmp - now); } else { @@ -2248,14 +2250,14 @@ static void _send_presence_notify(sofia_profile_t *profile, ); } - + switch_mutex_lock(profile->ireg_mutex); if (!profile->cseq_base) { profile->cseq_base = (now - 1312693200) * 10; } callsequence = ++profile->cseq_base; switch_mutex_unlock(profile->ireg_mutex); - + if (cparams) { send_contact = switch_mprintf("%s;%s", contact_str, cparams); contact_str = send_contact; @@ -2270,25 +2272,25 @@ static void _send_presence_notify(sofia_profile_t *profile, nua_notify(nh, NUTAG_NEWSUB(1), - TAG_IF(route_uri, NUTAG_PROXY(route_uri)), + TAG_IF(route_uri, NUTAG_PROXY(route_uri)), TAG_IF(dst->route, SIPTAG_ROUTE_STR(dst->route)), TAG_IF(user_via, SIPTAG_VIA_STR(user_via)), TAG_IF(path, SIPTAG_RECORD_ROUTE_STR(path)), - + SIPTAG_FROM_STR(full_to), SIPTAG_TO_STR(full_from), - + SIPTAG_CALL_ID_STR(call_id), TAG_IF(*expires_str, SIPTAG_EXPIRES_STR(expires_str)), - SIPTAG_SUBSCRIPTION_STATE_STR(sstr), - SIPTAG_EVENT_STR(event), + SIPTAG_SUBSCRIPTION_STATE_STR(sstr), + SIPTAG_EVENT_STR(event), TAG_IF(!zstr(ct), SIPTAG_CONTENT_TYPE_STR(ct)), TAG_IF(!zstr(pl), SIPTAG_PAYLOAD_STR(pl)), TAG_IF(!zstr(call_info), SIPTAG_CALL_INFO_STR(call_info)), TAG_IF(!exptime, SIPTAG_EXPIRES_STR("0")), SIPTAG_CSEQ(cseq), TAG_END()); - + switch_safe_free(route_uri); switch_safe_free(dcs); @@ -2320,20 +2322,20 @@ static int sofia_dialog_probe_notify_callback(void *pArg, int argc, char **argv, char *contact = argv[9]; char *remote_ip = argv[10]; char *remote_port = argv[11]; - + switch_stream_handle_t stream = { 0 }; char *to; const char *pl = NULL; const char *ct = "application/dialog-info+xml"; if (mod_sofia_globals.debug_presence > 0) { - int i; + int i; for(i = 0; i < argc; i++) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "arg %d[%s] = [%s]\n", i, columnNames[i], argv[i]); } } - + if (mod_sofia_globals.debug_presence > 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "SEND DIALOG\nTo: \t%s@%s\nFrom: \t%s@%s\nCall-ID: \t%s\n", @@ -2372,9 +2374,9 @@ static int sofia_dialog_probe_notify_callback(void *pArg, int argc, char **argv, } - send_presence_notify(sh->profile, - full_to, - full_from, + send_presence_notify(sh->profile, + full_to, + full_from, contact, expires, call_id, @@ -2460,13 +2462,13 @@ static char *gen_pidf(char *user_agent, char *id, char *url, char *open, char *r " \n" "
\n" " \n" - " \n" - "
\n" - "
\n" + " \n" + " \n" + " \n" "\n", status, id, id, url, open, prpid); } else { char *xml_rpid = NULL; - + *ct = "application/pidf+xml"; if (!strcasecmp(open, "closed")) { @@ -2477,7 +2479,7 @@ static char *gen_pidf(char *user_agent, char *id, char *url, char *open, char *r if (!strncasecmp(status, "Registered", 10)) { status = "Available"; } - + if (!strcasecmp(status, "Available")) { prpid = NULL; } @@ -2497,7 +2499,7 @@ static char *gen_pidf(char *user_agent, char *id, char *url, char *open, char *r status = "Available"; prpid = NULL; } - + if (prpid) { xml_rpid = switch_mprintf(" \r\n" " \n" @@ -2517,9 +2519,9 @@ static char *gen_pidf(char *user_agent, char *id, char *url, char *open, char *r " \n" "%s" " %s\n" - " \n" + " \n" "", id, open, switch_str_nil(xml_rpid), status); - + switch_safe_free(xml_rpid); } @@ -2582,7 +2584,7 @@ static int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char * if (mod_sofia_globals.debug_presence > 0) { - int i; + int i; for(i = 0; i < argc; i++) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "arg %d[%s] = [%s]\n", i, columnNames[i], argv[i]); } @@ -2613,7 +2615,7 @@ static int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char * if (!zstr(presence_id) && strchr(presence_id, '@')) { char *p; - + free_me = strdup(presence_id); if ((p = strchr(free_me, '@'))) { @@ -2622,7 +2624,7 @@ static int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char * user = free_me; } - + if (!zstr(orig_proto) && !strcmp(orig_proto, SOFIA_CHAT_PROTO)) { skip_proto = 1; @@ -2668,7 +2670,7 @@ static int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char * if (!rpid) { rpid = "unknown"; } - + // if (!strcasecmp(proto, SOFIA_CHAT_PROTO) || skip_proto) { // clean_id = switch_mprintf("sip:%s@%s", sub_to_user, sub_to_host); //} else { @@ -2736,7 +2738,7 @@ static int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char * //if (user_agent && switch_stristr("snom", user_agent) && uuid) { // default_dialog = "full" ; //} - + if (call_state && !strcasecmp(call_state, "cs_hangup")) { astate = "hangup"; holding = 0; @@ -2758,7 +2760,7 @@ static int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char * if (!strcasecmp(direction, "inbound")) { from_id = switch_str_nil(switch_event_get_header(helper->event, "Caller-Destination-Number")); - + } else { from_id = switch_str_nil(switch_event_get_header(helper->event, "Caller-Caller-ID-Number")); from_name = switch_event_get_header(helper->event, "Caller-Caller-ID-Name"); @@ -2770,7 +2772,7 @@ static int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char * if (zstr(from_name)) { from_name = switch_event_get_header(helper->event, "Other-Leg-Caller-ID-Name"); } - + } #if 0 @@ -2784,7 +2786,7 @@ static int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char * if (is_dialog) { SWITCH_STANDARD_STREAM(stream); } - + if (is_dialog) { // Usually we report the dialogs FROM the probed user. The exception is when the monitored endpoint is internal, // and its presence_id is set in the dialplan. Reverse the direction if this is not a registered entity. @@ -2815,14 +2817,14 @@ static int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char * "\n" "\n", version, default_dialog, clean_id); - + } if (!zstr(uuid)) { if (!zstr(answer_state)) { astate = answer_state; } - + if (zstr(astate)) { if (is_dialog) { astate = dft_state; @@ -2834,8 +2836,8 @@ static int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char * if (!strcasecmp(astate, "answered")) { astate = "confirmed"; } - - + + if (is_dialog) { if (!strcasecmp(astate, "ringing")) { @@ -2860,7 +2862,7 @@ static int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char * if (!strcasecmp(astate, "hangup")) { astate = "terminated"; } - + stream.write_function(&stream, "\n", uuid, direction); stream.write_function(&stream, "%s\n", astate); } else { @@ -2870,12 +2872,12 @@ static int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char * } - if ((sofia_test_pflag(profile, PFLAG_PRESENCE_DISABLE_EARLY) || switch_true(disable_early)) && + if ((sofia_test_pflag(profile, PFLAG_PRESENCE_DISABLE_EARLY) || switch_true(disable_early)) && ((!zstr(astate) && (!strcasecmp(astate, "early") || !strcasecmp(astate, "ringing") || (!strcasecmp(astate, "terminated") && !answered))))) { switch_safe_free(stream.data); goto end; } - + if (!strcasecmp(astate, "early") || !strcasecmp(astate, "confirmed")) { clean_to_user = switch_mprintf("%s", sub_to_user ? sub_to_user : to_user); @@ -2886,12 +2888,12 @@ static int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char * stream.write_function(&stream, "\nsip:%s@%s\n", clean_to_user, clean_to_user, host); stream.write_function(&stream, "\n", clean_to_user, host); stream.write_function(&stream, "\n", holding ? "no" : "yes"); - + stream.write_function(&stream, "\n\n"); if (switch_true(switch_event_get_header(helper->event, "Presence-Privacy"))) { stream.write_function(&stream, "\nsip:anonymous@anonymous.invalid\n"); } else { - stream.write_function(&stream, "\nsip:%s@%s\n", + stream.write_function(&stream, "\nsip:%s@%s\n", from_name ? from_name : clean_from_user, clean_from_user, host); } @@ -2938,7 +2940,7 @@ static int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char * } else if (!strcasecmp(proto, "conf")) { stream.write_function(&stream, "\nsip:%s@%s;proto=conference\n", !zstr(clean_to_user) ? clean_to_user : "unknown", host); - stream.write_function(&stream, "\n", + stream.write_function(&stream, "\n", !zstr(clean_to_user) ? clean_to_user : "unknown", host); stream.write_function(&stream, "\n\n\n"); stream.write_function(&stream, "\nsip:%s@%s\n", uuid, host); @@ -2965,9 +2967,9 @@ static int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char * ct = "application/dialog-info+xml"; } - if (!zstr(astate) && !zstr(uuid) && + if (!zstr(astate) && !zstr(uuid) && helper && helper->stream.data && strcmp(helper->last_uuid, uuid) && strcasecmp(astate, "terminated") && strchr(uuid, '-')) { - helper->stream.write_function(&helper->stream, "update sip_dialogs set state='%s' where hostname='%q' and profile_name='%q' and uuid='%s';", + helper->stream.write_function(&helper->stream, "update sip_dialogs set state='%s' where hostname='%q' and profile_name='%q' and uuid='%s';", astate, mod_sofia_globals.hostname, profile->name, uuid); switch_copy_string(helper->last_uuid, uuid, sizeof(helper->last_uuid)); } @@ -2983,7 +2985,7 @@ static int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char * if (switch_false(resub)) { const char *direction = switch_event_get_header(helper->event, "Caller-Direction"); const char *op, *what = "Ring"; - + if (direction && !strcasecmp(direction, "outbound")) { op = switch_event_get_header(helper->event, "Other-Leg-Caller-ID-Number"); } else { @@ -3031,7 +3033,7 @@ static int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char * //force_event_status = "Available"; term = 1; } - + if (!term && !strcmp(status, "hold")) { rpid = "on-the-phone"; if (!zstr(op)) { @@ -3051,7 +3053,7 @@ static int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char * if (!zstr(open_closed)) { open = open_closed; } - + prpid = translate_rpid(rpid); if (!zstr(dialog_status) && !force_status) { @@ -3065,11 +3067,11 @@ static int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char * switch_set_string(status_line, force_event_status); } - + if (!zstr(dialog_rpid)) { prpid = rpid = dialog_rpid; } - + pl = gen_pidf(user_agent, clean_id, profile->url, open, rpid, prpid, status_line, &ct); } @@ -3089,22 +3091,22 @@ static int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char * if (!zstr(dialog_status)) { status = dialog_status; } - + if (!zstr(dialog_rpid)) { prpid = rpid = dialog_rpid; } - + pl = gen_pidf(user_agent, clean_id, profile->url, open, rpid, prpid, status, &ct); } - if (!is_dialog && helper->event && !switch_stristr("registered", status_line)){ + if (!is_dialog && helper->event && !switch_stristr("registered", status_line)){ const char *uuid = switch_event_get_header_nil(helper->event, "unique-id"); const char *register_source = switch_event_get_header_nil(helper->event, "register-source"); - + if (!zstr(uuid) && strchr(uuid, '-') && !zstr(status_line) && !zstr(rpid) && (zstr(register_source) || strcasecmp(register_source, "register"))) { - char *sql = switch_mprintf("update sip_dialogs set rpid='%q',status='%q' where hostname='%q' and profile_name='%q' and uuid='%q'", + char *sql = switch_mprintf("update sip_dialogs set rpid='%q',status='%q' where hostname='%q' and profile_name='%q' and uuid='%q'", rpid, status_line, mod_sofia_globals.hostname, profile->name, uuid); sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE); @@ -3144,13 +3146,13 @@ static int sofia_presence_mwi_callback(void *pArg, int argc, char **argv, char * char *full_to = argv[16]; char *remote_ip = argv[17]; char *remote_port = argv[18]; - + struct mwi_helper *h = (struct mwi_helper *) pArg; sofia_profile_t *ext_profile = NULL, *profile = h->profile; if (mod_sofia_globals.debug_presence > 0) { - int i; + int i; for(i = 0; i < argc; i++) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "arg %d[%s] = [%s]\n", i, columnNames[i], argv[i]); } @@ -3162,9 +3164,9 @@ static int sofia_presence_mwi_callback(void *pArg, int argc, char **argv, char * } } - send_presence_notify(profile, - full_to, - full_from, + send_presence_notify(profile, + full_to, + full_from, contact, expires, call_id, @@ -3241,14 +3243,14 @@ static int broadsoft_sla_notify_callback(void *pArg, int argc, char **argv, char switch_snprintf(key, sizeof(key), "%s%s", user, host); data = switch_core_hash_find(sh->hash, key); - + if (data) { tmp = switch_core_sprintf(sh->pool, "%s,;appearance-index=*;appearance-state=idle", data, host); } else { tmp = switch_core_sprintf(sh->pool, ";appearance-index=*;appearance-state=idle", host); } - + if (!strcasecmp(event, "line-seize")) { char *hack; @@ -3260,13 +3262,13 @@ static int broadsoft_sla_notify_callback(void *pArg, int argc, char **argv, char if (mod_sofia_globals.debug_sla > 1) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "DB PRES NOTIFY: [%s]\n[%s]\n[%s]\n[%s]\n[%s]\n[%s]\n[%s]\n[%s]\n[%s]\n", argv[5], argv[6], argv[7], argv[8], call_id, event, argv[9], argv[10], tmp); - + } - + send_presence_notify(sh->profile, argv[5], argv[6], argv[7], argv[8], call_id, event, argv[9], argv[10], NULL, NULL, tmp); sh->total++; - + return 0; } @@ -3305,7 +3307,7 @@ static int broadsoft_sla_gather_state_callback(void *pArg, int argc, char **argv if (strcasecmp(state, "idle") && uuid && (session = switch_core_session_locate(uuid))) { switch_channel_t *channel = switch_core_session_get_channel(session); - if (switch_channel_test_flag(channel, CF_ORIGINATOR) || switch_channel_test_flag(channel, CF_BRIDGE_ORIGINATOR) || + if (switch_channel_test_flag(channel, CF_ORIGINATOR) || switch_channel_test_flag(channel, CF_BRIDGE_ORIGINATOR) || switch_channel_inbound_display(channel) || switch_channel_test_flag(channel, CF_SLA_BARGING)) { callee_name = switch_channel_get_variable(channel, "callee_id_name"); callee_number = switch_channel_get_variable(channel, "callee_id_number"); @@ -3313,7 +3315,7 @@ static int broadsoft_sla_gather_state_callback(void *pArg, int argc, char **argv if (zstr(callee_number)) { callee_number = switch_channel_get_variable(channel, "destination_number"); } - + } else { callee_name = switch_channel_get_variable(channel, "caller_id_name"); callee_number = switch_channel_get_variable(channel, "caller_id_number"); @@ -3350,7 +3352,7 @@ static int broadsoft_sla_gather_state_callback(void *pArg, int argc, char **argv if (zstr(callee_name)) { callee_name = "unknown"; } - + if (data) { tmp = switch_core_sprintf(sh->pool, "%s,;%s;appearance-state=%s;appearance-uri=\"\\\"%s\\\" \"", @@ -3391,20 +3393,20 @@ static int sync_sla(sofia_profile_t *profile, const char *to_user, const char *t "call_id='%q' " "and event='line-seize'", (long) switch_epoch_time_now(NULL), call_id); - + sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE); - + if (mod_sofia_globals.debug_sla > 1) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "CLEAR SQL %s\n", sql); } switch_safe_free(sql); - + sql = switch_mprintf("select full_to, full_from, contact, -1, call_id, event, network_ip, network_port, " "NULL as ct, NULL as pt " " from sip_subscriptions where call_id='%q' " - + "and event='line-seize'", call_id); - + sofia_glue_execute_sql_callback(profile, profile->dbh_mutex, sql, sofia_presence_send_sql, &cb); if (mod_sofia_globals.debug_sla > 1) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "CLEAR SQL %s\n", sql); @@ -3415,27 +3417,27 @@ static int sync_sla(sofia_profile_t *profile, const char *to_user, const char *t sql = switch_mprintf("update sip_subscriptions set version=version+1,expires=%ld where " "hostname='%q' and profile_name='%q' " "and sub_to_user='%q' and sub_to_host='%q' " - + "and event='line-seize'", (long) switch_epoch_time_now(NULL), mod_sofia_globals.hostname, profile->name, to_user, to_host ); - + if (mod_sofia_globals.debug_sla > 1) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "CLEAR SQL %s\n", sql); } sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE); - - + + sql = switch_mprintf("select full_to, full_from, contact, -1, call_id, event, network_ip, network_port, " "NULL as ct, NULL as pt " " from sip_subscriptions where " "hostname='%q' and profile_name='%q' " - "and sub_to_user='%q' and sub_to_host='%q' " + "and sub_to_user='%q' and sub_to_host='%q' " "and event='line-seized'", mod_sofia_globals.hostname, profile->name, to_user, to_host ); - + sofia_glue_execute_sql_callback(profile, profile->dbh_mutex, sql, sofia_presence_send_sql, &cb); if (mod_sofia_globals.debug_sla > 1) { @@ -3467,7 +3469,7 @@ static int sync_sla(sofia_profile_t *profile, const char *to_user, const char *t sql = switch_mprintf("select sip_from_user,sip_from_host,call_info,call_info_state,uuid from sip_dialogs " "where call_info_state is not null and call_info_state != '' and call_info_state != 'idle' and hostname='%q' and profile_name='%q' " "and ((sip_from_user='%q' and sip_from_host='%q') or presence_id='%q@%q') " - "and profile_name='%q'", + "and profile_name='%q'", mod_sofia_globals.hostname, profile->name, to_user, to_host, to_user, to_host, profile->name); @@ -3483,7 +3485,7 @@ static int sync_sla(sofia_profile_t *profile, const char *to_user, const char *t if (unseize) { sql = switch_mprintf("select call_id,expires,sub_to_user,sub_to_host,event,full_to,full_from,contact,expires,network_ip,network_port " "from sip_subscriptions where call_id='%q' and hostname='%q' and profile_name='%q' " - "and (event='call-info' or event='line-seize')", + "and (event='call-info' or event='line-seize')", call_id, mod_sofia_globals.hostname, profile->name); } else { @@ -3499,14 +3501,14 @@ static int sync_sla(sofia_profile_t *profile, const char *to_user, const char *t "from sip_subscriptions " "where hostname='%q' and profile_name='%q' " "and sub_to_user='%q' and sub_to_host='%q' " - "and (event='call-info' or event='line-seize') and (profile_name='%q' or presence_hosts like '%%%q%%')", + "and (event='call-info' or event='line-seize') and (profile_name='%q' or presence_hosts like '%%%q%%')", mod_sofia_globals.hostname, profile->name, to_user, to_host, profile->name, to_host); } else { sql = switch_mprintf("select call_id,expires,sub_to_user,sub_to_host,event,full_to,full_from,contact,expires,network_ip,network_port " "from sip_subscriptions " "where hostname='%q' and profile_name='%q' " "and sub_to_user='%q' and sub_to_host='%q' " "and (event='call-info') and " - "(profile_name='%q' or presence_hosts like '%%%q%%')", + "(profile_name='%q' or presence_hosts like '%%%q%%')", mod_sofia_globals.hostname, profile->name, to_user, to_host, profile->name, to_host); } } @@ -3524,7 +3526,7 @@ static int sync_sla(sofia_profile_t *profile, const char *to_user, const char *t - + return total; @@ -3731,9 +3733,9 @@ void sofia_presence_handle_sip_i_subscribe(int status, orig_proto = proto; proto = alt_proto; } - + if ((sub_state != nua_substate_terminated)) { - sql = switch_mprintf("select count(*) from sip_subscriptions where call_id='%q' and hostname='%q' and profile_name='%q'", + sql = switch_mprintf("select count(*) from sip_subscriptions where call_id='%q' and hostname='%q' and profile_name='%q'", call_id, mod_sofia_globals.hostname, profile->name); sofia_glue_execute_sql2str(profile, profile->dbh_mutex, sql, buf, sizeof(buf)); @@ -3747,13 +3749,13 @@ void sofia_presence_handle_sip_i_subscribe(int status, if ((subbed = atoi(buf)) > 0) { sub_state = nua_substate_active; - } + } } if (sub_state == nua_substate_active) { - + sstr = switch_mprintf("active;expires=%ld", exp_delta); - + sql = switch_mprintf("update sip_subscriptions " "set expires=%ld " "where hostname='%q' and profile_name='%q' and call_id='%q' and profile_name='%q'", @@ -3764,19 +3766,19 @@ void sofia_presence_handle_sip_i_subscribe(int status, switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "re-subscribe event %s, sql: %s\n", event, sql); } - + sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE); } else { if (sub_state == nua_substate_terminated) { - sql = switch_mprintf("delete from sip_subscriptions where call_id='%q' and profile_name='%q' and hostname='%q'", + sql = switch_mprintf("delete from sip_subscriptions where call_id='%q' and profile_name='%q' and hostname='%q'", call_id, profile->name, mod_sofia_globals.hostname); - + if (mod_sofia_globals.debug_presence > 0 || mod_sofia_globals.debug_sla > 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, - "sub del sql: %s\n", sql); + "sub del sql: %s\n", sql); } - + switch_assert(sql != NULL); sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE); sstr = switch_mprintf("terminated;reason=noresource"); @@ -3786,12 +3788,12 @@ void sofia_presence_handle_sip_i_subscribe(int status, char accept[256] = ""; sub_state = nua_substate_active; - + while (ap) { switch_snprintf(accept + strlen(accept), sizeof(accept) - strlen(accept), "%s%s ", ap->ac_type, ap->ac_next ? "," : ""); ap = ap->ac_next; } - + sql = switch_mprintf("insert into sip_subscriptions " "(proto,sip_user,sip_host,sub_to_user,sub_to_host,presence_hosts,event,contact,call_id,full_from," "full_via,expires,user_agent,accept,profile_name,hostname,network_port,network_ip,version,orig_proto, full_to) " @@ -3799,11 +3801,11 @@ void sofia_presence_handle_sip_i_subscribe(int status, proto, from_user, from_host, to_user, to_host, profile->presence_hosts ? profile->presence_hosts : "", event, contact_str, call_id, full_from, full_via, (long) switch_epoch_time_now(NULL) + exp_delta, - full_agent, accept, profile->name, mod_sofia_globals.hostname, + full_agent, accept, profile->name, mod_sofia_globals.hostname, np.network_port, np.network_ip, orig_proto, full_to, use_to_tag); switch_assert(sql != NULL); - + if (mod_sofia_globals.debug_presence > 0 || mod_sofia_globals.debug_sla > 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "%s SUBSCRIBE %s@%s %s@%s\n%s\n", @@ -3814,9 +3816,9 @@ void sofia_presence_handle_sip_i_subscribe(int status, sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE); sstr = switch_mprintf("active;expires=%ld", exp_delta); } - + } - + if ( sip->sip_event && sip->sip_event->o_type && !strcasecmp(sip->sip_event->o_type, "ua-profile") && contact_host ) { char *uri = NULL; char *ct = "application/url"; @@ -3827,15 +3829,15 @@ void sofia_presence_handle_sip_i_subscribe(int status, } else { uri = switch_mprintf("sip:%s", contact_host); } - - if ( uri ) { + + if ( uri ) { switch_event_t *params = NULL; - /* Grandstream REALLY uses a header called Message Body */ - extra_headers = switch_mprintf("MessageBody: %s\r\n", profile->pnp_prov_url); - + /* Grandstream REALLY uses a header called Message Body */ + extra_headers = switch_mprintf("MessageBody: %s\r\n", profile->pnp_prov_url); + nua_respond(nh, SIP_202_ACCEPTED, NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END()); - - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "sending pnp NOTIFY for %s to provision to %s\n", uri, profile->pnp_prov_url); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "sending pnp NOTIFY for %s to provision to %s\n", uri, profile->pnp_prov_url); switch_event_create(¶ms, SWITCH_EVENT_NOTIFY); switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "profile", profile->name); @@ -3846,19 +3848,19 @@ void sofia_presence_handle_sip_i_subscribe(int status, switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "content-type", ct); switch_event_add_body(params, "%s", profile->pnp_prov_url); switch_event_fire(¶ms); - + switch_safe_free(uri); - switch_safe_free(extra_headers); - + switch_safe_free(extra_headers); + goto end; - } + } } - + if (status < 200) { char *sticky = NULL; char *contactstr = profile->url, *cs = NULL; char *p = NULL, *new_contactstr = NULL; - + if (np.is_nat) { char params[128] = ""; @@ -3875,7 +3877,7 @@ void sofia_presence_handle_sip_i_subscribe(int status, contactstr = profile->url; } - + if (switch_stristr("port=tcp", contact->m_url->url_params)) { if (np.is_auto_nat) { cs = profile->tcp_public_contact; @@ -3894,7 +3896,7 @@ void sofia_presence_handle_sip_i_subscribe(int status, contactstr = cs; } - + if (nh && nh->nh_ds && nh->nh_ds->ds_usage) { /* nua_dialog_usage_set_refresh_range(nh->nh_ds->ds_usage, exp_delta + SUB_OVERLAP, exp_delta + SUB_OVERLAP); */ nua_dialog_usage_set_refresh_range(nh->nh_ds->ds_usage, exp_delta, exp_delta); @@ -3907,9 +3909,9 @@ void sofia_presence_handle_sip_i_subscribe(int status, new_contactstr = switch_mprintf("", to_user, p); } } - + sip_to_tag(nh->nh_home, sip->sip_to, use_to_tag); - + if (mod_sofia_globals.debug_presence > 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Responding to SUBSCRIBE with 202 Accepted\n"); } @@ -3918,10 +3920,10 @@ void sofia_presence_handle_sip_i_subscribe(int status, TAG_IF(new_contactstr, SIPTAG_CONTACT_STR(new_contactstr)), NUTAG_WITH_THIS_MSG(de->data->e_msg), SIPTAG_SUBSCRIPTION_STATE_STR(sstr), SIPTAG_EXPIRES_STR(exp_delta_str), TAG_IF(sticky, NUTAG_PROXY(sticky)), TAG_END()); - + switch_safe_free(new_contactstr); switch_safe_free(sticky); - + if (sub_state == nua_substate_terminated) { if (mod_sofia_globals.debug_presence > 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Sending NOTIFY with Expires [0] and State [%s]\n", sstr); @@ -3977,7 +3979,7 @@ void sofia_presence_handle_sip_i_subscribe(int status, su_free(nh->nh_home, full_call_info); } - + } else { if (!strcasecmp(event, "line-seize")) { char *full_call_info = NULL; @@ -3997,7 +3999,7 @@ void sofia_presence_handle_sip_i_subscribe(int status, SIPTAG_SUBSCRIPTION_STATE_STR(sstr), SIPTAG_EVENT_STR("line-seize"), TAG_IF(full_call_info, SIPTAG_CALL_INFO_STR(full_call_info)), TAG_END()); - + sql = switch_mprintf("delete from sip_dialogs where hostname='%q' and profile_name='%q' and " @@ -4014,7 +4016,7 @@ void sofia_presence_handle_sip_i_subscribe(int status, now = switch_epoch_time_now(NULL); sql = switch_mprintf("insert into sip_dialogs (sip_from_user,sip_from_host,call_info,call_info_state,hostname,expires,rcd,profile_name) " "values ('%q','%q','%q','seized','%q',%"TIME_T_FMT",%ld,'%q')", - to_user, to_host, switch_str_nil(p), mod_sofia_globals.hostname, + to_user, to_host, switch_str_nil(p), mod_sofia_globals.hostname, switch_epoch_time_now(NULL) + exp_delta, (long)now, profile->name); if (mod_sofia_globals.debug_sla > 1) { @@ -4037,6 +4039,7 @@ void sofia_presence_handle_sip_i_subscribe(int status, if (!strcasecmp(event, "as-feature-event")) { switch_event_t *event; char sip_cseq[40] = ""; + switch_snprintf(sip_cseq, sizeof(sip_cseq), "%d", sip->sip_cseq->cs_seq); switch_event_create(&event, SWITCH_EVENT_PHONE_FEATURE_SUBSCRIBE); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "user", from_user); @@ -4047,8 +4050,59 @@ void sofia_presence_handle_sip_i_subscribe(int status, switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "cseq", sip_cseq); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "profile_name", profile->name); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "hostname", mod_sofia_globals.hostname); + if (sip->sip_payload) { - switch_event_add_body(event, "%s", sip->sip_payload->pl_data); + switch_xml_t xml = NULL; + char *pd_dup = NULL; + + pd_dup = strdup(sip->sip_payload->pl_data); + + if ((xml = switch_xml_parse_str(pd_dup, strlen(pd_dup)))) { + switch_xml_t device = NULL; + + if ((device = switch_xml_child(xml, "device"))) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "device", device->txt); + } + + if (!strcmp(xml->name, "SetDoNotDisturb")) { + switch_xml_t action = NULL; + + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Feature-Action", "SetDoNotDisturb"); + if ((action = switch_xml_child(xml, "doNotDisturbOn"))) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Feature-Enabled", action->txt); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action-Name", action->name); + } + } + + if (!strcmp(xml->name, "SetForwarding")) { + switch_xml_t cfwd_type, cfwd_enable, cfwd_target; + + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Feature-Action", "SetCallForward"); + if ((cfwd_type = switch_xml_child(xml, "forwardingType")) + && (cfwd_enable = switch_xml_child(xml, "activateForward")) + && (cfwd_target = switch_xml_child(xml, "forwardDN"))) { + + if (!strcmp(cfwd_type->txt, "forwardImmediate")) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Feature-Enabled", cfwd_enable->txt); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action-Name", "forward_immediate"); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action-Value", cfwd_target->txt); + } else if (!strcmp(cfwd_type->txt, "forwardBusy")) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Feature-Enabled", cfwd_enable->txt); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action-Name", "forward_busy"); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action-Value", cfwd_target->txt); + } else if (!strcmp(cfwd_type->txt, "forwardNoAns")) { + switch_xml_t rc; + + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Feature-Enabled", cfwd_enable->txt); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action-Name", "forward_no_answer"); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action-Value", cfwd_target->txt); + if ((rc = switch_xml_child(xml, "ringCount"))) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "ringCount", rc->txt); + } + } + } + } + } } switch_event_fire(&event); } else if (!strcasecmp(event, "message-summary")) { @@ -4056,13 +4110,13 @@ void sofia_presence_handle_sip_i_subscribe(int status, "full_via,expires,user_agent,accept,profile_name,network_ip" " from sip_subscriptions where hostname='%q' and profile_name='%q' and " "event='message-summary' and sub_to_user='%q' " - "and (sip_host='%q' or presence_hosts like '%%%q%%')", + "and (sip_host='%q' or presence_hosts like '%%%q%%')", to_host, mod_sofia_globals.hostname, profile->name, to_user, to_host, to_host))) { if (mod_sofia_globals.debug_presence > 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, - "SUBSCRIBE MWI SQL: %s\n", sql); + "SUBSCRIBE MWI SQL: %s\n", sql); } @@ -4122,7 +4176,7 @@ void sofia_presence_handle_sip_i_subscribe(int status, switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "alt_event_type", "dialog"); switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "expires", exp_delta_str); switch_event_fire(&sevent); - + } } else { @@ -4154,7 +4208,7 @@ void sofia_presence_handle_sip_i_subscribe(int status, switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "status", "Registered"); switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "sub-call-id", call_id); switch_event_fire(&sevent); - } + } } } } @@ -4189,7 +4243,7 @@ void sofia_presence_handle_sip_i_subscribe(int status, if (!sofia_private || !sofia_private->is_call) { nua_handle_destroy(nh); } - + } @@ -4273,10 +4327,10 @@ void sofia_presence_handle_sip_r_subscribe(int status, static int sofia_presence_send_sql(void *pArg, int argc, char **argv, char **columnNames) { struct pres_sql_cb *cb = (struct pres_sql_cb *) pArg; - + if (mod_sofia_globals.debug_presence > 0) { - int i; + int i; for(i = 0; i < argc; i++) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "arg %d[%s] = [%s]\n", i, columnNames[i], argv[i]); } @@ -4293,20 +4347,20 @@ uint32_t sofia_presence_contact_count(sofia_profile_t *profile, const char *cont { char buf[32] = ""; char *sql; - - sql = switch_mprintf("select count(*) from sip_subscriptions where hostname='%q' and profile_name='%q' and contact='%q'", + + sql = switch_mprintf("select count(*) from sip_subscriptions where hostname='%q' and profile_name='%q' and contact='%q'", mod_sofia_globals.hostname, profile->name, contact_str); - + sofia_glue_execute_sql2str(profile, profile->dbh_mutex, sql, buf, sizeof(buf)); switch_safe_free(sql); - return atoi(buf); + return atoi(buf); } void sofia_presence_handle_sip_i_publish(nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip, sofia_dispatch_event_t *de, tagi_t tags[]) { - + sip_from_t const *from; char *from_user = NULL; char *from_host = NULL; @@ -4335,7 +4389,7 @@ void sofia_presence_handle_sip_i_publish(nua_t *nua, sofia_profile_t *profile, n from_user = (char *) from->a_url->url_user; from_host = (char *) from->a_url->url_host; } - + exp_delta = (sip->sip_expires ? sip->sip_expires->ex_delta : 3600); if ((profile->force_publish_expires > 0) && (profile->force_publish_expires < (uint32_t)exp_delta)) { exp_delta = profile->force_publish_expires; @@ -4356,7 +4410,7 @@ void sofia_presence_handle_sip_i_publish(nua_t *nua, sofia_profile_t *profile, n int network_port = 0; sofia_glue_get_addr(de->data->e_msg, network_ip, sizeof(network_ip), &network_port); - + pd_dup = strdup(payload->pl_data); if ((xml = switch_xml_parse_str(pd_dup, strlen(pd_dup)))) { @@ -4411,20 +4465,20 @@ void sofia_presence_handle_sip_i_publish(nua_t *nua, sofia_profile_t *profile, n if (count) { if ((sql = switch_mprintf("delete from sip_presence where sip_user='%q' and sip_host='%q' " - " and profile_name='%q' and hostname='%q'", + " and profile_name='%q' and hostname='%q'", from_user, from_host, profile->name, mod_sofia_globals.hostname))) { sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE); } - + if (sub_count > 0 && (sql = switch_mprintf("insert into sip_presence (sip_user, sip_host, status, rpid, expires, user_agent," " profile_name, hostname, open_closed, network_ip, network_port) " "values ('%q','%q','%q','%q',%ld,'%q','%q','%q','%q','%q','%d')", - from_user, from_host, note_txt, rpid, exp, full_agent, profile->name, + from_user, from_host, note_txt, rpid, exp, full_agent, profile->name, mod_sofia_globals.hostname, open_closed, network_ip, network_port))) { - + sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE); } - + } else if (contact_str) { struct pres_sql_cb cb = {profile, 0}; @@ -4432,12 +4486,12 @@ void sofia_presence_handle_sip_i_publish(nua_t *nua, sofia_profile_t *profile, n "'application/pidf+xml' as ct,'%q' as pt " " from sip_subscriptions where " "hostname='%q' and profile_name='%q' and sub_to_user='%q' and sub_to_host='%q' and event='%q'" - "and contact = '%q' ", - - switch_str_nil(payload->pl_data), + "and contact = '%q' ", + + switch_str_nil(payload->pl_data), mod_sofia_globals.hostname, profile->name, from_user, from_host, event_type, contact_str); - + sofia_glue_execute_sql_callback(profile, profile->dbh_mutex, sql, sofia_presence_send_sql, &cb); switch_safe_free(sql); } @@ -4494,7 +4548,7 @@ void sofia_presence_set_hash_key(char *hash_key, int32_t len, sip_t const *sip) void sofia_presence_handle_sip_i_message(int status, char const *phrase, - nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, + nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, switch_core_session_t *session, sofia_private_t *sofia_private, sip_t const *sip, sofia_dispatch_event_t *de, @@ -4643,7 +4697,7 @@ void sofia_presence_handle_sip_i_message(int status, switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "to", to_addr); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "subject", "SIMPLE MESSAGE"); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "context", profile->context); - + if (sip->sip_content_type && sip->sip_content_type->c_subtype) { switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "type", sip->sip_content_type->c_type); } else { @@ -4652,7 +4706,7 @@ void sofia_presence_handle_sip_i_message(int status, switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "from_full", full_from); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "sip_profile", profile->name); - + if (msg) { switch_event_add_body(event, "%s", msg); } @@ -4662,7 +4716,7 @@ void sofia_presence_handle_sip_i_message(int status, } - if (sofia_test_pflag(profile, PFLAG_FIRE_MESSAGE_EVENTS)) { + if (sofia_test_pflag(profile, PFLAG_FIRE_MESSAGE_EVENTS)) { if (switch_event_dup(&event_dup, event) == SWITCH_STATUS_SUCCESS) { event_dup->event_id = SWITCH_EVENT_RECV_MESSAGE; event_dup->flags |= EF_UNIQ_HEADERS; @@ -4676,12 +4730,12 @@ void sofia_presence_handle_sip_i_message(int status, switch_core_session_queue_event(session, &event_dup); } } - + } else { abort(); } - + if (sofia_test_pflag(profile, PFLAG_IN_DIALOG_CHAT) && (tech_pvt = (private_object_t *) switch_core_hash_find(profile->chat_hash, hash_key))) { switch_core_session_queue_event(tech_pvt->session, &event); } else { @@ -4734,7 +4788,7 @@ void sofia_presence_set_chat_hash(private_object_t *tech_pvt, sip_t const *sip) } -void sofia_presence_check_subscriptions(sofia_profile_t *profile, time_t now) +void sofia_presence_check_subscriptions(sofia_profile_t *profile, time_t now) { char *sql; @@ -4749,7 +4803,7 @@ void sofia_presence_check_subscriptions(sofia_profile_t *profile, time_t now) } sql = switch_mprintf("update sip_subscriptions set version=version+1 where " - "((expires > 0 and expires <= %ld)) and profile_name='%q' and hostname='%q'", + "((expires > 0 and expires <= %ld)) and profile_name='%q' and hostname='%q'", (long) now, profile->name, mod_sofia_globals.hostname); sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE); @@ -4770,7 +4824,7 @@ void sofia_presence_check_subscriptions(sofia_profile_t *profile, time_t now) if (mod_sofia_globals.debug_presence > 0 || mod_sofia_globals.debug_sla > 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, - "sub del sql: %s\n", sql); + "sub del sql: %s\n", sql); } sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE); diff --git a/src/mod/event_handlers/mod_format_cdr/Makefile b/src/mod/event_handlers/mod_format_cdr/Makefile new file mode 100644 index 0000000000..c2baec83cd --- /dev/null +++ b/src/mod/event_handlers/mod_format_cdr/Makefile @@ -0,0 +1 @@ +include ../../../../build/modmake.rules diff --git a/src/mod/event_handlers/mod_format_cdr/conf/autoload_configs/format_cdr.conf.xml b/src/mod/event_handlers/mod_format_cdr/conf/autoload_configs/format_cdr.conf.xml new file mode 100644 index 0000000000..227bcb4722 --- /dev/null +++ b/src/mod/event_handlers/mod_format_cdr/conf/autoload_configs/format_cdr.conf.xml @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mod/event_handlers/mod_format_cdr/mod_format_cdr.2008.vcproj b/src/mod/event_handlers/mod_format_cdr/mod_format_cdr.2008.vcproj new file mode 100644 index 0000000000..6c47b60af4 --- /dev/null +++ b/src/mod/event_handlers/mod_format_cdr/mod_format_cdr.2008.vcproj @@ -0,0 +1,289 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mod/event_handlers/mod_format_cdr/mod_format_cdr.2010.vcxproj b/src/mod/event_handlers/mod_format_cdr/mod_format_cdr.2010.vcxproj new file mode 100644 index 0000000000..3fc2efe176 --- /dev/null +++ b/src/mod/event_handlers/mod_format_cdr/mod_format_cdr.2010.vcxproj @@ -0,0 +1,149 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + mod_format_cdr + {08DAD348-9E0A-4A2E-97F1-F1E7E24A7836} + mod_format_cdr + Win32Proj + + + + DynamicLibrary + MultiByte + + + DynamicLibrary + MultiByte + + + DynamicLibrary + MultiByte + + + DynamicLibrary + MultiByte + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + + + + %(AdditionalIncludeDirectories) + + + + + false + + + + + + + X64 + + + %(AdditionalIncludeDirectories) + + + + + false + + + MachineX64 + + + + + %(AdditionalIncludeDirectories) + + + + + %(AdditionalLibraryDirectories) + false + + + + + + + X64 + + + %(AdditionalIncludeDirectories) + + + + + %(AdditionalLibraryDirectories) + false + + + MachineX64 + + + + + + + + {f6c55d93-b927-4483-bb69-15aef3dd2dff} + false + + + {87ee9da4-de1e-4448-8324-183c98dca588} + false + + + {202d7a4e-760d-4d0e-afa1-d7459ced30ff} + false + + + + + + \ No newline at end of file diff --git a/src/mod/event_handlers/mod_format_cdr/mod_format_cdr.2012.vcxproj b/src/mod/event_handlers/mod_format_cdr/mod_format_cdr.2012.vcxproj new file mode 100644 index 0000000000..6f8732c282 --- /dev/null +++ b/src/mod/event_handlers/mod_format_cdr/mod_format_cdr.2012.vcxproj @@ -0,0 +1,149 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + mod_format_cdr + {08DAD348-9E0A-4A2E-97F1-F1E7E24A7836} + mod_format_cdr + Win32Proj + + + + DynamicLibrary + MultiByte + v110 + + + DynamicLibrary + MultiByte + v110 + + + DynamicLibrary + MultiByte + v110 + + + DynamicLibrary + MultiByte + v110 + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + + + + %(AdditionalIncludeDirectories) + + + + + false + + + + + + + X64 + + + %(AdditionalIncludeDirectories) + + + + + false + + + MachineX64 + + + + + %(AdditionalIncludeDirectories) + + + + + %(AdditionalLibraryDirectories) + false + + + + + + + X64 + + + %(AdditionalIncludeDirectories) + + + + + %(AdditionalLibraryDirectories) + false + + + MachineX64 + + + + + + + + {f6c55d93-b927-4483-bb69-15aef3dd2dff} + false + + + {87ee9da4-de1e-4448-8324-183c98dca588} + false + + + {202d7a4e-760d-4d0e-afa1-d7459ced30ff} + false + + + + + + \ No newline at end of file diff --git a/src/mod/event_handlers/mod_format_cdr/mod_format_cdr.c b/src/mod/event_handlers/mod_format_cdr/mod_format_cdr.c new file mode 100644 index 0000000000..6b3ee46fc0 --- /dev/null +++ b/src/mod/event_handlers/mod_format_cdr/mod_format_cdr.c @@ -0,0 +1,812 @@ +/* + * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * Copyright (C) 2005-2012, Anthony Minessale II + * + * Version: MPL 1.1 + * + * 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. + * + * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * + * The Initial Developer of the Original Code is + * Anthony Minessale II + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Brian West + * Bret McDanel + * Justin Cassidy + * + * mod_format_cdr.c -- XML CDR Module to files or curl + * + */ +#include +#include +#include +#define MAX_URLS 20 +#define MAX_ERR_DIRS 20 + +#define ENCODING_NONE 0 +#define ENCODING_DEFAULT 1 +#define ENCODING_BASE64 2 +#define ENCODING_TEXTXML 3 +#define ENCODING_APPLJSON 4 + +static struct { + switch_hash_t *profile_hash; + switch_memory_pool_t *pool; + switch_event_node_t *node; + switch_mutex_t *mutex; + uint32_t shutdown; +} globals; + +struct cdr_profile { + char *name; + char *format; + char *cred; + char *urls[MAX_URLS + 1]; + int url_count; + int url_index; + switch_thread_rwlock_t *log_path_lock; + char *base_log_dir; + char *base_err_log_dir[MAX_ERR_DIRS]; + char *log_dir; + char *err_log_dir[MAX_ERR_DIRS]; + int err_dir_count; + uint32_t delay; + uint32_t retries; + uint32_t enable_cacert_check; + char *ssl_cert_file; + char *ssl_key_file; + char *ssl_key_password; + char *ssl_version; + char *ssl_cacert_file; + uint32_t enable_ssl_verifyhost; + int encode; + int encode_values; + int log_http_and_disk; + int log_b; + int prefix_a; + int disable100continue; + int rotate; + int auth_scheme; + int timeout; + switch_memory_pool_t *pool; +}; +typedef struct cdr_profile cdr_profile_t; + +SWITCH_MODULE_LOAD_FUNCTION(mod_format_cdr_load); +SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_format_cdr_shutdown); +SWITCH_MODULE_DEFINITION(mod_format_cdr, mod_format_cdr_load, mod_format_cdr_shutdown, NULL); + +/* this function would have access to the HTML returned by the webserver, we don't need it + * and the default curl activity is to print to stdout, something not as desirable + * so we have a dummy function here + */ +static size_t httpCallBack(char *buffer, size_t size, size_t nitems, void *outstream) +{ + return size * nitems; +} + +static switch_status_t set_format_cdr_log_dirs(cdr_profile_t *profile) +{ + switch_time_exp_t tm; + char *path = NULL; + char date[80] = ""; + switch_size_t retsize; + switch_status_t status = SWITCH_STATUS_SUCCESS, dir_status; + int err_dir_index; + + switch_time_exp_lt(&tm, switch_micro_time_now()); + switch_strftime_nocheck(date, &retsize, sizeof(date), "%Y-%m-%d-%H-%M-%S", &tm); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Rotating log file paths\n"); + + if (!zstr(profile->base_log_dir)) { + if (profile->rotate) { + if ((path = switch_mprintf("%s%s%s", profile->base_log_dir, SWITCH_PATH_SEPARATOR, date))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Rotating log file path to %s\n", path); + + dir_status = SWITCH_STATUS_SUCCESS; + if (switch_directory_exists(path, profile->pool) != SWITCH_STATUS_SUCCESS) { + dir_status = switch_dir_make(path, SWITCH_FPROT_OS_DEFAULT, profile->pool); + } + + if (dir_status == SWITCH_STATUS_SUCCESS) { + switch_thread_rwlock_wrlock(profile->log_path_lock); + switch_safe_free(profile->log_dir); + profile->log_dir = path; + switch_thread_rwlock_unlock(profile->log_path_lock); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to create new mod_format_cdr log_dir path\n"); + switch_safe_free(path); + status = SWITCH_STATUS_FALSE; + } + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to generate new mod_format_cdr log_dir path\n"); + status = SWITCH_STATUS_FALSE; + } + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Setting log file path to %s\n", profile->base_log_dir); + if ((path = switch_safe_strdup(profile->base_log_dir))) { + switch_thread_rwlock_wrlock(profile->log_path_lock); + switch_safe_free(profile->log_dir); + switch_dir_make_recursive(path, SWITCH_DEFAULT_DIR_PERMS, profile->pool); + profile->log_dir = path; + switch_thread_rwlock_unlock(profile->log_path_lock); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to set log_dir path\n"); + status = SWITCH_STATUS_FALSE; + } + } + } + + for (err_dir_index = 0; err_dir_index < profile->err_dir_count; err_dir_index++) { + if (profile->rotate) { + if ((path = switch_mprintf("%s%s%s", profile->base_err_log_dir[err_dir_index], SWITCH_PATH_SEPARATOR, date))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Rotating err log file path to %s\n", path); + + dir_status = SWITCH_STATUS_SUCCESS; + if (switch_directory_exists(path, profile->pool) != SWITCH_STATUS_SUCCESS) { + dir_status = switch_dir_make(path, SWITCH_FPROT_OS_DEFAULT, profile->pool); + } + + if (dir_status == SWITCH_STATUS_SUCCESS) { + switch_thread_rwlock_wrlock(profile->log_path_lock); + switch_safe_free(profile->err_log_dir[err_dir_index]); + profile->err_log_dir[err_dir_index] = path; + switch_thread_rwlock_unlock(profile->log_path_lock); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to create new mod_format_cdr err_log_dir path\n"); + switch_safe_free(path); + status = SWITCH_STATUS_FALSE; + } + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to generate new mod_format_cdr err_log_dir path\n"); + status = SWITCH_STATUS_FALSE; + } + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Setting err log file path to %s\n", profile->base_err_log_dir[err_dir_index]); + if ((path = switch_safe_strdup(profile->base_err_log_dir[err_dir_index]))) { + switch_thread_rwlock_wrlock(profile->log_path_lock); + switch_safe_free(profile->err_log_dir[err_dir_index]); + switch_dir_make_recursive(path, SWITCH_DEFAULT_DIR_PERMS, profile->pool); + profile->err_log_dir[err_dir_index] = path; + switch_thread_rwlock_unlock(profile->log_path_lock); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to set err_log_dir path\n"); + status = SWITCH_STATUS_FALSE; + } + } + } + + return status; +} + +static switch_status_t my_on_reporting_cb(switch_core_session_t *session, cdr_profile_t *profile) +{ + switch_xml_t xml_cdr = NULL; + cJSON *json_cdr = NULL; + char *cdr_text = NULL; + char *dpath = NULL; + char *path = NULL; + char *curl_cdr_text = NULL; + const char *logdir = NULL; + char *cdr_text_escaped = NULL; + int fd = -1; + uint32_t cur_try; + long httpRes; + switch_CURL *curl_handle = NULL; + switch_curl_slist_t *headers = NULL; + switch_curl_slist_t *slist = NULL; + switch_channel_t *channel = switch_core_session_get_channel(session); + switch_status_t status = SWITCH_STATUS_FALSE; + int is_b; + const char *a_prefix = ""; + + if (globals.shutdown) { + return SWITCH_STATUS_SUCCESS; + } + + is_b = channel && switch_channel_get_originator_caller_profile(channel); + if (!profile->log_b && is_b) { + const char *force_cdr = switch_channel_get_variable(channel, SWITCH_FORCE_PROCESS_CDR_VARIABLE); + if (!switch_true(force_cdr)) { + return SWITCH_STATUS_SUCCESS; + } + } + if (!is_b && profile->prefix_a) + a_prefix = "a_"; + + if ( ! strcasecmp(profile->format, "json") ) { + if (switch_ivr_generate_json_cdr(session, &json_cdr, profile->encode_values == ENCODING_DEFAULT) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Generating JSON Data!\n"); + return SWITCH_STATUS_FALSE; + } + + /* build the JSON */ + cdr_text = cJSON_PrintUnformatted(json_cdr); + + if (!cdr_text) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memory Error generating JSON!\n"); + goto error; + } + } else if ( ! strcasecmp(profile->format, "xml") ) { + if (switch_ivr_generate_xml_cdr(session, &xml_cdr) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Generating XML Data!\n"); + return SWITCH_STATUS_FALSE; + } + + /* build the XML */ + cdr_text = switch_xml_toxml(xml_cdr, SWITCH_TRUE); + if (!cdr_text) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memory Error generating XML!\n"); + goto error; + } + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Unhandled format for mod_format_cdr!\n"); + goto error; + } + + switch_thread_rwlock_rdlock(profile->log_path_lock); + + if (!(logdir = switch_channel_get_variable(channel, "format_cdr_base"))) { + logdir = profile->log_dir; + } + + if (!zstr(logdir) && (profile->log_http_and_disk || !profile->url_count)) { + dpath = switch_mprintf("%s%s%s", logdir, SWITCH_PATH_SEPARATOR, a_prefix); + path = switch_mprintf("%s%s%s%s.cdr.%s", logdir, SWITCH_PATH_SEPARATOR, a_prefix, switch_core_session_get_uuid(session), + profile->format); + switch_thread_rwlock_unlock(profile->log_path_lock); + if (path) { + if (switch_directory_exists(dpath, profile->pool) != SWITCH_STATUS_SUCCESS) { + switch_dir_make_recursive(dpath, SWITCH_FPROT_OS_DEFAULT, profile->pool); + } +#ifdef _MSC_VER + if ((fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR)) > -1) { +#else + if ((fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) > -1) { +#endif + int wrote; + wrote = write(fd, cdr_text, (unsigned) strlen(cdr_text)); + wrote++; + close(fd); + fd = -1; + } else { + char ebuf[512] = { 0 }; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error writing [%s][%s]\n", + path, switch_strerror_r(errno, ebuf, sizeof(ebuf))); + } + switch_safe_free(path); + switch_safe_free(dpath); + } + } else { + switch_thread_rwlock_unlock(profile->log_path_lock); + } + + /* try to post it to the web server */ + if (profile->url_count) { + char *destUrl = NULL; + curl_handle = switch_curl_easy_init(); + + if (profile->encode == ENCODING_TEXTXML) { + headers = switch_curl_slist_append(headers, "Content-Type: text/xml"); + } else if (profile->encode == ENCODING_APPLJSON) { + headers = switch_curl_slist_append(headers, "Content-Type: application/json"); + } else if (profile->encode) { + switch_size_t need_bytes = strlen(cdr_text) * 3 + 1; + + cdr_text_escaped = malloc(need_bytes); + switch_assert(cdr_text_escaped); + memset(cdr_text_escaped, 0, need_bytes); + if (profile->encode == ENCODING_DEFAULT) { + headers = switch_curl_slist_append(headers, "Content-Type: application/x-www-form-urlencoded"); + switch_url_encode(cdr_text, cdr_text_escaped, need_bytes); + } else { + headers = switch_curl_slist_append(headers, "Content-Type: application/x-www-form-base64-encoded"); + switch_b64_encode((unsigned char *) cdr_text, need_bytes / 3, (unsigned char *) cdr_text_escaped, need_bytes); + } + switch_safe_free(cdr_text); + cdr_text = cdr_text_escaped; + } else { + headers = switch_curl_slist_append(headers, "Content-Type: application/x-www-form-plaintext"); + } + + if (profile->encode == ENCODING_TEXTXML) { + curl_cdr_text = cdr_text; + } else if (profile->encode == ENCODING_APPLJSON) { + curl_cdr_text = cdr_text; + } else if (!(curl_cdr_text = switch_mprintf("cdr=%s", cdr_text))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memory Error!\n"); + goto error; + } + + if (!zstr(profile->cred)) { + switch_curl_easy_setopt(curl_handle, CURLOPT_HTTPAUTH, profile->auth_scheme); + switch_curl_easy_setopt(curl_handle, CURLOPT_USERPWD, profile->cred); + } + + switch_curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, headers); + switch_curl_easy_setopt(curl_handle, CURLOPT_POST, 1); + switch_curl_easy_setopt(curl_handle, CURLOPT_NOSIGNAL, 1); + switch_curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDS, curl_cdr_text); + switch_curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "freeswitch-format-cdr/1.0"); + switch_curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, httpCallBack); + + if (profile->disable100continue) { + slist = switch_curl_slist_append(slist, "Expect:"); + switch_curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, slist); + } + + if (profile->ssl_cert_file) { + switch_curl_easy_setopt(curl_handle, CURLOPT_SSLCERT, profile->ssl_cert_file); + } + + if (profile->ssl_key_file) { + switch_curl_easy_setopt(curl_handle, CURLOPT_SSLKEY, profile->ssl_key_file); + } + + if (profile->ssl_key_password) { + switch_curl_easy_setopt(curl_handle, CURLOPT_SSLKEYPASSWD, profile->ssl_key_password); + } + + if (profile->ssl_version) { + if (!strcasecmp(profile->ssl_version, "SSLv3")) { + switch_curl_easy_setopt(curl_handle, CURLOPT_SSLVERSION, CURL_SSLVERSION_SSLv3); + } else if (!strcasecmp(profile->ssl_version, "TLSv1")) { + switch_curl_easy_setopt(curl_handle, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1); + } + } + + if (profile->ssl_cacert_file) { + switch_curl_easy_setopt(curl_handle, CURLOPT_CAINFO, profile->ssl_cacert_file); + } + + switch_curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, profile->timeout); + + /* these were used for testing, optionally they may be enabled if someone desires + switch_curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1); // 302 recursion level + */ + + for (cur_try = 0; cur_try < profile->retries; cur_try++) { + if (cur_try > 0) { + switch_yield(profile->delay * 1000000); + } + + destUrl = switch_mprintf("%s?uuid=%s%s", profile->urls[profile->url_index], a_prefix, switch_core_session_get_uuid(session)); + switch_curl_easy_setopt(curl_handle, CURLOPT_URL, destUrl); + + if (!strncasecmp(destUrl, "https", 5)) { + switch_curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0); + switch_curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0); + } + + if (profile->enable_cacert_check) { + switch_curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, TRUE); + } + + if (profile->enable_ssl_verifyhost) { + switch_curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 2); + } + + switch_curl_easy_perform(curl_handle); + switch_curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &httpRes); + switch_safe_free(destUrl); + if (httpRes >= 200 && httpRes <= 299) { + goto success; + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Got error [%ld] posting to web server [%s]\n", + httpRes, profile->urls[profile->url_index]); + profile->url_index++; + switch_assert(profile->url_count <= MAX_URLS); + if (profile->url_index >= profile->url_count) { + profile->url_index = 0; + } + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Retry will be with url [%s]\n", profile->urls[profile->url_index]); + } + } + switch_curl_easy_cleanup(curl_handle); + switch_curl_slist_free_all(headers); + switch_curl_slist_free_all(slist); + slist = NULL; + headers = NULL; + curl_handle = NULL; + + /* if we are here the web post failed for some reason */ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unable to post to web server, writing to file\n"); + + switch_thread_rwlock_rdlock(profile->log_path_lock); + dpath = switch_mprintf("%s%s%s", profile->err_log_dir, SWITCH_PATH_SEPARATOR, a_prefix); + path = switch_mprintf("%s%s%s%s.cdr.%s", profile->err_log_dir, SWITCH_PATH_SEPARATOR, a_prefix, switch_core_session_get_uuid(session), + profile->format); + switch_thread_rwlock_unlock(profile->log_path_lock); + if (path) { + if (switch_directory_exists(dpath, profile->pool) != SWITCH_STATUS_SUCCESS) { + switch_dir_make_recursive(dpath, SWITCH_FPROT_OS_DEFAULT, profile->pool); + } +#ifdef _MSC_VER + if ((fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR)) > -1) { +#else + if ((fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) > -1) { +#endif + int wrote; + wrote = write(fd, cdr_text, (unsigned) strlen(cdr_text)); + wrote++; + close(fd); + fd = -1; + } else { + char ebuf[512] = { 0 }; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error![%s]\n", + switch_strerror_r(errno, ebuf, sizeof(ebuf))); + } + switch_safe_free(path); + switch_safe_free(dpath); + } + } + + success: + status = SWITCH_STATUS_SUCCESS; + + error: + if (curl_handle) { + switch_curl_easy_cleanup(curl_handle); + } + if (headers) { + switch_curl_slist_free_all(headers); + } + if (slist) { + switch_curl_slist_free_all(slist); + } + if (curl_cdr_text != cdr_text) { + switch_safe_free(curl_cdr_text); + } + switch_safe_free(cdr_text); + switch_safe_free(path); + switch_safe_free(dpath); + if ( xml_cdr ) + { + switch_xml_free(xml_cdr); + } + + if ( json_cdr ) + { + cJSON_Delete(json_cdr); + } + + return status; +} + +static switch_status_t my_on_reporting(switch_core_session_t *session) +{ + switch_hash_index_t *hi; + void *val; + switch_status_t status, tmpstatus; + + status = SWITCH_STATUS_SUCCESS; + + for (hi = switch_hash_first(NULL, globals.profile_hash); hi; hi = switch_hash_next(hi)) { + cdr_profile_t *profile; + switch_hash_this(hi, NULL, NULL, &val); + profile = (cdr_profile_t *) val; + + tmpstatus = my_on_reporting_cb(session, profile); + if ( tmpstatus != SWITCH_STATUS_SUCCESS ) { + status = tmpstatus; + } + } + + return status; +} + + +static void event_handler(switch_event_t *event) +{ + switch_hash_index_t *hi; + void *val; + + const char *sig = switch_event_get_header(event, "Trapped-Signal"); + + if (sig && !strcmp(sig, "HUP")) { + for (hi = switch_hash_first(NULL, globals.profile_hash); hi; hi = switch_hash_next(hi)) { + cdr_profile_t *profile; + switch_hash_this(hi, NULL, NULL, &val); + profile = (cdr_profile_t *) val; + + if (profile->rotate) { + set_format_cdr_log_dirs(profile); + } + } + } +} + +static switch_state_handler_table_t state_handlers = { + /*.on_init */ NULL, + /*.on_routing */ NULL, + /*.on_execute */ NULL, + /*.on_hangup */ NULL, + /*.on_exchange_media */ NULL, + /*.on_soft_execute */ NULL, + /*.on_consume_media */ NULL, + /*.on_hibernate */ NULL, + /*.on_reset */ NULL, + /*.on_park */ NULL, + /*.on_reporting */ my_on_reporting +}; + +switch_status_t mod_format_cdr_load_profile_xml(switch_xml_t xprofile) +{ + switch_memory_pool_t *pool = NULL; + cdr_profile_t *profile = NULL; + switch_xml_t settings, param; + char *profile_name = (char *) switch_xml_attr_soft(xprofile, "name"); + + if (switch_core_new_memory_pool(&pool) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "OH OH no pool\n"); + return SWITCH_STATUS_TERM; + } + + profile = switch_core_alloc(pool, sizeof(cdr_profile_t)); + memset(profile, 0, sizeof(cdr_profile_t)); + + profile->pool = pool; + profile->name = switch_core_strdup(profile->pool, profile_name); + + profile->log_http_and_disk = 0; + profile->log_b = 1; + profile->disable100continue = 0; + profile->auth_scheme = CURLAUTH_BASIC; + + switch_thread_rwlock_create(&profile->log_path_lock, pool); + + if ((settings = switch_xml_child(xprofile, "settings"))) { + for (param = switch_xml_child(settings, "param"); param; param = param->next) { + char *var = (char *) switch_xml_attr_soft(param, "name"); + char *val = (char *) switch_xml_attr_soft(param, "value"); + + if (!strcasecmp(var, "cred") && !zstr(val)) { + profile->cred = switch_core_strdup(profile->pool, val); + } else if (!strcasecmp(var, "format") && !zstr(val)) { + profile->format = switch_core_strdup(profile->pool, val); + } else if (!strcasecmp(var, "url") && !zstr(val)) { + if (profile->url_count >= MAX_URLS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "maximum urls configured!\n"); + } else { + profile->urls[profile->url_count++] = switch_core_strdup(profile->pool, val); + } + } else if (!strcasecmp(var, "log-http-and-disk")) { + profile->log_http_and_disk = switch_true(val); + } else if (!strcasecmp(var, "timeout")) { + int tmp = atoi(val); + if (tmp >= 0) { + profile->timeout = tmp; + } else { + profile->timeout = 0; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't set a negative timeout!\n"); + } + } else if (!strcasecmp(var, "delay") && !zstr(val)) { + profile->delay = switch_atoui(val); + } else if (!strcasecmp(var, "log-b-leg")) { + profile->log_b = switch_true(val); + } else if (!strcasecmp(var, "prefix-a-leg")) { + profile->prefix_a = switch_true(val); + } else if (!strcasecmp(var, "disable-100-continue") && switch_true(val)) { + profile->disable100continue = 1; + } else if (!strcasecmp(var, "encode") && !zstr(val)) { + if (!strcasecmp(val, "base64")) { + profile->encode = ENCODING_BASE64; + } else if (!strcasecmp(val, "textxml")) { + profile->encode = ENCODING_TEXTXML; + } else if (!strcasecmp(val, "appljson")) { + profile->encode = ENCODING_APPLJSON; + } else { + profile->encode = switch_true(val) ? ENCODING_DEFAULT : ENCODING_NONE; + } + } else if (!strcasecmp(var, "retries") && !zstr(val)) { + profile->retries = switch_atoui(val); + } else if (!strcasecmp(var, "rotate") && !zstr(val)) { + profile->rotate = switch_true(val); + } else if (!strcasecmp(var, "log-dir")) { + if (zstr(val)) { + profile->base_log_dir = switch_core_sprintf(profile->pool, "%s%sformat_cdr", SWITCH_GLOBAL_dirs.log_dir, SWITCH_PATH_SEPARATOR); + } else { + if (switch_is_file_path(val)) { + profile->base_log_dir = switch_core_strdup(profile->pool, val); + } else { + profile->base_log_dir = switch_core_sprintf(profile->pool, "%s%s%s", SWITCH_GLOBAL_dirs.log_dir, SWITCH_PATH_SEPARATOR, val); + } + } + } else if (!strcasecmp(var, "err-log-dir")) { + if (profile->err_dir_count >= MAX_ERR_DIRS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "maximum error directories configured!\n"); + } else { + + if (zstr(val)) { + profile->base_err_log_dir[profile->err_dir_count++] = switch_core_sprintf(profile->pool, "%s%sformat_cdr", SWITCH_GLOBAL_dirs.log_dir, SWITCH_PATH_SEPARATOR); + } else { + if (switch_is_file_path(val)) { + profile->base_err_log_dir[profile->err_dir_count++] = switch_core_strdup(profile->pool, val); + } else { + profile->base_err_log_dir[profile->err_dir_count++] = switch_core_sprintf(profile->pool, "%s%s%s", SWITCH_GLOBAL_dirs.log_dir, SWITCH_PATH_SEPARATOR, val); + } + } + + } + } else if (!strcasecmp(var, "enable-cacert-check") && switch_true(val)) { + profile->enable_cacert_check = 1; + } else if (!strcasecmp(var, "ssl-cert-path")) { + profile->ssl_cert_file = switch_core_strdup(profile->pool, val); + } else if (!strcasecmp(var, "ssl-key-path")) { + profile->ssl_key_file = switch_core_strdup(profile->pool, val); + } else if (!strcasecmp(var, "ssl-key-password")) { + profile->ssl_key_password = switch_core_strdup(profile->pool, val); + } else if (!strcasecmp(var, "ssl-version")) { + profile->ssl_version = switch_core_strdup(profile->pool, val); + } else if (!strcasecmp(var, "ssl-cacert-file")) { + profile->ssl_cacert_file = switch_core_strdup(profile->pool, val); + } else if (!strcasecmp(var, "enable-ssl-verifyhost") && switch_true(val)) { + profile->enable_ssl_verifyhost = 1; + } else if (!strcasecmp(var, "auth-scheme")) { + if (*val == '=') { + profile->auth_scheme = 0; + val++; + } + + if (!strcasecmp(val, "basic")) { + profile->auth_scheme |= CURLAUTH_BASIC; + } else if (!strcasecmp(val, "digest")) { + profile->auth_scheme |= CURLAUTH_DIGEST; + } else if (!strcasecmp(val, "NTLM")) { + profile->auth_scheme |= CURLAUTH_NTLM; + } else if (!strcasecmp(val, "GSS-NEGOTIATE")) { + profile->auth_scheme |= CURLAUTH_GSSNEGOTIATE; + } else if (!strcasecmp(val, "any")) { + profile->auth_scheme = CURLAUTH_ANY; + } + } else if (!strcasecmp(var, "encode-values") && !zstr(val)) { + profile->encode_values = switch_true(val) ? ENCODING_DEFAULT : ENCODING_NONE; + } + } + + if (!profile->err_dir_count) { + if (!zstr(profile->base_log_dir)) { + profile->base_err_log_dir[profile->err_dir_count++] = switch_core_strdup(profile->pool, profile->base_log_dir); + } else { + profile->base_err_log_dir[profile->err_dir_count++] = switch_core_sprintf(profile->pool, "%s%sformat_cdr", + SWITCH_GLOBAL_dirs.log_dir, SWITCH_PATH_SEPARATOR); + } + } + } + + if (profile->retries && profile->delay == 0) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Retries set but delay 0 setting to 5 seconds\n"); + profile->delay = 5; + } + + if ( ! profile->format || (strcasecmp(profile->format,"json") && strcasecmp(profile->format,"xml")) ) + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No valid format_cdr format specified, defaulting to xml.\n"); + profile->format = switch_core_strdup(profile->pool,"xml"); + } + + profile->retries++; + + switch_mutex_lock(globals.mutex); + switch_core_hash_insert(globals.profile_hash, profile->name, profile); + switch_mutex_unlock(globals.mutex); + + set_format_cdr_log_dirs(profile); + + return SWITCH_STATUS_SUCCESS; +} + +SWITCH_MODULE_LOAD_FUNCTION(mod_format_cdr_load) +{ + char *cf = "format_cdr.conf"; + switch_xml_t cfg, xml, xprofiles, xprofile; + switch_status_t status = SWITCH_STATUS_SUCCESS; + + /* test global state handlers */ + switch_core_add_state_handler(&state_handlers); + + *module_interface = switch_loadable_module_create_module_interface(pool, modname); + + memset(&globals, 0, sizeof(globals)); + + if (switch_event_bind_removable(modname, SWITCH_EVENT_TRAP, SWITCH_EVENT_SUBCLASS_ANY, + event_handler, NULL, &globals.node) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n"); + return SWITCH_STATUS_GENERR; + } + + globals.pool = pool; + + switch_mutex_init(&globals.mutex, SWITCH_MUTEX_NESTED, globals.pool); + switch_core_hash_init(&globals.profile_hash, globals.pool); + + /* parse the config */ + if (!(xml = switch_xml_open_cfg(cf, &cfg, NULL))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of %s failed\n", cf); + return SWITCH_STATUS_TERM; + } + + switch_mutex_lock(globals.mutex); + if ((xprofiles = switch_xml_child(cfg, "profiles"))) { + for (xprofile = switch_xml_child(xprofiles, "profile"); xprofile; xprofile = xprofile->next) { + char *profile_name = (char *) switch_xml_attr_soft(xprofile, "name"); + + if (zstr(profile_name)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, + " is missing name attribute\n"); + continue; + } + + mod_format_cdr_load_profile_xml(xprofile); + } + } + switch_xml_free(xml); + switch_mutex_unlock(globals.mutex); + + return status; +} + +void mod_format_cdr_profile_shutdown(cdr_profile_t *profile) +{ + int err_dir_index = 0; + + for (err_dir_index = 0; err_dir_index < profile->err_dir_count; err_dir_index++) { + switch_safe_free(profile->err_log_dir[err_dir_index]); + } + + switch_safe_free(profile->log_dir); + + switch_thread_rwlock_destroy(profile->log_path_lock); + + switch_core_destroy_memory_pool(&profile->pool); +} + +SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_format_cdr_shutdown) +{ + switch_hash_index_t *hi; + void *val; + + globals.shutdown = 1; + + switch_event_unbind(&globals.node); + switch_core_remove_state_handler(&state_handlers); + + for (hi = switch_hash_first(NULL, globals.profile_hash); hi; hi = switch_hash_next(hi)) { + cdr_profile_t *profile; + switch_hash_this(hi, NULL, NULL, &val); + profile = (cdr_profile_t *) val; + + if ( profile ) { + mod_format_cdr_profile_shutdown(profile); + } + } + + switch_core_hash_destroy(&globals.profile_hash); + + return SWITCH_STATUS_SUCCESS; +} + +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: + */ diff --git a/src/mod/event_handlers/mod_format_cdr/mod_format_cdr.vcproj b/src/mod/event_handlers/mod_format_cdr/mod_format_cdr.vcproj new file mode 100644 index 0000000000..38ba9daf2b --- /dev/null +++ b/src/mod/event_handlers/mod_format_cdr/mod_format_cdr.vcproj @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mod/event_handlers/mod_rayo/mod_rayo.c b/src/mod/event_handlers/mod_rayo/mod_rayo.c index e232ac8d38..92257aa2f6 100644 --- a/src/mod/event_handlers/mod_rayo/mod_rayo.c +++ b/src/mod/event_handlers/mod_rayo/mod_rayo.c @@ -128,6 +128,8 @@ struct rayo_call { switch_time_t idle_start_time; /** 1 if joined to call, 2 if joined to mixer */ int joined; + /** pending join */ + iks *pending_join_request; /** ID of joined party TODO this will be many mixers / calls */ const char *joined_id; /** set if response needs to be sent to IQ request */ @@ -937,6 +939,14 @@ static void rayo_call_cleanup(struct rayo_actor *actor) RAYO_SEND_MESSAGE_DUP(actor, rayo_call_get_dcp_jid(call), revent); } + /* lost the race: pending join failed... send IQ result to client now. */ + if (call->pending_join_request) { + iks *result = iks_new_error_detailed(call->pending_join_request, STANZA_ERROR_ITEM_NOT_FOUND, "call ended"); + RAYO_SEND_REPLY(call, iks_find_attrib_soft(call->pending_join_request, "from"), result); + iks_delete(call->pending_join_request); + call->pending_join_request = NULL; + } + iks_delete(revent); switch_event_destroy(&event); } @@ -1068,6 +1078,7 @@ static struct rayo_call *rayo_call_init(struct rayo_call *call, switch_memory_po call->joined = 0; call->joined_id = NULL; call->ringing_sent = 0; + call->pending_join_request = NULL; switch_core_hash_init(&call->pcps, pool); switch_safe_free(call_jid); @@ -1292,6 +1303,17 @@ static struct rayo_peer_server *rayo_peer_server_create(const char *jid) return rserver; } +/** + * Check if message sender has control of offered call. + * @param call the Rayo call + * @param msg the message + * @return 1 if sender has call control, 0 if sender does not have control + */ +static int has_call_control(struct rayo_call *call, struct rayo_message *msg) +{ + return (!strcmp(rayo_call_get_dcp_jid(call), msg->from_jid) || is_internal_message(msg) || is_admin_client_message(msg)); +} + /** * Check if message sender has control of offered call. Take control if nobody else does. * @param call the Rayo call @@ -1299,7 +1321,7 @@ static struct rayo_peer_server *rayo_peer_server_create(const char *jid) * @param msg the message * @return 1 if sender has call control */ -static int has_call_control(struct rayo_call *call, switch_core_session_t *session, struct rayo_message *msg) +static int take_call_control(struct rayo_call *call, switch_core_session_t *session, struct rayo_message *msg) { int control = 0; @@ -1313,7 +1335,7 @@ static int has_call_control(struct rayo_call *call, switch_core_session_t *sessi control = 1; switch_log_printf(SWITCH_CHANNEL_UUID_LOG(rayo_call_get_uuid(call)), SWITCH_LOG_INFO, "%s has control of call\n", rayo_call_get_dcp_jid(call)); } - } else if (!strcmp(rayo_call_get_dcp_jid(call), msg->from_jid) || is_internal_message(msg) || is_admin_client_message(msg)) { + } else if (has_call_control(call, msg)) { control = 1; } @@ -1358,7 +1380,7 @@ static iks *rayo_call_command_ok(struct rayo_call *call, switch_core_session_t * if (bad) { response = iks_new_error(node, STANZA_ERROR_BAD_REQUEST); - } else if (!has_call_control(call, session, msg)) { + } else if (!take_call_control(call, session, msg)) { response = iks_new_error(node, STANZA_ERROR_CONFLICT); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s, %s conflict\n", msg->from_jid, RAYO_JID(call)); } @@ -1711,13 +1733,14 @@ static iks *on_rayo_hangup(struct rayo_actor *call, struct rayo_message *msg, vo * Join calls together * @param call the call that joins * @param session the session - * @param node the join request + * @param msg the rayo join message * @param call_uri to join * @param media mode (direct/bridge) * @return the response */ -static iks *join_call(struct rayo_call *call, switch_core_session_t *session, iks *node, const char *call_uri, const char *media) +static iks *join_call(struct rayo_call *call, switch_core_session_t *session, struct rayo_message *msg, const char *call_uri, const char *media) { + iks *node = msg->payload; iks *response = NULL; /* take call out of media path if media = "direct" */ const char *bypass = !strcmp("direct", media) ? "true" : "false"; @@ -1727,6 +1750,9 @@ static iks *join_call(struct rayo_call *call, switch_core_session_t *session, ik if (!b_call) { /* not a rayo call */ response = iks_new_error_detailed(node, STANZA_ERROR_SERVICE_UNAVAILABLE, "b-leg is not a rayo call"); + } else if (!has_call_control(b_call, msg)) { + /* not allowed to join to this call */ + response = iks_new_error(node, STANZA_ERROR_NOT_ALLOWED); } else if (b_call->joined) { /* don't support multiple joined calls */ response = iks_new_error_detailed(node, STANZA_ERROR_CONFLICT, "multiple joined calls not supported"); @@ -1737,10 +1763,11 @@ static iks *join_call(struct rayo_call *call, switch_core_session_t *session, ik if (switch_false(bypass)) { switch_channel_pre_answer(switch_core_session_get_channel(session)); } - if (switch_ivr_uuid_bridge(rayo_call_get_uuid(call), rayo_call_get_uuid(b_call)) == SWITCH_STATUS_SUCCESS) { - response = iks_new_iq_result(node); - } else { + call->pending_join_request = iks_copy(node); + if (switch_ivr_uuid_bridge(rayo_call_get_uuid(call), rayo_call_get_uuid(b_call)) != SWITCH_STATUS_SUCCESS) { response = iks_new_error_detailed(node, STANZA_ERROR_INTERNAL_SERVER_ERROR, "failed to bridge call"); + iks_delete(call->pending_join_request); + call->pending_join_request = NULL; } RAYO_UNLOCK(b_call); } @@ -1763,13 +1790,14 @@ static void exec_conference_api(switch_core_session_t *session, const char *conf * Join call to a mixer * @param call the call that joins * @param session the session - * @param node the join request + * @param msg the join request * @param mixer_name the mixer to join * @param direction the media direction * @return the response */ -static iks *join_mixer(struct rayo_call *call, switch_core_session_t *session, iks *node, const char *mixer_name, const char *direction) +static iks *join_mixer(struct rayo_call *call, switch_core_session_t *session, struct rayo_message *msg, const char *mixer_name, const char *direction) { + iks *node = msg->payload; iks *response = NULL; if (call->joined_id) { @@ -1806,14 +1834,13 @@ static iks *join_mixer(struct rayo_call *call, switch_core_session_t *session, i * Handle request * @param call the Rayo call * @param session the session - * @param node the node + * @param msg the rayo join message */ static iks *on_rayo_join(struct rayo_actor *call, struct rayo_message *msg, void *session_data) { - iks *node = msg->payload; switch_core_session_t *session = (switch_core_session_t *)session_data; iks *response = NULL; - iks *join = iks_find(node, "join"); + iks *join = iks_find(msg->payload, "join"); const char *join_id; const char *mixer_name; const char *call_uri; @@ -1821,7 +1848,7 @@ static iks *on_rayo_join(struct rayo_actor *call, struct rayo_message *msg, void /* validate input attributes */ if (!VALIDATE_RAYO_JOIN(join)) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Bad join attrib\n"); - response = iks_new_error(node, STANZA_ERROR_BAD_REQUEST); + response = iks_new_error(msg->payload, STANZA_ERROR_BAD_REQUEST); goto done; } mixer_name = iks_find_attrib(join, "mixer-name"); @@ -1835,29 +1862,35 @@ static iks *on_rayo_join(struct rayo_actor *call, struct rayo_message *msg, void /* can't join both mixer and call */ if (!zstr(mixer_name) && !zstr(call_uri)) { - response = iks_new_error_detailed(node, STANZA_ERROR_BAD_REQUEST, "mixer-name and call-uri are mutually exclusive"); + response = iks_new_error_detailed(msg->payload, STANZA_ERROR_BAD_REQUEST, "mixer-name and call-uri are mutually exclusive"); goto done; } /* need to join *something* */ if (zstr(mixer_name) && zstr(call_uri)) { - response = iks_new_error_detailed(node, STANZA_ERROR_BAD_REQUEST, "mixer-name or call-uri is required"); + response = iks_new_error_detailed(msg->payload, STANZA_ERROR_BAD_REQUEST, "mixer-name or call-uri is required"); goto done; } if ((RAYO_CALL(call)->joined == JOINED_CALL) || (RAYO_CALL(call)->joined == JOINED_MIXER && strcmp(RAYO_CALL(call)->joined_id, join_id))) { /* already joined */ - response = iks_new_error_detailed(node, STANZA_ERROR_CONFLICT, "call is already joined"); + response = iks_new_error_detailed(msg->payload, STANZA_ERROR_CONFLICT, "call is already joined"); + goto done; + } + + if (RAYO_CALL(call)->pending_join_request) { + /* don't allow concurrent join requests */ + response = iks_new_error_detailed(msg->payload, STANZA_ERROR_UNEXPECTED_REQUEST, "(un)join request is pending"); goto done; } if (!zstr(mixer_name)) { /* join conference */ - response = join_mixer(RAYO_CALL(call), session, node, mixer_name, iks_find_attrib(join, "direction")); + response = join_mixer(RAYO_CALL(call), session, msg, mixer_name, iks_find_attrib(join, "direction")); } else { /* bridge calls */ - response = join_call(RAYO_CALL(call), session, node, call_uri, iks_find_attrib(join, "media")); + response = join_call(RAYO_CALL(call), session, msg, call_uri, iks_find_attrib(join, "media")); } done: @@ -1868,12 +1901,13 @@ done: * unjoin call to a bridge * @param call the call that unjoined * @param session the session - * @param node the unjoin request + * @param msg the unjoin request * @param call_uri the b-leg xmpp URI * @return the response */ -static iks *unjoin_call(struct rayo_call *call, switch_core_session_t *session, iks *node, const char *call_uri) +static iks *unjoin_call(struct rayo_call *call, switch_core_session_t *session, struct rayo_message *msg, const char *call_uri) { + iks *node = msg->payload; iks *response = NULL; const char *bleg_uuid = switch_channel_get_variable(switch_core_session_get_channel(session), SWITCH_BRIDGE_UUID_VARIABLE); const char *bleg_uri = switch_core_session_sprintf(session, "xmpp:%s@%s", bleg_uuid ? bleg_uuid : "", RAYO_JID(globals.server)); @@ -1881,7 +1915,7 @@ static iks *unjoin_call(struct rayo_call *call, switch_core_session_t *session, /* bleg must match call_uri */ if (!zstr(bleg_uri) && !strcmp(bleg_uri, call_uri)) { /* unbridge call */ - response = iks_new_iq_result(node); + call->pending_join_request = iks_copy(node); switch_ivr_park_session(session); } else { /* not bridged or wrong b-leg URI */ @@ -1895,15 +1929,16 @@ static iks *unjoin_call(struct rayo_call *call, switch_core_session_t *session, * unjoin call to a mixer * @param call the call that unjoined * @param session the session - * @param node the unjoin request + * @param msg the unjoin request * @param mixer_name the mixer name * @return the response */ -static iks *unjoin_mixer(struct rayo_call *call, switch_core_session_t *session, iks *node, const char *mixer_name) +static iks *unjoin_mixer(struct rayo_call *call, switch_core_session_t *session, struct rayo_message *msg, const char *mixer_name) { switch_channel_t *channel = switch_core_session_get_channel(session); const char *conf_member_id = switch_channel_get_variable(channel, "conference_member_id"); const char *conf_name = switch_channel_get_variable(channel, "conference_name"); + iks *node = msg->payload; iks *response = NULL; /* not conferenced, or wrong conference */ @@ -1935,31 +1970,33 @@ done: */ static iks *on_rayo_unjoin(struct rayo_actor *call, struct rayo_message *msg, void *session_data) { - iks *node = msg->payload; switch_core_session_t *session = (switch_core_session_t *)session_data; iks *response = NULL; - iks *unjoin = iks_find(node, "unjoin"); + iks *unjoin = iks_find(msg->payload, "unjoin"); const char *call_uri = iks_find_attrib(unjoin, "call-uri"); const char *mixer_name = iks_find_attrib(unjoin, "mixer-name"); if (!zstr(call_uri) && !zstr(mixer_name)) { - response = iks_new_error(node, STANZA_ERROR_BAD_REQUEST); + response = iks_new_error(msg->payload, STANZA_ERROR_BAD_REQUEST); + } else if (RAYO_CALL(call)->pending_join_request) { + /* need to let pending request finish first */ + response = iks_new_error_detailed(msg->payload, STANZA_ERROR_UNEXPECTED_REQUEST, "(un)join request is pending"); } else if (!RAYO_CALL(call)->joined) { /* not joined to anything */ - response = iks_new_error(node, STANZA_ERROR_SERVICE_UNAVAILABLE); + response = iks_new_error(msg->payload, STANZA_ERROR_SERVICE_UNAVAILABLE); } else if (!zstr(call_uri)) { - response = unjoin_call(RAYO_CALL(call), session, node, call_uri); + response = unjoin_call(RAYO_CALL(call), session, msg, call_uri); } else if (!zstr(mixer_name)) { - response = unjoin_mixer(RAYO_CALL(call), session, node, mixer_name); + response = unjoin_mixer(RAYO_CALL(call), session, msg, mixer_name); } else { /* unjoin everything */ if (RAYO_CALL(call)->joined == JOINED_MIXER) { - response = unjoin_mixer(RAYO_CALL(call), session, node, RAYO_CALL(call)->joined_id); + response = unjoin_mixer(RAYO_CALL(call), session, msg, RAYO_CALL(call)->joined_id); } else if (RAYO_CALL(call)->joined == JOINED_CALL) { - response = unjoin_call(RAYO_CALL(call), session, node, RAYO_CALL(call)->joined_id); + response = unjoin_call(RAYO_CALL(call), session, msg, RAYO_CALL(call)->joined_id); } else { /* shouldn't happen */ - response = iks_new_error(node, STANZA_ERROR_INTERNAL_SERVER_ERROR); + response = iks_new_error(msg->payload, STANZA_ERROR_INTERNAL_SERVER_ERROR); } } @@ -2661,16 +2698,29 @@ static void on_call_bridge_event(struct rayo_client *rclient, switch_event_t *ev struct rayo_call *b_call; if (call) { - /* send A-leg event */ - iks *revent = iks_new_presence("joined", RAYO_NS, - switch_event_get_header(event, "variable_rayo_call_jid"), - switch_event_get_header(event, "variable_rayo_dcp_jid")); - iks *joined = iks_find(revent, "joined"); - iks_insert_attrib_printf(joined, "call-uri", "xmpp:%s@%s", b_uuid, RAYO_JID(globals.server)); + iks *revent; + iks *joined; call->joined = JOINED_CALL; call->joined_id = switch_core_strdup(RAYO_POOL(call), b_uuid); + /* send IQ result to client now. */ + switch_mutex_lock(RAYO_ACTOR(call)->mutex); + if (call->pending_join_request) { + iks *result = iks_new_iq_result(call->pending_join_request); + RAYO_SEND_REPLY(call, iks_find_attrib_soft(call->pending_join_request, "from"), result); + iks_delete(call->pending_join_request); + call->pending_join_request = NULL; + } + switch_mutex_unlock(RAYO_ACTOR(call)->mutex); + + /* send A-leg event */ + revent = iks_new_presence("joined", RAYO_NS, + switch_event_get_header(event, "variable_rayo_call_jid"), + switch_event_get_header(event, "variable_rayo_dcp_jid")); + joined = iks_find(revent, "joined"); + iks_insert_attrib_printf(joined, "call-uri", "xmpp:%s@%s", b_uuid, RAYO_JID(globals.server)); + RAYO_SEND_MESSAGE(call, RAYO_JID(rclient), revent); /* send B-leg event */ @@ -2703,17 +2753,30 @@ static void on_call_unbridge_event(struct rayo_client *rclient, switch_event_t * struct rayo_call *b_call; if (call) { - /* send A-leg event */ - iks *revent = iks_new_presence("unjoined", RAYO_NS, - switch_event_get_header(event, "variable_rayo_call_jid"), - switch_event_get_header(event, "variable_rayo_dcp_jid")); - iks *joined = iks_find(revent, "unjoined"); - iks_insert_attrib_printf(joined, "call-uri", "xmpp:%s@%s", b_uuid, RAYO_JID(globals.server)); - RAYO_SEND_MESSAGE(call, RAYO_JID(rclient), revent); + iks *revent; + iks *joined; call->joined = 0; call->joined_id = NULL; + /* send IQ result to client now. */ + switch_mutex_lock(RAYO_ACTOR(call)->mutex); + if (call->pending_join_request) { + iks *result = iks_new_iq_result(call->pending_join_request); + RAYO_SEND_REPLY(call, iks_find_attrib_soft(call->pending_join_request, "from"), result); + iks_delete(call->pending_join_request); + call->pending_join_request = NULL; + } + switch_mutex_unlock(RAYO_ACTOR(call)->mutex); + + /* send A-leg event */ + revent = iks_new_presence("unjoined", RAYO_NS, + switch_event_get_header(event, "variable_rayo_call_jid"), + switch_event_get_header(event, "variable_rayo_dcp_jid")); + joined = iks_find(revent, "unjoined"); + iks_insert_attrib_printf(joined, "call-uri", "xmpp:%s@%s", b_uuid, RAYO_JID(globals.server)); + RAYO_SEND_MESSAGE(call, RAYO_JID(rclient), revent); + /* send B-leg event */ b_call = RAYO_CALL_LOCATE_BY_ID(b_uuid); if (b_call) { diff --git a/src/mod/event_handlers/mod_rayo/rayo_output_component.c b/src/mod/event_handlers/mod_rayo/rayo_output_component.c index e85a12cece..e092ebd046 100644 --- a/src/mod/event_handlers/mod_rayo/rayo_output_component.c +++ b/src/mod/event_handlers/mod_rayo/rayo_output_component.c @@ -642,7 +642,7 @@ static switch_status_t fileman_file_open(switch_file_handle_t *handle, const cha switch_mutex_unlock(fileman_globals.mutex); context->max_frame_len = (handle->samplerate / 1000 * SWITCH_MAX_INTERVAL); - switch_zmalloc(context->abuf, FILE_STARTBYTES); + switch_zmalloc(context->abuf, FILE_STARTBYTES * sizeof(*context->abuf)); if (!context->fh.audio_buffer) { switch_log_printf(SWITCH_CHANNEL_UUID_LOG(context->uuid), SWITCH_LOG_DEBUG, "Create audio buffer\n"); diff --git a/src/switch.c b/src/switch.c index 8624682bc5..5a16fca2b3 100644 --- a/src/switch.c +++ b/src/switch.c @@ -435,7 +435,7 @@ static const char usage[] = "\t-version -- print the version and exit\n" "\t-rp -- enable high(realtime) priority settings\n" "\t-lp -- enable low priority settings\n" - "\t-np -- enable normal priority settings (system defaults)\n" + "\t-np -- enable normal priority settings\n" "\t-vg -- run under valgrind\n" "\t-nosql -- disable internal sql scoreboard\n" "\t-heavy-timer -- Heavy Timer, possibly more accurate but at a cost\n" diff --git a/src/switch_apr.c b/src/switch_apr.c index f13bdcd618..d7717290bd 100644 --- a/src/switch_apr.c +++ b/src/switch_apr.c @@ -717,7 +717,7 @@ SWITCH_DECLARE(switch_status_t) switch_socket_connect(switch_socket_t *sock, swi SWITCH_DECLARE(switch_status_t) switch_socket_send(switch_socket_t *sock, const char *buf, switch_size_t *len) { - switch_status_t status = SWITCH_STATUS_SUCCESS; + int status = SWITCH_STATUS_SUCCESS; switch_size_t req = *len, wrote = 0, need = *len; int to_count = 0; @@ -737,7 +737,7 @@ SWITCH_DECLARE(switch_status_t) switch_socket_send(switch_socket_t *sock, const } *len = wrote; - return status; + return (switch_status_t)status; } SWITCH_DECLARE(switch_status_t) switch_socket_send_nonblock(switch_socket_t *sock, const char *buf, switch_size_t *len) @@ -760,7 +760,7 @@ SWITCH_DECLARE(switch_status_t) switch_socket_sendto(switch_socket_t *sock, swit SWITCH_DECLARE(switch_status_t) switch_socket_recv(switch_socket_t *sock, char *buf, switch_size_t *len) { - switch_status_t r; + int r; r = apr_socket_recv(sock, buf, len); @@ -768,7 +768,7 @@ SWITCH_DECLARE(switch_status_t) switch_socket_recv(switch_socket_t *sock, char * r = SWITCH_STATUS_BREAK; } - return r; + return (switch_status_t)r; } SWITCH_DECLARE(switch_status_t) switch_sockaddr_create(switch_sockaddr_t **sa, switch_memory_pool_t *pool) @@ -866,7 +866,7 @@ SWITCH_DECLARE(switch_status_t) switch_socket_atmark(switch_socket_t *sock, int SWITCH_DECLARE(switch_status_t) switch_socket_recvfrom(switch_sockaddr_t *from, switch_socket_t *sock, int32_t flags, char *buf, size_t *len) { - apr_status_t r = SWITCH_STATUS_GENERR; + int r = SWITCH_STATUS_GENERR; if (from && sock && (r = apr_socket_recvfrom(from, sock, flags, buf, len)) == APR_SUCCESS) { from->port = ntohs(from->sa.sin.sin_port); @@ -879,7 +879,7 @@ SWITCH_DECLARE(switch_status_t) switch_socket_recvfrom(switch_sockaddr_t *from, r = SWITCH_STATUS_BREAK; } - return r; + return (switch_status_t)r; } /* poll stubs */ diff --git a/src/switch_console.c b/src/switch_console.c index eea6d5510b..63fe575856 100644 --- a/src/switch_console.c +++ b/src/switch_console.c @@ -798,7 +798,7 @@ SWITCH_DECLARE(unsigned char) switch_console_complete(const char *line, const ch if (h.words == 0) { sql = switch_mprintf("select distinct name from interfaces where type='api' and name like '%q%%' and hostname='%q' order by name", - buf, switch_core_get_switchname()); + buf, switch_core_get_hostname()); } if (sql) { @@ -826,7 +826,7 @@ SWITCH_DECLARE(unsigned char) switch_console_complete(const char *line, const ch if (h.words == 0) { stream.write_function(&stream, "select distinct a1 from complete where " "a1 not in (select name from interfaces where hostname='%s') %s ", - switch_core_get_switchname(), argc ? "and" : ""); + switch_core_get_hostname(), argc ? "and" : ""); } else { if (switch_cache_db_get_type(db) == SCDB_TYPE_CORE_DB) { stream.write_function(&stream, "select distinct a%d,'%q','%q' from complete where ", h.words + 1, switch_str_nil(dup), switch_str_nil(lp)); @@ -855,7 +855,7 @@ SWITCH_DECLARE(unsigned char) switch_console_complete(const char *line, const ch } } - stream.write_function(&stream, " and hostname='%s' order by a%d", switch_core_get_switchname(), h.words + 1); + stream.write_function(&stream, " and hostname='%s' order by a%d", switch_core_get_hostname(), h.words + 1); switch_cache_db_execute_sql_callback(db, stream.data, comp_callback, &h, &errmsg); @@ -1859,7 +1859,7 @@ SWITCH_DECLARE(switch_status_t) switch_console_set_complete(const char *string) } } } - mystream.write_function(&mystream, " '%s')", switch_core_get_switchname()); + mystream.write_function(&mystream, " '%s')", switch_core_get_hostname()); switch_core_sql_exec(mystream.data); status = SWITCH_STATUS_SUCCESS; } else if (!strcasecmp(argv[0], "add")) { @@ -1875,14 +1875,15 @@ SWITCH_DECLARE(switch_status_t) switch_console_set_complete(const char *string) } } } - mystream.write_function(&mystream, " '%s')", switch_core_get_switchname()); + mystream.write_function(&mystream, " '%s')", switch_core_get_hostname()); switch_core_sql_exec(mystream.data); status = SWITCH_STATUS_SUCCESS; } else if (!strcasecmp(argv[0], "del")) { char *what = argv[1]; if (!strcasecmp(what, "*")) { - switch_core_sql_exec("delete from complete"); + mystream.write_function(&mystream, "delete from complete where hostname='%s'", switch_core_get_hostname()); + switch_core_sql_exec(mystream.data); } else { mystream.write_function(&mystream, "delete from complete where "); for (x = 0; x < argc - 1; x++) { @@ -1892,7 +1893,7 @@ SWITCH_DECLARE(switch_status_t) switch_console_set_complete(const char *string) mystream.write_function(&mystream, "a%d = '%w'%w", x + 1, switch_str_nil(argv[x + 1]), x == argc - 2 ? "" : " and "); } } - mystream.write_function(&mystream, " and hostname='%s'", switch_core_get_switchname()); + mystream.write_function(&mystream, " and hostname='%s'", switch_core_get_hostname()); switch_core_sql_exec(mystream.data); } status = SWITCH_STATUS_SUCCESS; diff --git a/src/switch_core.c b/src/switch_core.c index 2f6cd7b023..8cefdd2e63 100644 --- a/src/switch_core.c +++ b/src/switch_core.c @@ -1659,6 +1659,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_init(switch_core_flag_t flags, switc runtime.console = stdout; } + SSL_library_init(); switch_ssl_init_ssl_locks(); switch_curl_init(); @@ -1792,6 +1793,7 @@ static void switch_load_core_config(const char *file) switch_core_hash_insert(runtime.ptimes, "isac", &d_30); switch_core_hash_insert(runtime.ptimes, "G723", &d_30); + if ((xml = switch_xml_open_cfg(file, &cfg, NULL))) { switch_xml_t settings, param; @@ -1964,7 +1966,7 @@ static void switch_load_core_config(const char *file) } else if (!strcasecmp(var, "tipping-point") && !zstr(val)) { runtime.tipping_point = atoi(val); } else if (!strcasecmp(var, "events-use-dispatch") && !zstr(val)) { - runtime.events_use_dispatch = 1; + runtime.events_use_dispatch = switch_true(val); } else if (!strcasecmp(var, "initial-event-threads") && !zstr(val)) { int tmp; @@ -2086,6 +2088,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_init_and_modload(switch_core_flag_t } runtime.runlevel++; + runtime.events_use_dispatch = 1; switch_core_set_signal_handlers(); switch_load_network_lists(SWITCH_FALSE); @@ -2611,7 +2614,6 @@ SWITCH_DECLARE(switch_status_t) switch_core_destroy(void) switch_nat_shutdown(); } switch_xml_destroy(); - switch_core_session_uninit(); switch_console_shutdown(); switch_channel_global_uninit(); @@ -2621,6 +2623,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_destroy(void) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Finalizing Shutdown.\n"); switch_log_shutdown(); + switch_core_session_uninit(); switch_core_unset_variables(); switch_core_memory_stop(); diff --git a/src/switch_core_file.c b/src/switch_core_file.c index 9c4ae53cc2..4d6a0f7f19 100644 --- a/src/switch_core_file.c +++ b/src/switch_core_file.c @@ -39,7 +39,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_perform_file_open(const char *file, const char *func, int line, switch_file_handle_t *fh, const char *file_path, - uint8_t channels, uint32_t rate, unsigned int flags, switch_memory_pool_t *pool) + uint32_t channels, uint32_t rate, unsigned int flags, switch_memory_pool_t *pool) { char *ext; switch_status_t status = SWITCH_STATUS_FALSE; @@ -292,7 +292,12 @@ SWITCH_DECLARE(switch_status_t) switch_core_file_read(switch_file_handle_t *fh, rlen = asis ? fh->pre_buffer_datalen : fh->pre_buffer_datalen / 2; if (switch_buffer_inuse(fh->pre_buffer) < rlen * 2) { - if ((status = fh->file_interface->file_read(fh, fh->pre_buffer_data, &rlen)) != SWITCH_STATUS_SUCCESS || !rlen) { + if ((status = fh->file_interface->file_read(fh, fh->pre_buffer_data, &rlen)) == SWITCH_STATUS_BREAK) { + return SWITCH_STATUS_BREAK; + } + + + if (status != SWITCH_STATUS_SUCCESS || !rlen) { switch_set_flag(fh, SWITCH_FILE_BUFFER_DONE); } else { fh->samples_in += rlen; @@ -316,7 +321,11 @@ SWITCH_DECLARE(switch_status_t) switch_core_file_read(switch_file_handle_t *fh, } else { - if ((status = fh->file_interface->file_read(fh, data, len)) != SWITCH_STATUS_SUCCESS || !*len) { + if ((status = fh->file_interface->file_read(fh, data, len)) == SWITCH_STATUS_BREAK) { + return SWITCH_STATUS_BREAK; + } + + if (status != SWITCH_STATUS_SUCCESS || !*len) { switch_set_flag(fh, SWITCH_FILE_DONE); goto top; } diff --git a/src/switch_core_io.c b/src/switch_core_io.c index 2b3c3b6d66..aad6192ece 100644 --- a/src/switch_core_io.c +++ b/src/switch_core_io.c @@ -773,7 +773,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi switch_buffer_create_dynamic(&session->raw_read_buffer, bytes * SWITCH_BUFFER_BLOCK_FRAMES, bytes * SWITCH_BUFFER_START_FRAMES, 0); } - if (!switch_buffer_write(session->raw_read_buffer, read_frame->data, read_frame->datalen)) { + if (read_frame->datalen && (!switch_buffer_write(session->raw_read_buffer, read_frame->data, read_frame->datalen))) { status = SWITCH_STATUS_MEMERR; goto done; } diff --git a/src/switch_core_session.c b/src/switch_core_session.c index 07b0391bf4..430b20d013 100644 --- a/src/switch_core_session.c +++ b/src/switch_core_session.c @@ -721,6 +721,10 @@ static const char *message_names[] = { "AUDIO_DATA", "BLIND_TRANSFER_RESPONSE", "STUN_ERROR", + "MEDIA_RENEG", + "ANSWER_EVENT", + "PROGRESS_EVENT", + "RING_EVENT", "INVALID" }; @@ -1390,7 +1394,7 @@ SWITCH_DECLARE(void) switch_core_session_perform_destroy(switch_core_session_t * switch_channel_get_name((*session)->channel), switch_channel_state_name(switch_channel_get_state((*session)->channel))); - switch_core_session_reset(*session, TRUE, SWITCH_TRUE); + switch_core_session_reset(*session, SWITCH_TRUE, SWITCH_TRUE); switch_core_media_bug_remove_all(*session); switch_ivr_deactivate_unicast(*session); @@ -1584,6 +1588,7 @@ static void *SWITCH_THREAD_FUNC switch_core_session_thread_pool_worker(switch_th int check = 0; switch_mutex_lock(session_manager.mutex); + session_manager.starting--; session_manager.running++; switch_mutex_unlock(session_manager.mutex); #ifdef DEBUG_THREAD_POOL @@ -1678,6 +1683,33 @@ static void thread_launch_failure(void) switch_mutex_unlock(session_manager.mutex); } +static int wake_queue(void) +{ + switch_status_t status; + int tries = 0; + + top: + + status = switch_mutex_trylock(session_manager.cond_mutex); + + if (status == SWITCH_STATUS_SUCCESS) { + switch_thread_cond_signal(session_manager.cond); + switch_mutex_unlock(session_manager.cond_mutex); + return 1; + } else { + if (switch_mutex_trylock(session_manager.cond2_mutex) == SWITCH_STATUS_SUCCESS) { + switch_mutex_unlock(session_manager.cond2_mutex); + } else { + if (++tries < 10) { + switch_cond_next(); + goto top; + } + } + } + + return 0; +} + static switch_status_t check_queue(void) { switch_status_t status = SWITCH_STATUS_FALSE; @@ -1686,7 +1718,7 @@ static switch_status_t check_queue(void) switch_mutex_lock(session_manager.mutex); ttl = switch_queue_size(session_manager.thread_queue); - x = (session_manager.running - session_manager.busy); + x = ((session_manager.running + session_manager.starting) - session_manager.busy); switch_mutex_unlock(session_manager.mutex); @@ -1713,6 +1745,10 @@ static switch_status_t check_queue(void) } else { status = SWITCH_STATUS_SUCCESS; } + + switch_mutex_lock(session_manager.mutex); + session_manager.starting++; + switch_mutex_unlock(session_manager.mutex); x++; } @@ -1722,12 +1758,20 @@ static switch_status_t check_queue(void) static void *SWITCH_THREAD_FUNC switch_core_session_thread_pool_manager(switch_thread_t *thread, void *obj) { - int x = 0; + + uint32_t sleep = 10000000; + switch_time_t next = switch_micro_time_now() + sleep; + + switch_mutex_lock(session_manager.cond_mutex); while(session_manager.ready) { - switch_yield(100000); + int check = 1; - if (++x == 300) { + switch_mutex_lock(session_manager.cond2_mutex); + switch_thread_cond_timedwait(session_manager.cond, session_manager.cond_mutex, sleep); + switch_mutex_unlock(session_manager.cond2_mutex); + + if (switch_micro_time_now() >= next) { if (session_manager.popping) { #ifdef DEBUG_THREAD_POOL switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG10, @@ -1735,17 +1779,20 @@ static void *SWITCH_THREAD_FUNC switch_core_session_thread_pool_manager(switch_t #endif switch_queue_interrupt_all(session_manager.thread_queue); - x--; - - continue; + sleep = 100000; + check = 0; } else { - x = 0; + sleep = 10000000; } } - check_queue(); + if (check) check_queue(); + + next = switch_micro_time_now() + sleep; } + switch_mutex_unlock(session_manager.cond_mutex); + while(session_manager.running) { switch_queue_interrupt_all(session_manager.thread_queue); switch_yield(20000); @@ -1766,7 +1813,7 @@ SWITCH_DECLARE(switch_status_t) switch_thread_pool_launch_thread(switch_thread_d *tdp = NULL; switch_queue_push(session_manager.thread_queue, td); - check_queue(); + wake_queue(); return status; } @@ -1789,7 +1836,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_thread_pool_launch(switch_co td->obj = session; td->func = switch_core_session_thread; switch_queue_push(session_manager.thread_queue, td); - check_queue(); + wake_queue(); } switch_mutex_unlock(session->mutex); @@ -2434,11 +2481,14 @@ void switch_core_session_init(switch_memory_pool_t *pool) switch_threadattr_t *thd_attr; switch_mutex_init(&session_manager.mutex, SWITCH_MUTEX_NESTED, session_manager.memory_pool); + switch_thread_cond_create(&session_manager.cond, session_manager.memory_pool); + switch_mutex_init(&session_manager.cond_mutex, SWITCH_MUTEX_NESTED, session_manager.memory_pool); + switch_mutex_init(&session_manager.cond2_mutex, SWITCH_MUTEX_NESTED, session_manager.memory_pool); switch_queue_create(&session_manager.thread_queue, 100000, session_manager.memory_pool); switch_threadattr_create(&thd_attr, session_manager.memory_pool); switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE); - switch_thread_create(&session_manager.manager_thread, thd_attr, switch_core_session_thread_pool_manager, NULL, session_manager.memory_pool); session_manager.ready = 1; + switch_thread_create(&session_manager.manager_thread, thd_attr, switch_core_session_thread_pool_manager, NULL, session_manager.memory_pool); } } @@ -2448,15 +2498,16 @@ void switch_core_session_uninit(void) int sanity = 100; switch_status_t st = SWITCH_STATUS_FALSE; - switch_core_hash_destroy(&session_manager.session_table); session_manager.ready = 0; - - switch_thread_join(&st, session_manager.manager_thread); + wake_queue(); while(session_manager.running && --sanity > 0) { switch_queue_interrupt_all(session_manager.thread_queue); switch_yield(100000); } + + switch_thread_join(&st, session_manager.manager_thread); + switch_core_hash_destroy(&session_manager.session_table); } diff --git a/src/switch_core_sqldb.c b/src/switch_core_sqldb.c index e270a0c29c..a9c8d22fbc 100644 --- a/src/switch_core_sqldb.c +++ b/src/switch_core_sqldb.c @@ -2012,7 +2012,7 @@ static void core_event_handler(switch_event_t *event) new_sql() = switch_mprintf("insert into tasks values(%q,'%q','%q',%q, '%q')", id, switch_event_get_header_nil(event, "task-desc"), - switch_event_get_header_nil(event, "task-group"), manager ? manager : "0", switch_core_get_switchname() + switch_event_get_header_nil(event, "task-group"), manager ? manager : "0", switch_core_get_hostname() ); } } @@ -2020,7 +2020,7 @@ static void core_event_handler(switch_event_t *event) case SWITCH_EVENT_DEL_SCHEDULE: case SWITCH_EVENT_EXE_SCHEDULE: new_sql() = switch_mprintf("delete from tasks where task_id=%q and hostname='%q'", - switch_event_get_header_nil(event, "task-id"), switch_core_get_switchname()); + switch_event_get_header_nil(event, "task-id"), switch_core_get_hostname()); break; case SWITCH_EVENT_RE_SCHEDULE: { @@ -2031,7 +2031,7 @@ static void core_event_handler(switch_event_t *event) new_sql() = switch_mprintf("update tasks set task_desc='%q',task_group='%q', task_sql_manager=%q where task_id=%q and hostname='%q'", switch_event_get_header_nil(event, "task-desc"), switch_event_get_header_nil(event, "task-group"), manager ? manager : "0", id, - switch_core_get_switchname()); + switch_core_get_hostname()); } } break; @@ -2317,7 +2317,7 @@ static void core_event_handler(switch_event_t *event) new_sql() = switch_mprintf("delete from channels where hostname='%q';" "delete from interfaces where hostname='%q';" "delete from calls where hostname='%q'", - switch_core_get_switchname(), switch_core_get_switchname(), switch_core_get_switchname() + switch_core_get_switchname(), switch_core_get_hostname(), switch_core_get_switchname() ); break; case SWITCH_EVENT_LOG: @@ -2335,7 +2335,7 @@ static void core_event_handler(switch_event_t *event) switch_mprintf ("insert into interfaces (type,name,description,syntax,ikey,filename,hostname) values('%q','%q','%q','%q','%q','%q','%q')", type, name, switch_str_nil(description), switch_str_nil(syntax), switch_str_nil(key), switch_str_nil(filename), - switch_core_get_switchname() + switch_core_get_hostname() ); } break; @@ -2346,7 +2346,7 @@ static void core_event_handler(switch_event_t *event) const char *name = switch_event_get_header_nil(event, "name"); if (!zstr(type) && !zstr(name)) { new_sql() = switch_mprintf("delete from interfaces where type='%q' and name='%q' and hostname='%q'", type, name, - switch_core_get_switchname()); + switch_core_get_hostname()); } break; } @@ -2369,12 +2369,12 @@ static void core_event_handler(switch_event_t *event) if (!strcmp("add", op)) { new_sql() = switch_mprintf("insert into nat (port, proto, sticky, hostname) values (%s, %s, %d,'%q')", switch_event_get_header_nil(event, "port"), - switch_event_get_header_nil(event, "proto"), sticky, switch_core_get_switchname() + switch_event_get_header_nil(event, "proto"), sticky, switch_core_get_hostname() ); } else if (!strcmp("del", op)) { new_sql() = switch_mprintf("delete from nat where port=%s and proto=%s and hostname='%q'", switch_event_get_header_nil(event, "port"), - switch_event_get_header_nil(event, "proto"), switch_core_get_switchname()); + switch_event_get_header_nil(event, "proto"), switch_core_get_hostname()); } else if (!strcmp("status", op)) { /* call show nat api */ } else if (!strcmp("status_response", op)) { @@ -3106,7 +3106,7 @@ switch_status_t switch_core_sqldb_start(switch_memory_pool_t *pool, switch_bool_ case SCDB_TYPE_ODBC: if (switch_test_flag((&runtime), SCF_CLEAR_SQL)) { char sql[512] = ""; - char *tables[] = { "channels", "calls", "interfaces", "tasks", NULL }; + char *tables[] = { "channels", "calls", "tasks", NULL }; int i; const char *hostname = switch_core_get_switchname(); @@ -3265,8 +3265,18 @@ switch_status_t switch_core_sqldb_start(switch_memory_pool_t *pool, switch_bool_ break; } + if (switch_test_flag((&runtime), SCF_CLEAR_SQL)) { + char sql[512] = ""; + char *tables[] = { "complete", "interfaces", NULL }; + int i; + const char *hostname = switch_core_get_hostname(); + + for (i = 0; tables[i]; i++) { + switch_snprintfv(sql, sizeof(sql), "delete from %q where hostname='%q'", tables[i], hostname); + switch_cache_db_execute_sql(sql_manager.dbh, sql, NULL); + } + } - switch_cache_db_execute_sql(sql_manager.dbh, "delete from complete where sticky=0", NULL); switch_cache_db_execute_sql(sql_manager.dbh, "delete from aliases where sticky=0", NULL); switch_cache_db_execute_sql(sql_manager.dbh, "delete from nat where sticky=0", NULL); switch_cache_db_execute_sql(sql_manager.dbh, "create index alias1 on aliases (alias)", NULL); diff --git a/src/switch_event.c b/src/switch_event.c index b87d1d4d4b..080a331dcd 100644 --- a/src/switch_event.c +++ b/src/switch_event.c @@ -571,6 +571,25 @@ SWITCH_DECLARE(switch_status_t) switch_event_shutdown(void) return SWITCH_STATUS_SUCCESS; } +static void check_dispatch(void) +{ + if (!EVENT_DISPATCH_QUEUE) { + switch_mutex_lock(BLOCK); + + if (!EVENT_DISPATCH_QUEUE) { + switch_queue_create(&EVENT_DISPATCH_QUEUE, DISPATCH_QUEUE_LEN * MAX_DISPATCH, THRUNTIME_POOL); + switch_event_launch_dispatch_threads(1); + + while (!THREAD_COUNT) { + switch_cond_next(); + } + } + switch_mutex_unlock(BLOCK); + } +} + + + SWITCH_DECLARE(void) switch_event_launch_dispatch_threads(uint32_t max) { switch_threadattr_t *thd_attr; @@ -580,6 +599,8 @@ SWITCH_DECLARE(void) switch_event_launch_dispatch_threads(uint32_t max) switch_memory_pool_t *pool = RUNTIME_POOL; + check_dispatch(); + if (max > MAX_DISPATCH) { return; } @@ -644,30 +665,12 @@ SWITCH_DECLARE(switch_status_t) switch_event_init(switch_memory_pool_t *pool) switch_find_local_ip(guess_ip_v6, sizeof(guess_ip_v6), NULL, AF_INET6); - //switch_queue_create(&EVENT_QUEUE[0], POOL_COUNT_MAX + 10, THRUNTIME_POOL); - //switch_queue_create(&EVENT_QUEUE[1], POOL_COUNT_MAX + 10, THRUNTIME_POOL); - //switch_queue_create(&EVENT_QUEUE[2], POOL_COUNT_MAX + 10, THRUNTIME_POOL); #ifdef SWITCH_EVENT_RECYCLE switch_queue_create(&EVENT_RECYCLE_QUEUE, 250000, THRUNTIME_POOL); switch_queue_create(&EVENT_HEADER_RECYCLE_QUEUE, 250000, THRUNTIME_POOL); #endif - //switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE); - - if (runtime.events_use_dispatch) { - switch_queue_create(&EVENT_DISPATCH_QUEUE, DISPATCH_QUEUE_LEN * MAX_DISPATCH, pool); - switch_event_launch_dispatch_threads(1); - } - - //switch_thread_create(&EVENT_QUEUE_THREADS[0], thd_attr, switch_event_thread, EVENT_QUEUE[0], RUNTIME_POOL); - //switch_thread_create(&EVENT_QUEUE_THREADS[1], thd_attr, switch_event_thread, EVENT_QUEUE[1], RUNTIME_POOL); - //switch_thread_create(&EVENT_QUEUE_THREADS[2], thd_attr, switch_event_thread, EVENT_QUEUE[2], RUNTIME_POOL); - - if (runtime.events_use_dispatch) { - while (!THREAD_COUNT) { - switch_cond_next(); - } - } + check_dispatch(); switch_mutex_lock(EVENT_QUEUE_MUTEX); SYSTEM_RUNNING = 1; @@ -1921,6 +1924,8 @@ SWITCH_DECLARE(switch_status_t) switch_event_fire_detailed(const char *file, con if (runtime.events_use_dispatch) { + check_dispatch(); + if (switch_event_queue_dispatch_event(event) != SWITCH_STATUS_SUCCESS) { switch_event_destroy(event); return SWITCH_STATUS_FALSE; diff --git a/src/switch_ivr_async.c b/src/switch_ivr_async.c index 159bdb5f6e..3bf20b5839 100644 --- a/src/switch_ivr_async.c +++ b/src/switch_ivr_async.c @@ -1204,20 +1204,21 @@ static switch_bool_t record_callback(switch_media_bug_t *bug, void *user_data, s switch_channel_set_variable(channel, "RECORD_DISCARDED", "true"); switch_file_remove(rh->file, switch_core_session_get_pool(session)); } - } + if (read_impl.actual_samples_per_second) { + switch_channel_set_variable_printf(channel, "record_seconds", "%d", rh->fh->samples_out / read_impl.actual_samples_per_second); + switch_channel_set_variable_printf(channel, "record_ms", "%d", rh->fh->samples_out / (read_impl.actual_samples_per_second / 1000)); + } + switch_channel_set_variable_printf(channel, "record_samples", "%d", rh->fh->samples_out); + + } + if (switch_event_create(&event, SWITCH_EVENT_RECORD_STOP) == SWITCH_STATUS_SUCCESS) { switch_channel_event_set_data(channel, event); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Record-File-Path", rh->file); switch_event_fire(&event); } - - if (read_impl.actual_samples_per_second) { - switch_channel_set_variable_printf(channel, "record_seconds", "%d", rh->fh->samples_out / read_impl.actual_samples_per_second); - switch_channel_set_variable_printf(channel, "record_ms", "%d", rh->fh->samples_out / (read_impl.actual_samples_per_second / 1000)); - } - switch_channel_set_variable_printf(channel, "record_samples", "%d", rh->fh->samples_out); - + switch_channel_execute_on(channel, SWITCH_RECORD_POST_PROCESS_EXEC_APP_VARIABLE); if ((var = switch_channel_get_variable(channel, SWITCH_RECORD_POST_PROCESS_EXEC_API_VARIABLE))) { diff --git a/src/switch_ivr_bridge.c b/src/switch_ivr_bridge.c index 0927fe95b5..356e03f43d 100644 --- a/src/switch_ivr_bridge.c +++ b/src/switch_ivr_bridge.c @@ -1122,6 +1122,9 @@ static switch_status_t signal_bridge_on_hangup(switch_core_session_t *session) } switch_channel_hangup(other_channel, switch_channel_get_cause(channel)); } else { + if (!switch_channel_test_flag(channel, CF_ANSWERED)) { + switch_channel_handle_cause(other_channel, switch_channel_get_cause(channel)); + } switch_channel_set_state(other_channel, CS_EXECUTE); } } else { diff --git a/src/switch_ivr_originate.c b/src/switch_ivr_originate.c index 9825681475..52ef822cad 100644 --- a/src/switch_ivr_originate.c +++ b/src/switch_ivr_originate.c @@ -927,7 +927,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_wait_for_answer(switch_core_session_t switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Codec Error!\n"); if (caller_channel) { - switch_channel_hangup(caller_channel, SWITCH_CAUSE_NORMAL_TEMPORARY_FAILURE); + switch_channel_hangup(caller_channel, SWITCH_CAUSE_BEARERCAPABILITY_NOTIMPL); } read_codec = NULL; goto done; @@ -1254,7 +1254,7 @@ static switch_status_t setup_ringback(originate_global_t *oglobals, originate_st switch_core_session_set_read_codec(oglobals->session, write_codec); } else { switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(caller_channel), SWITCH_LOG_ERROR, "Codec Error!\n"); - switch_channel_hangup(caller_channel, SWITCH_CAUSE_NORMAL_TEMPORARY_FAILURE); + switch_channel_hangup(caller_channel, SWITCH_CAUSE_BEARERCAPABILITY_NOTIMPL); read_codec = NULL; switch_goto_status(SWITCH_STATUS_BREAK, end); } diff --git a/src/switch_ivr_play_say.c b/src/switch_ivr_play_say.c index 7222c43533..3d7894ff74 100644 --- a/src/switch_ivr_play_say.c +++ b/src/switch_ivr_play_say.c @@ -1049,6 +1049,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess int more_data = 0; switch_event_t *event; uint32_t test_native = 0, last_native = 0; + uint32_t buflen = 0; if (switch_channel_pre_answer(channel) != SWITCH_STATUS_SUCCESS) { return SWITCH_STATUS_FALSE; @@ -1110,6 +1111,9 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess fh->samples = 0; } + + + for (cur = 0; switch_channel_ready(channel) && !done && cur < argc; cur++) { file = argv[cur]; eof = 0; @@ -1255,9 +1259,9 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess if (!abuf) { - switch_zmalloc(abuf, FILE_STARTSAMPLES * sizeof(*abuf)); + buflen = write_frame.buflen = FILE_STARTSAMPLES * sizeof(*abuf) * fh->channels; + switch_zmalloc(abuf, write_frame.buflen); write_frame.data = abuf; - write_frame.buflen = FILE_STARTSAMPLES; } if (sample_start > 0) { @@ -1454,6 +1458,14 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess } } + buflen = FILE_STARTSAMPLES * sizeof(*abuf) * fh->cur_channels; + + if (buflen > write_frame.buflen) { + abuf = realloc(abuf, buflen); + write_frame.data = abuf; + write_frame.buflen = buflen; + } + if (switch_test_flag(fh, SWITCH_FILE_PAUSE)) { if (framelen > FILE_STARTSAMPLES) { framelen = FILE_STARTSAMPLES; @@ -1493,6 +1505,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess olen = switch_test_flag(fh, SWITCH_FILE_NATIVE) ? framelen : ilen; } else { + switch_status_t rstatus; + if (eof) { break; } @@ -1500,7 +1514,12 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess if (!switch_test_flag(fh, SWITCH_FILE_NATIVE)) { olen /= 2; } - if (switch_core_file_read(fh, abuf, &olen) != SWITCH_STATUS_SUCCESS) { + switch_set_flag(fh, SWITCH_FILE_BREAK_ON_CHANGE); + if ((rstatus = switch_core_file_read(fh, abuf, &olen)) == SWITCH_STATUS_BREAK) { + continue; + } + + if (rstatus != SWITCH_STATUS_SUCCESS) { eof++; continue; } diff --git a/src/switch_rtp.c b/src/switch_rtp.c index a5b091fe17..c7f15f01f1 100644 --- a/src/switch_rtp.c +++ b/src/switch_rtp.c @@ -3961,6 +3961,10 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t status = switch_socket_recvfrom(rtp_session->from_addr, rtp_session->sock_input, 0, (void *) &rtp_session->recv_msg, bytes); + if (*bytes) { + rtp_session->missed_count = 0; + } + if (check_rtcp_and_ice(rtp_session) == -1) { return SWITCH_STATUS_GENERR; } @@ -4641,7 +4645,15 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_ ret = -1; goto end; } - + + if (rtp_session->max_missed_packets && read_loops == 1 && !rtp_session->flags[SWITCH_RTP_FLAG_VIDEO]) { + if (bytes) { + rtp_session->missed_count = 0; + } else if (++rtp_session->missed_count >= rtp_session->max_missed_packets) { + ret = -2; + goto end; + } + } if (rtp_session->flags[SWITCH_RTP_FLAG_VIDEO]) { //switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_CRIT, "Read bytes (%i) %ld\n", status, bytes); @@ -4837,15 +4849,6 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_ goto end; } - if (rtp_session->max_missed_packets && read_loops == 1 && !rtp_session->flags[SWITCH_RTP_FLAG_VIDEO]) { - if (bytes) { - rtp_session->missed_count = 0; - } else if (++rtp_session->missed_count >= rtp_session->max_missed_packets) { - ret = -2; - goto end; - } - } - check = !bytes; if (rtp_session->flags[SWITCH_RTP_FLAG_FLUSH]) { diff --git a/support-d/gl b/support-d/gl new file mode 100755 index 0000000000..c4e878ba98 --- /dev/null +++ b/support-d/gl @@ -0,0 +1,82 @@ +#!/usr/bin/perl + +my $pager = `which less` || `which more`; +my $tmpdir = "/tmp/FSJIRA"; + +system("mkdir -p $tmpdir"); + +my $cmd = "git log " . join(" ", @ARGV); + +open(CMD, "$cmd |"); +open(PAGER, "|$pager"); +select PAGER; + +while(my $line = ) { + + print $line; + + if ($line =~ /([A-Z]+\-[0-9]+)/) { + my $bug = $1; + my $txt = bugtxt($bug); + if ($txt) { + print "=" x 80 . "\n"; + print $txt; + print "=" x 80 . "\n"; + } + } +} + +close(CMD); +close(PAGER); + +sub catfile($) { + my $file = shift; + open(I, $file) or return; + $/ = undef; + my $txt = ; + $/ = "\n"; + close(I); + return $txt; +} + + +sub bugtxt($) +{ + my $bug = shift or return ""; + my $now = time; + my $tmp; + + $bug =~ s/\.\.//g; + $bug =~ s/^\///g; + $bug =~ s/~//g; + $bug =~ s/[^a-zA-Z0-9\-]//g; + + $tmp = "$tmpdir/$bug.txt"; + + if(-f $tmp) { + return catfile($tmp); + } + + my $cmd = "wget -q http://jira.freeswitch.org/si/jira.issueviews:issue-xml/$bug/$bug.xml -O $tmp"; + + system($cmd); + + my $txt = catfile($tmp); + + my ($a,$title) = $txt =~ /\(.*?)\<\/title\>/smg; + my ($status) = $txt =~ /\(.*?)\<\/status\>/smg; + my ($a,$des) = $txt =~ /\(.*?)\<\/description\>/smg; + my ($alogin, $aname) = $txt =~ /\(.*?)\<\/assignee\>/smg; + my ($rlogin, $rname) = $txt =~ /\(.*?)\<\/reporter\>/smg; + + + if ($rname && $aname) { + my $data = "$title\nReporter: $rname [$rlogin]\nAssignee: $aname [$alogin]\nStatus: $status\nhttp://jira.freeswitch.org/browse/$bug\n"; + open(O, ">$tmp"); + print O $data; + close(O); + return $data; + } else { + unlink($tmp); + } +}