diff --git a/Makefile.am b/Makefile.am index 1a1befe7e0..886c5edf63 100644 --- a/Makefile.am +++ b/Makefile.am @@ -640,6 +640,11 @@ python-reconf: rm -f src/mod/languages/mod_python/Makefile ./config.status +reconf: + rm config.cache + sh ./config.status --recheck + sh ./config.status + srtp-reconf: cd libs/srtp && $(MAKE) clean cd libs/srtp && sh ./config.status --recheck diff --git a/build/buildopal.sh b/build/buildopal.sh index 6009f1048d..f5845a7ce8 100755 --- a/build/buildopal.sh +++ b/build/buildopal.sh @@ -42,7 +42,7 @@ fi cd $FS_DIR/libs -svn co https://opalvoip.svn.sourceforge.net/svnroot/opalvoip/ptlib/$PTLIB_VERSION ptlib +svn co https://svn.code.sf.net/p/opalvoip/code/ptlib/$PTLIB_VERSION ptlib cd $FS_DIR/libs/ptlib # LDAP disabled due to conflict wit libs in spidermonkey ./configure --disable-plugins --disable-openldap --prefix=$INSTALLDIR @@ -50,7 +50,7 @@ ${MAKE} sudo ${MAKE} install cd $FS_DIR/libs -svn co https://opalvoip.svn.sourceforge.net/svnroot/opalvoip/opal/$OPAL_VERSION opal +svn co https://svn.code.sf.net/p/opalvoip/code/opal/$OPAL_VERSION opal cd $FS_DIR/libs/opal ./configure --disable-plugins --prefix=$INSTALLDIR $MAKE diff --git a/build/modules.conf.in b/build/modules.conf.in index 66b649f6f3..1af56eef31 100644 --- a/build/modules.conf.in +++ b/build/modules.conf.in @@ -105,6 +105,7 @@ event_handlers/mod_event_socket #event_handlers/mod_format_cdr #event_handlers/mod_json_cdr #event_handlers/mod_radius_cdr +#event_handlers/mod_odbc_cdr #event_handlers/mod_rayo #event_handlers/mod_snmp formats/mod_local_stream @@ -131,6 +132,7 @@ loggers/mod_syslog #say/mod_say_de say/mod_say_en #say/mod_say_es +#say/mod_say_es_ar #say/mod_say_fa #say/mod_say_fr #say/mod_say_he diff --git a/conf/curl/autoload_configs/switch.conf.xml b/conf/curl/autoload_configs/switch.conf.xml index 09d1c07393..bb9af4f3fa 100644 --- a/conf/curl/autoload_configs/switch.conf.xml +++ b/conf/curl/autoload_configs/switch.conf.xml @@ -18,6 +18,8 @@ + + diff --git a/conf/insideout/autoload_configs/switch.conf.xml b/conf/insideout/autoload_configs/switch.conf.xml index 09d1c07393..bb9af4f3fa 100644 --- a/conf/insideout/autoload_configs/switch.conf.xml +++ b/conf/insideout/autoload_configs/switch.conf.xml @@ -18,6 +18,8 @@ + + diff --git a/conf/rayo/autoload_configs/rayo.conf.xml b/conf/rayo/autoload_configs/rayo.conf.xml index 50af0f7ecd..a5f8748416 100644 --- a/conf/rayo/autoload_configs/rayo.conf.xml +++ b/conf/rayo/autoload_configs/rayo.conf.xml @@ -2,8 +2,14 @@ + + + + + + @@ -52,8 +58,8 @@ - - + + diff --git a/conf/rayo/autoload_configs/switch.conf.xml b/conf/rayo/autoload_configs/switch.conf.xml index ddf41f8996..e618069ab2 100644 --- a/conf/rayo/autoload_configs/switch.conf.xml +++ b/conf/rayo/autoload_configs/switch.conf.xml @@ -24,6 +24,9 @@ + + + diff --git a/conf/sbc/autoload_configs/switch.conf.xml b/conf/sbc/autoload_configs/switch.conf.xml index 09d1c07393..bb9af4f3fa 100644 --- a/conf/sbc/autoload_configs/switch.conf.xml +++ b/conf/sbc/autoload_configs/switch.conf.xml @@ -18,6 +18,8 @@ + + diff --git a/conf/vanilla/autoload_configs/graylog2.conf.xml b/conf/vanilla/autoload_configs/graylog2.conf.xml new file mode 100644 index 0000000000..0a05482bf8 --- /dev/null +++ b/conf/vanilla/autoload_configs/graylog2.conf.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/conf/vanilla/autoload_configs/modules.conf.xml b/conf/vanilla/autoload_configs/modules.conf.xml index e5a297e8af..092372d68c 100644 --- a/conf/vanilla/autoload_configs/modules.conf.xml +++ b/conf/vanilla/autoload_configs/modules.conf.xml @@ -3,6 +3,7 @@ + @@ -53,6 +54,7 @@ + diff --git a/conf/vanilla/autoload_configs/opus.conf.xml b/conf/vanilla/autoload_configs/opus.conf.xml index 747a8f762f..2ac3f66f86 100644 --- a/conf/vanilla/autoload_configs/opus.conf.xml +++ b/conf/vanilla/autoload_configs/opus.conf.xml @@ -2,5 +2,18 @@ + + + + + diff --git a/conf/vanilla/autoload_configs/switch.conf.xml b/conf/vanilla/autoload_configs/switch.conf.xml index d508ad1844..102a2a7f1e 100644 --- a/conf/vanilla/autoload_configs/switch.conf.xml +++ b/conf/vanilla/autoload_configs/switch.conf.xml @@ -24,6 +24,9 @@ + + + diff --git a/configure.ac b/configure.ac index 476c89bafb..bf4f2f602b 100644 --- a/configure.ac +++ b/configure.ac @@ -1558,6 +1558,7 @@ AC_CONFIG_FILES([Makefile src/mod/event_handlers/mod_format_cdr/Makefile src/mod/event_handlers/mod_json_cdr/Makefile src/mod/event_handlers/mod_radius_cdr/Makefile + src/mod/event_handlers/mod_odbc_cdr/Makefile src/mod/event_handlers/mod_rayo/Makefile src/mod/event_handlers/mod_snmp/Makefile src/mod/event_handlers/mod_event_zmq/Makefile @@ -1586,6 +1587,7 @@ AC_CONFIG_FILES([Makefile src/mod/say/mod_say_de/Makefile src/mod/say/mod_say_en/Makefile src/mod/say/mod_say_es/Makefile + src/mod/say/mod_say_es_ar/Makefile src/mod/say/mod_say_fa/Makefile src/mod/say/mod_say_fr/Makefile src/mod/say/mod_say_he/Makefile diff --git a/debian/bootstrap.sh b/debian/bootstrap.sh index c749981770..b179f594c0 100755 --- a/debian/bootstrap.sh +++ b/debian/bootstrap.sh @@ -35,11 +35,13 @@ avoid_mods=( ) avoid_mods_sid=( directories/mod_ldap + formats/mod_shout languages/mod_java ) avoid_mods_jessie=( directories/mod_ldap languages/mod_java + formats/mod_shout ) avoid_mods_wheezy=( languages/mod_java diff --git a/debian/control-modules b/debian/control-modules index a494304f6e..84b7d8d140 100644 --- a/debian/control-modules +++ b/debian/control-modules @@ -333,9 +333,9 @@ Description: mod_opus Adds mod_opus. Module: codecs/mod_sangoma_codec -Build-Depends: libsngtc-dev Description: mod_sangoma_codec Adds mod_sangoma_codec. +Build-Depends: libsngtc-dev Module: codecs/mod_silk Description: mod_silk @@ -500,6 +500,10 @@ Module: event_handlers/mod_json_cdr Description: mod_json_cdr Adds mod_json_cdr. +Module: event_handlers/mod_odbc_cdr +Description: mod_odbc_cdr + Adds mod_odbc_cdr. + Module: event_handlers/mod_radius_cdr Description: mod_radius_cdr Adds mod_radius_cdr. @@ -630,6 +634,10 @@ Module: say/mod_say_es Description: mod_say_es Adds mod_say_es. +Module: say/mod_say_es_ar +Description: mod_say_es_ar + Adds mod_say_es_ar. + Module: say/mod_say_fa Description: mod_say_fa Adds mod_say_fa. diff --git a/debian/freeswitch-sysvinit.freeswitch.init b/debian/freeswitch-sysvinit.freeswitch.init index 3a2089ad21..98be1af324 100644 --- a/debian/freeswitch-sysvinit.freeswitch.init +++ b/debian/freeswitch-sysvinit.freeswitch.init @@ -19,8 +19,7 @@ DESC=freeswitch NAME=freeswitch DAEMON=/usr/bin/freeswitch USER=freeswitch -GROUP=freeswitch -DAEMON_ARGS="-u $USER -g $GROUP -ncwait" +DAEMON_ARGS="-u $USER -ncwait" CONFDIR=/etc/$NAME RUNDIR=/var/run/$NAME PIDFILE=$RUNDIR/$NAME.pid @@ -35,13 +34,15 @@ WORKDIR=/var/lib/$NAME do_start() { if ! [ -f $CONFDIR/freeswitch.xml ]; then echo "$NAME is not configured so not starting.">&2 - echo "Please review /usr/share/doc/$NAME/README.Debian">&2 + echo "Please add configuration under /etc/freeswitch">&2 + echo "e.g. Install freeswitch-conf-vanilla, then:">&2 + echo "cp -a /usr/share/freeswitch/conf/vanilla /etc/freeswitch">&2 return 3 fi # Directory in /var/run may disappear on reboot (e.g. when tmpfs used for /var/run). mkdir -p $RUNDIR - chown -R $USER:$GROUP $RUNDIR + chown -R $USER: $RUNDIR chmod -R ug=rwX,o= $RUNDIR start-stop-daemon --start --quiet \ diff --git a/debian/rules b/debian/rules index eefc3bc277..cf6a7ed1ea 100755 --- a/debian/rules +++ b/debian/rules @@ -55,7 +55,6 @@ clean: dh $@ override_dh_auto_clean: - dh_clean .stamp-bootstrap: @$(call show_vars) diff --git a/freeswitch.spec b/freeswitch.spec index eba27714c4..67ceb70562 100644 --- a/freeswitch.spec +++ b/freeswitch.spec @@ -129,6 +129,7 @@ Source10: http://files.freeswitch.org/downloads/libs/libmemcached-0.32.tar.gz Source11: http://files.freeswitch.org/downloads/libs/json-c-0.9.tar.gz Source12: http://files.freeswitch.org/downloads/libs/opus-1.1-p2.tar.gz Source13: http://files.freeswitch.org/downloads/libs/v8-3.24.14.tar.bz2 +Source14: http://files.freeswitch.org/downloads/libs/mongo-c-driver-0.92.2.tar.gz Prefix: %{prefix} @@ -482,6 +483,14 @@ is a "high-performance, distributed memory object caching system, generic in nature, but intended for use in speeding up dynamic web applications by alleviating database load." +%package application-mongo +Summary: FreeSWITCH mod_mongo +Group: System/Libraries +Requires: %{name} = %{version}-%{release} + +%description application-mongo +Provides FreeSWITCH mod_mongo, which implements an API interface to mongodb. + %package application-nibblebill Summary: FreeSWITCH mod_nibblebill Group: System/Libraries @@ -1028,6 +1037,18 @@ BuildRequires: net-snmp-devel %description event-snmp SNMP stats reporter for the FreeSWITCH open source telephony platform +###################################################################################################################### +# FreeSWITCH Logger Modules +###################################################################################################################### + +%package logger-graylog2 +Summary: GELF logger for Graylog2 and Logstash +Group: System/Libraries +Requires: %{name} = %{version}-%{release} + +%description logger-graylog2 +GELF logger for Graylog2 and Logstash + ###################################################################################################################### # FreeSWITCH Media Format Modules ###################################################################################################################### @@ -1371,7 +1392,7 @@ APPLICATION_MODULES_DE+="applications/mod_esl" APPLICATION_MODULES_FR="applications/mod_fifo applications/mod_fsk applications/mod_fsv applications/mod_hash \ applications/mod_httapi applications/mod_http_cache applications/mod_lcr applications/mod_limit \ - applications/mod_memcache applications/mod_nibblebill applications/mod_redis applications/mod_rss" + applications/mod_memcache applications/mod_mongo applications/mod_nibblebill applications/mod_redis applications/mod_rss" APPLICATION_MODULES_SZ="applications/mod_sms applications/mod_snapshot applications/mod_snom applications/mod_soundtouch \ applications/mod_spandsp applications/mod_spy applications/mod_stress \ @@ -1463,7 +1484,7 @@ LANGUAGES_MODULES="languages/mod_lua languages/mod_perl languages/mod_python " # Logging Modules # ###################################################################################################################### -LOGGERS_MODULES="loggers/mod_console loggers/mod_logfile loggers/mod_syslog" +LOGGERS_MODULES="loggers/mod_console loggers/mod_graylog2 loggers/mod_logfile loggers/mod_syslog" ###################################################################################################################### # @@ -1807,6 +1828,7 @@ fi %config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/autoload_configs/fax.conf.xml %config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/autoload_configs/fifo.conf.xml %config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/autoload_configs/format_cdr.conf.xml +%config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/autoload_configs/graylog2.conf.xml %config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/autoload_configs/hash.conf.xml %config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/autoload_configs/httapi.conf.xml %config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/autoload_configs/http_cache.conf.xml @@ -1968,6 +1990,9 @@ fi %files application-memcache %{MODINSTDIR}/mod_memcache.so* +%files application-mongo +%{MODINSTDIR}/mod_mongo.so* + %files application-nibblebill %{MODINSTDIR}/mod_nibblebill.so* @@ -2339,6 +2364,15 @@ fi %config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/lang/sv/vm/*.xml %{MODINSTDIR}/mod_say_sv.so* +###################################################################################################################### +# +# Logger Modules +# +###################################################################################################################### + +%files logger-graylog2 +%{MODINSTDIR}/mod_graylog2.so* + ###################################################################################################################### # # Timer Modules @@ -2371,6 +2405,8 @@ fi # ###################################################################################################################### %changelog +* Tue Nov 04 2014 - crienzo@grasshopper.com +- add mod_graylog2 and mod_mongo * Thu Sep 11 2014 - krice@freeswitch.org - add and fix mod_verto and mod_rtc * Fri Jul 20 2014 - krice@freeswitch.org diff --git a/html5/verto/js/Makefile b/html5/verto/js/Makefile index 9ee3be803f..d5144b1193 100644 --- a/html5/verto/js/Makefile +++ b/html5/verto/js/Makefile @@ -8,8 +8,14 @@ jsmin: jsmin.c verto-min.js: jsmin $(JSFILES) cat $(JSFILES) | ./jsmin > $@ +verto-max.js: jsmin $(JSFILES) + cat $(JSFILES) > $@ + clean: - rm -f verto-min.js jsmin *~ + rm -f verto-min.js verto-max.js jsmin *~ install-demo: all cp verto-min.js ../demo/js + +install-maxdemo: all verto-max.js + cp verto-max.js ../demo/js/verto-min.js diff --git a/html5/verto/js/src/jquery.FSRTC.js b/html5/verto/js/src/jquery.FSRTC.js index d4f25f4fb9..4635106069 100644 --- a/html5/verto/js/src/jquery.FSRTC.js +++ b/html5/verto/js/src/jquery.FSRTC.js @@ -64,8 +64,9 @@ var newLine = []; var index = 0; for (var i = 0; i < elements.length; i++) { - if (index === 3) // Format of media starts from the fourth. - newLine[index++] = payload; // Put target payload to the first. + if (index === 3) { // Format of media starts from the fourth. + newLine[index++] = payload; // Put target payload to the first. + } if (elements[i] !== payload) newLine[index++] = elements[i]; } return newLine.join(' '); @@ -76,7 +77,7 @@ useVideo: null, useStereo: false, userData: null, - iceServers: false, + iceServers: false, videoParams: {}, audioParams: {}, callbacks: { @@ -84,8 +85,7 @@ onICE: function() {}, onOfferSDP: function() {} } - }, - options); + }, options); this.mediaData = { SDP: null, @@ -163,9 +163,9 @@ function setCompat() { $.FSRTC.moz = !!navigator.mozGetUserMedia; //navigator.getUserMedia || (navigator.getUserMedia = navigator.mozGetUserMedia || navigator.webkitGetUserMedia || navigator.msGetUserMedia); - if (!navigator.getUserMedia) { - navigator.getUserMedia = navigator.mozGetUserMedia || navigator.webkitGetUserMedia || navigator.msGetUserMedia; - } + if (!navigator.getUserMedia) { + navigator.getUserMedia = navigator.mozGetUserMedia || navigator.webkitGetUserMedia || navigator.msGetUserMedia; + } } function checkCompat() { @@ -307,7 +307,7 @@ return onChannelError(self, e); }, constraints: self.constraints, - iceServers: self.options.iceServers, + iceServers: self.options.iceServers, offerSDP: { type: "offer", sdp: self.remoteSDP @@ -324,9 +324,9 @@ getUserMedia({ constraints: { audio: { - mandatory: this.options.audioParams, - optional: [] - }, + mandatory: this.options.audioParams, + optional: [] + }, video: this.options.useVideo ? { mandatory: this.options.videoParams, optional: [] @@ -371,7 +371,7 @@ return onChannelError(self, e); }, constraints: self.constraints, - iceServers: self.options.iceServers, + iceServers: self.options.iceServers, }); onStreamSuccess(self); @@ -384,9 +384,9 @@ getUserMedia({ constraints: { audio: { - mandatory: this.options.audioParams, - optional: [] - }, + mandatory: this.options.audioParams, + optional: [] + }, video: this.options.useVideo ? { mandatory: this.options.videoParams, optional: [] @@ -398,11 +398,11 @@ }); /* - navigator.getUserMedia({ + navigator.getUserMedia({ video: this.options.useVideo, audio: true - }, onSuccess, onError); -*/ + }, onSuccess, onError); + */ }; @@ -428,34 +428,34 @@ credential: 'homeo' }; - var iceServers = null; + var iceServers = null; - if (options.iceServers) { - var tmp = options.iceServers;; + if (options.iceServers) { + var tmp = options.iceServers;; - if (typeof(tmp) === "boolean") { - tmp = null; - } + if (typeof(tmp) === "boolean") { + tmp = null; + } - if (tmp && typeof(tmp) !== "array") { - console.warn("iceServers must be an array, reverting to default ice servers"); - tmp = null; - } + if (tmp && typeof(tmp) !== "array") { + console.warn("iceServers must be an array, reverting to default ice servers"); + tmp = null; + } iceServers = { - iceServers: tmp || [STUN] + iceServers: tmp || [STUN] }; if (!moz && !tmp) { - if (parseInt(navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./)[2]) >= 28) TURN = { + if (parseInt(navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./)[2]) >= 28) TURN = { url: 'turn:turn.bistri.com:80', credential: 'homeo', username: 'homeo' - }; + }; - iceServers.iceServers = [STUN]; + iceServers.iceServers = [STUN]; } - } + } var optional = { optional: [] @@ -488,30 +488,30 @@ options.onICESDP(peer.localDescription); //x = 1; /* - x = 1; - peer.createOffer(function(sessionDescription) { - sessionDescription.sdp = serializeSdp(sessionDescription.sdp); - peer.setLocalDescription(sessionDescription); - if (options.onICESDP) { - options.onICESDP(sessionDescription); - } - }, onSdpError, constraints); - */ + x = 1; + peer.createOffer(function(sessionDescription) { + sessionDescription.sdp = serializeSdp(sessionDescription.sdp); + peer.setLocalDescription(sessionDescription); + if (options.onICESDP) { + options.onICESDP(sessionDescription); + } + }, onSdpError, constraints); + */ } } else { if (!x && options.onICESDP) { options.onICESDP(peer.localDescription); //x = 1; /* - x = 1; - peer.createAnswer(function(sessionDescription) { - sessionDescription.sdp = serializeSdp(sessionDescription.sdp); - peer.setLocalDescription(sessionDescription); - if (options.onICESDP) { - options.onICESDP(sessionDescription); - } - }, onSdpError, constraints); - */ + x = 1; + peer.createAnswer(function(sessionDescription) { + sessionDescription.sdp = serializeSdp(sessionDescription.sdp); + peer.setLocalDescription(sessionDescription); + if (options.onICESDP) { + options.onICESDP(sessionDescription); + } + }, onSdpError, constraints); + */ } } } @@ -730,8 +730,8 @@ channel: channel, sendData: function(message) { if (channel) { - channel.send(message); - } + channel.send(message); + } }, stop: function() { @@ -770,8 +770,8 @@ //video.play(); } if (options.onsuccess) { - options.onsuccess(stream); - } + options.onsuccess(stream); + } media = stream; } diff --git a/html5/verto/js/src/jquery.jsonrpcclient.js b/html5/verto/js/src/jquery.jsonrpcclient.js index be2a7a2620..51244e1672 100644 --- a/html5/verto/js/src/jquery.jsonrpcclient.js +++ b/html5/verto/js/src/jquery.jsonrpcclient.js @@ -62,605 +62,599 @@ * The returned instance must have readyState <= 1, and if less than 1, * react to onopen binding. */ - $.JsonRpcClient = function(options) { - var self = this; - this.options = $.extend({ - ajaxUrl : null, - socketUrl : null, ///< The ws-url for default getSocket. - onmessage : null, ///< Other onmessage-handler. - login : null, /// auth login - passwd : null, /// auth passwd - sessid : null, - getSocket : function(onmessage_cb) { return self._getSocket(onmessage_cb); } - }, options); - - self.ws_cnt = 0; + $.JsonRpcClient = function(options) { + var self = this; + this.options = $.extend({ + ajaxUrl : null, + socketUrl : null, ///< The ws-url for default getSocket. + onmessage : null, ///< Other onmessage-handler. + login : null, /// auth login + passwd : null, /// auth passwd + sessid : null, + getSocket : function(onmessage_cb) { return self._getSocket(onmessage_cb); } + }, options); - // Declare an instance version of the onmessage callback to wrap 'this'. - this.wsOnMessage = function(event) { self._wsOnMessage(event); }; - }; + self.ws_cnt = 0; - /// Holding the WebSocket on default getsocket. - $.JsonRpcClient.prototype._ws_socket = null; - - /// Object : { success_cb: cb, error_cb: cb } - $.JsonRpcClient.prototype._ws_callbacks = {}; - - /// The next JSON-RPC request id. - $.JsonRpcClient.prototype._current_id = 1; - - /** - * @fn call - * @memberof $.JsonRpcClient - * - * @param method The method to run on JSON-RPC server. - * @param params The params; an array or object. - * @param success_cb A callback for successful request. - * @param error_cb A callback for error. - */ - $.JsonRpcClient.prototype.call = function(method, params, success_cb, error_cb) { - // Construct the JSON-RPC 2.0 request. - - if (!params) { - params = {}; - } - - if (this.options.sessid) { - params.sessid = this.options.sessid; - } - - var request = { - jsonrpc : '2.0', - method : method, - params : params, - id : this._current_id++ // Increase the id counter to match request/response + // Declare an instance version of the onmessage callback to wrap 'this'. + this.wsOnMessage = function(event) { self._wsOnMessage(event); }; }; - if (!success_cb) { - success_cb = function(e){console.log("Success: ", e);}; - } + /// Holding the WebSocket on default getsocket. + $.JsonRpcClient.prototype._ws_socket = null; - if (!error_cb) { - error_cb = function(e){console.log("Error: ", e);}; - } + /// Object : { success_cb: cb, error_cb: cb } + $.JsonRpcClient.prototype._ws_callbacks = {}; - // Try making a WebSocket call. - var socket = this.options.getSocket(this.wsOnMessage); - if (socket !== null) { - this._wsCall(socket, request, success_cb, error_cb); - return; - } + /// The next JSON-RPC request id. + $.JsonRpcClient.prototype._current_id = 1; - // No WebSocket, and no HTTP backend? This won't work. - if (this.options.ajaxUrl === null) { - throw "$.JsonRpcClient.call used with no websocket and no http endpoint."; - } - - $.ajax({ - type : 'POST', - url : this.options.ajaxUrl, - data : $.toJSON(request), - dataType : 'json', - cache : false, - - success : function(data) { - if ('error' in data) error_cb(data.error, this); - success_cb(data.result, this); - }, - - // JSON-RPC Server could return non-200 on error - error : function(jqXHR, textStatus, errorThrown) { - try { - var response = $.parseJSON(jqXHR.responseText); - if ('console' in window) console.log(response); - error_cb(response.error, this); - } - catch (err) { - // Perhaps the responseText wasn't really a jsonrpc-error. - error_cb({ error: jqXHR.responseText }, this); - } - } - }); - }; - - /** - * Notify sends a command to the server that won't need a response. In http, there is probably - * an empty response - that will be dropped, but in ws there should be no response at all. - * - * This is very similar to call, but has no id and no handling of callbacks. - * - * @fn notify - * @memberof $.JsonRpcClient - * - * @param method The method to run on JSON-RPC server. - * @param params The params; an array or object. - */ - $.JsonRpcClient.prototype.notify = function(method, params) { + /** + * @fn call + * @memberof $.JsonRpcClient + * + * @param method The method to run on JSON-RPC server. + * @param params The params; an array or object. + * @param success_cb A callback for successful request. + * @param error_cb A callback for error. + */ + $.JsonRpcClient.prototype.call = function(method, params, success_cb, error_cb) { // Construct the JSON-RPC 2.0 request. - if (this.options.sessid) { - params.sessid = this.options.sessid; - } - - var request = { - jsonrpc: '2.0', - method: method, - params: params - }; - - // Try making a WebSocket call. - var socket = this.options.getSocket(this.wsOnMessage); - if (socket !== null) { - this._wsCall(socket, request); - return; - } - - // No WebSocket, and no HTTP backend? This won't work. - if (this.options.ajaxUrl === null) { - throw "$.JsonRpcClient.notify used with no websocket and no http endpoint."; - } - - $.ajax({ - type : 'POST', - url : this.options.ajaxUrl, - data : $.toJSON(request), - dataType : 'json', - cache : false - }); - }; - - /** - * Make a batch-call by using a callback. - * - * The callback will get an object "batch" as only argument. On batch, you can call the methods - * "call" and "notify" just as if it was a normal $.JsonRpcClient object, and all calls will be - * sent as a batch call then the callback is done. - * - * @fn batch - * @memberof $.JsonRpcClient - * - * @param callback The main function which will get a batch handler to run call and notify on. - * @param all_done_cb A callback function to call after all results have been handled. - * @param error_cb A callback function to call if there is an error from the server. - * Note, that batch calls should always get an overall success, and the - * only error - */ - $.JsonRpcClient.prototype.batch = function(callback, all_done_cb, error_cb) { - var batch = new $.JsonRpcClient._batchObject(this, all_done_cb, error_cb); - callback(batch); - batch._execute(); - }; - - /** - * The default getSocket handler. - * - * @param onmessage_cb The callback to be bound to onmessage events on the socket. - * - * @fn _getSocket - * @memberof $.JsonRpcClient - */ - - $.JsonRpcClient.prototype.socketReady = function() { - if (this._ws_socket === null || this._ws_socket.readyState > 1) { - return false; - } - - return true; - } - - $.JsonRpcClient.prototype.closeSocket = function() { - if (self.socketReady()) { - this._ws_socket.onclose = function (w) {console.log("Closing Socket")} - this._ws_socket.close(); - } - } - - $.JsonRpcClient.prototype.loginData = function(params) { - self.options.login = params.login; - self.options.passwd = params.passwd; - } - - $.JsonRpcClient.prototype.connectSocket = function(onmessage_cb) { - var self = this; - - if (self.to) { - clearTimeout(self.to); - } - - if (!self.socketReady()) { - self.authing = false; - - if (self._ws_socket) { - delete self._ws_socket; - } - - // No socket, or dying socket, let's get a new one. - self._ws_socket = new WebSocket(self.options.socketUrl); - - if (self._ws_socket) { - // Set up onmessage handler. - self._ws_socket.onmessage = onmessage_cb; - self._ws_socket.onclose = function (w) { - if (!self.ws_sleep) { - self.ws_sleep = 1000; - } - - if (self.options.onWSClose) { - self.options.onWSClose(self); - } - - console.error("Websocket Lost " + self.ws_cnt + " sleep: " + self.ws_sleep + "msec"); - - self.to = setTimeout(function() { - console.log("Attempting Reconnection...."); - self.connectSocket(onmessage_cb); - }, self.ws_sleep); - - self.ws_cnt++; - - if (self.ws_sleep < 3000 && (self.ws_cnt % 10) == 0) { - self.ws_sleep += 1000; - } - } - - // Set up sending of message for when the socket is open. - self._ws_socket.onopen = function() { - if (self.to) { - clearTimeout(self.to); - } - self.ws_sleep = 1000; - self.ws_cnt = 0; - if (self.options.onWSConnect) { - self.options.onWSConnect(self); - } - - var req; - // Send the requests. - while (req = $.JsonRpcClient.q.pop()) { - self._ws_socket.send(req); - } - } - } - } - - return self._ws_socket ? true : false; - } - - $.JsonRpcClient.prototype._getSocket = function(onmessage_cb) { - // If there is no ws url set, we don't have a socket. - // Likewise, if there is no window.WebSocket. - if (this.options.socketUrl === null || !("WebSocket" in window)) return null; - - this.connectSocket(onmessage_cb); - - return this._ws_socket; - }; - - /** - * Queue to save messages delivered when websocket is not ready - */ - $.JsonRpcClient.q = []; - - /** - * Internal handler to dispatch a JRON-RPC request through a websocket. - * - * @fn _wsCall - * @memberof $.JsonRpcClient - */ - $.JsonRpcClient.prototype._wsCall = function(socket, request, success_cb, error_cb) { - var request_json = $.toJSON(request); - - if (socket.readyState < 1) { - // The websocket is not open yet; we have to set sending of the message in onopen. - self = this; // In closure below, this is set to the WebSocket. Use self instead. - - $.JsonRpcClient.q.push(request_json); - - - } - else { - // We have a socket and it should be ready to send on. - socket.send(request_json); - } - - // Setup callbacks. If there is an id, this is a call and not a notify. - if ('id' in request && typeof success_cb !== 'undefined') { - this._ws_callbacks[request.id] = { request: request_json, request_obj: request, success_cb: success_cb, error_cb: error_cb }; - } - }; - - /** - * Internal handler for the websocket messages. It determines if the message is a JSON-RPC - * response, and if so, tries to couple it with a given callback. Otherwise, it falls back to - * given external onmessage-handler, if any. - * - * @param event The websocket onmessage-event. - */ - $.JsonRpcClient.prototype._wsOnMessage = function(event) { - // Check if this could be a JSON RPC message. - var response; - try { - response = $.parseJSON(event.data); - - /// @todo Make using the jsonrcp 2.0 check optional, to use this on JSON-RPC 1 backends. - - if (typeof response === 'object' - && 'jsonrpc' in response - && response.jsonrpc === '2.0') { - - /// @todo Handle bad response (without id). - - // If this is an object with result, it is a response. - if ('result' in response && this._ws_callbacks[response.id]) { - // Get the success callback. - var success_cb = this._ws_callbacks[response.id].success_cb; - -/* - // set the sessid if present - if ('sessid' in response.result && !this.options.sessid || (this.options.sessid != response.result.sessid)) { - this.options.sessid = response.result.sessid; - if (this.options.sessid) { - console.log("setting session UUID to: " + this.options.sessid); - } - } -*/ - // Delete the callback from the storage. - delete this._ws_callbacks[response.id]; - - // Run callback with result as parameter. - success_cb(response.result, this); - return; + if (!params) { + params = {}; } - // If this is an object with error, it is an error response. - else if ('error' in response && this._ws_callbacks[response.id]) { - - // Get the error callback. - var error_cb = this._ws_callbacks[response.id].error_cb; - var orig_req = this._ws_callbacks[response.id].request; - - // if this is an auth request, send the credentials and resend the failed request - if (!self.authing && response.error.code == -32000 && self.options.login && self.options.passwd) { - self.authing = true; - - this.call("login", { login: self.options.login, passwd: self.options.passwd}, - this._ws_callbacks[response.id].request_obj.method == "login" - ? - function(e) { - self.authing = false; - console.log("logged in"); - delete self._ws_callbacks[response.id]; - - if (self.options.onWSLogin) { - self.options.onWSLogin(true, self); - } - } - - : - - function(e) { - self.authing = false; - console.log("logged in, resending request id: " + response.id); - var socket = self.options.getSocket(self.wsOnMessage); - if (socket !== null) { - socket.send(orig_req); - } - if (self.options.onWSLogin) { - self.options.onWSLogin(true, self); - } - }, - - function(e) { - console.log("error logging in, request id:", response.id); - delete self._ws_callbacks[response.id]; - error_cb(response.error, this); - if (self.options.onWSLogin) { - self.options.onWSLogin(false, self); - } - } - - ); - return; - } - - // Delete the callback from the storage. - delete this._ws_callbacks[response.id]; - - // Run callback with the error object as parameter. - error_cb(response.error, this); - - return; + if (this.options.sessid) { + params.sessid = this.options.sessid; } - } - } - catch (err) { - // Probably an error while parsing a non json-string as json. All real JSON-RPC cases are - // handled above, and the fallback method is called below. - console.log("ERROR: "+ err); - return; - } - // This is not a JSON-RPC response. Call the fallback message handler, if given. - if (typeof this.options.onmessage === 'function') { - event.eventData = response; - if (!event.eventData) { - event.eventData = {}; - } - - var reply = this.options.onmessage(event); - - if (reply && typeof reply === "object" && event.eventData.id) { - var msg = { - jsonrpc: "2.0", - id: event.eventData.id, - result: reply - }; - - var socket = self.options.getSocket(self.wsOnMessage); - if (socket !== null) { - socket.send($.toJSON(msg)); - } - } - - } - }; - - - /************************************************************************************************ - * Batch object with methods - ************************************************************************************************/ - - /** - * Handling object for batch calls. - */ - $.JsonRpcClient._batchObject = function(jsonrpcclient, all_done_cb, error_cb) { - // Array of objects to hold the call and notify requests. Each objects will have the request - // object, and unless it is a notify, success_cb and error_cb. - this._requests = []; - - this.jsonrpcclient = jsonrpcclient; - this.all_done_cb = all_done_cb; - this.error_cb = typeof error_cb === 'function' ? error_cb : function() {}; - - }; - - /** - * @sa $.JsonRpcClient.prototype.call - */ - $.JsonRpcClient._batchObject.prototype.call = function(method, params, success_cb, error_cb) { - - if (!params) { - params = {}; - } - - if (this.options.sessid) { - params.sessid = this.options.sessid; - } - - if (!success_cb) { - success_cb = function(e){console.log("Success: ", e);}; - } - - if (!error_cb) { - error_cb = function(e){console.log("Error: ", e);}; - } - - this._requests.push({ - request : { - jsonrpc : '2.0', - method : method, - params : params, - id : this.jsonrpcclient._current_id++ // Use the client's id series. - }, - success_cb : success_cb, - error_cb : error_cb - }); - }; - - /** - * @sa $.JsonRpcClient.prototype.notify - */ - $.JsonRpcClient._batchObject.prototype.notify = function(method, params) { - if (this.options.sessid) { - params.sessid = this.options.sessid; - } - - this._requests.push({ - request : { - jsonrpc : '2.0', - method : method, - params : params - } - }); - }; - - /** - * Executes the batched up calls. - */ - $.JsonRpcClient._batchObject.prototype._execute = function() { - var self = this; - - if (this._requests.length === 0) return; // All done :P - - // Collect all request data and sort handlers by request id. - var batch_request = []; - var handlers = {}; - - // If we have a WebSocket, just send the requests individually like normal calls. - var socket = self.jsonrpcclient.options.getSocket(self.jsonrpcclient.wsOnMessage); - if (socket !== null) { - for (var i = 0; i < this._requests.length; i++) { - var call = this._requests[i]; - var success_cb = ('success_cb' in call) ? call.success_cb : undefined; - var error_cb = ('error_cb' in call) ? call.error_cb : undefined; - self.jsonrpcclient._wsCall(socket, call.request, success_cb, error_cb); - } - if (typeof all_done_cb === 'function') all_done_cb(result); - return; - } - - for (var i = 0; i < this._requests.length; i++) { - var call = this._requests[i]; - batch_request.push(call.request); - - // If the request has an id, it should handle returns (otherwise it's a notify). - if ('id' in call.request) { - handlers[call.request.id] = { - success_cb : call.success_cb, - error_cb : call.error_cb + var request = { + jsonrpc : '2.0', + method : method, + params : params, + id : this._current_id++ // Increase the id counter to match request/response }; - } - } - var success_cb = function(data) { self._batchCb(data, handlers, self.all_done_cb); }; - - // No WebSocket, and no HTTP backend? This won't work. - if (self.jsonrpcclient.options.ajaxUrl === null) { - throw "$.JsonRpcClient.batch used with no websocket and no http endpoint."; - } - - // Send request - $.ajax({ - url : self.jsonrpcclient.options.ajaxUrl, - data : $.toJSON(batch_request), - dataType : 'json', - cache : false, - type : 'POST', - - // Batch-requests should always return 200 - error : function(jqXHR, textStatus, errorThrown) { - self.error_cb(jqXHR, textStatus, errorThrown); - }, - success : success_cb - }); - }; - - /** - * Internal helper to match the result array from a batch call to their respective callbacks. - * - * @fn _batchCb - * @memberof $.JsonRpcClient - */ - $.JsonRpcClient._batchObject.prototype._batchCb = function(result, handlers, all_done_cb) { - for (var i = 0; i < result.length; i++) { - var response = result[i]; - - // Handle error - if ('error' in response) { - if (response.id === null || !(response.id in handlers)) { - // An error on a notify? Just log it to the console. - if ('console' in window) console.log(response); + if (!success_cb) { + success_cb = function(e){console.log("Success: ", e);}; } - else handlers[response.id].error_cb(response.error, this); - } - else { - // Here we should always have a correct id and no error. - if (!(response.id in handlers) && 'console' in window) console.log(response); - else handlers[response.id].success_cb(response.result, this); - } + + if (!error_cb) { + error_cb = function(e){console.log("Error: ", e);}; + } + + // Try making a WebSocket call. + var socket = this.options.getSocket(this.wsOnMessage); + if (socket !== null) { + this._wsCall(socket, request, success_cb, error_cb); + return; + } + + // No WebSocket, and no HTTP backend? This won't work. + if (this.options.ajaxUrl === null) { + throw "$.JsonRpcClient.call used with no websocket and no http endpoint."; + } + + $.ajax({ + type : 'POST', + url : this.options.ajaxUrl, + data : $.toJSON(request), + dataType : 'json', + cache : false, + + success : function(data) { + if ('error' in data) error_cb(data.error, this); + success_cb(data.result, this); + }, + + // JSON-RPC Server could return non-200 on error + error : function(jqXHR, textStatus, errorThrown) { + try { + var response = $.parseJSON(jqXHR.responseText); + + if ('console' in window) console.log(response); + + error_cb(response.error, this); + } catch (err) { + // Perhaps the responseText wasn't really a jsonrpc-error. + error_cb({ error: jqXHR.responseText }, this); + } + } + }); + }; + + /** + * Notify sends a command to the server that won't need a response. In http, there is probably + * an empty response - that will be dropped, but in ws there should be no response at all. + * + * This is very similar to call, but has no id and no handling of callbacks. + * + * @fn notify + * @memberof $.JsonRpcClient + * + * @param method The method to run on JSON-RPC server. + * @param params The params; an array or object. + */ + $.JsonRpcClient.prototype.notify = function(method, params) { + // Construct the JSON-RPC 2.0 request. + + if (this.options.sessid) { + params.sessid = this.options.sessid; + } + + var request = { + jsonrpc: '2.0', + method: method, + params: params + }; + + // Try making a WebSocket call. + var socket = this.options.getSocket(this.wsOnMessage); + if (socket !== null) { + this._wsCall(socket, request); + return; + } + + // No WebSocket, and no HTTP backend? This won't work. + if (this.options.ajaxUrl === null) { + throw "$.JsonRpcClient.notify used with no websocket and no http endpoint."; + } + + $.ajax({ + type : 'POST', + url : this.options.ajaxUrl, + data : $.toJSON(request), + dataType : 'json', + cache : false + }); + }; + + /** + * Make a batch-call by using a callback. + * + * The callback will get an object "batch" as only argument. On batch, you can call the methods + * "call" and "notify" just as if it was a normal $.JsonRpcClient object, and all calls will be + * sent as a batch call then the callback is done. + * + * @fn batch + * @memberof $.JsonRpcClient + * + * @param callback The main function which will get a batch handler to run call and notify on. + * @param all_done_cb A callback function to call after all results have been handled. + * @param error_cb A callback function to call if there is an error from the server. + * Note, that batch calls should always get an overall success, and the + * only error + */ + $.JsonRpcClient.prototype.batch = function(callback, all_done_cb, error_cb) { + var batch = new $.JsonRpcClient._batchObject(this, all_done_cb, error_cb); + callback(batch); + batch._execute(); + }; + + /** + * The default getSocket handler. + * + * @param onmessage_cb The callback to be bound to onmessage events on the socket. + * + * @fn _getSocket + * @memberof $.JsonRpcClient + */ + + $.JsonRpcClient.prototype.socketReady = function() { + if (this._ws_socket === null || this._ws_socket.readyState > 1) { + return false; + } + + return true; } - if (typeof all_done_cb === 'function') all_done_cb(result); - }; + $.JsonRpcClient.prototype.closeSocket = function() { + if (self.socketReady()) { + this._ws_socket.onclose = function (w) {console.log("Closing Socket")} + this._ws_socket.close(); + } + } + + $.JsonRpcClient.prototype.loginData = function(params) { + self.options.login = params.login; + self.options.passwd = params.passwd; + } + + $.JsonRpcClient.prototype.connectSocket = function(onmessage_cb) { + var self = this; + + if (self.to) { + clearTimeout(self.to); + } + + if (!self.socketReady()) { + self.authing = false; + + if (self._ws_socket) { + delete self._ws_socket; + } + + // No socket, or dying socket, let's get a new one. + self._ws_socket = new WebSocket(self.options.socketUrl); + + if (self._ws_socket) { + // Set up onmessage handler. + self._ws_socket.onmessage = onmessage_cb; + self._ws_socket.onclose = function (w) { + if (!self.ws_sleep) { + self.ws_sleep = 1000; + } + + if (self.options.onWSClose) { + self.options.onWSClose(self); + } + + console.error("Websocket Lost " + self.ws_cnt + " sleep: " + self.ws_sleep + "msec"); + + self.to = setTimeout(function() { + console.log("Attempting Reconnection...."); + self.connectSocket(onmessage_cb); + }, self.ws_sleep); + + self.ws_cnt++; + + if (self.ws_sleep < 3000 && (self.ws_cnt % 10) == 0) { + self.ws_sleep += 1000; + } + } + + // Set up sending of message for when the socket is open. + self._ws_socket.onopen = function() { + if (self.to) { + clearTimeout(self.to); + } + self.ws_sleep = 1000; + self.ws_cnt = 0; + if (self.options.onWSConnect) { + self.options.onWSConnect(self); + } + + var req; + // Send the requests. + while (req = $.JsonRpcClient.q.pop()) { + self._ws_socket.send(req); + } + } + } + } + + return self._ws_socket ? true : false; + } + + $.JsonRpcClient.prototype._getSocket = function(onmessage_cb) { + // If there is no ws url set, we don't have a socket. + // Likewise, if there is no window.WebSocket. + if (this.options.socketUrl === null || !("WebSocket" in window)) return null; + + this.connectSocket(onmessage_cb); + + return this._ws_socket; + }; + + /** + * Queue to save messages delivered when websocket is not ready + */ + $.JsonRpcClient.q = []; + + /** + * Internal handler to dispatch a JRON-RPC request through a websocket. + * + * @fn _wsCall + * @memberof $.JsonRpcClient + */ + $.JsonRpcClient.prototype._wsCall = function(socket, request, success_cb, error_cb) { + var request_json = $.toJSON(request); + + if (socket.readyState < 1) { + // The websocket is not open yet; we have to set sending of the message in onopen. + self = this; // In closure below, this is set to the WebSocket. Use self instead. + $.JsonRpcClient.q.push(request_json); + } else { + // We have a socket and it should be ready to send on. + socket.send(request_json); + } + + // Setup callbacks. If there is an id, this is a call and not a notify. + if ('id' in request && typeof success_cb !== 'undefined') { + this._ws_callbacks[request.id] = { request: request_json, request_obj: request, success_cb: success_cb, error_cb: error_cb }; + } + }; + + /** + * Internal handler for the websocket messages. It determines if the message is a JSON-RPC + * response, and if so, tries to couple it with a given callback. Otherwise, it falls back to + * given external onmessage-handler, if any. + * + * @param event The websocket onmessage-event. + */ + $.JsonRpcClient.prototype._wsOnMessage = function(event) { + // Check if this could be a JSON RPC message. + var response; + try { + response = $.parseJSON(event.data); + + /// @todo Make using the jsonrcp 2.0 check optional, to use this on JSON-RPC 1 backends. + + if (typeof response === 'object' + && 'jsonrpc' in response + && response.jsonrpc === '2.0') { + + /// @todo Handle bad response (without id). + + // If this is an object with result, it is a response. + if ('result' in response && this._ws_callbacks[response.id]) { + // Get the success callback. + var success_cb = this._ws_callbacks[response.id].success_cb; + + /* + // set the sessid if present + if ('sessid' in response.result && !this.options.sessid || (this.options.sessid != response.result.sessid)) { + this.options.sessid = response.result.sessid; + if (this.options.sessid) { + console.log("setting session UUID to: " + this.options.sessid); + } + } + */ + // Delete the callback from the storage. + delete this._ws_callbacks[response.id]; + + // Run callback with result as parameter. + success_cb(response.result, this); + return; + } else if ('error' in response && this._ws_callbacks[response.id]) { + // If this is an object with error, it is an error response. + + // Get the error callback. + var error_cb = this._ws_callbacks[response.id].error_cb; + var orig_req = this._ws_callbacks[response.id].request; + + // if this is an auth request, send the credentials and resend the failed request + if (!self.authing && response.error.code == -32000 && self.options.login && self.options.passwd) { + self.authing = true; + + this.call("login", { login: self.options.login, passwd: self.options.passwd}, + this._ws_callbacks[response.id].request_obj.method == "login" + ? + function(e) { + self.authing = false; + console.log("logged in"); + delete self._ws_callbacks[response.id]; + + if (self.options.onWSLogin) { + self.options.onWSLogin(true, self); + } + } + + : + + function(e) { + self.authing = false; + console.log("logged in, resending request id: " + response.id); + var socket = self.options.getSocket(self.wsOnMessage); + if (socket !== null) { + socket.send(orig_req); + } + if (self.options.onWSLogin) { + self.options.onWSLogin(true, self); + } + }, + + function(e) { + console.log("error logging in, request id:", response.id); + delete self._ws_callbacks[response.id]; + error_cb(response.error, this); + if (self.options.onWSLogin) { + self.options.onWSLogin(false, self); + } + }); + return; + } + + // Delete the callback from the storage. + delete this._ws_callbacks[response.id]; + + // Run callback with the error object as parameter. + error_cb(response.error, this); + return; + } + } + } catch (err) { + // Probably an error while parsing a non json-string as json. All real JSON-RPC cases are + // handled above, and the fallback method is called below. + console.log("ERROR: "+ err); + return; + } + + // This is not a JSON-RPC response. Call the fallback message handler, if given. + if (typeof this.options.onmessage === 'function') { + event.eventData = response; + if (!event.eventData) { + event.eventData = {}; + } + + var reply = this.options.onmessage(event); + + if (reply && typeof reply === "object" && event.eventData.id) { + var msg = { + jsonrpc: "2.0", + id: event.eventData.id, + result: reply + }; + + var socket = self.options.getSocket(self.wsOnMessage); + if (socket !== null) { + socket.send($.toJSON(msg)); + } + } + } + }; + + + /************************************************************************************************ + * Batch object with methods + ************************************************************************************************/ + + /** + * Handling object for batch calls. + */ + $.JsonRpcClient._batchObject = function(jsonrpcclient, all_done_cb, error_cb) { + // Array of objects to hold the call and notify requests. Each objects will have the request + // object, and unless it is a notify, success_cb and error_cb. + this._requests = []; + + this.jsonrpcclient = jsonrpcclient; + this.all_done_cb = all_done_cb; + this.error_cb = typeof error_cb === 'function' ? error_cb : function() {}; + + }; + + /** + * @sa $.JsonRpcClient.prototype.call + */ + $.JsonRpcClient._batchObject.prototype.call = function(method, params, success_cb, error_cb) { + + if (!params) { + params = {}; + } + + if (this.options.sessid) { + params.sessid = this.options.sessid; + } + + if (!success_cb) { + success_cb = function(e){console.log("Success: ", e);}; + } + + if (!error_cb) { + error_cb = function(e){console.log("Error: ", e);}; + } + + this._requests.push({ + request : { + jsonrpc : '2.0', + method : method, + params : params, + id : this.jsonrpcclient._current_id++ // Use the client's id series. + }, + success_cb : success_cb, + error_cb : error_cb + }); + }; + + /** + * @sa $.JsonRpcClient.prototype.notify + */ + $.JsonRpcClient._batchObject.prototype.notify = function(method, params) { + if (this.options.sessid) { + params.sessid = this.options.sessid; + } + + this._requests.push({ + request : { + jsonrpc : '2.0', + method : method, + params : params + } + }); + }; + + /** + * Executes the batched up calls. + */ + $.JsonRpcClient._batchObject.prototype._execute = function() { + var self = this; + + if (this._requests.length === 0) return; // All done :P + + // Collect all request data and sort handlers by request id. + var batch_request = []; + var handlers = {}; + + // If we have a WebSocket, just send the requests individually like normal calls. + var socket = self.jsonrpcclient.options.getSocket(self.jsonrpcclient.wsOnMessage); + if (socket !== null) { + for (var i = 0; i < this._requests.length; i++) { + var call = this._requests[i]; + var success_cb = ('success_cb' in call) ? call.success_cb : undefined; + var error_cb = ('error_cb' in call) ? call.error_cb : undefined; + self.jsonrpcclient._wsCall(socket, call.request, success_cb, error_cb); + } + + if (typeof all_done_cb === 'function') all_done_cb(result); + return; + } + + for (var i = 0; i < this._requests.length; i++) { + var call = this._requests[i]; + batch_request.push(call.request); + + // If the request has an id, it should handle returns (otherwise it's a notify). + if ('id' in call.request) { + handlers[call.request.id] = { + success_cb : call.success_cb, + error_cb : call.error_cb + }; + } + } + + var success_cb = function(data) { self._batchCb(data, handlers, self.all_done_cb); }; + + // No WebSocket, and no HTTP backend? This won't work. + if (self.jsonrpcclient.options.ajaxUrl === null) { + throw "$.JsonRpcClient.batch used with no websocket and no http endpoint."; + } + + // Send request + $.ajax({ + url : self.jsonrpcclient.options.ajaxUrl, + data : $.toJSON(batch_request), + dataType : 'json', + cache : false, + type : 'POST', + + // Batch-requests should always return 200 + error : function(jqXHR, textStatus, errorThrown) { + self.error_cb(jqXHR, textStatus, errorThrown); + }, + success : success_cb + }); + }; + + /** + * Internal helper to match the result array from a batch call to their respective callbacks. + * + * @fn _batchCb + * @memberof $.JsonRpcClient + */ + $.JsonRpcClient._batchObject.prototype._batchCb = function(result, handlers, all_done_cb) { + for (var i = 0; i < result.length; i++) { + var response = result[i]; + + // Handle error + if ('error' in response) { + if (response.id === null || !(response.id in handlers)) { + // An error on a notify? Just log it to the console. + if ('console' in window) console.log(response); + } else { + handlers[response.id].error_cb(response.error, this); + } + } else { + // Here we should always have a correct id and no error. + if (!(response.id in handlers) && 'console' in window) { + console.log(response); + } else { + handlers[response.id].success_cb(response.result, this); + } + } + } + + if (typeof all_done_cb === 'function') all_done_cb(result); + }; })(jQuery); diff --git a/html5/verto/js/src/jquery.verto.js b/html5/verto/js/src/jquery.verto.js index a9f028d6d9..4beedc6548 100644 --- a/html5/verto/js/src/jquery.verto.js +++ b/html5/verto/js/src/jquery.verto.js @@ -73,10 +73,9 @@ tag: null, videoParams: {}, audioParams: {}, - iceServers: false, + iceServers: false, ringSleep: 6000 - }, - options); + }, options); verto.sessid = $.cookie('verto_session_uuid') || generateGUID(); $.cookie('verto_session_uuid', verto.sessid, { @@ -84,9 +83,7 @@ }); verto.dialogs = {}; - verto.callbacks = callbacks || {}; - verto.eventSUBS = {}; verto.rpcClient = new $.JsonRpcClient({ @@ -123,7 +120,6 @@ $.verto.prototype.iceServers = function(on) { var verto = this; - verto.options.iceServers = on; }; @@ -172,7 +168,7 @@ $.verto.prototype.processReply = function(method, success, e) { var verto = this; - var i; + var i; //console.log("Response: " + method, success, e); @@ -228,7 +224,7 @@ } var SERNO = 1; - + function do_subscribe(verto, channel, subChannels, sparams) { var params = sparams || {}; @@ -298,7 +294,7 @@ $.verto.prototype.unsubscribe = function(handle) { var verto = this; - var i; + var i; if (!handle) { for (i in verto.eventSUBS) { @@ -309,7 +305,7 @@ } else { var unsubChannels = {}; var sendChannels = []; - var channel; + var channel; if (typeof(handle) == "string") { delete verto.eventSUBS[handle]; @@ -368,13 +364,13 @@ $.verto.prototype.purge = function(callID) { var verto = this; var x = 0; - var i; + var i; for (i in verto.dialogs) { if (!x) { console.log("purging dialogs"); } - x++; + x++; verto.dialogs[i].setState($.verto.enum.state.purge); } @@ -423,10 +419,10 @@ $.verto.prototype.handleMessage = function(data) { var verto = this; - if (!(data && data.method)) { - console.error("Invalid Data", data); - return; - } + if (!(data && data.method)) { + console.error("Invalid Data", data); + return; + } if (data.params.callID) { var dialog = verto.dialogs[data.params.callID]; @@ -467,10 +463,10 @@ data.params.useStereo = true; } - dialog = new $.verto.dialog($.verto.enum.direction.inbound, verto, data.params); + dialog = new $.verto.dialog($.verto.enum.direction.inbound, verto, data.params); dialog.setState($.verto.enum.state.recovering); - break; + break; case 'verto.invite': if (data.params.sdp && data.params.sdp.indexOf("m=video") > 0) { @@ -510,10 +506,10 @@ } } - if (!list && key && key === verto.sessid) { - if (verto.callbacks.onMessage) { - verto.callbacks.onMessage(verto, null, $.verto.enum.message.pvtEvent, data.params); - } + if (!list && key && key === verto.sessid) { + if (verto.callbacks.onMessage) { + verto.callbacks.onMessage(verto, null, $.verto.enum.message.pvtEvent, data.params); + } } else if (!list && key && verto.dialogs[key]) { verto.dialogs[key].sendMessage($.verto.enum.message.pvtEvent, data.params); } else if (!list) { @@ -944,21 +940,21 @@ la.verto.unsubscribe(binding); }; - la.sendCommand = function(cmd, obj) { + la.sendCommand = function(cmd, obj) { var self = la; - self.broadcast(self.context, { - liveArray: { + self.broadcast(self.context, { + liveArray: { command: cmd, context: self.context, name: self.name, obj: obj } - }); - }; + }); + }; la.bootstrap = function(obj) { var self = la; - la.sendCommand("bootstrap", obj); + la.sendCommand("bootstrap", obj); //self.heartbeat(); }; @@ -1128,7 +1124,7 @@ } else { obj.errs = 0; } - + }; la.onChange(la, { @@ -1138,211 +1134,205 @@ }; var CONFMAN_SERNO = 1; - + $.verto.confMan = function(verto, params) { - var confMan = this; - conf + var confMan = this; + conf confMan.params = $.extend({ - tableID: null, - statusID: null, - mainModID: null, - dialog: null, - hasVid: false, - laData: null, - onBroadcast: null, - onLaChange: null, - onLaRow: null - }, - params); + tableID: null, + statusID: null, + mainModID: null, + dialog: null, + hasVid: false, + laData: null, + onBroadcast: null, + onLaChange: null, + onLaRow: null + }, params); - confMan.verto = verto; - confMan.serno = CONFMAN_SERNO++; + confMan.verto = verto; + confMan.serno = CONFMAN_SERNO++; - function genMainMod(jq) { - var play_id = "play_" + confMan.serno; - var stop_id = "stop_" + confMan.serno; - var recording_id = "recording_" + confMan.serno; - var rec_stop_id = "recording_stop" + confMan.serno; - var div_id = "confman_" + confMan.serno; + function genMainMod(jq) { + var play_id = "play_" + confMan.serno; + var stop_id = "stop_" + confMan.serno; + var recording_id = "recording_" + confMan.serno; + var rec_stop_id = "recording_stop" + confMan.serno; + var div_id = "confman_" + confMan.serno; - var html = "

" + - "" + - "" + - "" + - "" + var html = "

" + + "" + + "" + + "" + + "" - + "

"; + + "

"; - jq.html(html); + jq.html(html); - $("#" + play_id).click(function() { - var file = prompt("Please enter file name", ""); - confMan.modCommand("play", null, file); - }); + $("#" + play_id).click(function() { + var file = prompt("Please enter file name", ""); + confMan.modCommand("play", null, file); + }); - $("#" + stop_id).click(function() { - confMan.modCommand("stop", null, "all"); - }); + $("#" + stop_id).click(function() { + confMan.modCommand("stop", null, "all"); + }); - $("#" + recording_id).click(function() { - var file = prompt("Please enter file name", ""); - confMan.modCommand("recording", null, ["start", file]); - }); + $("#" + recording_id).click(function() { + var file = prompt("Please enter file name", ""); + confMan.modCommand("recording", null, ["start", file]); + }); - $("#" + rec_stop_id).click(function() { - confMan.modCommand("recording", null, ["stop", "all"]); - }); + $("#" + rec_stop_id).click(function() { + confMan.modCommand("recording", null, ["stop", "all"]); + }); - } + } - function genControls(jq, rowid) { - var x = parseInt(rowid); - var kick_id = "kick_" + x; - var tmute_id = "tmute_" + x; - var box_id = "box_" + x; - var volup_id = "volume_in_up" + x; - var voldn_id = "volume_in_dn" + x; - var transfer_id = "transfer" + x; - - - var html = "
" + - "" + - "" + - "" + - "" + - "" + - "
" - ; - - jq.html(html); - - if (!jq.data("mouse")) { - $("#" + box_id).hide(); - } - - jq.mouseover(function(e) { - jq.data({"mouse": true}); - $("#" + box_id).show(); - }); - - jq.mouseout(function(e) { - jq.data({"mouse": false}); - $("#" + box_id).hide(); - }); - - $("#" + transfer_id).click(function() { - var xten = prompt("Enter Extension"); - confMan.modCommand("transfer", x, xten); - }); - - $("#" + kick_id).click(function() { - confMan.modCommand("kick", x); - }); - - $("#" + tmute_id).click(function() { - confMan.modCommand("tmute", x); - }); - - $("#" + volup_id).click(function() { - confMan.modCommand("volume_in", x, "up"); - }); - - $("#" + voldn_id).click(function() { - confMan.modCommand("volume_in", x, "down"); - }); - - return html; - } + function genControls(jq, rowid) { + var x = parseInt(rowid); + var kick_id = "kick_" + x; + var tmute_id = "tmute_" + x; + var box_id = "box_" + x; + var volup_id = "volume_in_up" + x; + var voldn_id = "volume_in_dn" + x; + var transfer_id = "transfer" + x; + var html = "
" + + "" + + "" + + "" + + "" + + "" + + "
" + ; + + jq.html(html); + + if (!jq.data("mouse")) { + $("#" + box_id).hide(); + } + + jq.mouseover(function(e) { + jq.data({"mouse": true}); + $("#" + box_id).show(); + }); + + jq.mouseout(function(e) { + jq.data({"mouse": false}); + $("#" + box_id).hide(); + }); + + $("#" + transfer_id).click(function() { + var xten = prompt("Enter Extension"); + confMan.modCommand("transfer", x, xten); + }); + + $("#" + kick_id).click(function() { + confMan.modCommand("kick", x); + }); + + $("#" + tmute_id).click(function() { + confMan.modCommand("tmute", x); + }); + + $("#" + volup_id).click(function() { + confMan.modCommand("volume_in", x, "up"); + }); + + $("#" + voldn_id).click(function() { + confMan.modCommand("volume_in", x, "down"); + }); + + return html; + } + + var atitle = ""; + var awidth = 0; - var atitle = ""; - var awidth = 0; - //$(".jsDataTable").width(confMan.params.hasVid ? "900px" : "800px"); - - if (confMan.params.laData.role === "moderator") { - atitle = "Action"; - awidth = 200; - - if (confMan.params.mainModID) { - genMainMod($(confMan.params.mainModID)); - $(confMan.params.displayID).html("Moderator Controls Ready

") - } else { - $(confMan.params.mainModID).html(""); - } - verto.subscribe(confMan.params.laData.modChannel, { - handler: function(v, e) { - console.error("MODDATA:", e.data); - if (confMan.params.onBroadcast) { - confMan.params.onBroadcast(verto, confMan, e.data); - } - if (!confMan.destroyed && confMan.params.displayID) { - $(confMan.params.displayID).html(e.data.response + "

"); - if (confMan.lastTimeout) { - clearTimeout(confMan.lastTimeout); - confMan.lastTimeout = 0; - } - confMan.lastTimeout = setTimeout(function() { $(confMan.params.displayID).html(confMan.destroyed ? "" : "Moderator Controls Ready

")}, 4000); - } + if (confMan.params.laData.role === "moderator") { + atitle = "Action"; + awidth = 200; - } - }); - - } - - var row_callback = null; + if (confMan.params.mainModID) { + genMainMod($(confMan.params.mainModID)); + $(confMan.params.displayID).html("Moderator Controls Ready

") + } else { + $(confMan.params.mainModID).html(""); + } - if (confMan.params.laData.role === "moderator") { - row_callback = function(nRow, aData, iDisplayIndex, iDisplayIndexFull) { - if (!aData[5]) { - var $row = $('td:eq(5)', nRow); - genControls($row, aData); - - if (confMan.params.onLaRow) { - confMan.params.onLaRow(verto, confMan, $row, aData); - } + verto.subscribe(confMan.params.laData.modChannel, { + handler: function(v, e) { + console.error("MODDATA:", e.data); + if (confMan.params.onBroadcast) { + confMan.params.onBroadcast(verto, confMan, e.data); + } + if (!confMan.destroyed && confMan.params.displayID) { + $(confMan.params.displayID).html(e.data.response + "

"); + if (confMan.lastTimeout) { + clearTimeout(confMan.lastTimeout); + confMan.lastTimeout = 0; + } + confMan.lastTimeout = setTimeout(function() { $(confMan.params.displayID).html(confMan.destroyed ? "" : "Moderator Controls Ready

")}, 4000); + } + } + }); + } + + var row_callback = null; + + if (confMan.params.laData.role === "moderator") { + row_callback = function(nRow, aData, iDisplayIndex, iDisplayIndexFull) { + if (!aData[5]) { + var $row = $('td:eq(5)', nRow); + genControls($row, aData); + + if (confMan.params.onLaRow) { + confMan.params.onLaRow(verto, confMan, $row, aData); + } + } + }; + } - } - }; - } - confMan.lt = new $.verto.liveTable(verto, confMan.params.laData.laChannel, confMan.params.laData.laName, $(confMan.params.tableID), { subParams: { callID: confMan.params.dialog ? confMan.params.dialog.callID : null }, - - + "onChange": function(obj, args) { $(confMan.params.statusID).text("Conference Members: " + " (" + obj.arrayLen() + " Total)"); - if (confMan.params.onLaChange) { - confMan.params.onLaChange(verto, confMan, $.verto.enum.confEvent.laChange, obj, args); - } + if (confMan.params.onLaChange) { + confMan.params.onLaChange(verto, confMan, $.verto.enum.confEvent.laChange, obj, args); + } }, "aaData": [], - "aoColumns": [{ - "sTitle": "ID" - }, - { - "sTitle": "Number" - }, - { - "sTitle": "Name" - }, - { - "sTitle": "Codec" - }, - { - "sTitle": "Status", - "sWidth": confMan.params.hasVid ? "300px" : "150px" - }, - { - "sTitle": atitle, - "sWidth": awidth, - - }], + "aoColumns": [ + { + "sTitle": "ID" + }, + { + "sTitle": "Number" + }, + { + "sTitle": "Name" + }, + { + "sTitle": "Codec" + }, + { + "sTitle": "Status", + "sWidth": confMan.params.hasVid ? "300px" : "150px" + }, + { + "sTitle": atitle, + "sWidth": awidth, + } + ], "bAutoWidth": true, "bDestroy": true, "bSort": false, @@ -1356,41 +1346,41 @@ "sEmptyTable": "The Conference is Empty....." }, - "fnRowCallback": row_callback + "fnRowCallback": row_callback }); } $.verto.confMan.prototype.modCommand = function(cmd, id, value) { - var confMan = this; - - confMan.verto.sendMethod("verto.broadcast", { - "eventChannel": confMan.params.laData.modChannel, - "data": { - "application": "conf-control", - "command": cmd, - "id": id, - "value": value - } - }); + var confMan = this; + + confMan.verto.sendMethod("verto.broadcast", { + "eventChannel": confMan.params.laData.modChannel, + "data": { + "application": "conf-control", + "command": cmd, + "id": id, + "value": value + } + }); } $.verto.confMan.prototype.destroy = function() { - var confMan = this; + var confMan = this; - confMan.destroyed = true; + confMan.destroyed = true; - if (confMan.lt) { - confMan.lt.destroy(); - } + if (confMan.lt) { + confMan.lt.destroy(); + } - if (confMan.params.laData.modChannel) { - confMan.verto.unsubscribe(confMan.params.laData.modChannel); - } + if (confMan.params.laData.modChannel) { + confMan.verto.unsubscribe(confMan.params.laData.modChannel); + } - if (confMan.params.mainModID) { - $(confMan.params.mainModID).html(""); - } + if (confMan.params.mainModID) { + $(confMan.params.mainModID).html(""); + } } $.verto.dialog = function(direction, verto, params) { @@ -1400,9 +1390,8 @@ useVideo: verto.options.useVideo, useStereo: verto.options.useStereo, tag: verto.options.tag, - login: verto.options.login - }, - params); + login: verto.options.login + }, params); dialog.verto = verto; dialog.direction = direction; @@ -1431,13 +1420,13 @@ var RTCcallbacks = {}; if (dialog.direction == $.verto.enum.direction.inbound) { - if (dialog.params.display_direction === "outbound") { - dialog.params.remote_caller_id_name = dialog.params.caller_id_name; - dialog.params.remote_caller_id_number = dialog.params.caller_id_number; - } else { - dialog.params.remote_caller_id_name = dialog.params.callee_id_name; - dialog.params.remote_caller_id_number = dialog.params.callee_id_number; - } + if (dialog.params.display_direction === "outbound") { + dialog.params.remote_caller_id_name = dialog.params.caller_id_name; + dialog.params.remote_caller_id_number = dialog.params.caller_id_number; + } else { + dialog.params.remote_caller_id_name = dialog.params.callee_id_name; + dialog.params.remote_caller_id_number = dialog.params.callee_id_number; + } if (!dialog.params.remote_caller_id_name) { dialog.params.remote_caller_id_name = "Nobody"; @@ -1469,14 +1458,13 @@ dialog.sendMethod("verto.invite", { sdp: rtc.mediaData.SDP }); - } else { //answer + } else { //answer dialog.setState($.verto.enum.state.answering); dialog.sendMethod(dialog.attach ? "verto.attach" : "verto.answer", { sdp: dialog.rtc.mediaData.SDP }); } - }; RTCcallbacks.onICE = function(rtc) { @@ -1485,7 +1473,6 @@ console.log("offer", rtc.mediaData.candidate); return; } - }; RTCcallbacks.onError = function(e) { @@ -1500,7 +1487,7 @@ useStereo: dialog.params.useStereo, videoParams: verto.options.videoParams, audioParams: verto.options.audioParams, - iceServers: verto.options.iceServers + iceServers: verto.options.iceServers }); dialog.rtc.verto = dialog.verto; @@ -1570,14 +1557,14 @@ dialog.lastState = dialog.state; dialog.state = state; - - if (!dialog.causeCode) { - dialog.causeCode = 16; - } - if (!dialog.cause) { - dialog.cause = "NORMAL CLEARING"; - } + if (!dialog.causeCode) { + dialog.causeCode = 16; + } + + if (!dialog.cause) { + dialog.cause = "NORMAL CLEARING"; + } if (dialog.callbacks.onDialogState) { dialog.callbacks.onDialogState(this); @@ -1585,12 +1572,12 @@ switch (dialog.state) { case $.verto.enum.state.trying: - setTimeout(function() { + setTimeout(function() { if (dialog.state == $.verto.enum.state.trying) { - dialog.setState($.verto.enum.state.hangup); + dialog.setState($.verto.enum.state.hangup); } }, 30000); - break; + break; case $.verto.enum.state.purge: dialog.setState($.verto.enum.state.destroy); break; @@ -1603,7 +1590,7 @@ dialog.setState($.verto.enum.state.destroy); break; case $.verto.enum.state.destroy: - delete dialog.verto.dialogs[dialog.callID]; + delete dialog.verto.dialogs[dialog.callID]; dialog.rtc.stop(); break; } @@ -1664,15 +1651,15 @@ $.verto.dialog.prototype.hangup = function(params) { var dialog = this; - if (params) { - if (params.causeCode) { - dialog.causeCode = params.causeCode; - } - - if (params.cause) { - dialog.cause = params.cause; - } - } + if (params) { + if (params.causeCode) { + dialog.causeCode = params.causeCode; + } + + if (params.cause) { + dialog.cause = params.cause; + } + } if (dialog.state.val > $.verto.enum.state.new.val && dialog.state.val < $.verto.enum.state.hangup.val) { dialog.setState($.verto.enum.state.hangup); @@ -1784,7 +1771,7 @@ var dialog = this; var err = 0; - msg.from = dialog.params.login; + msg.from = dialog.params.login; if (!msg.to) { console.error("Missing To"); @@ -1815,8 +1802,8 @@ if (params.useVideo) { dialog.useVideo(true); } - dialog.params.callee_id_name = params.callee_id_name; - dialog.params.callee_id_number = params.callee_id_number; + dialog.params.callee_id_name = params.callee_id_name; + dialog.params.callee_id_number = params.callee_id_number; } dialog.rtc.createAnswer(dialog.params.sdp); dialog.answered = true; @@ -1826,7 +1813,7 @@ $.verto.dialog.prototype.handleAnswer = function(params) { var dialog = this; - dialog.gotAnswer = true; + dialog.gotAnswer = true; if (dialog.state.val >= $.verto.enum.state.active.val) { return; @@ -1835,20 +1822,19 @@ if (dialog.state.val >= $.verto.enum.state.early.val) { dialog.setState($.verto.enum.state.active); } else { - if (dialog.gotEarly) { - console.log("Dialog " + dialog.callID + "Got answer while still establishing early media, delaying..."); - } else { - console.log("Dialog " + dialog.callID + "Answering Channel"); - dialog.rtc.answer(params.sdp, function() { + if (dialog.gotEarly) { + console.log("Dialog " + dialog.callID + "Got answer while still establishing early media, delaying..."); + } else { + console.log("Dialog " + dialog.callID + "Answering Channel"); + dialog.rtc.answer(params.sdp, function() { dialog.setState($.verto.enum.state.active); - }, - function(e) { - console.error(e); - dialog.hangup(); - }); - console.log("Dialog " + dialog.callID + "ANSWER SDP", params.sdp); + }, function(e) { + console.error(e); + dialog.hangup(); + }); + console.log("Dialog " + dialog.callID + "ANSWER SDP", params.sdp); } - } + } }; $.verto.dialog.prototype.cidString = function(enc) { @@ -1891,18 +1877,17 @@ return; } - dialog.gotEarly = true; - - dialog.rtc.answer(params.sdp, function() { - console.log("Dialog " + dialog.callID + "Establishing early media"); - dialog.setState($.verto.enum.state.early); + dialog.gotEarly = true; - if (dialog.gotAnswer) { - console.log("Dialog " + dialog.callID + "Answering Channel"); - dialog.setState($.verto.enum.state.active); - } - }, - function(e) { + dialog.rtc.answer(params.sdp, function() { + console.log("Dialog " + dialog.callID + "Establishing early media"); + dialog.setState($.verto.enum.state.early); + + if (dialog.gotAnswer) { + console.log("Dialog " + dialog.callID + "Answering Channel"); + dialog.setState($.verto.enum.state.active); + } + }, function(e) { console.error(e); dialog.hangup(); }); @@ -1926,7 +1911,7 @@ $.verto.enum.states = Object.freeze({ new: { requesting: 1, - recovering: 1, + recovering: 1, ringing: 1, destroy: 1, answering: 1 @@ -1953,8 +1938,8 @@ hangup: 1 }, active: { - answering: 1, - requesting: 1, + answering: 1, + requesting: 1, hangup: 1, held: 1 }, diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index 846f9cb789..e8468c0394 100644 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -566,7 +566,7 @@ static switch_status_t channel_on_hangup(switch_core_session_t *session) } if (!uuid_found) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Device [%d:%d] is no longer attached to %s. Nothing to do.\n", span_id, chan_id, name); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Device [%d:%d] is no longer attached to %s\n", span_id, chan_id, name); goto end; } @@ -3830,6 +3830,7 @@ static switch_status_t load_config(void) const char *tonegroup = NULL; char *digit_timeout = NULL; char *dial_timeout = NULL; + char *release_guard_time_ms = NULL; char *max_digits = NULL; char *dial_regex = NULL; char *hold_music = NULL; @@ -3839,7 +3840,7 @@ static switch_status_t load_config(void) char *answer_supervision = str_false; char *immediate_ringback = str_false; char *ringback_file = str_empty; - uint32_t span_id = 0, to = 0, max = 0, dial_timeout_int = 0; + uint32_t span_id = 0, to = 0, max = 0, dial_timeout_int = 0, release_guard_time_ms_int = 0; ftdm_span_t *span = NULL; analog_option_t analog_options = ANALOG_OPTION_NONE; @@ -3853,6 +3854,8 @@ static switch_status_t load_config(void) digit_timeout = val; } else if (!strcasecmp(var, "dial-timeout")) { dial_timeout = val; + } else if (!strcasecmp(var, "release-guard-time-ms")) { + release_guard_time_ms = val; } else if (!strcasecmp(var, "context")) { context = val; } else if (!strcasecmp(var, "dialplan")) { @@ -3893,6 +3896,10 @@ static switch_status_t load_config(void) dial_timeout_int = atoi(dial_timeout); } + if (release_guard_time_ms) { + release_guard_time_ms_int = atoi(release_guard_time_ms); + } + if (max_digits) { max = atoi(max_digits); } @@ -3928,6 +3935,7 @@ static switch_status_t load_config(void) "ringback_file", ringback_file, "digit_timeout", &to, "dial_timeout", &dial_timeout_int, + "release_guard_time_ms", &release_guard_time_ms_int, "max_dialstr", &max, FTDM_TAG_END) != FTDM_SUCCESS) { LOAD_ERROR("Error starting FreeTDM span %d\n", span_id); @@ -5246,6 +5254,98 @@ end: return SWITCH_STATUS_SUCCESS; } +#define CASINTS(cas) ((cas) & (1 << 3)) ? 1 : 0, \ + ((cas) & (1 << 2)) ? 1 : 0, \ + ((cas) & (1 << 1)) ? 1 : 0, \ + ((cas) & (1 << 0)) ? 1 : 0 +FTDM_CLI_DECLARE(ftdm_cmd_cas) +{ + uint32_t chan_id = 0; + switch_bool_t do_read = SWITCH_FALSE; + ftdm_channel_t *chan; + ftdm_iterator_t *iter = NULL; + ftdm_iterator_t *curr = NULL; + ftdm_span_t *span = NULL; + const char *write_bits_str = ""; + int32_t abcd_bits = 0; + + if (argc < 3) { + print_usage(stream, cli); + goto end; + } + + if (!strcasecmp(argv[1], "read")) { + do_read = SWITCH_TRUE; + chan_id = argc > 3 ? atoi(argv[3]) : 0; + } else if (!strcasecmp(argv[1], "write") && argc >= 4) { + const char *str = NULL; + int mask = 0x08; + do_read = SWITCH_FALSE; + if (argc == 4) { + chan_id = 0; + write_bits_str = argv[3]; + } else { + chan_id = atoi(argv[3]); + write_bits_str = argv[4]; + } + if (strlen(write_bits_str) != 4) { + stream->write_function(stream, "-ERR Invalid CAS bits '%s'. CAS ABCD string must be composed of only four 1's and 0's (e.g. 1101)\n", write_bits_str); + goto end; + } + str = write_bits_str; + while (*str) { + if (*str == '1') { + abcd_bits |= mask; + } else if (*str != '0') { + stream->write_function(stream, "-ERR Invalid CAS bits '%s'. CAS ABCD string must be composed of only four 1's and 0's (e.g. 1101)\n", write_bits_str); + goto end; + } + str++; + mask = (mask >> 1); + } + } else { + print_usage(stream, cli); + goto end; + } + + ftdm_span_find_by_name(argv[2], &span); + if (!span) { + stream->write_function(stream, "-ERR failed to find span %s\n", argv[2]); + goto end; + } + + if (chan_id) { + if (chan_id > ftdm_span_get_chan_count(span)) { + stream->write_function(stream, "-ERR invalid channel\n"); + goto end; + } + chan = ftdm_span_get_channel(span, chan_id); + if (do_read) { + ftdm_channel_command(chan, FTDM_COMMAND_GET_CAS_BITS, &abcd_bits); + stream->write_function(stream, "Read CAS bits from channel %d: %d%d%d%d (0x0%X)\n", chan_id, CASINTS(abcd_bits), abcd_bits); + } else { + stream->write_function(stream, "Writing 0x0%X to channel %d\n", abcd_bits, chan_id); + } + } else { + iter = ftdm_span_get_chan_iterator(span, NULL); + for (curr = iter; curr; curr = ftdm_iterator_next(curr)) { + chan = ftdm_iterator_current(curr); + //ftdm_channel_command(); + chan_id = ftdm_channel_get_id(chan); + if (do_read) { + ftdm_channel_command(chan, FTDM_COMMAND_GET_CAS_BITS, &abcd_bits); + stream->write_function(stream, "Read CAS bits from channel %d: %d%d%d%d (0x0%X)\n", chan_id, CASINTS(abcd_bits), abcd_bits); + } else { + stream->write_function(stream, "Writing 0x0%X to channel %d\n", abcd_bits, chan_id); + } + } + ftdm_iterator_free(iter); + } + stream->write_function(stream, "+OK\n"); +end: + return SWITCH_STATUS_SUCCESS; +} + SWITCH_STANDARD_API(ftdm_api_exec_usage) { char *mycmd = NULL, *argv[10] = { 0 }; @@ -5326,6 +5426,7 @@ static ftdm_cli_entry_t ftdm_cli_options[] = { "queuesize", " []", "", NULL, ftdm_cmd_queuesize, NULL }, { "iostats", "enable|disable|flush|print ", "::[enable:disable:flush:print", NULL, ftdm_cmd_iostats, NULL }, { "ioread", " [num_times] [interval]", "", NULL, ftdm_cmd_ioread, NULL }, + { "cas", "read|write [] []", "::[read:write", NULL, ftdm_cmd_cas, NULL }, /* Stand-alone commands (not part of the generic ftdm API */ { "ftdm_usage", " ", "", "Return channel call count", NULL, ftdm_api_exec_usage }, diff --git a/libs/freetdm/src/ftdm_backtrace.c b/libs/freetdm/src/ftdm_backtrace.c index b27c8ebbe8..8f6756d939 100644 --- a/libs/freetdm/src/ftdm_backtrace.c +++ b/libs/freetdm/src/ftdm_backtrace.c @@ -2,6 +2,9 @@ * * */ +#ifndef _DEFAULT_SOURCE +#define _DEFAULT_SOURCE +#endif #define _BSD_SOURCE #include "private/ftdm_core.h" diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index 650ef359d4..0b0673ba84 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -1489,6 +1489,16 @@ static __inline__ int chan_is_avail(ftdm_channel_t *check) return 0; } } + /* release guard time check */ + if (check->span->sig_release_guard_time_ms && check->last_release_time) { + ftdm_time_t time_diff = (ftdm_current_time_in_ms() - check->last_release_time); + if (time_diff < check->span->sig_release_guard_time_ms) { + return 0; + } + /* circuit now available for outbound dialing */ + check->last_release_time = 0; + ftdm_log_chan(check, FTDM_LOG_DEBUG, "Channel is now available, release guard timer expired %zdms ago\n", (time_diff - check->span->sig_release_guard_time_ms)); + } return 1; } @@ -2981,6 +2991,11 @@ static ftdm_status_t ftdm_channel_done(ftdm_channel_t *ftdmchan) ftdmchan->packet_len = ftdmchan->native_interval * (ftdmchan->effective_codec == FTDM_CODEC_SLIN ? 16 : 8); ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_TRANSCODE); } + + if (ftdmchan->span->sig_release_guard_time_ms) { + ftdmchan->last_release_time = ftdm_current_time_in_ms(); + } + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "channel done\n"); return FTDM_SUCCESS; } @@ -3442,7 +3457,7 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_co ftdmchan->dtmf_on = val; GOTO_STATUS(done, FTDM_SUCCESS); } else { - snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "invalid value %d range 10-1000", val); + ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "invalid value %d range 10-1000", val); GOTO_STATUS(done, FTDM_FAIL); } } @@ -3456,7 +3471,7 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_co ftdmchan->dtmf_off = val; GOTO_STATUS(done, FTDM_SUCCESS); } else { - snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "invalid value %d range 10-1000", val); + ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "invalid value %d range 10-1000", val); GOTO_STATUS(done, FTDM_FAIL); } } @@ -5096,6 +5111,12 @@ FT_DECLARE(ftdm_status_t) ftdm_configure_span_channels(ftdm_span_t *span, const if (chan_config->dtmf_on_start) { span->channels[chan_index]->dtmfdetect.trigger_on_start = 1; } + if (chan_config->dtmf_time_on) { + ftdm_channel_command(span->channels[chan_index], FTDM_COMMAND_SET_DTMF_ON_PERIOD, &chan_config->dtmf_time_on); + } + if (chan_config->dtmf_time_off) { + ftdm_channel_command(span->channels[chan_index], FTDM_COMMAND_SET_DTMF_OFF_PERIOD, &chan_config->dtmf_time_off); + } } return FTDM_SUCCESS; @@ -5335,6 +5356,14 @@ static ftdm_status_t load_config(void) chan_config.dtmf_on_start = FTDM_FALSE; } } + } else if (!strcasecmp(var, "dtmf_time_on")) { + if (sscanf(val, "%u", &(chan_config.dtmf_time_on)) != 1) { + ftdm_log(FTDM_LOG_ERROR, "invalid dtmf_time_on: '%s'\n", val); + } + } else if (!strcasecmp(var, "dtmf_time_off")) { + if (sscanf(val, "%u", &(chan_config.dtmf_time_off)) != 1) { + ftdm_log(FTDM_LOG_ERROR, "invalid dtmf_time_off: '%s'\n", val); + } } else if (!strncasecmp(var, "iostats", sizeof("iostats")-1)) { if (ftdm_true(val)) { chan_config.iostats = FTDM_TRUE; diff --git a/libs/freetdm/src/ftmod/ftmod_analog/ftdm_analog.h b/libs/freetdm/src/ftmod/ftmod_analog/ftdm_analog.h index ec20070262..2bc1717556 100644 --- a/libs/freetdm/src/ftmod/ftmod_analog/ftdm_analog.h +++ b/libs/freetdm/src/ftmod/ftmod_analog/ftdm_analog.h @@ -43,7 +43,7 @@ typedef enum { FTDM_ANALOG_POLARITY_CALLERID = (1 << 4) } ftdm_analog_flag_t; -#define FTDM_MAX_HOTLINE_STR 20 +#define FTDM_MAX_HOTLINE_STR 32 #define MAX_DTMF 256 struct ftdm_analog_data { diff --git a/libs/freetdm/src/ftmod/ftmod_analog_em/ftdm_analog_em.h b/libs/freetdm/src/ftmod/ftmod_analog_em/ftdm_analog_em.h index 121381d522..e52a319155 100644 --- a/libs/freetdm/src/ftmod/ftmod_analog_em/ftdm_analog_em.h +++ b/libs/freetdm/src/ftmod/ftmod_analog_em/ftdm_analog_em.h @@ -44,10 +44,12 @@ #define MAX_DIALSTRING 256 typedef enum { - FTDM_ANALOG_EM_RUNNING = (1 << 0) + FTDM_ANALOG_EM_RUNNING = (1 << 0), + FTDM_ANALOG_EM_LOCAL_WRITE = (1 << 2), + FTDM_ANALOG_EM_LOCAL_SUSPEND = (1 << 3), + FTDM_ANALOG_EM_REMOTE_SUSPEND = (1 << 4), } ftdm_analog_em_flag_t; - struct ftdm_analog_data { uint32_t flags; uint32_t max_dialstr; diff --git a/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.c b/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.c index 8a537bb5e6..98fde2a514 100644 --- a/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.c +++ b/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.c @@ -178,8 +178,7 @@ static ftdm_status_t ftdm_analog_em_sig_write(ftdm_channel_t *ftdmchan, void *da ftdm_analog_em_data_t *analog_data = ftdmchan->span->signal_data; if (ftdmchan->state == FTDM_CHANNEL_STATE_PROGRESS_MEDIA && analog_data->immediate_ringback - && ftdmchan->call_data) { - /* DO NOT USE ftdmchan->call_data, as is a dummy non-null pointer */ + && ftdm_test_sflag(ftdmchan, FTDM_ANALOG_EM_LOCAL_WRITE)) { /* ringback is being played in the analog thread, ignore user data for now */ return FTDM_BREAK; } @@ -283,7 +282,7 @@ static FIO_SPAN_GET_SIG_STATUS_FUNCTION(analog_em_get_span_sig_status) return FTDM_SUCCESS; } -static FIO_CHANNEL_SET_SIG_STATUS_FUNCTION(analog_em_set_channel_sig_status) +static ftdm_status_t analog_em_set_channel_sig_status_ex(ftdm_channel_t *ftdmchan, ftdm_signaling_status_t status, ftdm_bool_t remote) { switch (status) { case FTDM_SIG_STATE_DOWN: @@ -299,17 +298,30 @@ static FIO_CHANNEL_SET_SIG_STATUS_FUNCTION(analog_em_set_channel_sig_status) } ftdm_analog_set_chan_sig_status(ftdmchan, FTDM_SIG_STATE_SUSPENDED); } + if (remote) { + ftdm_set_sflag(ftdmchan, FTDM_ANALOG_EM_REMOTE_SUSPEND); + } else { + ftdm_set_sflag(ftdmchan, FTDM_ANALOG_EM_LOCAL_SUSPEND); + } break; case FTDM_SIG_STATE_UP: if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_SUSPENDED)) { - int cas_bits = 0x00; - ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_SUSPENDED); - ftdm_channel_command(ftdmchan, FTDM_COMMAND_SET_CAS_BITS, &cas_bits); - if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OFFHOOK)) { - ftdm_channel_command(ftdmchan, FTDM_COMMAND_ONHOOK, NULL); + if (remote) { + ftdm_clear_sflag(ftdmchan, FTDM_ANALOG_EM_REMOTE_SUSPEND); + } else { + ftdm_clear_sflag(ftdmchan, FTDM_ANALOG_EM_LOCAL_SUSPEND); } - if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_IN_ALARM)) { - ftdm_analog_set_chan_sig_status(ftdmchan, FTDM_SIG_STATE_UP); + if (!ftdm_test_sflag(ftdmchan, FTDM_ANALOG_EM_REMOTE_SUSPEND) && + !ftdm_test_sflag(ftdmchan, FTDM_ANALOG_EM_LOCAL_SUSPEND)) { + int cas_bits = 0x00; + ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_SUSPENDED); + ftdm_channel_command(ftdmchan, FTDM_COMMAND_SET_CAS_BITS, &cas_bits); + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OFFHOOK)) { + ftdm_channel_command(ftdmchan, FTDM_COMMAND_ONHOOK, NULL); + } + if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_IN_ALARM)) { + ftdm_analog_set_chan_sig_status(ftdmchan, FTDM_SIG_STATE_UP); + } } } break; @@ -320,6 +332,11 @@ static FIO_CHANNEL_SET_SIG_STATUS_FUNCTION(analog_em_set_channel_sig_status) return FTDM_SUCCESS; } +static FIO_CHANNEL_SET_SIG_STATUS_FUNCTION(analog_em_set_channel_sig_status) +{ + return analog_em_set_channel_sig_status_ex(ftdmchan, status, FTDM_FALSE); +} + static FIO_SPAN_SET_SIG_STATUS_FUNCTION(analog_em_set_span_sig_status) { ftdm_iterator_t *chaniter = NULL; @@ -335,7 +352,7 @@ static FIO_SPAN_SET_SIG_STATUS_FUNCTION(analog_em_set_span_sig_status) ftdm_channel_t *fchan = ftdm_iterator_current(citer); /* we set channel's state through analog_em_set_channel_sig_status(), since it already takes care of notifying the user when appropriate */ ftdm_channel_lock(fchan); - if ((analog_em_set_channel_sig_status(fchan, status)) != FTDM_SUCCESS) { + if ((analog_em_set_channel_sig_status_ex(fchan, status, FTDM_FALSE)) != FTDM_SUCCESS) { ftdm_log_chan(fchan, FTDM_LOG_ERROR, "Failed to set signaling status to %s\n", ftdm_signaling_status2str(status)); } ftdm_channel_unlock(fchan); @@ -361,6 +378,7 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_analog_em_configure_span) uint32_t digit_timeout = 2000; uint32_t max_dialstr = 11; uint32_t dial_timeout = 0; + uint32_t release_guard_time_ms = 500; ftdm_bool_t answer_supervision = FTDM_FALSE; const char *var, *val; int *intval; @@ -412,6 +430,11 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_analog_em_configure_span) break; } max_dialstr = *intval; + } else if (!strcasecmp(var, "release_guard_time_ms")) { + if (!(intval = va_arg(ap, int *))) { + break; + } + release_guard_time_ms = *intval; } else { ftdm_log(FTDM_LOG_ERROR, "Invalid parameter for analog em span: '%s'\n", var); return FTDM_FAIL; @@ -443,6 +466,7 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_analog_em_configure_span) span->get_span_sig_status = analog_em_get_span_sig_status; span->set_channel_sig_status = analog_em_set_channel_sig_status; span->set_span_sig_status = analog_em_set_span_sig_status; + span->sig_release_guard_time_ms = release_guard_time_ms; ftdm_span_load_tones(span, tonemap); if (immediate_ringback || !ftdm_strlen_zero(ringback_file)) { analog_data->immediate_ringback = FTDM_TRUE; @@ -496,6 +520,7 @@ static void *ftdm_analog_em_channel_run(ftdm_thread_t *me, void *obj) uint32_t cas_hangup = 0; int cas_answer_ms = 500; int cas_hangup_ms = 500; + ftdm_bool_t busy_timeout = FTDM_FALSE; FILE *ringback_f = NULL; ftdm_bool_t digits_sent = FTDM_FALSE; @@ -762,6 +787,7 @@ static void *ftdm_analog_em_channel_run(ftdm_thread_t *me, void *obj) indicate = 1; } else { ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN); + busy_timeout = FTDM_TRUE; } } break; @@ -925,17 +951,25 @@ read_try: } } - /* we must lock the channel and make sure we let our own generated audio thru (ftdmchan->call_data is tested in the ftdm_analog_em_sig_write handler)*/ + /* we must lock the channel and make sure we let our own generated audio thru (FTDM_ANALOG_EM_LOCAL_WRITE is tested in the ftdm_analog_em_sig_write handler)*/ ftdm_channel_lock(ftdmchan); - ftdmchan->call_data = (void *)0xFF; /* ugh! */ + ftdm_set_sflag(ftdmchan, FTDM_ANALOG_EM_LOCAL_WRITE); ftdm_channel_write(ftdmchan, frame, sizeof(frame), &rlen); - ftdmchan->call_data = NULL; + ftdm_clear_sflag(ftdmchan, FTDM_ANALOG_EM_LOCAL_WRITE); ftdm_channel_unlock(ftdmchan); } done: ftdm_channel_command(ftdmchan, FTDM_COMMAND_ONHOOK, NULL); + if (busy_timeout) { + ftdm_channel_command(ftdmchan, FTDM_COMMAND_GET_CAS_BITS, &cas_bits); + if (cas_bits == 0XF) { + /* the remote end never sent any digits, neither moved to onhook, let's stay suspended */ + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Moving channel to suspended after timeout, remote end still offhook\n"); + analog_em_set_channel_sig_status_ex(ftdmchan, FTDM_SIG_STATE_SUSPENDED, FTDM_TRUE); + } + } closed_chan = ftdmchan; ftdm_channel_close(&ftdmchan); @@ -984,6 +1018,11 @@ static __inline__ ftdm_status_t process_event(ftdm_span_t *span, ftdm_event_t *e ftdm_mutex_lock(event->channel->mutex); locked++; + if (event->enum_id == FTDM_OOB_ONHOOK && ftdm_test_sflag(event->channel, FTDM_ANALOG_EM_REMOTE_SUSPEND)) { + /* We've got remote suspend, now we're back on hook, lift the remote suspend status */ + analog_em_set_channel_sig_status_ex(event->channel, FTDM_SIG_STATE_UP, FTDM_TRUE); + } + if (ftdm_test_flag(event->channel, FTDM_CHANNEL_SUSPENDED)) { ftdm_log(FTDM_LOG_WARNING, "Ignoring event %s on channel %d:%d in state %s, channel is suspended\n", ftdm_oob_event2str(event->enum_id), event->channel->span_id, event->channel->chan_id, ftdm_channel_state2str(event->channel->state)); diff --git a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c index 026b7b17df..2dea680987 100755 --- a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c +++ b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c @@ -38,6 +38,9 @@ */ #ifdef __linux__ +#ifndef _DEFAULT_SOURCE +#define _DEFAULT_SOURCE +#endif #ifndef _BSD_SOURCE #define _BSD_SOURCE /* for strsep() */ #endif diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c index b414d4dfb1..f9516235b7 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c @@ -203,8 +203,17 @@ void sngisdn_process_con_ind (sngisdn_event_data_t *sngisdn_event) } } #endif - if (signal_data->overlap_dial == SNGISDN_OPT_TRUE && !conEvnt->sndCmplt.eh.pres) { - ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_COLLECT); + if (signal_data->overlap_dial == SNGISDN_OPT_TRUE) { + ftdm_size_t min_digits = ((sngisdn_span_data_t*)ftdmchan->span->signal_data)->min_digits; + ftdm_size_t num_digits; + + num_digits = strlen(ftdmchan->caller_data.dnis.digits); + + if (conEvnt->sndCmplt.eh.pres || num_digits >= min_digits) { + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RING); + } else { + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_COLLECT); + } } else { ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RING); } diff --git a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c index ca60e30352..0e8b73e9c0 100755 --- a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c +++ b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c @@ -40,6 +40,9 @@ * */ #ifdef WP_DEBUG_IO +#ifndef _DEFAULT_SOURCE +#define _DEFAULT_SOURCE +#endif #define _BSD_SOURCE #include #endif diff --git a/libs/freetdm/src/include/freetdm.h b/libs/freetdm/src/include/freetdm.h index c5b82c9b06..46bf880e12 100755 --- a/libs/freetdm/src/include/freetdm.h +++ b/libs/freetdm/src/include/freetdm.h @@ -74,10 +74,10 @@ extern "C" { #endif /*! \brief Limit to span names */ -#define FTDM_MAX_NAME_STR_SZ 80 +#define FTDM_MAX_NAME_STR_SZ 128 /*! \brief Limit to channel number strings */ -#define FTDM_MAX_NUMBER_STR_SZ 20 +#define FTDM_MAX_NUMBER_STR_SZ 32 /*! \brief Hangup cause codes */ typedef enum { @@ -355,7 +355,7 @@ typedef enum { FTDM_STR2ENUM_P(ftdm_str2ftdm_transfer_response, ftdm_transfer_response2str, ftdm_transfer_response_t) /*! \brief Digit limit used in DNIS/ANI */ -#define FTDM_DIGITS_LIMIT 25 +#define FTDM_DIGITS_LIMIT 64 #define FTDM_SILENCE_VALUE(fchan) (fchan)->native_codec == FTDM_CODEC_ULAW ? 255 : (fchan)->native_codec == FTDM_CODEC_ALAW ? 0xD5 : 0x00 @@ -533,6 +533,8 @@ typedef struct ftdm_channel_config { uint8_t debugdtmf; uint8_t dtmf_on_start; uint32_t dtmfdetect_ms; + uint32_t dtmf_time_on; + uint32_t dtmf_time_off; uint8_t iostats; } ftdm_channel_config_t; diff --git a/libs/freetdm/src/include/private/ftdm_core.h b/libs/freetdm/src/include/private/ftdm_core.h index f4a1fe4e29..609198e731 100644 --- a/libs/freetdm/src/include/private/ftdm_core.h +++ b/libs/freetdm/src/include/private/ftdm_core.h @@ -477,6 +477,7 @@ struct ftdm_channel { int32_t rxdrops; ftdm_usrmsg_t *usrmsg; ftdm_time_t last_state_change_time; + ftdm_time_t last_release_time; }; struct ftdm_span { @@ -515,6 +516,7 @@ struct ftdm_span { ftdm_channel_sig_write_t sig_write; ftdm_channel_sig_dtmf_t sig_queue_dtmf; ftdm_channel_sig_dtmf_t sig_send_dtmf; + uint32_t sig_release_guard_time_ms; ftdm_channel_state_processor_t state_processor; /*!< This guy is called whenever state processing is required */ void *io_data; /*!< Private I/O data per span. Do not touch unless you are an I/O module */ char *type; diff --git a/libs/iksemel/include/iksemel.h b/libs/iksemel/include/iksemel.h index 2b11070671..dc6df91022 100644 --- a/libs/iksemel/include/iksemel.h +++ b/libs/iksemel/include/iksemel.h @@ -226,7 +226,7 @@ void iks_disconnect (iksparser *prs); int iks_has_tls (void); int iks_is_secure (iksparser *prs); int iks_start_tls (iksparser *prs); -int iks_proceed_tls (iksparser *prs, const char *cert_file, const char *key_file, int use_ssl); +int iks_proceed_tls (iksparser *prs, const char *cert_file, const char *key_file); int iks_start_sasl (iksparser *prs, enum ikssasltype type, char *username, char *pass); /***** jabber *****/ diff --git a/libs/iksemel/src/stream.c b/libs/iksemel/src/stream.c index 658c40207c..eda6cb0fe7 100644 --- a/libs/iksemel/src/stream.c +++ b/libs/iksemel/src/stream.c @@ -36,7 +36,6 @@ typedef unsigned __int32 uint32_t; #define SF_TRY_SECURE 2 #define SF_SECURE 4 #define SF_SERVER 8 -#define SF_SSLv23 16 struct stream_data { iksparser *prs; @@ -319,11 +318,7 @@ handshake (struct stream_data *data) SSL_load_error_strings(); if (data->flags & SF_SERVER) { - if (data->flags & SF_SSLv23) { - data->ssl_ctx = SSL_CTX_new(SSLv23_server_method()); - } else { - data->ssl_ctx = SSL_CTX_new(TLSv1_server_method()); - } + data->ssl_ctx = SSL_CTX_new(TLSv1_server_method()); if(!data->ssl_ctx) return IKS_NOMEM; if (SSL_CTX_use_certificate_file(data->ssl_ctx, data->cert_file, SSL_FILETYPE_PEM) <= 0) { @@ -985,7 +980,7 @@ iks_start_tls (iksparser *prs) } int -iks_proceed_tls (iksparser *prs, const char *cert_file, const char *key_file, int use_ssl) +iks_proceed_tls (iksparser *prs, const char *cert_file, const char *key_file) { #ifdef HAVE_GNUTLS int ret; @@ -996,9 +991,6 @@ iks_proceed_tls (iksparser *prs, const char *cert_file, const char *key_file, in data->cert_file = iks_stack_strdup(data->s, cert_file, 0); data->key_file = iks_stack_strdup(data->s, key_file, 0); data->flags |= SF_TRY_SECURE | SF_SERVER; - if (use_ssl) { - data->flags |= SF_SSLv23; - } return handshake (data); #elif HAVE_SSL int ret; @@ -1009,9 +1001,6 @@ iks_proceed_tls (iksparser *prs, const char *cert_file, const char *key_file, in data->cert_file = iks_stack_strdup(data->s, cert_file, 0); data->key_file = iks_stack_strdup(data->s, key_file, 0); data->flags |= SF_TRY_SECURE | SF_SERVER; - if (use_ssl) { - data->flags |= SF_SSLv23; - } return handshake (data); #else return IKS_NET_NOTSUPP; diff --git a/libs/libnatpmp/natpmp.c b/libs/libnatpmp/natpmp.c index c79e92bdfd..d2ff9d5fd3 100644 --- a/libs/libnatpmp/natpmp.c +++ b/libs/libnatpmp/natpmp.c @@ -15,6 +15,9 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifdef __linux__ +#ifndef _DEFAULT_SOURCE +#define _DEFAULT_SOURCE +#endif #define _BSD_SOURCE 1 #endif #include diff --git a/libs/libzrtp/include/zrtp_config.h b/libs/libzrtp/include/zrtp_config.h index 3f954fc836..0e2ee73b71 100644 --- a/libs/libzrtp/include/zrtp_config.h +++ b/libs/libzrtp/include/zrtp_config.h @@ -101,6 +101,18 @@ */ #define ZRTP_BYTE_ORDER ZBO_BIG_ENDIAN +#elif defined(__MIPSEB__) +/* + * mips, big endian + */ +#define ZRTP_BYTE_ORDER ZBO_BIG_ENDIAN + +#elif defined(__MIPSEL__) +/* + * mips, little endian + */ +#define ZRTP_BYTE_ORDER ZBO_LITTLE_ENDIAN + #endif /* Automatic byte order detection */ #endif diff --git a/libs/sofia-sip/.update b/libs/sofia-sip/.update index fb3ae1977e..d3d7dac4b3 100644 --- a/libs/sofia-sip/.update +++ b/libs/sofia-sip/.update @@ -1 +1 @@ -Fri Oct 31 13:48:09 CDT 2014 +Wed Nov 12 13:07:56 CST 2014 diff --git a/libs/sofia-sip/libsofia-sip-ua/nta/nta.c b/libs/sofia-sip/libsofia-sip-ua/nta/nta.c index 98d1ad25e1..bb68025749 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nta/nta.c +++ b/libs/sofia-sip/libsofia-sip-ua/nta/nta.c @@ -3188,7 +3188,9 @@ int agent_check_request_via(nta_agent_t *agent, else if (agent->sa_server_rport == 2 || (agent->sa_server_rport == 3 && sip && sip->sip_user_agent && sip->sip_user_agent->g_string && - (!strncasecmp(sip->sip_user_agent->g_string, "Polycom", 7) || !strncasecmp(sip->sip_user_agent->g_string, "KIRK Wireless Server", 20)))) { + (!strncasecmp(sip->sip_user_agent->g_string, "Polycom", 7) || + !strncasecmp(sip->sip_user_agent->g_string, "KIRK Wireless Server", 20) || + !strncasecmp(sip->sip_user_agent->g_string, "ADTRAN_Total_Access", 19)))) { rport = su_sprintf(msg_home(msg), "rport=%u", ntohs(from->su_port)); msg_header_replace_param(msg_home(msg), v->v_common, rport); } diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c b/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c index 933d76249e..d9261324d5 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c +++ b/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c @@ -1549,10 +1549,12 @@ static void nua_session_usage_refresh(nua_handle_t *nh, nua_client_request_in_progress(cr)) return; + if (ds->ds_cr) return; /* request queued */ + /* UPDATE has been queued */ - for (cr = ds->ds_cr; cr; cr = cr->cr_next) - if (cr->cr_method == sip_method_update) - return; + //for (cr = ds->ds_cr; cr; cr = cr->cr_next) + //if (cr->cr_method == sip_method_update) + // return; /* INVITE or UPDATE in progress on server side */ for (sr = ds->ds_sr; sr; sr = sr->sr_next) diff --git a/libs/xmlrpc-c/lib/abyss/src/conf.c b/libs/xmlrpc-c/lib/abyss/src/conf.c index e0feff9f6b..891aa96c1c 100644 --- a/libs/xmlrpc-c/lib/abyss/src/conf.c +++ b/libs/xmlrpc-c/lib/abyss/src/conf.c @@ -34,6 +34,9 @@ #define _XOPEN_SOURCE 600 /* For strdup() */ #define _BSD_SOURCE /* For xmlrpc_strcaseeq */ +#ifndef _DEFAULT_SOURCE +#define _DEFAULT_SOURCE +#endif #include #include diff --git a/libs/xmlrpc-c/lib/abyss/src/http.c b/libs/xmlrpc-c/lib/abyss/src/http.c index 4f9ef10118..c4269e21cd 100644 --- a/libs/xmlrpc-c/lib/abyss/src/http.c +++ b/libs/xmlrpc-c/lib/abyss/src/http.c @@ -2,6 +2,9 @@ #define _XOPEN_SOURCE 600 /* For strdup() */ #define _BSD_SOURCE /* For xmlrpc_strcaseeq() */ +#ifndef _DEFAULT_SOURCE +#define _DEFAULT_SOURCE +#endif #include #include diff --git a/libs/xmlrpc-c/lib/abyss/src/server.c b/libs/xmlrpc-c/lib/abyss/src/server.c index 392f36813a..6337dcfd78 100644 --- a/libs/xmlrpc-c/lib/abyss/src/server.c +++ b/libs/xmlrpc-c/lib/abyss/src/server.c @@ -2,6 +2,9 @@ #define _XOPEN_SOURCE 600 /* Make sure strdup() is in */ #define _BSD_SOURCE /* Make sure setgroups()is in */ +#ifndef _DEFAULT_SOURCE +#define _DEFAULT_SOURCE +#endif #include #include diff --git a/scripts/perl/mkgws.pl b/scripts/perl/mkgws.pl new file mode 100644 index 0000000000..6743c969d0 --- /dev/null +++ b/scripts/perl/mkgws.pl @@ -0,0 +1,37 @@ +#!/usr/bin/perl +# +# Make bulk gateway xml from csv file. +# + +open(CSV, "gateways.csv"); +my @data = ; +close(CSV); + +foreach my $line (@data) { + chomp($line); + my ($gwname, $username, $password) = split(/,/, $line); + print < + + + + + + + + + + + + + + + + + + + + +XML + +} diff --git a/src/include/switch.h b/src/include/switch.h index 2fda7e7ade..ca95045248 100644 --- a/src/include/switch.h +++ b/src/include/switch.h @@ -63,6 +63,9 @@ #ifndef _BSD_SOURCE #define _BSD_SOURCE #endif +#ifndef _DEFAULT_SOURCE +#define _DEFAULT_SOURCE +#endif #endif #ifndef __BSD_VISIBLE #define __BSD_VISIBLE 1 diff --git a/src/include/switch_core_media.h b/src/include/switch_core_media.h index d5baac404a..1915b742ae 100644 --- a/src/include/switch_core_media.h +++ b/src/include/switch_core_media.h @@ -146,6 +146,15 @@ typedef struct switch_core_media_params_s { switch_core_media_dtmf_t dtmf_type; switch_payload_t cng_pt; + /* a core_video_thread will be started automatically + when uses rtp based media, + external_video_source should be set to SWITCH_TRUE and + switch_core_media_start_video_thread() + should be explicitly called to start the video thread + if uses the media handle for non-rtp based media + */ + switch_bool_t external_video_source; + } switch_core_media_params_t; static inline const char *switch_media_type2str(switch_media_type_t type) @@ -252,6 +261,7 @@ SWITCH_DECLARE(void) switch_core_media_deinit(void); SWITCH_DECLARE(void) switch_core_media_set_stats(switch_core_session_t *session); SWITCH_DECLARE(void) switch_core_session_wake_video_thread(switch_core_session_t *session); SWITCH_DECLARE(void) switch_core_session_clear_crypto(switch_core_session_t *session); +SWITCH_DECLARE(switch_status_t) switch_core_media_start_video_thread(switch_core_session_t *session); SWITCH_DECLARE(switch_status_t) switch_core_session_get_payload_code(switch_core_session_t *session, switch_media_type_t type, diff --git a/src/include/switch_types.h b/src/include/switch_types.h index 6b9f303f47..69602de419 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -361,7 +361,8 @@ typedef enum { SCF_CORE_NON_SQLITE_DB_REQ = (1 << 20), SCF_DEBUG_SQL = (1 << 21), SCF_API_EXPANSION = (1 << 22), - SCF_SESSION_THREAD_POOL = (1 << 23) + SCF_SESSION_THREAD_POOL = (1 << 23), + SCF_DIALPLAN_TIMESTAMPS = (1 << 24) } switch_core_flag_enum_t; typedef uint32_t switch_core_flag_t; diff --git a/src/include/switch_utils.h b/src/include/switch_utils.h index e8b6843d14..523e3a4768 100644 --- a/src/include/switch_utils.h +++ b/src/include/switch_utils.h @@ -541,6 +541,28 @@ SWITCH_DECLARE(int) switch_build_uri(char *uri, switch_size_t size, const char * #define SWITCH_STATUS_IS_BREAK(x) (x == SWITCH_STATUS_BREAK || x == 730035 || x == 35 || x == SWITCH_STATUS_INTR) + +#ifdef _MSC_VER + +#define switch_errno() WSAGetLastError() + +static inline int switch_errno_is_break(int errcode) +{ + return errcode == WSAEWOULDBLOCK || errcode == WSAEINPROGRESS || errcode == WSAEINTR; +} + +#else + +#define switch_errno() errno + +static inline int switch_errno_is_break(int errcode) +{ + return errcode == EAGAIN || errcode == EWOULDBLOCK || errcode == EINPROGRESS || errcode == EINTR || errcode == ETIMEDOUT; +} + +#endif + + /*! \brief Return a printable name of a switch_priority_t \param priority the priority to get the name of diff --git a/src/mod/applications/mod_conference/mod_conference.c b/src/mod/applications/mod_conference/mod_conference.c index 99511c8a9d..1dfbe311d3 100644 --- a/src/mod/applications/mod_conference/mod_conference.c +++ b/src/mod/applications/mod_conference/mod_conference.c @@ -2277,7 +2277,8 @@ static switch_status_t conference_add_member(conference_obj_t *conference, confe } if (conference->count > 1) { - if (conference->moh_sound && !switch_test_flag(conference, CFLAG_WAIT_MOD)) { + if ((conference->moh_sound && !switch_test_flag(conference, CFLAG_WAIT_MOD)) || + (switch_test_flag(conference, CFLAG_WAIT_MOD) && !switch_true(switch_channel_get_variable(channel, "conference_permanent_wait_mod_moh")))) { /* stop MoH if any */ conference_stop_file(conference, FILE_STOP_ASYNC); } @@ -2287,10 +2288,9 @@ static switch_status_t conference_add_member(conference_obj_t *conference, confe if (switch_test_flag(conference, CFLAG_ENTER_SOUND)) { if (!zstr(enter_sound)) { conference_play_file(conference, (char *)enter_sound, CONF_DEFAULT_LEADIN, - switch_core_session_get_channel(member->session), !switch_test_flag(conference, CFLAG_WAIT_MOD) ? 0 : 1); + switch_core_session_get_channel(member->session), 0); } else { - conference_play_file(conference, conference->enter_sound, CONF_DEFAULT_LEADIN, switch_core_session_get_channel(member->session), - !switch_test_flag(conference, CFLAG_WAIT_MOD) ? 0 : 1); + conference_play_file(conference, conference->enter_sound, CONF_DEFAULT_LEADIN, switch_core_session_get_channel(member->session), 0); } } } @@ -2316,7 +2316,7 @@ static switch_status_t conference_add_member(conference_obj_t *conference, confe if (conference->alone_sound && !switch_test_flag(member, MFLAG_GHOST)) { conference_stop_file(conference, FILE_STOP_ASYNC); conference_play_file(conference, conference->alone_sound, CONF_DEFAULT_LEADIN, - switch_core_session_get_channel(member->session), 1); + switch_core_session_get_channel(member->session), 0); } else { switch_snprintf(msg, sizeof(msg), "You are currently the only person in this conference."); conference_member_say(member, msg, CONF_DEFAULT_LEADIN); @@ -2683,7 +2683,7 @@ static switch_status_t conference_del_member(conference_obj_t *conference, confe if (member->session && (exit_sound = switch_channel_get_variable(switch_core_session_get_channel(member->session), "conference_exit_sound"))) { conference_play_file(conference, (char *)exit_sound, CONF_DEFAULT_LEADIN, - switch_core_session_get_channel(member->session), !switch_test_flag(conference, CFLAG_WAIT_MOD) ? 0 : 1); + switch_core_session_get_channel(member->session), 0); } @@ -2786,12 +2786,16 @@ static switch_status_t conference_del_member(conference_obj_t *conference, confe || (switch_test_flag(conference, CFLAG_DYNAMIC) && (conference->count + conference->count_ghosts == 0))) { switch_set_flag(conference, CFLAG_DESTRUCT); } else { + if (!switch_true(switch_channel_get_variable(channel, "conference_permanent_wait_mod_moh")) && switch_test_flag(conference, CFLAG_WAIT_MOD)) { + /* Stop MOH if any */ + conference_stop_file(conference, FILE_STOP_ASYNC); + } if (!exit_sound && conference->exit_sound && switch_test_flag(conference, CFLAG_EXIT_SOUND)) { conference_play_file(conference, conference->exit_sound, 0, channel, 0); } if (conference->count == 1 && conference->alone_sound && !switch_test_flag(conference, CFLAG_WAIT_MOD) && !switch_test_flag(member, MFLAG_GHOST)) { conference_stop_file(conference, FILE_STOP_ASYNC); - conference_play_file(conference, conference->alone_sound, 0, channel, 1); + conference_play_file(conference, conference->alone_sound, 0, channel, 0); } } @@ -3146,7 +3150,7 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v if (conference->perpetual_sound && !conference->async_fnode) { conference_play_file(conference, conference->perpetual_sound, CONF_DEFAULT_LEADIN, NULL, 1); } else if (conference->moh_sound && ((nomoh == 0 && conference->count == 1) - || switch_test_flag(conference, CFLAG_WAIT_MOD)) && !conference->async_fnode) { + || switch_test_flag(conference, CFLAG_WAIT_MOD)) && !conference->async_fnode && !conference->fnode) { conference_play_file(conference, conference->moh_sound, CONF_DEFAULT_LEADIN, NULL, 1); } @@ -6143,7 +6147,7 @@ static switch_status_t conf_api_sub_mute(conference_member_t *member, switch_str switch_clear_flag_locked(member, MFLAG_CAN_SPEAK); switch_clear_flag_locked(member, MFLAG_TALKING); - if (member->session && !switch_test_flag(member, MFLAG_INDICATE_MUTE)) { + if (member->session && !switch_test_flag(member, MFLAG_MUTE_DETECT)) { switch_core_media_hard_mute(member->session, SWITCH_TRUE); } @@ -6241,7 +6245,7 @@ static switch_status_t conf_api_sub_unmute(conference_member_t *member, switch_s switch_set_flag_locked(member, MFLAG_CAN_SPEAK); - if (member->session && !switch_test_flag(member, MFLAG_INDICATE_MUTE)) { + if (member->session && !switch_test_flag(member, MFLAG_MUTE_DETECT)) { switch_core_media_hard_mute(member->session, SWITCH_FALSE); } @@ -8757,6 +8761,8 @@ static void set_mflags(const char *flags, member_flag_t *f) char *argv[10] = { 0 }; int i, argc = 0; + *f |= MFLAG_CAN_SPEAK | MFLAG_CAN_HEAR; + for (p = dup; p && *p; p++) { if (*p == ',') { *p = '|'; @@ -9081,6 +9087,7 @@ SWITCH_STANDARD_APP(conference_function) char *profile_name = NULL; switch_xml_t cxml = NULL, cfg = NULL, profiles = NULL; const char *flags_str, *v_flags_str; + const char *cflags_str, *v_cflags_str; member_flag_t mflags = 0; switch_core_session_message_t msg = { 0 }; uint8_t rl = 0, isbr = 0; @@ -9144,6 +9151,16 @@ SWITCH_STANDARD_APP(conference_function) } } + cflags_str = flags_str; + + if ((v_cflags_str = switch_channel_get_variable(channel, "conference_flags"))) { + if (zstr(cflags_str)) { + cflags_str = v_cflags_str; + } else { + cflags_str = switch_core_session_sprintf(session, "%s|%s", cflags_str, v_cflags_str); + } + } + /* is this a bridging conference ? */ if (!strncasecmp(mydata, bridge_prefix, strlen(bridge_prefix))) { isbr = 1; @@ -9234,6 +9251,8 @@ SWITCH_STANDARD_APP(conference_function) goto done; } + set_cflags(cflags_str, &conference->flags); + if (locked) { switch_mutex_unlock(globals.setup_mutex); locked = 0; @@ -9279,7 +9298,7 @@ SWITCH_STANDARD_APP(conference_function) set_mflags(flags_str,&mflags); if (!(mflags & MFLAG_CAN_SPEAK)) { - if (!(mflags & MFLAG_INDICATE_MUTE)) { + if (!(mflags & MFLAG_MUTE_DETECT)) { switch_core_media_hard_mute(session, SWITCH_TRUE); } } @@ -9316,6 +9335,8 @@ SWITCH_STANDARD_APP(conference_function) goto done; } + set_cflags(cflags_str, &conference->flags); + if (locked) { switch_mutex_unlock(globals.setup_mutex); locked = 0; @@ -9582,7 +9603,7 @@ SWITCH_STANDARD_APP(conference_function) mflags |= MFLAG_RUNNING; if (!(mflags & MFLAG_CAN_SPEAK)) { - if (!(mflags & MFLAG_INDICATE_MUTE)) { + if (!(mflags & MFLAG_MUTE_DETECT)) { switch_core_media_hard_mute(member.session, SWITCH_TRUE); } } diff --git a/src/mod/applications/mod_curl/mod_curl.c b/src/mod/applications/mod_curl/mod_curl.c index bff5df864c..b5b49c0d7b 100644 --- a/src/mod/applications/mod_curl/mod_curl.c +++ b/src/mod/applications/mod_curl/mod_curl.c @@ -51,7 +51,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_curl_load); */ SWITCH_MODULE_DEFINITION(mod_curl, mod_curl_load, mod_curl_shutdown, NULL); -static char *SYNTAX = "curl url [headers|json|content-type |timeout ] [get|head|post|delete|put [data]]"; +static char *SYNTAX = "curl url [headers|json|content-type |connect-timeout |timeout ] [get|head|post|delete|put [data]]"; #define HTTP_SENDFILE_ACK_EVENT "curl_sendfile::ack" #define HTTP_SENDFILE_RESPONSE_SIZE 32768 @@ -241,6 +241,7 @@ static http_data_t *do_lookup_url(switch_memory_pool_t *pool, const char *url, c } switch_curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1); switch_curl_easy_setopt(curl_handle, CURLOPT_MAXREDIRS, 15); + switch_curl_easy_setopt(curl_handle, CURLOPT_HTTPAUTH, CURLAUTH_ANY); switch_curl_easy_setopt(curl_handle, CURLOPT_URL, url); switch_curl_easy_setopt(curl_handle, CURLOPT_NOSIGNAL, 1); switch_curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, file_callback); @@ -944,12 +945,22 @@ SWITCH_STANDARD_API(curl_function) if (++i < argc) { content_type = switch_core_strdup(pool, argv[i]); } - } else if (!strcasecmp("timeout", argv[i])) { + } else if (!strcasecmp("connect-timeout", argv[i])) { if (++i < argc) { int tmp = atoi(argv[i]); if (tmp > 0) { options.connect_timeout = tmp; + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Invalid connect-timeout!\n"); + } + } + } else if (!strcasecmp("timeout", argv[i])) { + if (++i < argc) { + int tmp = atoi(argv[i]); + + if (tmp > 0) { + options.timeout = tmp; } else { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Invalid timeout!\n"); } diff --git a/src/mod/applications/mod_fifo/mod_fifo.c b/src/mod/applications/mod_fifo/mod_fifo.c index ac0d1167b7..d6877ef8dc 100644 --- a/src/mod/applications/mod_fifo/mod_fifo.c +++ b/src/mod/applications/mod_fifo/mod_fifo.c @@ -79,6 +79,15 @@ SWITCH_MODULE_DEFINITION(mod_fifo, mod_fifo_load, mod_fifo_shutdown, NULL); * The /enterprise/ outbound strategy does not preserve the caller ID * of the caller thereby allowing deliver of callers to agents at the * fastest possible rate. + * + * outbound_per_cycle is used to define the maximum number of agents + * who will be available to answer a single caller. In ringall this + * maximum is the number who will be called, in enterprise the need defines + * how many agents will be called. outbound_per_cycle_min will define + * the minimum agents who will be called to answer a caller regardless of + * need, giving the enterprise strategy the ability to ring through more + * than one agent for one caller. + * * ## Manual calls * @@ -391,6 +400,7 @@ struct fifo_node { long busy; int is_static; int outbound_per_cycle; + int outbound_per_cycle_min; char *outbound_name; outbound_strategy_t outbound_strategy; int ring_timeout; @@ -1985,6 +1995,21 @@ static int place_call_enterprise_callback(void *pArg, int argc, char **argv, cha * the results. The enterprise strategy handler can simply take each * member one at a time, so the `place_call_enterprise_callback` takes * care of invoking the handler. + * + * Within the ringall call strategy outbound_per_cycle is used to define + * how many agents exactly are assigned to the caller. With ringall if + * multiple callers are calling in and one is answered, because the call + * is assigned to all agents the call to the agents that is not answered + * will be lose raced and the other agents will drop the call before the + * next one will begin to ring. When oubound_per_cycle is used in the + * enterprise strategy it acts as a maximum value for how many agents + * are rung at once on any call, the caller is not assigned to any agent + * until the call is answered. Enterprise only rings the number of phones + * that are needed, so outbound_per_cycle as a max does not give you the + * effect of ringall. outbound_per_cycle_min defines how many agents minimum + * will be rung by an incoming caller through fifo, which can give a ringall + * effect. outbound_per_cycle and outbound_per_cycle_min both default to 1. + * */ static void find_consumers(fifo_node_t *node) { @@ -2005,6 +2030,8 @@ static void find_consumers(fifo_node_t *node) if (node->outbound_per_cycle && node->outbound_per_cycle < need) { need = node->outbound_per_cycle; + } else if (node->outbound_per_cycle_min && node->outbound_per_cycle_min > need) { + need = node->outbound_per_cycle_min; } fifo_execute_sql_callback(globals.sql_mutex, sql, place_call_enterprise_callback, &need); @@ -4045,6 +4072,9 @@ static void list_node(fifo_node_t *node, switch_xml_t x_report, int *off, int ve switch_snprintf(tmp, sizeof(buffer), "%u", node->outbound_per_cycle); switch_xml_set_attr_d(x_fifo, "outbound_per_cycle", tmp); + switch_snprintf(tmp, sizeof(buffer), "%u", node->outbound_per_cycle_min); + switch_xml_set_attr_d(x_fifo, "outbound_per_cycle_min", tmp); + switch_snprintf(tmp, sizeof(buffer), "%u", node->ring_timeout); switch_xml_set_attr_d(x_fifo, "ring_timeout", tmp); @@ -4088,6 +4118,7 @@ void node_dump(switch_stream_handle_t *stream) stream->write_function(stream, "node: %s\n" " outbound_name: %s\n" " outbound_per_cycle: %d" + " outbound_per_cycle_min: %d" " outbound_priority: %d" " outbound_strategy: %s\n" " has_outbound: %d\n" @@ -4096,7 +4127,7 @@ void node_dump(switch_stream_handle_t *stream) " ready: %d\n" " waiting: %d\n" , - node->name, node->outbound_name, node->outbound_per_cycle, + node->name, node->outbound_name, node->outbound_per_cycle, node->outbound_per_cycle_min, node->outbound_priority, print_strategy(node->outbound_strategy), node->has_outbound, node->outbound_priority, @@ -4508,6 +4539,13 @@ static switch_status_t load_config(int reload, int del_all) node->has_outbound = 1; } + node->outbound_per_cycle_min = 1; + if ((val = switch_xml_attr(fifo, "outbound_per_cycle_min"))) { + if (!((i = atoi(val)) < 0)) { + node->outbound_per_cycle_min = i; + } + } + if ((val = switch_xml_attr(fifo, "retry_delay"))) { if ((i = atoi(val)) < 0) i = 0; node->retry_delay = i; diff --git a/src/mod/applications/mod_httapi/mod_httapi.c b/src/mod/applications/mod_httapi/mod_httapi.c index fede125ffb..420b7578d9 100644 --- a/src/mod/applications/mod_httapi/mod_httapi.c +++ b/src/mod/applications/mod_httapi/mod_httapi.c @@ -155,6 +155,7 @@ static struct { int not_found_expires; int cache_ttl; int abs_cache_ttl; + client_profile_t *profile; } globals; @@ -1624,10 +1625,19 @@ static switch_status_t httapi_sync(client_t *client) if (client->profile->ssl_version) { if (!strcasecmp(client->profile->ssl_version, "SSLv3")) { switch_curl_easy_setopt(curl_handle, CURLOPT_SSLVERSION, CURL_SSLVERSION_SSLv3); - } else if (!strcasecmp(client->profile->ssl_version, "TLSv1")) { - switch_curl_easy_setopt(curl_handle, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1); +#ifdef CURL_SSLVERSION_TLSv1_1 + } else if (!strcasecmp(client->profile->ssl_version, "TLSv1.1")) { + switch_curl_easy_setopt(curl_handle, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_1); +#endif +#ifdef CURL_SSLVERSION_TLSv1_2 + } else if (!strcasecmp(client->profile->ssl_version, "TLSv1.2")) { + switch_curl_easy_setopt(curl_handle, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2); +#endif } + } else { + switch_curl_easy_setopt(curl_handle, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1); } + if (client->profile->ssl_cacert_file) { switch_curl_easy_setopt(curl_handle, CURLOPT_CAINFO, client->profile->ssl_cacert_file); @@ -2150,6 +2160,8 @@ static switch_status_t do_config(void) profile->name = switch_core_strdup(globals.pool, bname); + if (!globals.profile) globals.profile = profile; + switch_core_hash_insert(globals.profile_hash, bname, profile); x++; @@ -2429,16 +2441,33 @@ static size_t save_file_callback(void *ptr, size_t size, size_t nmemb, void *dat static switch_status_t fetch_cache_data(http_file_context_t *context, const char *url, switch_event_t **headers, const char *save_path) { switch_CURL *curl_handle = NULL; - client_t client = { 0 }; + client_t *client = NULL; long code; switch_status_t status = SWITCH_STATUS_FALSE; char *dup_creds = NULL, *dynamic_url = NULL, *use_url; char *ua = NULL; + const char *profile_name = NULL; + + + if (context->url_params) { + profile_name = switch_event_get_header(context->url_params, "profile_name"); + } + + if (zstr(profile_name)) { + if (globals.profile) profile_name = globals.profile->name; + } + + if (zstr(profile_name)) { + profile_name = "default"; + } + + if (!(client = client_create(NULL, profile_name, NULL))) { + return SWITCH_STATUS_FALSE; + } - client.fd = -1; if (save_path) { - if ((client.fd = open(save_path, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR)) < 0) { + if ((client->fd = open(save_path, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR)) < 0) { return SWITCH_STATUS_FALSE; } } @@ -2478,31 +2507,84 @@ static switch_status_t fetch_cache_data(http_file_context_t *context, const char switch_curl_easy_setopt(curl_handle, CURLOPT_NOSIGNAL, 1); switch_curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 1); - switch_curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0); - switch_curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0); + if (!strncasecmp(url, "https", 5)) { + switch_curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0); + switch_curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0); + } - client.max_bytes = HTTAPI_MAX_FILE_BYTES; + client->max_bytes = HTTAPI_MAX_FILE_BYTES; switch_curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1); switch_curl_easy_setopt(curl_handle, CURLOPT_MAXREDIRS, 10); switch_curl_easy_setopt(curl_handle, CURLOPT_URL, url); + if (client->profile->timeout) { + switch_curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, client->profile->timeout); + } + + if (client->profile->ssl_cert_file) { + switch_curl_easy_setopt(curl_handle, CURLOPT_SSLCERT, client->profile->ssl_cert_file); + } + + if (client->profile->ssl_key_file) { + switch_curl_easy_setopt(curl_handle, CURLOPT_SSLKEY, client->profile->ssl_key_file); + } + + if (client->profile->ssl_key_password) { + switch_curl_easy_setopt(curl_handle, CURLOPT_SSLKEYPASSWD, client->profile->ssl_key_password); + } + + if (client->profile->ssl_version) { + if (!strcasecmp(client->profile->ssl_version, "SSLv3")) { + switch_curl_easy_setopt(curl_handle, CURLOPT_SSLVERSION, CURL_SSLVERSION_SSLv3); +#ifdef CURL_SSLVERSION_TLSv1_1 + } else if (!strcasecmp(client->profile->ssl_version, "TLSv1.1")) { + switch_curl_easy_setopt(curl_handle, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_1); +#endif +#ifdef CURL_SSLVERSION_TLSv1_2 + } else if (!strcasecmp(client->profile->ssl_version, "TLSv1.2")) { + switch_curl_easy_setopt(curl_handle, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2); +#endif + } + } else { + switch_curl_easy_setopt(curl_handle, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1); + } + + if (client->profile->ssl_cacert_file) { + switch_curl_easy_setopt(curl_handle, CURLOPT_CAINFO, client->profile->ssl_cacert_file); + } + + if (client->profile->enable_ssl_verifyhost) { + switch_curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 2); + } + + if (client->profile->cookie_file) { + switch_curl_easy_setopt(curl_handle, CURLOPT_COOKIEJAR, client->profile->cookie_file); + switch_curl_easy_setopt(curl_handle, CURLOPT_COOKIEFILE, client->profile->cookie_file); + } else { + switch_curl_easy_setopt(curl_handle, CURLOPT_COOKIE, ""); + } + + if (client->profile->bind_local) { + curl_easy_setopt(curl_handle, CURLOPT_INTERFACE, client->profile->bind_local); + } + if (save_path) { switch_curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, save_file_callback); - switch_curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *) &client); + switch_curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *) client); } else { switch_curl_easy_setopt(curl_handle, CURLOPT_HEADER, 1); switch_curl_easy_setopt(curl_handle, CURLOPT_NOBODY, 1); } if (headers) { - switch_event_create(&client.headers, SWITCH_EVENT_CLONE); + switch_event_create(&client->headers, SWITCH_EVENT_CLONE); if (save_path) { switch_curl_easy_setopt(curl_handle, CURLOPT_HEADERFUNCTION, get_header_callback); - switch_curl_easy_setopt(curl_handle, CURLOPT_WRITEHEADER, (void *) &client); + switch_curl_easy_setopt(curl_handle, CURLOPT_WRITEHEADER, (void *) client); } else { switch_curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, get_header_callback); - switch_curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *) &client); + switch_curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *) client); } } @@ -2516,19 +2598,20 @@ static switch_status_t fetch_cache_data(http_file_context_t *context, const char switch_curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &code); switch_curl_easy_cleanup(curl_handle); - if (client.fd > -1) { - close(client.fd); + if (client->fd > -1) { + close(client->fd); } - if (headers && client.headers) { - switch_event_add_header(client.headers, SWITCH_STACK_BOTTOM, "http-response-code", "%ld", code); - *headers = client.headers; + if (headers && client->headers) { + switch_event_add_header(client->headers, SWITCH_STACK_BOTTOM, "http-response-code", "%ld", code); + *headers = client->headers; + client->headers = NULL; } switch(code) { case 200: if (save_path) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "caching: url:%s to %s (%" SWITCH_SIZE_T_FMT " bytes)\n", url, save_path, client.bytes); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "caching: url:%s to %s (%" SWITCH_SIZE_T_FMT " bytes)\n", url, save_path, client->bytes); } status = SWITCH_STATUS_SUCCESS; break; @@ -2544,7 +2627,7 @@ static switch_status_t fetch_cache_data(http_file_context_t *context, const char switch_safe_free(dynamic_url); switch_safe_free(dup_creds); - + client_destroy(&client); return status; } @@ -2704,6 +2787,7 @@ static switch_status_t locate_url_file(http_file_context_t *context, const char if (switch_file_exists(context->cache_file, context->pool) != SWITCH_STATUS_SUCCESS && unreachable) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "File at url [%s] is unreachable!\n", url); + status = SWITCH_STATUS_NOTFOUND; goto end; } diff --git a/src/mod/applications/mod_http_cache/aws.c b/src/mod/applications/mod_http_cache/aws.c index 58c4b4d917..cb637f8ad0 100644 --- a/src/mod/applications/mod_http_cache/aws.c +++ b/src/mod/applications/mod_http_cache/aws.c @@ -1,6 +1,6 @@ /* * aws.c for FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application - * Copyright (C) 2013, Grasshopper + * Copyright (C) 2013-2014, Grasshopper * * Version: MPL 1.1 * @@ -41,8 +41,18 @@ * @param url to check * @return true if this is an S3 url */ -int aws_s3_is_s3_url(const char *url) +int aws_s3_is_s3_url(const char *url, const char *base_domain) { + if (!zstr(base_domain)) { + char *base_domain_escaped; + char regex[1024]; + int result; + base_domain_escaped = switch_string_replace(base_domain, ".", "\\."); + switch_snprintf(regex, 1024, "^https?://\\w[-\\w.]{1,61}\\w\\.%s/.*$", base_domain_escaped); + result = !zstr(url) && switch_regex_match(url, regex) == SWITCH_STATUS_SUCCESS; + switch_safe_free(base_domain_escaped); + return result; + } /* AWS bucket naming rules are complex... this match only supports virtual hosting of buckets */ return !zstr(url) && switch_regex_match(url, "^https?://\\w[-\\w.]{1,61}\\w\\.s3([-\\w]+)?\\.amazonaws\\.com/.*$") == SWITCH_STATUS_SUCCESS; } @@ -141,10 +151,11 @@ static char *my_strrstr(const char *haystack, const char *needle) /** * Parse bucket and object from URL * @param url to parse. This value is modified. + * @param base_domain of URL (assumes s3.amazonaws.com if not specified) * @param bucket to store result in * @param bucket_length of result buffer */ -void aws_s3_parse_url(char *url, char **bucket, char **object) +void aws_s3_parse_url(char *url, const char *base_domain, char **bucket, char **object) { char *bucket_start = NULL; char *bucket_end; @@ -153,7 +164,7 @@ void aws_s3_parse_url(char *url, char **bucket, char **object) *bucket = NULL; *object = NULL; - if (!aws_s3_is_s3_url(url)) { + if (!aws_s3_is_s3_url(url, base_domain)) { return; } @@ -167,8 +178,15 @@ void aws_s3_parse_url(char *url, char **bucket, char **object) /* invalid URL */ return; } - - bucket_end = my_strrstr(bucket_start, ".s3"); + + { + char base_domain_match[1024]; + if (zstr(base_domain)) { + base_domain = "s3"; + } + switch_snprintf(base_domain_match, 1024, ".%s", base_domain); + bucket_end = my_strrstr(bucket_start, base_domain_match); + } if (!bucket_end) { /* invalid URL */ return; @@ -195,6 +213,7 @@ void aws_s3_parse_url(char *url, char **bucket, char **object) * Create a pre-signed URL for AWS S3 * @param verb (PUT/GET) * @param url address (virtual-host-style) + * @param base_domain (optional - amazon aws assumed if not specified) * @param content_type optional content type * @param content_md5 optional content MD5 checksum * @param aws_access_key_id secret access key identifier @@ -202,7 +221,7 @@ void aws_s3_parse_url(char *url, char **bucket, char **object) * @param expires seconds since the epoch * @return presigned_url */ -char *aws_s3_presigned_url_create(const char *verb, const char *url, const char *content_type, const char *content_md5, const char *aws_access_key_id, const char *aws_secret_access_key, const char *expires) +char *aws_s3_presigned_url_create(const char *verb, const char *url, const char *base_domain, const char *content_type, const char *content_md5, const char *aws_access_key_id, const char *aws_secret_access_key, const char *expires) { char signature[S3_SIGNATURE_LENGTH_MAX]; char signature_url_encoded[S3_SIGNATURE_LENGTH_MAX]; @@ -212,7 +231,7 @@ char *aws_s3_presigned_url_create(const char *verb, const char *url, const char char *object; /* create URL encoded signature */ - aws_s3_parse_url(url_dup, &bucket, &object); + aws_s3_parse_url(url_dup, base_domain, &bucket, &object); string_to_sign = aws_s3_string_to_sign(verb, bucket, object, content_type, content_md5, expires); signature[0] = '\0'; aws_s3_signature(signature, S3_SIGNATURE_LENGTH_MAX, string_to_sign, aws_secret_access_key); @@ -230,6 +249,7 @@ char *aws_s3_presigned_url_create(const char *verb, const char *url, const char * @param authentication_length maximum result length * @param verb (PUT/GET) * @param url address (virtual-host-style) + * @param base_domain (optional - amazon aws assumed if not specified) * @param content_type optional content type * @param content_md5 optional content MD5 checksum * @param aws_access_key_id secret access key identifier @@ -237,7 +257,7 @@ char *aws_s3_presigned_url_create(const char *verb, const char *url, const char * @param date header * @return signature for Authorization header */ -char *aws_s3_authentication_create(const char *verb, const char *url, const char *content_type, const char *content_md5, const char *aws_access_key_id, const char *aws_secret_access_key, const char *date) +char *aws_s3_authentication_create(const char *verb, const char *url, const char *base_domain, const char *content_type, const char *content_md5, const char *aws_access_key_id, const char *aws_secret_access_key, const char *date) { char signature[S3_SIGNATURE_LENGTH_MAX]; char *string_to_sign; @@ -246,7 +266,7 @@ char *aws_s3_authentication_create(const char *verb, const char *url, const char char *object; /* create base64 encoded signature */ - aws_s3_parse_url(url_dup, &bucket, &object); + aws_s3_parse_url(url_dup, base_domain, &bucket, &object); string_to_sign = aws_s3_string_to_sign(verb, bucket, object, content_type, content_md5, date); signature[0] = '\0'; aws_s3_signature(signature, S3_SIGNATURE_LENGTH_MAX, string_to_sign, aws_secret_access_key); diff --git a/src/mod/applications/mod_http_cache/aws.h b/src/mod/applications/mod_http_cache/aws.h index d86f75f1dc..e95001d026 100644 --- a/src/mod/applications/mod_http_cache/aws.h +++ b/src/mod/applications/mod_http_cache/aws.h @@ -1,6 +1,6 @@ /* * aws.h for FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application - * Copyright (C) 2013, Grasshopper + * Copyright (C) 2013-2014, Grasshopper * * Version: MPL 1.1 * @@ -34,12 +34,12 @@ /* (SHA1_LENGTH * 1.37 base64 bytes per byte * 3 url-encoded bytes per byte) */ #define S3_SIGNATURE_LENGTH_MAX 83 -int aws_s3_is_s3_url(const char *url); -void aws_s3_parse_url(char *url, char **bucket, char **object); +int aws_s3_is_s3_url(const char *url, const char *base_domain); +void aws_s3_parse_url(char *url, const char *base_domain, char **bucket, char **object); char *aws_s3_string_to_sign(const char *verb, const char *bucket, const char *object, const char *content_type, const char *content_md5, const char *date); char *aws_s3_signature(char *signature, int signature_length, const char *string_to_sign, const char *aws_secret_access_key); -char *aws_s3_presigned_url_create(const char *verb, const char *url, const char *content_type, const char *content_md5, const char *aws_access_key_id, const char *aws_secret_access_key, const char *expires); -char *aws_s3_authentication_create(const char *verb, const char *url, const char *content_type, const char *content_md5, const char *aws_access_key_id, const char *aws_secret_access_key, const char *date); +char *aws_s3_presigned_url_create(const char *verb, const char *url, const char *base_domain, const char *content_type, const char *content_md5, const char *aws_access_key_id, const char *aws_secret_access_key, const char *expires); +char *aws_s3_authentication_create(const char *verb, const char *url, const char *base_domain, const char *content_type, const char *content_md5, const char *aws_access_key_id, const char *aws_secret_access_key, const char *date); #endif diff --git a/src/mod/applications/mod_http_cache/conf/autoload_configs/http_cache.conf.xml b/src/mod/applications/mod_http_cache/conf/autoload_configs/http_cache.conf.xml index ce68ea09b0..6e2698bf90 100644 --- a/src/mod/applications/mod_http_cache/conf/autoload_configs/http_cache.conf.xml +++ b/src/mod/applications/mod_http_cache/conf/autoload_configs/http_cache.conf.xml @@ -18,6 +18,7 @@ + diff --git a/src/mod/applications/mod_http_cache/mod_http_cache.c b/src/mod/applications/mod_http_cache/mod_http_cache.c index f1ec2b69ed..8a7718ea49 100644 --- a/src/mod/applications/mod_http_cache/mod_http_cache.c +++ b/src/mod/applications/mod_http_cache/mod_http_cache.c @@ -1,6 +1,6 @@ /* * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application - * Copyright (C) 2005-2013, Anthony Minessale II + * Copyright (C) 2005-2014, Anthony Minessale II * * Version: MPL 1.1 * @@ -61,6 +61,7 @@ struct http_profile { const char *name; const char *aws_s3_access_key_id; const char *aws_s3_secret_access_key; + const char *aws_s3_base_domain; }; typedef struct http_profile http_profile_t; @@ -201,7 +202,7 @@ static void url_cache_unlock(url_cache_t *cache, switch_core_session_t *session) static void url_cache_clear(url_cache_t *cache, switch_core_session_t *session); static http_profile_t *url_cache_http_profile_find(url_cache_t *cache, const char *name); static http_profile_t *url_cache_http_profile_find_by_fqdn(url_cache_t *cache, const char *url); -static http_profile_t *url_cache_http_profile_add(url_cache_t *cache, const char *name, const char *aws_s3_access_key_id, const char *aws_s3_secret_access_key); +static http_profile_t *url_cache_http_profile_add(url_cache_t *cache, const char *name, const char *aws_s3_access_key_id, const char *aws_s3_secret_access_key, const char *aws_s3_base_domain); static switch_curl_slist_t *append_aws_s3_headers(switch_curl_slist_t *headers, http_profile_t *profile, const char *verb, const char *content_type, const char *url); @@ -792,7 +793,7 @@ static http_profile_t *url_cache_http_profile_find_by_fqdn(url_cache_t *cache, c /** * Add a profile to the cache */ -static http_profile_t *url_cache_http_profile_add(url_cache_t *cache, const char *name, const char *aws_s3_access_key_id, const char *aws_s3_secret_access_key) +static http_profile_t *url_cache_http_profile_add(url_cache_t *cache, const char *name, const char *aws_s3_access_key_id, const char *aws_s3_secret_access_key, const char *aws_s3_base_domain) { http_profile_t *profile = switch_core_alloc(cache->pool, sizeof(*profile)); profile->name = switch_core_strdup(cache->pool, name); @@ -802,6 +803,10 @@ static http_profile_t *url_cache_http_profile_add(url_cache_t *cache, const char if (aws_s3_secret_access_key) { profile->aws_s3_secret_access_key = switch_core_strdup(cache->pool, aws_s3_secret_access_key); } + if (aws_s3_base_domain) { + profile->aws_s3_base_domain = switch_core_strdup(cache->pool, aws_s3_base_domain); + } + switch_core_hash_insert(cache->profiles, profile->name, profile); return profile; } @@ -919,7 +924,7 @@ static void cached_url_destroy(cached_url_t *url, switch_memory_pool_t *pool) static switch_curl_slist_t *append_aws_s3_headers(switch_curl_slist_t *headers, http_profile_t *profile, const char *verb, const char *content_type, const char *url) { /* check if Amazon headers are needed */ - if (profile && profile->aws_s3_access_key_id && aws_s3_is_s3_url(url)) { + if (profile && profile->aws_s3_access_key_id && aws_s3_is_s3_url(url, profile->aws_s3_base_domain)) { char date[256]; char header[1024]; char *authenticate; @@ -930,7 +935,7 @@ static switch_curl_slist_t *append_aws_s3_headers(switch_curl_slist_t *headers, headers = switch_curl_slist_append(headers, header); /* Authorization: */ - authenticate = aws_s3_authentication_create(verb, url, content_type, "", profile->aws_s3_access_key_id, profile->aws_s3_secret_access_key, date); + authenticate = aws_s3_authentication_create(verb, url, profile->aws_s3_base_domain, content_type, "", profile->aws_s3_access_key_id, profile->aws_s3_secret_access_key, date); snprintf(header, 1024, "Authorization: %s", authenticate); free(authenticate); headers = switch_curl_slist_append(headers, header); @@ -1397,7 +1402,9 @@ static switch_status_t do_config(url_cache_t *cache) switch_xml_t s3 = switch_xml_child(profile, "aws-s3"); char *access_key_id = NULL; char *secret_access_key = NULL; + char *base_domain = NULL; if (s3) { + switch_xml_t base_domain_xml = switch_xml_child(s3, "base-domain"); switch_xml_t id = switch_xml_child(s3, "access-key-id"); switch_xml_t secret = switch_xml_child(s3, "secret-access-key"); if (id && secret) { @@ -1412,12 +1419,21 @@ static switch_status_t do_config(url_cache_t *cache) } } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Missing key id or secret\n"); + continue; + } + if (base_domain_xml) { + base_domain = switch_strip_whitespace(switch_xml_txt(base_domain_xml)); + if (zstr(base_domain)) { + switch_safe_free(base_domain); + base_domain = NULL; + } } } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Adding profile \"%s\" to cache\n", name); - profile_obj = url_cache_http_profile_add(cache, name, access_key_id, secret_access_key); + profile_obj = url_cache_http_profile_add(cache, name, access_key_id, secret_access_key, base_domain); switch_safe_free(access_key_id); switch_safe_free(secret_access_key); + switch_safe_free(base_domain); domains = switch_xml_child(profile, "domains"); if (domains) { diff --git a/src/mod/applications/mod_http_cache/test_aws/main.c b/src/mod/applications/mod_http_cache/test_aws/main.c index f661c5954f..e36c746819 100644 --- a/src/mod/applications/mod_http_cache/test_aws/main.c +++ b/src/mod/applications/mod_http_cache/test_aws/main.c @@ -41,24 +41,28 @@ static void test_signature(void) */ static void test_check_url(void) { - ASSERT_TRUE(aws_s3_is_s3_url("http://bucket.s3-us-west-1.amazonaws.com/object.ext")); - ASSERT_TRUE(aws_s3_is_s3_url("https://bucket.s3-us-west-1.amazonaws.com/object.ext")); - ASSERT_TRUE(aws_s3_is_s3_url("http://bucket.s3.amazonaws.com/object.ext")); - ASSERT_TRUE(aws_s3_is_s3_url("http://bucket.s3.amazonaws.com/object.ext")); - ASSERT_TRUE(aws_s3_is_s3_url("http://bucket.s3.amazonaws.com/object")); - ASSERT_TRUE(aws_s3_is_s3_url("http://red.bucket.s3.amazonaws.com/object.ext")); - ASSERT_TRUE(aws_s3_is_s3_url("https://bucket.s3.amazonaws.com/object.ext")); - ASSERT_TRUE(aws_s3_is_s3_url("https://bucket.s3.amazonaws.com/object")); - ASSERT_TRUE(aws_s3_is_s3_url("https://bucket.s3.amazonaws.com/recordings/1240fwjf8we.mp3")); - ASSERT_TRUE(aws_s3_is_s3_url("https://bucket.s3.amazonaws.com/en/us/8000/1232345.mp3")); - ASSERT_TRUE(aws_s3_is_s3_url("https://bucket_with_underscore.s3.amazonaws.com/en/us/8000/1232345.mp3")); - ASSERT_FALSE(aws_s3_is_s3_url("bucket.s3.amazonaws.com/object.ext")); - ASSERT_FALSE(aws_s3_is_s3_url("https://s3.amazonaws.com/bucket/object")); - ASSERT_FALSE(aws_s3_is_s3_url("http://s3.amazonaws.com/bucket/object")); - ASSERT_FALSE(aws_s3_is_s3_url("http://google.com/")); - ASSERT_FALSE(aws_s3_is_s3_url("http://phono.com/audio/troporocks.mp3")); - ASSERT_FALSE(aws_s3_is_s3_url("")); - ASSERT_FALSE(aws_s3_is_s3_url(NULL)); + ASSERT_TRUE(aws_s3_is_s3_url("http://bucket.s3-us-west-1.amazonaws.com/object.ext", NULL)); + ASSERT_TRUE(aws_s3_is_s3_url("https://bucket.s3-us-west-1.amazonaws.com/object.ext", NULL)); + ASSERT_TRUE(aws_s3_is_s3_url("http://bucket.s3.amazonaws.com/object.ext", NULL)); + ASSERT_TRUE(aws_s3_is_s3_url("http://bucket.s3.amazonaws.com/object.ext", NULL)); + ASSERT_TRUE(aws_s3_is_s3_url("http://bucket.s3.amazonaws.com/object", NULL)); + ASSERT_TRUE(aws_s3_is_s3_url("http://red.bucket.s3.amazonaws.com/object.ext", NULL)); + ASSERT_TRUE(aws_s3_is_s3_url("https://bucket.s3.amazonaws.com/object.ext", NULL)); + ASSERT_TRUE(aws_s3_is_s3_url("https://bucket.s3.amazonaws.com/object", NULL)); + ASSERT_TRUE(aws_s3_is_s3_url("https://bucket.s3.amazonaws.com/recordings/1240fwjf8we.mp3", NULL)); + ASSERT_TRUE(aws_s3_is_s3_url("https://bucket.s3.amazonaws.com/en/us/8000/1232345.mp3", NULL)); + ASSERT_TRUE(aws_s3_is_s3_url("https://bucket_with_underscore.s3.amazonaws.com/en/us/8000/1232345.mp3", NULL)); + ASSERT_FALSE(aws_s3_is_s3_url("bucket.s3.amazonaws.com/object.ext", NULL)); + ASSERT_FALSE(aws_s3_is_s3_url("https://s3.amazonaws.com/bucket/object", NULL)); + ASSERT_FALSE(aws_s3_is_s3_url("http://s3.amazonaws.com/bucket/object", NULL)); + ASSERT_FALSE(aws_s3_is_s3_url("http://google.com/", NULL)); + ASSERT_FALSE(aws_s3_is_s3_url("http://phono.com/audio/troporocks.mp3", NULL)); + ASSERT_FALSE(aws_s3_is_s3_url("", NULL)); + ASSERT_FALSE(aws_s3_is_s3_url(NULL, NULL)); + ASSERT_FALSE(aws_s3_is_s3_url("https://example.com/bucket/object", "example.com")); + ASSERT_TRUE(aws_s3_is_s3_url("http://bucket.example.com/object", "example.com")); + ASSERT_FALSE(aws_s3_is_s3_url("", "example.com")); + ASSERT_FALSE(aws_s3_is_s3_url(NULL, "example.com")); } /** @@ -68,51 +72,55 @@ static void test_parse_url(void) { char *bucket; char *object; - aws_s3_parse_url(strdup("http://quotes.s3.amazonaws.com/nelson"), &bucket, &object); + aws_s3_parse_url(strdup("http://quotes.s3.amazonaws.com/nelson"), NULL, &bucket, &object); ASSERT_STRING_EQUALS("quotes", bucket); ASSERT_STRING_EQUALS("nelson", object); - aws_s3_parse_url(strdup("https://quotes.s3.amazonaws.com/nelson.mp3"), &bucket, &object); + aws_s3_parse_url(strdup("https://quotes.s3.amazonaws.com/nelson.mp3"), NULL, &bucket, &object); ASSERT_STRING_EQUALS("quotes", bucket); ASSERT_STRING_EQUALS("nelson.mp3", object); - aws_s3_parse_url(strdup("http://s3.amazonaws.com/quotes/nelson"), &bucket, &object); + aws_s3_parse_url(strdup("http://s3.amazonaws.com/quotes/nelson"), NULL, &bucket, &object); ASSERT_NULL(bucket); ASSERT_NULL(object); - aws_s3_parse_url(strdup("http://quotes/quotes/nelson"), &bucket, &object); + aws_s3_parse_url(strdup("http://quotes/quotes/nelson"), NULL, &bucket, &object); ASSERT_NULL(bucket); ASSERT_NULL(object); - aws_s3_parse_url(strdup("http://quotes.s3.amazonaws.com/"), &bucket, &object); + aws_s3_parse_url(strdup("http://quotes.s3.amazonaws.com/"), NULL, &bucket, &object); ASSERT_NULL(bucket); ASSERT_NULL(object); - aws_s3_parse_url(strdup("http://quotes.s3.amazonaws.com"), &bucket, &object); + aws_s3_parse_url(strdup("http://quotes.s3.amazonaws.com"), NULL, &bucket, &object); ASSERT_NULL(bucket); ASSERT_NULL(object); - aws_s3_parse_url(strdup("http://quotes"), &bucket, &object); + aws_s3_parse_url(strdup("http://quotes"), NULL, &bucket, &object); ASSERT_NULL(bucket); ASSERT_NULL(object); - aws_s3_parse_url(strdup(""), &bucket, &object); + aws_s3_parse_url(strdup(""), NULL, &bucket, &object); ASSERT_NULL(bucket); ASSERT_NULL(object); - aws_s3_parse_url(NULL, &bucket, &object); + aws_s3_parse_url(NULL, NULL, &bucket, &object); ASSERT_NULL(bucket); ASSERT_NULL(object); - aws_s3_parse_url(strdup("http://bucket.s3.amazonaws.com/voicemails/recording.wav"), &bucket, &object); + aws_s3_parse_url(strdup("http://bucket.s3.amazonaws.com/voicemails/recording.wav"), NULL, &bucket, &object); ASSERT_STRING_EQUALS("bucket", bucket); ASSERT_STRING_EQUALS("voicemails/recording.wav", object); - aws_s3_parse_url(strdup("https://my-bucket-with-dash.s3-us-west-2.amazonaws.com/greeting/file/1002/Lumino.mp3"), &bucket, &object); + aws_s3_parse_url(strdup("https://my-bucket-with-dash.s3-us-west-2.amazonaws.com/greeting/file/1002/Lumino.mp3"), NULL, &bucket, &object); ASSERT_STRING_EQUALS("my-bucket-with-dash", bucket); ASSERT_STRING_EQUALS("greeting/file/1002/Lumino.mp3", object); - aws_s3_parse_url(strdup("http://quotes.s3.foo.bar.s3.amazonaws.com/greeting/file/1002/Lumino.mp3"), &bucket, &object); + aws_s3_parse_url(strdup("http://quotes.s3.foo.bar.s3.amazonaws.com/greeting/file/1002/Lumino.mp3"), NULL, &bucket, &object); + ASSERT_STRING_EQUALS("quotes.s3.foo.bar", bucket); + ASSERT_STRING_EQUALS("greeting/file/1002/Lumino.mp3", object); + + aws_s3_parse_url(strdup("http://quotes.s3.foo.bar.example.com/greeting/file/1002/Lumino.mp3"), "example.com", &bucket, &object); ASSERT_STRING_EQUALS("quotes.s3.foo.bar", bucket); ASSERT_STRING_EQUALS("greeting/file/1002/Lumino.mp3", object); } @@ -122,7 +130,9 @@ static void test_parse_url(void) */ static void test_authorization_header(void) { - ASSERT_STRING_EQUALS("AWS AKIAIOSFODNN7EXAMPLE:YJkomOaqUJlvEluDq4fpusID38Y=", aws_s3_authentication_create("GET", "https://vault.s3.amazonaws.com/awesome.mp3", "audio/mpeg", "", "AKIAIOSFODNN7EXAMPLE", "0123456789012345678901234567890123456789", "1234567890")); + ASSERT_STRING_EQUALS("AWS AKIAIOSFODNN7EXAMPLE:YJkomOaqUJlvEluDq4fpusID38Y=", aws_s3_authentication_create("GET", "https://vault.s3.amazonaws.com/awesome.mp3", NULL, "audio/mpeg", "", "AKIAIOSFODNN7EXAMPLE", "0123456789012345678901234567890123456789", "1234567890")); + ASSERT_STRING_EQUALS("AWS AKIAIOSFODNN7EXAMPLE:YJkomOaqUJlvEluDq4fpusID38Y=", aws_s3_authentication_create("GET", "https://vault.s3.amazonaws.com/awesome.mp3", "s3.amazonaws.com", "audio/mpeg", "", "AKIAIOSFODNN7EXAMPLE", "0123456789012345678901234567890123456789", "1234567890")); + ASSERT_STRING_EQUALS("AWS AKIAIOSFODNN7EXAMPLE:YJkomOaqUJlvEluDq4fpusID38Y=", aws_s3_authentication_create("GET", "https://vault.example.com/awesome.mp3", "example.com", "audio/mpeg", "", "AKIAIOSFODNN7EXAMPLE", "0123456789012345678901234567890123456789", "1234567890")); } /** @@ -130,7 +140,9 @@ static void test_authorization_header(void) */ static void test_presigned_url(void) { - ASSERT_STRING_EQUALS("https://vault.s3.amazonaws.com/awesome.mp3?Signature=YJkomOaqUJlvEluDq4fpusID38Y%3D&Expires=1234567890&AWSAccessKeyId=AKIAIOSFODNN7EXAMPLE", aws_s3_presigned_url_create("GET", "https://vault.s3.amazonaws.com/awesome.mp3", "audio/mpeg", "", "AKIAIOSFODNN7EXAMPLE", "0123456789012345678901234567890123456789", "1234567890")); + ASSERT_STRING_EQUALS("https://vault.s3.amazonaws.com/awesome.mp3?Signature=YJkomOaqUJlvEluDq4fpusID38Y%3D&Expires=1234567890&AWSAccessKeyId=AKIAIOSFODNN7EXAMPLE", aws_s3_presigned_url_create("GET", "https://vault.s3.amazonaws.com/awesome.mp3", NULL, "audio/mpeg", "", "AKIAIOSFODNN7EXAMPLE", "0123456789012345678901234567890123456789", "1234567890")); + ASSERT_STRING_EQUALS("https://vault.s3.amazonaws.com/awesome.mp3?Signature=YJkomOaqUJlvEluDq4fpusID38Y%3D&Expires=1234567890&AWSAccessKeyId=AKIAIOSFODNN7EXAMPLE", aws_s3_presigned_url_create("GET", "https://vault.s3.amazonaws.com/awesome.mp3", "s3.amazonaws.com", "audio/mpeg", "", "AKIAIOSFODNN7EXAMPLE", "0123456789012345678901234567890123456789", "1234567890")); + ASSERT_STRING_EQUALS("https://vault.example.com/awesome.mp3?Signature=YJkomOaqUJlvEluDq4fpusID38Y%3D&Expires=1234567890&AWSAccessKeyId=AKIAIOSFODNN7EXAMPLE", aws_s3_presigned_url_create("GET", "https://vault.example.com/awesome.mp3", "example.com", "audio/mpeg", "", "AKIAIOSFODNN7EXAMPLE", "0123456789012345678901234567890123456789", "1234567890")); } /** diff --git a/src/mod/applications/mod_redis/mod_redis.c b/src/mod/applications/mod_redis/mod_redis.c index 5e84b196e9..1f8877b6a1 100644 --- a/src/mod/applications/mod_redis/mod_redis.c +++ b/src/mod/applications/mod_redis/mod_redis.c @@ -40,6 +40,7 @@ static struct{ char *host; int port; int timeout; + switch_bool_t ignore_connect_fail; } globals; static switch_xml_config_item_t instructions[] = { @@ -47,6 +48,7 @@ static switch_xml_config_item_t instructions[] = { SWITCH_CONFIG_ITEM_STRING_STRDUP("host", CONFIG_RELOAD, &globals.host, NULL, "localhost", "Hostname for redis server"), SWITCH_CONFIG_ITEM("port", SWITCH_CONFIG_INT, CONFIG_RELOADABLE, &globals.port, (void *) 6379, NULL,NULL, NULL), SWITCH_CONFIG_ITEM("timeout", SWITCH_CONFIG_INT, CONFIG_RELOADABLE, &globals.timeout, (void *) 10000, NULL,NULL, NULL), + SWITCH_CONFIG_ITEM("ignore_connect_fail", SWITCH_CONFIG_BOOL, CONFIG_RELOADABLE, &globals.ignore_connect_fail, SWITCH_FALSE, NULL, "true|false", "Set to true in order to continue when redis is not contactable"), SWITCH_CONFIG_ITEM_END() }; @@ -85,9 +87,14 @@ SWITCH_LIMIT_INCR(limit_incr_redis) REDIS redis; if (redis_factory(&redis) != SWITCH_STATUS_SUCCESS) { - return SWITCH_STATUS_FALSE; + if ( globals.ignore_connect_fail ) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ignore_connect_fail=true, so ignoring the fact that redis was not contactabl and continuing with the call\n" ); + return SWITCH_STATUS_SUCCESS; + } else { + return SWITCH_STATUS_FALSE; + } } - + /* Get the keys for redis server */ uuid_rediskey = switch_core_session_sprintf(session,"%s_%s_%s", switch_core_get_switchname(), realm, resource); rediskey = switch_core_session_sprintf(session, "%s_%s", realm, resource); @@ -163,7 +170,13 @@ SWITCH_LIMIT_RELEASE(limit_release_redis) } if (redis_factory(&redis) != SWITCH_STATUS_SUCCESS) { - return SWITCH_STATUS_FALSE; + if ( globals.ignore_connect_fail ) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ignore_connect_fail=true, so ignoring the fact that redis was not contactabl and continuing with the call\n" ); + return SWITCH_STATUS_SUCCESS; + } else { + return SWITCH_STATUS_FALSE; + } + } switch_mutex_lock(pvt->mutex); diff --git a/src/mod/applications/mod_sms/mod_sms.c b/src/mod/applications/mod_sms/mod_sms.c index cb1d3a49dc..2283e5d3a2 100644 --- a/src/mod/applications/mod_sms/mod_sms.c +++ b/src/mod/applications/mod_sms/mod_sms.c @@ -522,6 +522,25 @@ SWITCH_STANDARD_CHAT_APP(set_function) return SWITCH_STATUS_SUCCESS; } +SWITCH_STANDARD_CHAT_APP(unset_function) +{ + char *var; + + if (!data) return SWITCH_STATUS_SUCCESS; + + var = strdup(data); + + if (!var) return SWITCH_STATUS_SUCCESS; + + if (!zstr(var)) { + switch_event_del_header(message, var); + } + + free(var); + + return SWITCH_STATUS_SUCCESS; +} + SWITCH_STANDARD_CHAT_APP(fire_function) { switch_event_t *fireme; @@ -573,6 +592,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_sms_load) SWITCH_ADD_CHAT_APP(chat_app_interface, "reply", "reply to a message", "reply to a message", reply_function, "", SCAF_NONE); SWITCH_ADD_CHAT_APP(chat_app_interface, "stop", "stop execution", "stop execution", stop_function, "", SCAF_NONE); SWITCH_ADD_CHAT_APP(chat_app_interface, "set", "set a variable", "set a variable", set_function, "", SCAF_NONE); + SWITCH_ADD_CHAT_APP(chat_app_interface, "unset", "unset a variable", "unset a variable", unset_function, "", SCAF_NONE); SWITCH_ADD_CHAT_APP(chat_app_interface, "send", "send the message as-is", "send the message as-is", send_function, "", SCAF_NONE); SWITCH_ADD_CHAT_APP(chat_app_interface, "fire", "fire the message", "fire the message", fire_function, "", SCAF_NONE); SWITCH_ADD_CHAT_APP(chat_app_interface, "system", "execute a system command", "execute a sytem command", system_function, "", SCAF_NONE); diff --git a/src/mod/applications/mod_spandsp/mod_spandsp.c b/src/mod/applications/mod_spandsp/mod_spandsp.c index 5cd3b1ebf8..12a8a95948 100644 --- a/src/mod/applications/mod_spandsp/mod_spandsp.c +++ b/src/mod/applications/mod_spandsp/mod_spandsp.c @@ -788,12 +788,12 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_spandsp_init) if (mod_spandsp_dsp_load(module_interface, pool) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't load or process spandsp.conf, not adding tone_detect applications\n"); } else { - SWITCH_ADD_APP(app_interface, "start_tone_detect", "Start background tone detection with cadence", "", start_tone_detect_app, "", SAF_NONE); - SWITCH_ADD_APP(app_interface, "stop_tone_detect", "Stop background tone detection with cadence", "", stop_tone_detect_app, "", SAF_NONE); - SWITCH_ADD_API(api_interface, "start_tone_detect", "Start background tone detection with cadence", start_tone_detect_api, " "); - SWITCH_ADD_API(api_interface, "stop_tone_detect", "Stop background tone detection with cadence", stop_tone_detect_api, ""); - switch_console_set_complete("add start_tone_detect ::console::list_uuid"); - switch_console_set_complete("add stop_tone_detect ::console::list_uuid"); + SWITCH_ADD_APP(app_interface, "spandsp_start_tone_detect", "Start background tone detection with cadence", "", start_tone_detect_app, "", SAF_NONE); + SWITCH_ADD_APP(app_interface, "spandsp_stop_tone_detect", "Stop background tone detection with cadence", "", stop_tone_detect_app, "", SAF_NONE); + SWITCH_ADD_API(api_interface, "spandsp_start_tone_detect", "Start background tone detection with cadence", start_tone_detect_api, " "); + SWITCH_ADD_API(api_interface, "spandsp_stop_tone_detect", "Stop background tone detection with cadence", stop_tone_detect_api, ""); + switch_console_set_complete("add spandsp_start_tone_detect ::console::list_uuid"); + switch_console_set_complete("add spandsp_stop_tone_detect ::console::list_uuid"); } SWITCH_ADD_API(api_interface, "start_tdd_detect", "Start background tdd detection", start_tdd_detect_api, ""); diff --git a/src/mod/codecs/mod_isac/typedefs.h b/src/mod/codecs/mod_isac/typedefs.h index ba87309638..e4a85afe30 100644 --- a/src/mod/codecs/mod_isac/typedefs.h +++ b/src/mod/codecs/mod_isac/typedefs.h @@ -76,6 +76,10 @@ //#define WEBRTC_ARCH_ARMEL #define WEBRTC_ARCH_32_BITS #define WEBRTC_ARCH_LITTLE_ENDIAN +#elif defined(__MIPSEB__) +#define WEBRTC_ARCH_BIG_ENDIAN +#elif defined(__MIPSEL__) +#define WEBRTC_ARCH_LITTLE_ENDIAN #else #error Please add support for your architecture in typedefs.h #endif diff --git a/src/mod/codecs/mod_opus/mod_opus.c b/src/mod/codecs/mod_opus/mod_opus.c index dfb939f3b8..dc51a653f1 100644 --- a/src/mod/codecs/mod_opus/mod_opus.c +++ b/src/mod/codecs/mod_opus/mod_opus.c @@ -42,6 +42,7 @@ struct opus_codec_settings { int useinbandfec; int usedtx; int maxaveragebitrate; + int maxplaybackrate; int stereo; int cbr; int sprop_maxcapturerate; @@ -57,6 +58,7 @@ static opus_codec_settings_t default_codec_settings = { /*.useinbandfec */ 1, /*.usedtx */ 1, /*.maxaveragebitrate */ 30000, + /*.maxplaybackrate */ 48000, /*.stereo*/ 0, /*.cbr*/ 0, /*.sprop_maxcapturerate*/ 0, @@ -76,6 +78,8 @@ struct opus_context { struct { int use_vbr; int complexity; + int maxaveragebitrate; + int maxplaybackrate; switch_mutex_t *mutex; } opus_prefs; @@ -151,52 +155,23 @@ static switch_status_t switch_opus_fmtp_parse(const char *fmtp, switch_codec_fmt if (!strcasecmp(data, "maxaveragebitrate")) { codec_settings->maxaveragebitrate = atoi(arg); - switch(codec_fmtp->actual_samples_per_second) { - case 8000: - { - if(codec_settings->maxaveragebitrate < 6000 || codec_settings->maxaveragebitrate > 20000) { - codec_settings->maxaveragebitrate = 20000; - } - break; - } - case 12000: - { - if(codec_settings->maxaveragebitrate < 7000 || codec_settings->maxaveragebitrate > 25000) { - codec_settings->maxaveragebitrate = 25000; - } - break; - } - case 16000: - { - if(codec_settings->maxaveragebitrate < 8000 || codec_settings->maxaveragebitrate > 30000) { - codec_settings->maxaveragebitrate = 30000; - } - break; - } - case 24000: - { - if(codec_settings->maxaveragebitrate < 12000 || codec_settings->maxaveragebitrate > 40000) { - codec_settings->maxaveragebitrate = 40000; - } - break; - } - - default: - /* this should never happen but 20000 is common among all rates */ - codec_settings->maxaveragebitrate = 20000; - break; + if ( codec_settings->maxaveragebitrate < 6000 || codec_settings->maxaveragebitrate > 510000 ) { + codec_settings->maxaveragebitrate = 0; /* values outside the range between 6000 and 510000 SHOULD be ignored */ } - - - codec_fmtp->bits_per_second = codec_settings->maxaveragebitrate; } + if (!strcasecmp(data, "maxplaybackrate")) { + codec_settings->maxplaybackrate = atoi(arg); + if ( codec_settings->maxplaybackrate != 8000 && codec_settings->maxplaybackrate != 12000 && codec_settings->maxplaybackrate != 16000 + && codec_settings->maxplaybackrate != 24000 && codec_settings->maxplaybackrate != 48000) { + codec_settings->maxplaybackrate = 0; /* value not supported */ + } + } } } } free(fmtp_dup); } - //codec_fmtp->bits_per_second = bit_rate; return SWITCH_STATUS_SUCCESS; } return SWITCH_STATUS_FALSE; @@ -216,7 +191,10 @@ static char *gen_fmtp(opus_codec_settings_t *settings, switch_memory_pool_t *poo if (settings->maxaveragebitrate) { snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "maxaveragebitrate=%d; ", settings->maxaveragebitrate); - + } + + if (settings->maxplaybackrate) { + snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "maxplaybackrate=%d; ", settings->maxplaybackrate); } if (settings->ptime) { @@ -264,6 +242,15 @@ static switch_status_t switch_opus_init(switch_codec_t *codec, switch_codec_flag memset(&codec_fmtp, '\0', sizeof(struct switch_codec_fmtp)); codec_fmtp.private_info = &opus_codec_settings; switch_opus_fmtp_parse(codec->fmtp_in, &codec_fmtp); + + /* Verify if the local or remote configuration are lowering maxaveragebitrate and/or maxplaybackrate */ + if ( opus_prefs.maxaveragebitrate && (opus_prefs.maxaveragebitrate < opus_codec_settings.maxaveragebitrate || !opus_codec_settings.maxaveragebitrate) ) { + opus_codec_settings.maxaveragebitrate = opus_prefs.maxaveragebitrate; + } + if ( opus_prefs.maxplaybackrate && (opus_prefs.maxplaybackrate < opus_codec_settings.maxplaybackrate || !opus_codec_settings.maxplaybackrate) ) { + opus_codec_settings.maxplaybackrate = opus_prefs.maxplaybackrate; + } + codec->fmtp_out = gen_fmtp(&opus_codec_settings, codec->memory_pool); if (encoding) { @@ -283,15 +270,39 @@ static switch_status_t switch_opus_init(switch_codec_t *codec, switch_codec_flag return SWITCH_STATUS_GENERR; } - opus_encoder_ctl(context->encoder_object, OPUS_SET_BITRATE(bitrate_bps)); - - if (codec->implementation->actual_samples_per_second == 8000) { - opus_encoder_ctl(context->encoder_object, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND)); - opus_encoder_ctl(context->encoder_object, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND)); + + /* Setting documented in "RTP Payload Format for Opus Speech and Audio Codec" draft-spittka-payload-rtp-opus-03 */ + if( opus_codec_settings.maxaveragebitrate ) { /* Remote codec settings found in SDP "fmtp", we accept to tune the Encoder */ + opus_encoder_ctl(context->encoder_object, OPUS_SET_BITRATE(opus_codec_settings.maxaveragebitrate)); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Opus encoder set bitrate based on maxaveragebitrate found in SDP [%dbps]\n", opus_codec_settings.maxaveragebitrate); } else { - opus_encoder_ctl(context->encoder_object, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND)); + /* Default codec settings used, may have been modified by SDP "samplerate" */ + opus_encoder_ctl(context->encoder_object, OPUS_SET_BITRATE(bitrate_bps)); + if (codec->implementation->actual_samples_per_second == 8000) { + opus_encoder_ctl(context->encoder_object, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND)); + opus_encoder_ctl(context->encoder_object, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND)); + } else { + opus_encoder_ctl(context->encoder_object, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND)); + } + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Opus encoder set bitrate to local settings [%dbps]\n", bitrate_bps); } - + + /* Another setting from "RTP Payload Format for Opus Speech and Audio Codec" */ + if ( opus_codec_settings.maxplaybackrate ) { + if (opus_codec_settings.maxplaybackrate == 8000) { /* Audio Bandwidth: 0-4000Hz Sampling Rate: 8000Hz */ + opus_encoder_ctl(context->encoder_object, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND)); + } else if (opus_codec_settings.maxplaybackrate == 12000) { /* Audio Bandwidth: 0-6000Hz Sampling Rate: 12000Hz */ + opus_encoder_ctl(context->encoder_object, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_MEDIUMBAND)); + } else if (opus_codec_settings.maxplaybackrate == 16000) { /* Audio Bandwidth: 0-8000Hz Sampling Rate: 16000Hz */ + opus_encoder_ctl(context->encoder_object, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_WIDEBAND)); + } else if (opus_codec_settings.maxplaybackrate == 24000) { /* Audio Bandwidth: 0-12000Hz Sampling Rate: 24000Hz */ + opus_encoder_ctl(context->encoder_object, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_SUPERWIDEBAND)); + } else if (opus_codec_settings.maxplaybackrate == 48000) { /* Audio Bandwidth: 0-20000Hz Sampling Rate: 48000Hz */ + opus_encoder_ctl(context->encoder_object, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND)); + } + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Opus encoder set bandwidth based on maxplaybackrate found in SDP [%dHz]\n", opus_codec_settings.maxplaybackrate); + } + if (use_vbr) { opus_encoder_ctl(context->encoder_object, OPUS_SET_VBR(use_vbr)); } @@ -428,6 +439,17 @@ static switch_status_t opus_load_config(switch_bool_t reload) opus_prefs.use_vbr = atoi(val); } else if (!strcasecmp(key, "complexity")) { opus_prefs.complexity = atoi(val); + } else if (!strcasecmp(key, "maxaveragebitrate")) { + opus_prefs.maxaveragebitrate = atoi(val); + if ( opus_prefs.maxaveragebitrate < 6000 || opus_prefs.maxaveragebitrate > 510000 ) { + opus_prefs.maxaveragebitrate = 0; /* values outside the range between 6000 and 510000 SHOULD be ignored */ + } + } else if (!strcasecmp(key, "maxplaybackrate")) { + opus_prefs.maxplaybackrate = atoi(val); + if ( opus_prefs.maxplaybackrate != 8000 && opus_prefs.maxplaybackrate != 12000 && opus_prefs.maxplaybackrate != 16000 + && opus_prefs.maxplaybackrate != 24000 && opus_prefs.maxplaybackrate != 48000) { + opus_prefs.maxplaybackrate = 0; /* value not supported */ + } } } } diff --git a/src/mod/dialplans/mod_dialplan_xml/mod_dialplan_xml.c b/src/mod/dialplans/mod_dialplan_xml/mod_dialplan_xml.c index b5ff5e63a6..71908b36f0 100644 --- a/src/mod/dialplans/mod_dialplan_xml/mod_dialplan_xml.c +++ b/src/mod/dialplans/mod_dialplan_xml/mod_dialplan_xml.c @@ -148,10 +148,15 @@ static int parse_exten(switch_core_session_t *session, switch_caller_profile_t * req_nest = switch_true(req_nesta); } - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, + if ( switch_core_test_flag(SCF_DIALPLAN_TIMESTAMPS) ) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%sDialplan: Processing recursive conditions level:%d [%s] require-nested=%s\n", space, recur, exten_name, req_nest ? "TRUE" : "FALSE"); - + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, + "%sDialplan: Processing recursive conditions level:%d [%s] require-nested=%s\n", space, + recur, exten_name, req_nest ? "TRUE" : "FALSE"); + } } else { if ((tmp = switch_xml_attr(xexten, "name"))) { exten_name = tmp; @@ -204,15 +209,27 @@ static int parse_exten(switch_core_session_t *session, switch_caller_profile_t * } if (time_match == 1) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, + if ( switch_core_test_flag(SCF_DIALPLAN_TIMESTAMPS) ) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%sDialplan: %s Date/Time Match (PASS) [%s] break=%s\n", space, switch_channel_get_name(channel), exten_name, do_break_a ? do_break_a : "on-false"); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, + "%sDialplan: %s Date/Time Match (PASS) [%s] break=%s\n", space, + switch_channel_get_name(channel), exten_name, do_break_a ? do_break_a : "on-false"); + } anti_action = SWITCH_FALSE; proceed = 1; } else if (time_match == 0) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, + if ( switch_core_test_flag(SCF_DIALPLAN_TIMESTAMPS) ) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%sDialplan: %s Date/TimeMatch (FAIL) [%s] break=%s\n", space, switch_channel_get_name(channel), exten_name, do_break_a ? do_break_a : "on-false"); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, + "%sDialplan: %s Date/TimeMatch (FAIL) [%s] break=%s\n", space, + switch_channel_get_name(channel), exten_name, do_break_a ? do_break_a : "on-false"); + } } @@ -230,14 +247,26 @@ static int parse_exten(switch_core_session_t *session, switch_caller_profile_t * time_match = switch_xml_std_datetime_check(xregex, tzoff ? &offset : NULL, tzname_); if (time_match == 1) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, + if ( switch_core_test_flag(SCF_DIALPLAN_TIMESTAMPS) ) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%sDialplan: %s Date/Time Match (PASS) [%s]\n", space, switch_channel_get_name(channel), exten_name); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, + "%sDialplan: %s Date/Time Match (PASS) [%s]\n", space, + switch_channel_get_name(channel), exten_name); + } anti_action = SWITCH_FALSE; } else if (time_match == 0) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, + if ( switch_core_test_flag(SCF_DIALPLAN_TIMESTAMPS) ) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%sDialplan: %s Date/TimeMatch (FAIL) [%s]\n", space, switch_channel_get_name(channel), exten_name); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, + "%sDialplan: %s Date/TimeMatch (FAIL) [%s]\n", space, + switch_channel_get_name(channel), exten_name); + } } @@ -273,22 +302,40 @@ static int parse_exten(switch_core_session_t *session, switch_caller_profile_t * } if ((proceed = switch_regex_perform(field_data, expression, &re, ovector, sizeof(ovector) / sizeof(ovector[0])))) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, + if ( switch_core_test_flag(SCF_DIALPLAN_TIMESTAMPS) ) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%sDialplan: %s Regex (PASS) [%s] %s(%s) =~ /%s/ match=%s\n", space, switch_channel_get_name(channel), exten_name, field, field_data, expression, all ? "all" : "any"); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, + "%sDialplan: %s Regex (PASS) [%s] %s(%s) =~ /%s/ match=%s\n", space, + switch_channel_get_name(channel), exten_name, field, field_data, expression, all ? "all" : "any"); + } pass++; if (!all && !xor) break; } else { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, + if ( switch_core_test_flag(SCF_DIALPLAN_TIMESTAMPS) ) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%sDialplan: %s Regex (FAIL) [%s] %s(%s) =~ /%s/ match=%s\n", space, switch_channel_get_name(channel), exten_name, field, field_data, expression, all ? "all" : "any"); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, + "%sDialplan: %s Regex (FAIL) [%s] %s(%s) =~ /%s/ match=%s\n", space, + switch_channel_get_name(channel), exten_name, field, field_data, expression, all ? "all" : "any"); + } fail++; if (all && !xor) break; } } else if (time_match == -1) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, + if ( switch_core_test_flag(SCF_DIALPLAN_TIMESTAMPS) ) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%sDialplan: %s Absolute Condition [%s] match=%s\n", space, switch_channel_get_name(channel), exten_name, all ? "all" : "any"); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, + "%sDialplan: %s Absolute Condition [%s] match=%s\n", space, + switch_channel_get_name(channel), exten_name, all ? "all" : "any"); + } pass++; proceed = 1; if (!all && !xor) break; @@ -367,19 +414,37 @@ static int parse_exten(switch_core_session_t *session, switch_caller_profile_t * } if ((proceed = switch_regex_perform(field_data, expression, &re, ovector, sizeof(ovector) / sizeof(ovector[0])))) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, + if ( switch_core_test_flag(SCF_DIALPLAN_TIMESTAMPS) ) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%sDialplan: %s Regex (PASS) [%s] %s(%s) =~ /%s/ break=%s\n", space, switch_channel_get_name(channel), exten_name, field, field_data, expression, do_break_a ? do_break_a : "on-false"); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, + "%sDialplan: %s Regex (PASS) [%s] %s(%s) =~ /%s/ break=%s\n", space, + switch_channel_get_name(channel), exten_name, field, field_data, expression, do_break_a ? do_break_a : "on-false"); + } anti_action = SWITCH_FALSE; } else { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, + if ( switch_core_test_flag(SCF_DIALPLAN_TIMESTAMPS) ) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%sDialplan: %s Regex (FAIL) [%s] %s(%s) =~ /%s/ break=%s\n", space, switch_channel_get_name(channel), exten_name, field, field_data, expression, do_break_a ? do_break_a : "on-false"); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, + "%sDialplan: %s Regex (FAIL) [%s] %s(%s) =~ /%s/ break=%s\n", space, + switch_channel_get_name(channel), exten_name, field, field_data, expression, do_break_a ? do_break_a : "on-false"); + } } } else if (time_match == -1) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, + if ( switch_core_test_flag(SCF_DIALPLAN_TIMESTAMPS) ) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%sDialplan: %s Absolute Condition [%s]\n", space, switch_channel_get_name(channel), exten_name); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, + "%sDialplan: %s Absolute Condition [%s]\n", space, + switch_channel_get_name(channel), exten_name); + } anti_action = SWITCH_FALSE; proceed = 1; } @@ -427,9 +492,15 @@ static int parse_exten(switch_core_session_t *session, switch_caller_profile_t * } for (;loop_count > 0; loop_count--) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, + if ( switch_core_test_flag(SCF_DIALPLAN_TIMESTAMPS) ) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%sDialplan: %s ANTI-Action %s(%s) %s\n", space, switch_channel_get_name(channel), application, data, xinline ? "INLINE" : ""); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, + "%sDialplan: %s ANTI-Action %s(%s) %s\n", space, + switch_channel_get_name(channel), application, data, xinline ? "INLINE" : ""); + } if (xinline) { exec_app(session, application, data); @@ -488,9 +559,15 @@ static int parse_exten(switch_core_session_t *session, switch_caller_profile_t * loop_count = atoi(loop); } for (;loop_count > 0; loop_count--) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, + if ( switch_core_test_flag(SCF_DIALPLAN_TIMESTAMPS) ) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%sDialplan: %s Action %s(%s) %s\n", space, switch_channel_get_name(channel), application, app_data, xinline ? "INLINE" : ""); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, + "%sDialplan: %s Action %s(%s) %s\n", space, + switch_channel_get_name(channel), application, app_data, xinline ? "INLINE" : ""); + } if (xinline) { exec_app(session, application, app_data); @@ -607,9 +684,15 @@ SWITCH_STANDARD_DIALPLAN(dialplan_hunt) exten_name = "UNKNOWN"; } - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, + if ( switch_core_test_flag(SCF_DIALPLAN_TIMESTAMPS) ) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Dialplan: %s parsing [%s->%s] continue=%s\n", switch_channel_get_name(channel), caller_profile->context, exten_name, cont ? cont : "false"); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, + "Dialplan: %s parsing [%s->%s] continue=%s\n", + switch_channel_get_name(channel), caller_profile->context, exten_name, cont ? cont : "false"); + } proceed = parse_exten(session, caller_profile, xexten, &extension, exten_name, 0); diff --git a/src/mod/endpoints/mod_skinny/mod_skinny.c b/src/mod/endpoints/mod_skinny/mod_skinny.c index 5f6bf1f14e..5925abebe4 100644 --- a/src/mod/endpoints/mod_skinny/mod_skinny.c +++ b/src/mod/endpoints/mod_skinny/mod_skinny.c @@ -954,27 +954,29 @@ int channel_on_hangup_callback(void *pArg, int argc, char **argv, char **columnN send_clear_prompt_status(listener, line_instance, call_id); } send_set_lamp(listener, SKINNY_BUTTON_LINE, line_instance, SKINNY_LAMP_OFF); - switch (helper->cause) { - case SWITCH_CAUSE_UNALLOCATED_NUMBER: - send_start_tone(listener, SKINNY_TONE_REORDER, 0, line_instance, call_id); - skinny_session_send_call_info(helper->tech_pvt->session, listener, line_instance); - label = skinny_textid2raw(SKINNY_TEXTID_UNKNOWN_NUMBER); - send_display_prompt_status(listener, 0, label, line_instance, call_id); - switch_safe_free(label); - break; - case SWITCH_CAUSE_USER_BUSY: - send_start_tone(listener, SKINNY_TONE_BUSYTONE, 0, line_instance, call_id); - label = skinny_textid2raw(SKINNY_TEXTID_BUSY); - send_display_prompt_status(listener, 0, label, line_instance, call_id); - switch_safe_free(label); - break; - case SWITCH_CAUSE_NORMAL_CLEARING: - send_clear_prompt_status(listener, line_instance, call_id); - break; - default: - send_display_prompt_status(listener, 0, switch_channel_cause2str(helper->cause), line_instance, call_id); - } + if((call_state == SKINNY_PROCEED) || (call_state == SKINNY_RING_OUT) || (call_state == SKINNY_CONNECTED)) { /* calling parties */ + switch (helper->cause) { + case SWITCH_CAUSE_UNALLOCATED_NUMBER: + send_start_tone(listener, SKINNY_TONE_REORDER, 0, line_instance, call_id); + skinny_session_send_call_info(helper->tech_pvt->session, listener, line_instance); + label = skinny_textid2raw(SKINNY_TEXTID_UNKNOWN_NUMBER); + send_display_prompt_status(listener, 0, label, line_instance, call_id); + switch_safe_free(label); + break; + case SWITCH_CAUSE_USER_BUSY: + send_start_tone(listener, SKINNY_TONE_BUSYTONE, 0, line_instance, call_id); + label = skinny_textid2raw(SKINNY_TEXTID_BUSY); + send_display_prompt_status(listener, 0, label, line_instance, call_id); + switch_safe_free(label); + break; + case SWITCH_CAUSE_NORMAL_CLEARING: + send_clear_prompt_status(listener, line_instance, call_id); + break; + default: + send_display_prompt_status(listener, 0, switch_channel_cause2str(helper->cause), line_instance, call_id); + } + skinny_session_stop_media(helper->tech_pvt->session, listener, line_instance); } diff --git a/src/mod/endpoints/mod_skinny/skinny_protocol.c b/src/mod/endpoints/mod_skinny/skinny_protocol.c index fc4ee532a0..1e1c539150 100644 --- a/src/mod/endpoints/mod_skinny/skinny_protocol.c +++ b/src/mod/endpoints/mod_skinny/skinny_protocol.c @@ -506,9 +506,11 @@ switch_status_t perform_send_register_ack(listener_t *listener, message->data.reg_ack.secondary_keep_alive = keep_alive; switch_copy_string(message->data.reg_ack.reserved2, reserved2, 4); - skinny_log_l_ffl(listener, file, func, line, SWITCH_LOG_DEBUG, - "Sending Register Ack with Keep Alive (%d), Date Format (%s), Secondary Keep Alive (%d)\n", - keep_alive, date_format, secondary_keep_alive); + if ( listener->profile->debug >= 9 ) { + skinny_log_l_ffl(listener, file, func, line, SWITCH_LOG_DEBUG, + "Sending Register Ack with Keep Alive (%d), Date Format (%s), Secondary Keep Alive (%d)\n", + keep_alive, date_format, secondary_keep_alive); + } return skinny_send_reply_quiet(listener, message, SWITCH_TRUE); } @@ -527,9 +529,11 @@ switch_status_t perform_send_speed_dial_stat_res(listener_t *listener, switch_copy_string(message->data.speed_dial_res.line, speed_line, 24); switch_copy_string(message->data.speed_dial_res.label, speed_label, 40); - skinny_log_l_ffl(listener, file, func, line, SWITCH_LOG_DEBUG, - "Sending Speed Dial Stat Res with Number (%d), Line (%s), Label (%s)\n", - number, speed_line, speed_label); + if ( listener->profile->debug >= 9 ) { + skinny_log_l_ffl(listener, file, func, line, SWITCH_LOG_DEBUG, + "Sending Speed Dial Stat Res with Number (%d), Line (%s), Label (%s)\n", + number, speed_line, speed_label); + } return skinny_send_reply_quiet(listener, message, SWITCH_TRUE); } @@ -791,8 +795,10 @@ switch_status_t perform_send_call_info(listener_t *listener, message->data.call_info.call_security_status = call_security_status; message->data.call_info.party_pi_restriction_bits = party_pi_restriction_bits; - skinny_log_l_ffl(listener, file, func, line, SWITCH_LOG_DEBUG, - "Send Call Info with Line Instance (%d)...\n", line_instance); + if ( listener->profile->debug >= 9 ) { + skinny_log_l_ffl(listener, file, func, line, SWITCH_LOG_DEBUG, + "Send Call Info with Line Instance (%d)...\n", line_instance); + } return skinny_send_reply_quiet(listener, message, SWITCH_TRUE); } @@ -823,9 +829,11 @@ switch_status_t perform_send_define_time_date(listener_t *listener, message->data.define_time_date.milliseconds = milliseconds; message->data.define_time_date.timestamp = timestamp; - skinny_log_l_ffl(listener, file, func, line, SWITCH_LOG_DEBUG, - "Send Define Time Date with %.4d-%.2d-%.2d %.2d:%.2d:%.2d.%d, Timestamp (%d), DOW (%d)\n", - year, month, day, hour, minute, seconds, milliseconds, timestamp, day_of_week); + if ( listener->profile->debug >= 9 ) { + skinny_log_l_ffl(listener, file, func, line, SWITCH_LOG_DEBUG, + "Send Define Time Date with %.4d-%.2d-%.2d %.2d:%.2d:%.2d.%d, Timestamp (%d), DOW (%d)\n", + year, month, day, hour, minute, seconds, milliseconds, timestamp, day_of_week); + } return skinny_send_reply_quiet(listener, message, SWITCH_TRUE); } @@ -857,8 +865,10 @@ switch_status_t perform_send_capabilities_req(listener_t *listener, skinny_create_empty_message(message, CAPABILITIES_REQ_MESSAGE); - skinny_log_l_ffl(listener, file, func, line, SWITCH_LOG_DEBUG, - "Send Capabilities Req%s\n", ""); + if ( listener->profile->debug >= 9 ) { + skinny_log_l_ffl(listener, file, func, line, SWITCH_LOG_DEBUG, + "Send Capabilities Req%s\n", ""); + } return skinny_send_reply_quiet(listener, message, SWITCH_TRUE); } @@ -873,8 +883,10 @@ switch_status_t perform_send_version(listener_t *listener, memcpy(message->data.version.version, version, 16); - skinny_log_l_ffl(listener, file, func, line, SWITCH_LOG_DEBUG, - "Send Version with Version(%s)\n", version); + if ( listener->profile->debug >= 9 ) { + skinny_log_l_ffl(listener, file, func, line, SWITCH_LOG_DEBUG, + "Send Version with Version(%s)\n", version); + } return skinny_send_reply_quiet(listener, message, SWITCH_TRUE); } @@ -973,9 +985,11 @@ switch_status_t perform_send_select_soft_keys(listener_t *listener, message->data.select_soft_keys.soft_key_set = soft_key_set; message->data.select_soft_keys.valid_key_mask = valid_key_mask; - skinny_log_l_ffl(listener, file, func, line, SWITCH_LOG_DEBUG, - "Send Select Soft Keys with Line Instance (%d), Call ID (%d), Soft Key Set (%d), Valid Key Mask (%x)\n", + if ( listener->profile->debug >= 9 ) { + skinny_log_l_ffl(listener, file, func, line, SWITCH_LOG_DEBUG, + "Send Select Soft Keys with Line Instance (%d), Call ID (%d), Soft Key Set (%d), Valid Key Mask (%x)\n", line_instance, call_id, soft_key_set, valid_key_mask); + } return skinny_send_reply_quiet(listener, message, SWITCH_TRUE); } @@ -1299,7 +1313,8 @@ switch_status_t skinny_perform_send_reply(listener_t *listener, const char *file ptr = (char *) reply; if (listener_is_ready(listener)) { - if (listener->profile->debug >= 10 || reply->type != KEEP_ALIVE_ACK_MESSAGE) { + if (listener->profile->debug >= 10 || + (listener->profile->debug >= 9 && reply->type != KEEP_ALIVE_ACK_MESSAGE)) { skinny_log_l_ffl(listener, file, func, line, SWITCH_LOG_DEBUG, "Sending %s (type=%x,length=%d).\n", skinny_message_type2str(reply->type), reply->type, reply->length); diff --git a/src/mod/endpoints/mod_skinny/skinny_server.c b/src/mod/endpoints/mod_skinny/skinny_server.c index 64b6d16831..5a581de463 100644 --- a/src/mod/endpoints/mod_skinny/skinny_server.c +++ b/src/mod/endpoints/mod_skinny/skinny_server.c @@ -1621,8 +1621,10 @@ switch_status_t skinny_handle_forward_stat_req_message(listener_t *listener, ski message->data.forward_stat.line_instance = request->data.forward_stat_req.line_instance; - skinny_log_l(listener, SWITCH_LOG_DEBUG, "Handle Forward Stat Req Message with Line Instance (%d)\n", - request->data.forward_stat_req.line_instance); + if ( listener->profile->debug >= 9 ) { + skinny_log_l(listener, SWITCH_LOG_DEBUG, "Handle Forward Stat Req Message with Line Instance (%d)\n", + request->data.forward_stat_req.line_instance); + } skinny_send_reply_quiet(listener, message, SWITCH_TRUE); return SWITCH_STATUS_SUCCESS; @@ -1634,7 +1636,9 @@ switch_status_t skinny_handle_speed_dial_stat_request(listener_t *listener, skin skinny_check_data_length(request, sizeof(request->data.speed_dial_req)); - skinny_log_l(listener, SWITCH_LOG_DEBUG, "Handle Speed Dial Stat Request for Number (%d)\n", request->data.speed_dial_req.number); + if ( listener->profile->debug >= 9 ) { + skinny_log_l(listener, SWITCH_LOG_DEBUG, "Handle Speed Dial Stat Request for Number (%d)\n", request->data.speed_dial_req.number); + } skinny_speed_dial_get(listener, request->data.speed_dial_req.number, &button); @@ -1906,7 +1910,9 @@ switch_status_t skinny_handle_capabilities_response(listener_t *listener, skinny skinny_execute_sql(profile, sql, profile->sql_mutex); switch_safe_free(sql); } - skinny_log_l(listener, SWITCH_LOG_DEBUG, "Codecs %s supported.\n", codec_string); + if ( listener->profile->debug >= 9 ) { + skinny_log_l(listener, SWITCH_LOG_DEBUG, "Codecs %s supported.\n", codec_string); + } switch_safe_free(codec_string); return SWITCH_STATUS_SUCCESS; } @@ -2036,11 +2042,15 @@ switch_status_t skinny_handle_soft_key_set_request(listener_t *listener, skinny_ if (listener->soft_key_set_set) { message = switch_core_hash_find(listener->profile->soft_key_set_sets_hash, listener->soft_key_set_set); - skinny_log_l(listener, SWITCH_LOG_DEBUG, "Handle Soft Key Set Request with Set (%s)\n", listener->soft_key_set_set); + if ( listener->profile->debug >= 9 ) { + skinny_log_l(listener, SWITCH_LOG_DEBUG, "Handle Soft Key Set Request with Set (%s)\n", listener->soft_key_set_set); + } } if (!message) { message = switch_core_hash_find(listener->profile->soft_key_set_sets_hash, "default"); - skinny_log_l(listener, SWITCH_LOG_DEBUG, "Handle Soft Key Set Request with Set (%s)\n", "default"); + if ( listener->profile->debug >= 9 ) { + skinny_log_l(listener, SWITCH_LOG_DEBUG, "Handle Soft Key Set Request with Set (%s)\n", "default"); + } } if (message) { skinny_send_reply_quiet(listener, message, SWITCH_FALSE); @@ -2231,7 +2241,9 @@ switch_status_t skinny_handle_soft_key_template_request(listener_t *listener, sk message->data.soft_key_template.soft_key[i].soft_key_event = soft_key_template_default_events[i]; } - skinny_log_l_msg(listener, SWITCH_LOG_DEBUG, "Handle Soft Key Template Request with Default Template\n"); + if ( listener->profile->debug >= 9 ) { + skinny_log_l_msg(listener, SWITCH_LOG_DEBUG, "Handle Soft Key Template Request with Default Template\n"); + } skinny_send_reply_quiet(listener, message, SWITCH_TRUE); @@ -2254,8 +2266,10 @@ switch_status_t skinny_headset_status_message(listener_t *listener, skinny_messa switch_safe_free(sql); } - skinny_log_l(listener, SWITCH_LOG_DEBUG, "Update headset accessory status (%s)\n", - skinny_accessory_state2str(request->data.headset_status.mode)); + if ( listener->profile->debug >= 9 ) { + skinny_log_l(listener, SWITCH_LOG_DEBUG, "Update headset accessory status (%s)\n", + skinny_accessory_state2str(request->data.headset_status.mode)); + } return SWITCH_STATUS_SUCCESS; } @@ -2274,7 +2288,9 @@ switch_status_t skinny_handle_register_available_lines_message(listener_t *liste { skinny_check_data_length(request, sizeof(request->data.reg_lines)); - skinny_log_l_msg(listener, SWITCH_LOG_DEBUG, "Handle Register Available Lines\n"); + if ( listener->profile->debug >= 9 ) { + skinny_log_l_msg(listener, SWITCH_LOG_DEBUG, "Handle Register Available Lines\n"); + } /* Do nothing */ return SWITCH_STATUS_SUCCESS; @@ -2531,7 +2547,7 @@ switch_status_t skinny_handle_xml_alarm(listener_t *listener, skinny_message_t * switch_event_t *event = NULL; char *tmp = NULL; - skinny_log_l(listener, SWITCH_LOG_INFO, "Received XML alarm (length=%d).\n", request->length); + skinny_log_l(listener, SWITCH_LOG_DEBUG, "Received XML alarm (length=%d).\n", request->length); /* skinny::xml_alarm event */ skinny_device_event(listener, &event, SWITCH_EVENT_CUSTOM, SKINNY_EVENT_XML_ALARM); /* Ensure that the body is null-terminated */ @@ -2547,7 +2563,8 @@ switch_status_t skinny_handle_xml_alarm(listener_t *listener, skinny_message_t * switch_status_t skinny_handle_request(listener_t *listener, skinny_message_t *request) { - if (listener->profile->debug >= 10 || request->type != KEEP_ALIVE_MESSAGE) { + if (listener->profile->debug >= 10 || + (listener->profile->debug >= 9 && request->type != KEEP_ALIVE_MESSAGE)) { skinny_log_l(listener, SWITCH_LOG_DEBUG, "Received %s (type=%x,length=%d).\n", skinny_message_type2str(request->type), request->type, request->length); } diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index e116aaca73..599ab45867 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -1471,6 +1471,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi case SWITCH_MESSAGE_INDICATE_PHONE_EVENT: { const char *event = "talk"; + const char *full_to = NULL; if (!zstr(msg->string_arg) && strcasecmp(msg->string_arg, event)) { if (!strcasecmp(msg->string_arg, "hold")) { @@ -1484,7 +1485,9 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Operation not permitted on an inbound non-answered call leg!\n"); } else { - nua_notify(tech_pvt->nh, NUTAG_NEWSUB(1), NUTAG_SUBSTATE(nua_substate_active), SIPTAG_SUBSCRIPTION_STATE_STR("active"), + full_to = switch_str_nil(switch_channel_get_variable(channel, "sip_full_to")); + nua_notify(tech_pvt->nh, NUTAG_NEWSUB(1), NUTAG_SUBSTATE(nua_substate_active), + TAG_IF((full_to), SIPTAG_TO_STR(full_to)),SIPTAG_SUBSCRIPTION_STATE_STR("active"), SIPTAG_EVENT_STR(event), TAG_END()); } @@ -2932,15 +2935,27 @@ static switch_status_t cmd_xml_status(char **argv, int argc, switch_stream_handl for (x = 0; x < profile->rtpip_index; x++) { stream->write_function(stream, " %s\n", switch_str_nil(profile->rtpip[x])); } - stream->write_function(stream, " %s\n", profile->extrtpip); + if (profile->extrtpip) { + stream->write_function(stream, " %s\n", profile->extrtpip); + } stream->write_function(stream, " %s\n", switch_str_nil(profile->sipip)); - stream->write_function(stream, " %s\n", profile->extsipip); - stream->write_function(stream, " %s\n", switch_str_nil(profile->url)); - stream->write_function(stream, " %s\n", switch_str_nil(profile->bindurl)); - stream->write_function(stream, " %s\n", switch_str_nil(profile->tls_url)); - stream->write_function(stream, " %s\n", switch_str_nil(profile->tls_bindurl)); - stream->write_function(stream, " %s\n", switch_str_nil(profile->ws_bindurl)); - stream->write_function(stream, " %s\n", switch_str_nil(profile->wss_bindurl)); + if (profile->extsipip) { + stream->write_function(stream, " %s\n", profile->extsipip); + } + if (! sofia_test_pflag(profile, PFLAG_TLS) || ! profile->tls_only) { + stream->write_function(stream, " %s\n", switch_str_nil(profile->url)); + stream->write_function(stream, " %s\n", switch_str_nil(profile->bindurl)); + } + if (sofia_test_pflag(profile, PFLAG_TLS)) { + stream->write_function(stream, " %s\n", switch_str_nil(profile->tls_url)); + stream->write_function(stream, " %s\n", switch_str_nil(profile->tls_bindurl)); + } + if (profile->ws_bindurl) { + stream->write_function(stream, " %s\n", switch_str_nil(profile->ws_bindurl)); + } + if (profile->wss_bindurl) { + stream->write_function(stream, " %s\n", switch_str_nil(profile->wss_bindurl)); + } stream->write_function(stream, " %s\n", zstr(profile->hold_music) ? "N/A" : profile->hold_music); stream->write_function(stream, " %s\n", zstr(profile->outbound_proxy) ? "N/A" : profile->outbound_proxy); @@ -2948,9 +2963,13 @@ static switch_status_t cmd_xml_status(char **argv, int argc, switch_stream_handl stream->write_function(stream, " %s\n", switch_str_nil(profile->outbound_codec_string)); stream->write_function(stream, " %d\n", profile->te); - stream->write_function(stream, " rfc2833\n"); - stream->write_function(stream, " info\n"); - stream->write_function(stream, " none\n"); + if (profile->dtmf_type == DTMF_2833) { + stream->write_function(stream, " rfc2833\n"); + } else if (profile->dtmf_type == DTMF_INFO) { + stream->write_function(stream, " info\n"); + } else { + stream->write_function(stream, " none\n"); + } stream->write_function(stream, " %d\n", profile->cng_pt); stream->write_function(stream, " %d\n", profile->session_timeout); stream->write_function(stream, " %d\n", profile->max_proceeding); @@ -2960,9 +2979,13 @@ static switch_status_t cmd_xml_status(char **argv, int argc, switch_stream_handl stream->write_function(stream, " %s\n", sofia_test_flag(profile, TFLAG_ZRTP_PASSTHRU) ? "true" : "false"); stream->write_function(stream, " %s\n", sofia_test_pflag(profile, PFLAG_AGGRESSIVE_NAT_DETECTION) ? "true" : "false"); - stream->write_function(stream, " %s\n", switch_str_nil(profile->user_agent_filter)); - stream->write_function(stream, " %d\n", + if (profile->user_agent_filter) { + stream->write_function(stream, " %s\n", switch_str_nil(profile->user_agent_filter)); + } + if (profile->max_registrations_perext > 0) { + stream->write_function(stream, " %d\n", profile->max_registrations_perext); + } stream->write_function(stream, " %u\n", profile->ib_calls); stream->write_function(stream, " %u\n", profile->ob_calls); stream->write_function(stream, " %u\n", profile->ib_failed_calls); diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h index 6e9b70cc44..52307a2800 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.h +++ b/src/mod/endpoints/mod_sofia/mod_sofia.h @@ -810,6 +810,8 @@ struct private_object { time_t last_vid_info; uint32_t keepalive; uint32_t sent_invites; + uint32_t recv_invites; + uint8_t sent_last_invite; }; diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index 6e384ed215..3bff27e1cd 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -6538,9 +6538,17 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, if (!tech_pvt || !tech_pvt->nh) { goto done; } - - if ((status > 100 || switch_channel_test_flag(channel, CF_ANSWERED)) && status < 300 && !r_sdp && tech_pvt->mparams.last_sdp_str) { - r_sdp = tech_pvt->mparams.last_sdp_str; + + if (!r_sdp && (status > 100 || switch_channel_test_flag(channel, CF_ANSWERED)) && status < 300) { + if (ss_state == nua_callstate_ready) { + if (tech_pvt->mparams.last_sdp_response) { + r_sdp = tech_pvt->mparams.last_sdp_response; + } + } else { + if (tech_pvt->mparams.last_sdp_str) { + r_sdp = tech_pvt->mparams.last_sdp_str; + } + } } tech_pvt->mparams.last_sdp_str = NULL; @@ -6657,10 +6665,19 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, } if (channel && (status == 180 || status == 183) && switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { + const char *full_to = NULL; const char *val; if ((val = switch_channel_get_variable(channel, "sip_auto_answer")) && switch_true(val)) { - nua_notify(nh, NUTAG_NEWSUB(1), NUTAG_WITH_THIS_MSG(de->data->e_msg), - NUTAG_SUBSTATE(nua_substate_terminated),SIPTAG_SUBSCRIPTION_STATE_STR("terminated;reason=noresource"), SIPTAG_EVENT_STR("talk"), TAG_END()); + full_to = switch_str_nil(switch_channel_get_variable(channel, "sip_full_to")); + + nua_notify(nh, + NUTAG_NEWSUB(1), + NUTAG_WITH_THIS_MSG(de->data->e_msg), + NUTAG_SUBSTATE(nua_substate_terminated), + TAG_IF((full_to), SIPTAG_TO_STR(full_to)), + SIPTAG_SUBSCRIPTION_STATE_STR("terminated;reason=noresource"), + SIPTAG_EVENT_STR("talk"), + TAG_END()); } } @@ -6688,6 +6705,8 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, case nua_callstate_authenticating: break; case nua_callstate_calling: + tech_pvt->sent_last_invite = 1; + tech_pvt->sent_invites++; break; case nua_callstate_proceeding: @@ -6826,6 +6845,8 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, } goto done; case nua_callstate_received: + tech_pvt->recv_invites++; + tech_pvt->sent_last_invite = 0; if (!sofia_test_flag(tech_pvt, TFLAG_SDP)) { if (switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) { private_object_t *other_tech_pvt = switch_core_session_get_private(other_session); @@ -9913,7 +9934,15 @@ void sofia_handle_sip_i_invite(switch_core_session_t *session, nua_t *nua, sofia /* Loop thru unknown Headers Here so we can do something with them */ for (un = sip->sip_unknown; un; un = un->un_next) { - if (!strncasecmp(un->un_name, "Diversion", 9)) { + if (!strncasecmp(un->un_name, "Accept-Language", 15)) { + if (!zstr(un->un_value)) { + char *tmp_name; + if ((tmp_name = switch_mprintf("%s%s", SOFIA_SIP_HEADER_PREFIX, un->un_name))) { + switch_channel_set_variable(channel, tmp_name, un->un_value); + free(tmp_name); + } + } + } else if (!strncasecmp(un->un_name, "Diversion", 9)) { /* Basic Diversion Support for Diversion Indication in SIP */ /* draft-levy-sip-diversion-08 */ if (!zstr(un->un_value)) { diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index f4fbfddb8a..0aafd19789 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -1233,7 +1233,11 @@ switch_status_t sofia_glue_do_invite(switch_core_session_t *session) switch_channel_get_name(tech_pvt->channel), switch_version_full_human(), tech_pvt->mparams.local_sdp_str ? tech_pvt->mparams.local_sdp_str : "NO SDP PRESENT\n"); - tech_pvt->sent_invites++; + + + if (switch_channel_get_private(tech_pvt->channel, "t38_options")) { + sofia_clear_flag(tech_pvt, TFLAG_ENABLE_SOA); + } if (sofia_use_soa(tech_pvt)) { nua_invite(tech_pvt->nh, @@ -1268,6 +1272,7 @@ switch_status_t sofia_glue_do_invite(switch_core_session_t *session) TAG_IF(!zstr(tech_pvt->mparams.local_sdp_str), SOATAG_ADDRESS(tech_pvt->mparams.adv_sdp_audio_ip)), TAG_IF(!zstr(tech_pvt->mparams.local_sdp_str), SOATAG_USER_SDP_STR(tech_pvt->mparams.local_sdp_str)), TAG_IF(!zstr(tech_pvt->mparams.local_sdp_str), SOATAG_REUSE_REJECTED(1)), + TAG_IF(switch_channel_get_private(tech_pvt->channel, "t38_options"), SOATAG_ORDERED_USER(1)), TAG_IF(!zstr(tech_pvt->mparams.local_sdp_str), SOATAG_RTP_SORT(SOA_RTP_SORT_REMOTE)), TAG_IF(!zstr(tech_pvt->mparams.local_sdp_str), SOATAG_RTP_SELECT(SOA_RTP_SELECT_ALL)), TAG_IF(rep, SIPTAG_REPLACES_STR(rep)), diff --git a/src/mod/endpoints/mod_sofia/sofia_reg.c b/src/mod/endpoints/mod_sofia/sofia_reg.c index 46315c86ad..b72070ba63 100644 --- a/src/mod/endpoints/mod_sofia/sofia_reg.c +++ b/src/mod/endpoints/mod_sofia/sofia_reg.c @@ -1572,7 +1572,9 @@ uint8_t sofia_reg_handle_register_token(nua_t *nua, sofia_profile_t *profile, nu if (!is_tcp && !is_tls && (zstr(network_ip) || !switch_check_network_list_ip(network_ip, profile->local_network)) && profile->server_rport_level >= 2 && sip->sip_user_agent && sip->sip_user_agent->g_string && - ( !strncasecmp(sip->sip_user_agent->g_string, "Polycom", 7) || !strncasecmp(sip->sip_user_agent->g_string, "KIRK Wireless Server", 20) )) { + ( !strncasecmp(sip->sip_user_agent->g_string, "Polycom", 7) || + !strncasecmp(sip->sip_user_agent->g_string, "KIRK Wireless Server", 20) || + !strncasecmp(sip->sip_user_agent->g_string, "ADTRAN_Total_Access", 19) )) { if (sip && sip->sip_via) { const char *host = sip->sip_via->v_host; const char *c_port = sip->sip_via->v_port; diff --git a/src/mod/endpoints/mod_verto/mod_verto.c b/src/mod/endpoints/mod_verto/mod_verto.c index 7fb0039188..c784d8d1a2 100644 --- a/src/mod/endpoints/mod_verto/mod_verto.c +++ b/src/mod/endpoints/mod_verto/mod_verto.c @@ -4286,7 +4286,7 @@ static switch_status_t parse_config(const char *cf) } if (zstr(vhost->script_root)) { - vhost->root = SWITCH_GLOBAL_dirs.script_dir; + vhost->script_root = SWITCH_GLOBAL_dirs.script_dir; } if (zstr(vhost->index)) { diff --git a/src/mod/event_handlers/mod_odbc_cdr/Makefile.am b/src/mod/event_handlers/mod_odbc_cdr/Makefile.am new file mode 100644 index 0000000000..ce799a3e1e --- /dev/null +++ b/src/mod/event_handlers/mod_odbc_cdr/Makefile.am @@ -0,0 +1,9 @@ +include $(top_srcdir)/build/modmake.rulesam +MODNAME=mod_odbc_cdr + +mod_LTLIBRARIES = mod_odbc_cdr.la +mod_odbc_cdr_la_SOURCES = mod_odbc_cdr.c +mod_odbc_cdr_la_CFLAGS = $(AM_CFLAGS) +mod_odbc_cdr_la_LIBADD = $(switch_builddir)/libfreeswitch.la +mod_odbc_cdr_la_LDFLAGS = -avoid-version -module -no-undefined -shared + diff --git a/src/mod/event_handlers/mod_odbc_cdr/conf/autoload_configs/odbc_cdr.conf.xml b/src/mod/event_handlers/mod_odbc_cdr/conf/autoload_configs/odbc_cdr.conf.xml new file mode 100644 index 0000000000..0e764d14ec --- /dev/null +++ b/src/mod/event_handlers/mod_odbc_cdr/conf/autoload_configs/odbc_cdr.conf.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +
+ + + + + +
+
+
diff --git a/src/mod/event_handlers/mod_odbc_cdr/mod_odbc_cdr.c b/src/mod/event_handlers/mod_odbc_cdr/mod_odbc_cdr.c new file mode 100644 index 0000000000..edfdbf08c4 --- /dev/null +++ b/src/mod/event_handlers/mod_odbc_cdr/mod_odbc_cdr.c @@ -0,0 +1,565 @@ +/* + * 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): + * + * Emmanuel Schmidbauer + * + * mod_odbc_cdr.c + * + */ + +#include "switch.h" + +#define ODBC_CDR_SQLITE_DB_NAME "odbc_cdr" + +SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_odbc_cdr_shutdown); +SWITCH_MODULE_LOAD_FUNCTION(mod_odbc_cdr_load); +SWITCH_MODULE_DEFINITION(mod_odbc_cdr, mod_odbc_cdr_load, mod_odbc_cdr_shutdown, NULL); + +static const char *global_cf = "odbc_cdr.conf"; + +typedef enum { + ODBC_CDR_LOG_A, + ODBC_CDR_LOG_B, + ODBC_CDR_LOG_BOTH +} odbc_cdr_log_leg_t; + +typedef enum { + ODBC_CDR_CSV_ALWAYS, + ODBC_CDR_CSV_NEVER, + ODBC_CDR_CSV_ON_FAIL +} odbc_cdr_write_csv_t; + +static struct { + char *odbc_dsn; + char *dbname; + char *csv_path; + char *csv_fail_path; + odbc_cdr_log_leg_t log_leg; + odbc_cdr_write_csv_t write_csv; + switch_bool_t debug_sql; + switch_hash_t *table_hash; + uint32_t running; + switch_mutex_t *mutex; + switch_memory_pool_t *pool; +} globals; + +struct table_profile { + char *name; + odbc_cdr_log_leg_t log_leg; + switch_hash_t *field_hash; + uint32_t flags; + switch_mutex_t *mutex; + switch_memory_pool_t *pool; +}; +typedef struct table_profile table_profile_t; + +static table_profile_t *load_table(const char *table_name) +{ + table_profile_t *table = NULL; + switch_xml_t x_tables, cfg, xml, x_table, x_field; + + if (!(xml = switch_xml_open_cfg(global_cf, &cfg, NULL))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of %s failed\n", global_cf); + return table; + } + + if (!(x_tables = switch_xml_child(cfg, "tables"))) { + goto end; + } + + if ((x_table = switch_xml_find_child(x_tables, "table", "name", table_name))) { + switch_memory_pool_t *pool; + char *table_log_leg = (char *) switch_xml_attr_soft(x_table, "log-leg"); + + if (switch_core_new_memory_pool(&pool) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Pool Failure\n"); + goto end; + } + + if (!(table = switch_core_alloc(pool, sizeof(table_profile_t)))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Alloc Failure\n"); + switch_core_destroy_memory_pool(&pool); + goto end; + } + + table->pool = pool; + + switch_mutex_init(&table->mutex, SWITCH_MUTEX_NESTED, table->pool); + + table->name = switch_core_strdup(pool, table_name); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Found table [%s]\n", table->name); + + if (!strcasecmp(table_log_leg, "a-leg")) { + table->log_leg = ODBC_CDR_LOG_A; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set table [%s] to log A-legs only\n", table->name); + } else if (!strcasecmp(table_log_leg, "b-leg")) { + table->log_leg = ODBC_CDR_LOG_B; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set table [%s] to log B-legs only\n", table->name); + } else { + table->log_leg = ODBC_CDR_LOG_BOTH; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set table [%s] to log both legs\n", table->name); + } + + switch_core_hash_init(&table->field_hash); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Adding fields to table [%s]\n", table->name); + + for (x_field = switch_xml_child(x_table, "field"); x_field; x_field = x_field->next) { + char *var = (char *) switch_xml_attr_soft(x_field, "name"); + char *val = (char *) switch_xml_attr_soft(x_field, "chan-var-name"); + char *value = NULL; + if (zstr(var) || zstr(val)) { + continue; // Ignore empty entries + } + value = switch_core_strdup(pool, val); + switch_core_hash_insert_locked(table->field_hash, var, value, table->mutex); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Field [%s] (%s) added to [%s]\n", var, val, table->name); + } + + switch_core_hash_insert(globals.table_hash, table->name, table); + } + +end: + + if (xml) { + switch_xml_free(xml); + } + + return table; +} + +switch_cache_db_handle_t *get_db_handle(void) +{ + switch_cache_db_handle_t *dbh = NULL; + char *dsn; + if (!zstr(globals.odbc_dsn)) { + dsn = globals.odbc_dsn; + } else { + dsn = globals.dbname; + } + if (switch_cache_db_get_db_handle_dsn(&dbh, dsn) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB\n"); + dbh = NULL; + } + return dbh; +} + +static switch_status_t odbc_cdr_execute_sql_no_callback(char *sql) +{ + switch_cache_db_handle_t *dbh = NULL; + switch_status_t status = SWITCH_STATUS_FALSE; + + if (!(dbh = get_db_handle())) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB\n"); + goto end; + } + + status = switch_cache_db_execute_sql(dbh, sql, NULL); + +end: + + switch_cache_db_release_db_handle(&dbh); + + return status; +} + +static void write_cdr(const char *path, const char *log_line) +{ + int fd = -1; +#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, log_line, (unsigned) strlen(log_line)); + wrote += write(fd, "\n", 1); + wrote++; + close(fd); + fd = -1; + } +} + +static switch_status_t odbc_cdr_reporting(switch_core_session_t *session) +{ + switch_channel_t *channel = switch_core_session_get_channel(session); + switch_memory_pool_t *pool = switch_core_session_get_pool(session); + switch_caller_profile_t *caller_profile = switch_channel_get_caller_profile(channel); + switch_hash_index_t *hi; + const void *var; + void *val; + switch_console_callback_match_t *matches = NULL; + switch_console_callback_match_node_t *m; + const char *uuid = NULL; + + if (globals.log_leg == ODBC_CDR_LOG_A && caller_profile->direction == SWITCH_CALL_DIRECTION_OUTBOUND) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Only logging A-Leg, ignoring B-leg\n"); + return SWITCH_STATUS_SUCCESS; + } else if (globals.log_leg == ODBC_CDR_LOG_B && caller_profile->direction == SWITCH_CALL_DIRECTION_INBOUND) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Only logging B-Leg, ignoring A-leg\n"); + return SWITCH_STATUS_SUCCESS; + } + + if (!(uuid = switch_channel_get_variable(channel, "uuid"))) { + uuid = switch_core_strdup(pool, caller_profile->uuid); + } + + // copy all table names from global hash + switch_mutex_lock(globals.mutex); + for (hi = switch_core_hash_first(globals.table_hash); hi; hi = switch_core_hash_next(&hi)) { + switch_core_hash_this(hi, &var, NULL, &val); + switch_console_push_match(&matches, (const char *) var); + } + switch_mutex_unlock(globals.mutex); + + if (matches) { + table_profile_t *table = NULL; + + // loop through table names + for (m = matches->head; m; m = m->next) { + char *table_name = m->val; + switch_bool_t started = SWITCH_FALSE; + switch_bool_t skip_leg = SWITCH_FALSE; + + switch_mutex_lock(globals.mutex); + table = switch_core_hash_find(globals.table_hash, table_name); + switch_mutex_unlock(globals.mutex); + + if (!table) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Table [%s] not found, ignoring leg\n", table_name); + skip_leg = SWITCH_TRUE; + } + + if (table->log_leg == ODBC_CDR_LOG_A && caller_profile->direction == SWITCH_CALL_DIRECTION_OUTBOUND) { + skip_leg = SWITCH_TRUE; + } + + if (table->log_leg == ODBC_CDR_LOG_B && caller_profile->direction == SWITCH_CALL_DIRECTION_INBOUND) { + skip_leg = SWITCH_TRUE; + } + + if (skip_leg == SWITCH_FALSE) { + switch_hash_index_t *i_hi = NULL; + const void *i_var; + void *i_val; + char *field_hash_key; + char *field_hash_val; + char *sql = NULL; + char *full_path = NULL; + switch_stream_handle_t stream_field = { 0 }; + switch_stream_handle_t stream_value = { 0 }; + switch_bool_t insert_fail = SWITCH_FALSE; + + SWITCH_STANDARD_STREAM(stream_field); + SWITCH_STANDARD_STREAM(stream_value); + + for (i_hi = switch_core_hash_first_iter( table->field_hash, i_hi); i_hi; i_hi = switch_core_hash_next(&i_hi)) { + const char *tmp; + switch_core_hash_this(i_hi, &i_var, NULL, &i_val); + field_hash_key = (char *) i_var; + field_hash_val = (char *) i_val; + + if ((tmp = switch_channel_get_variable(channel, field_hash_val))) { + if (started == SWITCH_FALSE) { + stream_field.write_function(&stream_field, "%s", field_hash_key); + stream_value.write_function(&stream_value, "'%s'", tmp); + } else { + stream_field.write_function(&stream_field, ", %s", field_hash_key); + stream_value.write_function(&stream_value, ", '%s'", tmp); + } + started = SWITCH_TRUE; + } + + } + switch_safe_free(i_hi); + + sql = switch_mprintf("INSERT INTO %s (%s) VALUES (%s)", table_name, stream_field.data, stream_value.data); + if (globals.debug_sql == SWITCH_TRUE) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "sql %s\n", sql); + } + if (odbc_cdr_execute_sql_no_callback(sql) == SWITCH_STATUS_FALSE) { + insert_fail = SWITCH_TRUE; + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error executing query %s\n", sql); + } + + if (globals.write_csv == ODBC_CDR_CSV_ALWAYS) { + if (insert_fail == SWITCH_TRUE) { + full_path = switch_mprintf("%s%s%s.csv", globals.csv_fail_path, SWITCH_PATH_SEPARATOR, uuid); + } else { + full_path = switch_mprintf("%s%s%s.csv", globals.csv_path, SWITCH_PATH_SEPARATOR, uuid); + } + assert(full_path); + write_cdr(full_path, stream_value.data); + switch_safe_free(full_path); + } else if (globals.write_csv == ODBC_CDR_CSV_ON_FAIL && insert_fail == SWITCH_TRUE) { + full_path = switch_mprintf("%s%s%s.csv", globals.csv_fail_path, SWITCH_PATH_SEPARATOR, uuid); + assert(full_path); + write_cdr(full_path, stream_value.data); + switch_safe_free(full_path); + } + + switch_safe_free(sql); + + switch_safe_free(stream_field.data); + switch_safe_free(stream_value.data); + + } + + } + + switch_console_free_matches(&matches); + } + + switch_safe_free(hi); + + return SWITCH_STATUS_SUCCESS; +} + + +switch_state_handler_table_t odbc_cdr_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 */ odbc_cdr_reporting, + /*.on_destroy */ NULL +}; + +static switch_status_t odbc_cdr_load_config(void) +{ + switch_status_t status = SWITCH_STATUS_SUCCESS; + switch_xml_t cfg, xml, settings, param, tables, table; + switch_cache_db_handle_t *dbh = NULL; + + switch_mutex_lock(globals.mutex); + + if (!(xml = switch_xml_open_cfg(global_cf, &cfg, NULL))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of %s failed\n", global_cf); + status = SWITCH_STATUS_TERM; + goto end; + } + + globals.debug_sql = SWITCH_FALSE; + globals.log_leg = ODBC_CDR_LOG_BOTH; + globals.write_csv = ODBC_CDR_CSV_NEVER; + + if ((settings = switch_xml_child(cfg, "settings")) != NULL) { + 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 (zstr(var) || zstr(val)) { + continue; // Ignore empty entries + } + if (!strcasecmp(var, "dbname")) { + globals.dbname = strdup(val); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Set dbname [%s]\n", globals.dbname); + } else if (!strcasecmp(var, "odbc-dsn")) { + globals.odbc_dsn = strdup(val); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Set odbc-dsn [%s]\n", globals.odbc_dsn); + } else if (!strcasecmp(var, "log-leg")) { + if (!strcasecmp(val, "a-leg")) { + globals.log_leg = ODBC_CDR_LOG_A; + } else if (!strcasecmp(val, "b-leg")) { + globals.log_leg = ODBC_CDR_LOG_B; + } + } else if (!strcasecmp(var, "debug-sql") && switch_true(val)) { + globals.debug_sql = SWITCH_TRUE; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Set debug-sql [true]\n"); + } else if (!strcasecmp(var, "write-csv") && !zstr(val)) { + if (!strcasecmp(val, "always")) { + globals.write_csv = ODBC_CDR_CSV_ALWAYS; + } else if (!strcasecmp(val, "on-db-fail")) { + globals.write_csv = ODBC_CDR_CSV_ON_FAIL; + } + } else if (!strcasecmp(var, "csv-path") && !zstr(val)) { + globals.csv_path = switch_mprintf("%s%s", val, SWITCH_PATH_SEPARATOR); + } else if (!strcasecmp(var, "csv-path-on-fail") && !zstr(val)) { + globals.csv_fail_path = switch_mprintf("%s%s", val, SWITCH_PATH_SEPARATOR); + } + } + } + + if (globals.log_leg == ODBC_CDR_LOG_A) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Set log-leg [a-leg]\n"); + } else if (globals.log_leg == ODBC_CDR_LOG_B) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Set log-leg [b-leg]\n"); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Set log-leg [both]\n"); + } + + if (!globals.csv_path) { + globals.csv_path = switch_mprintf("%s%sodbc-cdr", SWITCH_GLOBAL_dirs.log_dir, SWITCH_PATH_SEPARATOR); + } + + if (!globals.csv_fail_path) { + globals.csv_fail_path = switch_mprintf("%s%sodbc-cdr-failed", SWITCH_GLOBAL_dirs.log_dir, SWITCH_PATH_SEPARATOR); + } + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Set csv-path [%s]\n", globals.csv_path); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Set csv-path-on-fail [%s]\n", globals.csv_fail_path); + + if ((tables = switch_xml_child(cfg, "tables"))) { + for (table = switch_xml_child(tables, "table"); table; table = table->next) { + load_table(switch_xml_attr_soft(table, "name")); + } + } + + if (!globals.dbname) { + globals.dbname = strdup(ODBC_CDR_SQLITE_DB_NAME); + } + + // Initialize database + if (!(dbh = get_db_handle())) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Cannot open DB!\n"); + status = SWITCH_STATUS_TERM; + goto end; + } + + switch_cache_db_release_db_handle(&dbh); + +end: + switch_mutex_unlock(globals.mutex); + + if (xml) { + switch_xml_free(xml); + } + + return status; +} + + +SWITCH_MODULE_LOAD_FUNCTION(mod_odbc_cdr_load) +{ + switch_status_t status; + + memset(&globals, 0, sizeof(globals)); + switch_core_hash_init(&globals.table_hash); + if (switch_mutex_init(&globals.mutex, SWITCH_MUTEX_NESTED, pool) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to initialize mutex\n"); + } + globals.pool = pool; + + if ((status = odbc_cdr_load_config()) != SWITCH_STATUS_SUCCESS) { + return status; + } + + if (globals.write_csv != ODBC_CDR_CSV_NEVER) { + if ((status = switch_dir_make_recursive(globals.csv_path, SWITCH_DEFAULT_DIR_PERMS, pool)) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error creating %s\n", globals.csv_path); + return status; + } + if (strcasecmp(globals.csv_path, globals.csv_fail_path)) { + if ((status = switch_dir_make_recursive(globals.csv_fail_path, SWITCH_DEFAULT_DIR_PERMS, pool)) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error creating %s\n", globals.csv_path); + return status; + } + } + } + + switch_mutex_lock(globals.mutex); + globals.running = 1; + switch_mutex_unlock(globals.mutex); + + switch_core_add_state_handler(&odbc_cdr_state_handlers); + *module_interface = switch_loadable_module_create_module_interface(pool, modname); + + /* indicate that the module should continue to be loaded */ + return SWITCH_STATUS_SUCCESS; +} + +/* + Called when the system shuts down + Macro expands to: switch_status_t mod_odbc_cdr_shutdown() */ +SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_odbc_cdr_shutdown) +{ + switch_hash_index_t *hi = NULL; + table_profile_t *table; + void *val = NULL; + const void *key; + switch_ssize_t keylen; + + switch_mutex_lock(globals.mutex); + if (globals.running == 1) { + globals.running = 0; + } + + while ((hi = switch_core_hash_first_iter(globals.table_hash, hi))) { + switch_hash_index_t *field_hi = NULL; + void *field_val = NULL; + const void *field_key; + switch_ssize_t field_keylen; + + switch_core_hash_this(hi, &key, &keylen, &val); + table = (table_profile_t *) val; + + while ((field_hi = switch_core_hash_first_iter(table->field_hash, field_hi))) { + switch_core_hash_this(field_hi, &field_key, &field_keylen, &field_val); + switch_core_hash_delete_locked(table->field_hash, field_key, table->mutex); + } + switch_core_hash_destroy(&table->field_hash); + switch_safe_free(field_hi); + + switch_core_hash_delete(globals.table_hash, table->name); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Destroying table %s\n", table->name); + + switch_core_destroy_memory_pool(&table->pool); + table = NULL; + } + switch_core_hash_destroy(&globals.table_hash); + switch_safe_free(hi); + + switch_safe_free(globals.csv_path) + switch_safe_free(globals.csv_fail_path) + switch_safe_free(globals.odbc_dsn); + switch_safe_free(globals.dbname); + + switch_mutex_unlock(globals.mutex); + switch_mutex_destroy(globals.mutex); + + switch_core_remove_state_handler(&odbc_cdr_state_handlers); + + 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 + */ diff --git a/src/mod/event_handlers/mod_rayo/conf/autoload_configs/rayo.conf.xml b/src/mod/event_handlers/mod_rayo/conf/autoload_configs/rayo.conf.xml index 50af0f7ecd..a5f8748416 100644 --- a/src/mod/event_handlers/mod_rayo/conf/autoload_configs/rayo.conf.xml +++ b/src/mod/event_handlers/mod_rayo/conf/autoload_configs/rayo.conf.xml @@ -2,8 +2,14 @@ + + + + + + @@ -52,8 +58,8 @@ - - + + diff --git a/src/mod/event_handlers/mod_rayo/mod_rayo.c b/src/mod/event_handlers/mod_rayo/mod_rayo.c index cc7fc65037..614975ee15 100644 --- a/src/mod/event_handlers/mod_rayo/mod_rayo.c +++ b/src/mod/event_handlers/mod_rayo/mod_rayo.c @@ -229,6 +229,8 @@ static struct { int pause_when_offline; /** flag to reduce log noise */ int offline_logged; + /** if true, channel variables are added to offer */ + int add_variables_to_offer; } globals; /** @@ -3682,18 +3684,23 @@ static iks *rayo_create_offer(struct rayo_call *call, switch_core_session_t *ses iks_insert_attrib(offer, "to", profile->destination_number); } - /* add signaling headers */ + /* add headers to offer */ { switch_event_header_t *var; add_header(offer, "from", switch_channel_get_variable(channel, "sip_full_from")); add_header(offer, "to", switch_channel_get_variable(channel, "sip_full_to")); add_header(offer, "via", switch_channel_get_variable(channel, "sip_full_via")); - /* get all variables prefixed with sip_h_ */ + /* add all SIP header variables and (if configured) all other variables */ for (var = switch_channel_variable_first(channel); var; var = var->next) { if (!strncmp("sip_h_", var->name, 6)) { add_header(offer, var->name + 6, var->value); } + if (globals.add_variables_to_offer) { + char var_name[1024]; + snprintf(var_name, 1024, "variable-%s", var->name); + add_header(offer, var_name, var->value); + } } switch_channel_variable_last(channel); } @@ -4066,6 +4073,7 @@ static switch_status_t do_config(switch_memory_pool_t *pool, const char *config_ globals.num_message_threads = 8; globals.offer_uri = 1; globals.pause_when_offline = 0; + globals.add_variables_to_offer = 0; /* get params */ { @@ -4102,6 +4110,10 @@ static switch_status_t do_config(switch_memory_pool_t *pool, const char *config_ if (switch_true(val)) { globals.pause_when_offline = 1; } + } else if (!strcasecmp(var, "add-variables-to-offer")) { + if (switch_true(val)) { + globals.add_variables_to_offer = 1; + } } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unsupported param: %s\n", var); } 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 9d075dc6ae..ef097b6411 100644 --- a/src/mod/event_handlers/mod_rayo/rayo_output_component.c +++ b/src/mod/event_handlers/mod_rayo/rayo_output_component.c @@ -368,6 +368,8 @@ struct rayo_file_context { struct rayo_component *component; /** number of times played */ int play_count; + /** have any files successfully opened? */ + int could_open; }; /** @@ -376,6 +378,7 @@ struct rayo_file_context { */ static switch_status_t next_file(switch_file_handle_t *handle) { + int loops = 0; struct rayo_file_context *context = handle->private_info; struct output_component *output = context->component ? OUTPUT_COMPONENT(context->component) : NULL; @@ -404,7 +407,7 @@ static switch_status_t next_file(switch_file_handle_t *handle) /* done? */ if (!context->cur_doc) { - if (output->repeat_times == 0 || ++context->play_count < output->repeat_times) { + if (context->could_open && ++loops < 2 && (output->repeat_times == 0 || ++context->play_count < output->repeat_times)) { /* repeat all document(s) */ if (!output->repeat_interval_ms) { goto top; @@ -464,6 +467,8 @@ static switch_status_t next_file(switch_file_handle_t *handle) if (switch_core_file_open(&context->fh, context->ssml, handle->channels, handle->samplerate, handle->flags, NULL) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Failed to open %s\n", context->ssml); goto top; + } else { + context->could_open = 1; } handle->samples = context->fh.samples; @@ -503,6 +508,7 @@ static switch_status_t rayo_file_open(switch_file_handle_t *handle, const char * handle->private_info = context; context->cur_doc = NULL; context->play_count = 0; + context->could_open = 0; status = next_file(handle); } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "File error! %s\n", path); diff --git a/src/mod/event_handlers/mod_rayo/xmpp_streams.c b/src/mod/event_handlers/mod_rayo/xmpp_streams.c index cf5aafb413..7fe27e22fb 100644 --- a/src/mod/event_handlers/mod_rayo/xmpp_streams.c +++ b/src/mod/event_handlers/mod_rayo/xmpp_streams.c @@ -450,7 +450,7 @@ static void xmpp_send_outbound_server_header(struct xmpp_stream *stream) static void on_stream_starttls(struct xmpp_stream *stream, iks *node) { /* wait for handshake to start */ - if (iks_proceed_tls(stream->parser, stream->context->cert_pem_file, stream->context->key_pem_file, 1) == IKS_OK) { + if (iks_proceed_tls(stream->parser, stream->context->cert_pem_file, stream->context->key_pem_file) == IKS_OK) { stream->state = XSS_SECURE; } else { stream->state = XSS_ERROR; diff --git a/src/mod/formats/mod_shout/mod_shout.c b/src/mod/formats/mod_shout/mod_shout.c index 553ef4e889..e6ba9a94b2 100644 --- a/src/mod/formats/mod_shout/mod_shout.c +++ b/src/mod/formats/mod_shout/mod_shout.c @@ -123,6 +123,7 @@ struct shout_context { int lame_ready; int eof; int channels; + int stream_channels; int16_t *l; switch_size_t llen; int16_t *r; @@ -371,14 +372,25 @@ static size_t stream_callback(void *ptr, size_t size, size_t nmemb, void *data) shout_context_t *context = data; int decode_status = 0; size_t usedlen; - uint32_t buf_size = 1024 * 128; /* do not make this 64 or less, stutter will ensue after - first 64k buffer is dry */ + uint32_t buf_size = 1024 * 128; /* do not make this 64 or less, stutter will ensue after first 64k buffer is dry */ switch_size_t used; + if (!context->stream_channels) { + long rate = 0; + int channels = 0; + int encoding = 0; + mpg123_getformat(context->mh, &rate, &channels, &encoding); + context->stream_channels = channels; + } + if (context->prebuf) { buf_size = context->prebuf; } + if (context->stream_channels) { + buf_size = buf_size * context->stream_channels; + } + /* make sure we aren't over zealous by slowing down the stream when the buffer is too full */ while (!context->err) { switch_mutex_lock(context->audio_mutex); diff --git a/src/mod/formats/mod_sndfile/mod_sndfile.c b/src/mod/formats/mod_sndfile/mod_sndfile.c index 5d8d0865b5..4b6e9112a6 100644 --- a/src/mod/formats/mod_sndfile/mod_sndfile.c +++ b/src/mod/formats/mod_sndfile/mod_sndfile.c @@ -54,10 +54,13 @@ struct sndfile_context { typedef struct sndfile_context sndfile_context; +static switch_status_t sndfile_perform_open(sndfile_context *context, const char *path, const char *mask, int mode); + static switch_status_t sndfile_file_open(switch_file_handle_t *handle, const char *path) { sndfile_context *context; int mode = 0; + const char *mask = "rb"; char *ext; struct format_map *map = NULL; switch_status_t status = SWITCH_STATUS_SUCCESS; @@ -84,8 +87,10 @@ static switch_status_t sndfile_file_open(switch_file_handle_t *handle, const cha if (switch_test_flag(handle, SWITCH_FILE_FLAG_WRITE)) { if (switch_test_flag(handle, SWITCH_FILE_WRITE_APPEND) || switch_test_flag(handle, SWITCH_FILE_WRITE_OVER) || handle->offset_pos) { + mask = "ab+"; mode += SFM_RDWR; } else { + mask = "wb+"; mode += SFM_WRITE; } } @@ -181,7 +186,7 @@ static switch_status_t sndfile_file_open(switch_file_handle_t *handle, const cha ldup = strdup(last); switch_assert(ldup); switch_snprintf(last, alt_len - (last - alt_path), "%d%s%s", handle->samplerate, SWITCH_PATH_SEPARATOR, ldup); - if ((context->handle = sf_open(alt_path, mode, &context->sfinfo))) { + if (sndfile_perform_open(context, alt_path, mask, mode) == SWITCH_STATUS_SUCCESS) { path = alt_path; } else { /* Try to find the file at the highest rate possible if we can't find one that matches the exact rate. @@ -189,7 +194,7 @@ static switch_status_t sndfile_file_open(switch_file_handle_t *handle, const cha */ for (i = 3; i >= 0; i--) { switch_snprintf(last, alt_len - (last - alt_path), "%d%s%s", rates[i], SWITCH_PATH_SEPARATOR, ldup); - if ((context->handle = sf_open(alt_path, mode, &context->sfinfo))) { + if (sndfile_perform_open(context, alt_path, mask, mode) == SWITCH_STATUS_SUCCESS) { path = alt_path; break; } @@ -198,7 +203,7 @@ static switch_status_t sndfile_file_open(switch_file_handle_t *handle, const cha } if (!context->handle) { - if ((context->handle = sf_open(path, mode, &context->sfinfo)) == 0) { + if (sndfile_perform_open(context, path, mask, mode) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening File [%s] [%s]\n", path, sf_strerror(context->handle)); status = SWITCH_STATUS_GENERR; goto end; @@ -236,6 +241,20 @@ static switch_status_t sndfile_file_open(switch_file_handle_t *handle, const cha return status; } +static switch_status_t sndfile_perform_open(sndfile_context *context, const char *path, const char *mask, int mode) +{ + FILE *fd = NULL; + fd = fopen(path, mask); + if (!fd) { + return SWITCH_STATUS_FALSE; + } + if ((context->handle = sf_open_fd(fileno(fd), mode, &context->sfinfo, SWITCH_TRUE)) == 0) { + fclose(fd); + return SWITCH_STATUS_FALSE; + } + return SWITCH_STATUS_SUCCESS; +} + static switch_status_t sndfile_file_truncate(switch_file_handle_t *handle, int64_t offset) { sndfile_context *context = handle->private_info; diff --git a/src/mod/languages/mod_lua/freeswitch_lua.cpp b/src/mod/languages/mod_lua/freeswitch_lua.cpp index 12a663c3a7..593ff8a6c4 100644 --- a/src/mod/languages/mod_lua/freeswitch_lua.cpp +++ b/src/mod/languages/mod_lua/freeswitch_lua.cpp @@ -394,9 +394,9 @@ bool Dbh::test_reactive(char *test_sql, char *drop_sql, char *reactive_sql) if (switch_cache_db_test_reactive(dbh, test_sql, drop_sql, reactive_sql) == SWITCH_TRUE) { return true; } + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "DBH NOT Connected.\n"); } - - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "DBH NOT Connected.\n"); return false; } diff --git a/src/mod/languages/mod_managed/managed/Loader.cs b/src/mod/languages/mod_managed/managed/Loader.cs index 19ab3a52db..e3803ae427 100644 --- a/src/mod/languages/mod_managed/managed/Loader.cs +++ b/src/mod/languages/mod_managed/managed/Loader.cs @@ -26,6 +26,7 @@ * Michael Giagnocavo * David Brazier * Jeff Lenk + * Artur Kraev * * Loader.cs -- mod_managed loader * @@ -33,7 +34,6 @@ using System; using System.Collections.Generic; -using System.Text; using System.IO; using System.Linq; using System.Reflection; @@ -47,7 +47,7 @@ namespace FreeSWITCH { [UnmanagedFunctionPointer(CallingConvention.Cdecl)] delegate bool ExecuteBackgroundDelegate(string cmd); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] delegate bool RunDelegate(string cmd, IntPtr session); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] delegate bool ReloadDelegate(string cmd); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] delegate bool ListDelegate(string cmd); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] delegate bool ListDelegate(string cmd, IntPtr streamH, IntPtr eventH); static readonly ExecuteDelegate _execute = Execute; static readonly ExecuteBackgroundDelegate _executeBackground = ExecuteBackground; static readonly RunDelegate _run = Run; @@ -66,7 +66,12 @@ namespace FreeSWITCH { managedDir = Path.Combine(Native.freeswitch.SWITCH_GLOBAL_dirs.mod_dir, "managed"); shadowDir = Path.Combine(managedDir, "shadow"); if (Directory.Exists(shadowDir)) { - Directory.Delete(shadowDir, true); + try { + Directory.Delete(shadowDir, true); + } catch (Exception ex) { + Log.WriteLine(LogLevel.Warning, "Cannot delete shadow directory: {0}", ex); + } + Directory.CreateDirectory(shadowDir); } @@ -220,11 +225,35 @@ namespace FreeSWITCH { setup.ConfigurationFile = fileName + ".config"; } setup.ApplicationBase = Native.freeswitch.SWITCH_GLOBAL_dirs.mod_dir; - setup.ShadowCopyDirectories = managedDir + ";"; setup.LoaderOptimization = LoaderOptimization.MultiDomainHost; // TODO: would MultiDomain work better since FreeSWITCH.Managed isn't gac'd? setup.CachePath = shadowDir; setup.ShadowCopyFiles = "true"; - setup.PrivateBinPath = "managed"; + + // computing private bin path + var binPath = setup.PrivateBinPath ?? string.Empty; + + var binPaths = binPath.Split(new[] { ";" }, StringSplitOptions.RemoveEmptyEntries) + .Select(x => x.Trim()) + .ToList(); + + // adding "managed" (modules) directory + if (!binPaths.Contains("managed")) { + binPaths.Add("managed"); + } + + // adding "managed/" directory for per-module references support + var moduleRefsDir = Path.GetFileName(fileName); + moduleRefsDir = Path.GetFileNameWithoutExtension(moduleRefsDir); + + if (moduleRefsDir != null && moduleRefsDir.Trim() != "") { + moduleRefsDir = Path.Combine("managed", moduleRefsDir); + if (!binPaths.Contains(moduleRefsDir, StringComparer.OrdinalIgnoreCase)) { + binPaths.Add(moduleRefsDir); + } + } + + // bringing all together + setup.PrivateBinPath = string.Join(";", binPaths); // Create domain and load PM inside System.Threading.Interlocked.Increment(ref appDomainCount); @@ -408,16 +437,24 @@ namespace FreeSWITCH { } } - public static bool List(string command) { + public static bool List(string command, IntPtr streamHandle, IntPtr eventHandle) + { try { - Log.WriteLine(LogLevel.Info, "Available APIs:"); - getApiExecs().Values.ForEach(x => { - Log.WriteLine(LogLevel.Info, "{0}: {1}", x.Name, String.Join(",", x.Aliases.ToArray())); - }); - Log.WriteLine(LogLevel.Info, "Available Apps:"); - getAppExecs().Values.ForEach(x => { - Log.WriteLine(LogLevel.Info, "{0}: {1}", x.Name, String.Join(",", x.Aliases.ToArray())); - }); + if (streamHandle != IntPtr.Zero) { + using (var stream = new Native.Stream(new Native.switch_stream_handle(streamHandle, false))) { + stream.Write("Available APIs:\n"); + + getApiExecs().Values.ForEach(x => stream.Write(string.Format("{0}: {1}\n", x.Name, String.Join(",", x.Aliases.ToArray())))); + + stream.Write("Available Apps:\n"); + getAppExecs().Values.ForEach(x => stream.Write(string.Format("{0}: {1}\n", x.Name, String.Join(",", x.Aliases.ToArray())))); + } + } else { + Log.WriteLine(LogLevel.Info, "Available APIs:"); + getApiExecs().Values.ForEach(x => Log.WriteLine(LogLevel.Info, "{0}: {1}", x.Name, String.Join(",", x.Aliases.ToArray()))); + Log.WriteLine(LogLevel.Info, "Available Apps:"); + getAppExecs().Values.ForEach(x => Log.WriteLine(LogLevel.Info, "{0}: {1}", x.Name, String.Join(",", x.Aliases.ToArray()))); + } return true; } catch (Exception ex) { Log.WriteLine(LogLevel.Error, "Exception listing managed modules: {0}", ex.ToString()); diff --git a/src/mod/languages/mod_managed/managed/Log.cs b/src/mod/languages/mod_managed/managed/Log.cs index 1c58ff1458..aa2bacf57e 100644 --- a/src/mod/languages/mod_managed/managed/Log.cs +++ b/src/mod/languages/mod_managed/managed/Log.cs @@ -57,6 +57,7 @@ namespace FreeSWITCH static string ToLogString(this LogLevel level) { switch (level) { + case LogLevel.Console: return "CONSOLE"; case LogLevel.Alert: return "ALERT"; case LogLevel.Critical: return "CRIT"; case LogLevel.Debug: return "DEBUG"; @@ -85,6 +86,7 @@ namespace FreeSWITCH };*/ public enum LogLevel { + Console, Debug, Info, Error, diff --git a/src/mod/languages/mod_managed/managed/ManagedSession.cs b/src/mod/languages/mod_managed/managed/ManagedSession.cs index bed7a03878..84718df60f 100644 --- a/src/mod/languages/mod_managed/managed/ManagedSession.cs +++ b/src/mod/languages/mod_managed/managed/ManagedSession.cs @@ -149,6 +149,23 @@ namespace FreeSWITCH.Native }; return del; } + + /// Wraps a nice handler into a delegate suitable for reverse P/Invoke. For native api using + public static switch_state_handler_t_delegate CreateStateHandlerDelegate(Action handler) + { + // We create a ManagedSession on top of the session so callbacks can use it "nicely" + // Then we sort of dispose it. + switch_state_handler_t_delegate del = ptr => + { + using (var sess = new ManagedSession(new SWIGTYPE_p_switch_core_session(ptr, false))) + { + handler(sess); + return switch_status_t.SWITCH_STATUS_SUCCESS; + } + }; + return del; + } + public static SWIGTYPE_p_f_p_switch_core_session__switch_status_t WrapStateHandlerDelegate(switch_state_handler_t_delegate del) { return new SWIGTYPE_p_f_p_switch_core_session__switch_status_t(Marshal.GetFunctionPointerForDelegate(del), false); } diff --git a/src/mod/languages/mod_managed/managed/Util.cs b/src/mod/languages/mod_managed/managed/Util.cs index 18c2d89369..7fd5194770 100644 --- a/src/mod/languages/mod_managed/managed/Util.cs +++ b/src/mod/languages/mod_managed/managed/Util.cs @@ -46,5 +46,31 @@ namespace FreeSWITCH { if (cons == null) throw new ArgumentException(ty.Name + " constructor not found."); return (T)cons.Invoke(new object[] { cPtr, false }); } + + /// + /// Getting IntPtr from wrapper + /// + /// swig generated class + /// instance + /// Original pointer + public static IntPtr GetPtr(T obj) + { + // internal static HandleRef getCPtr(CoreSession obj) + var ty = typeof(T); + var bflags = BindingFlags.Static | BindingFlags.NonPublic; + var getCPtr = ty.GetMethod("getCPtr", bflags, null, new[] { typeof(T) }, null); + + if (getCPtr != null) + { + var handleRef = getCPtr.Invoke(null, new object[] { obj }); + + if (handleRef is HandleRef) + { + return ((HandleRef)handleRef).Handle; + } + } + + return IntPtr.Zero; + } } } diff --git a/src/mod/languages/mod_managed/mod_managed.cpp b/src/mod/languages/mod_managed/mod_managed.cpp index 215a98336b..6831aec930 100644 --- a/src/mod/languages/mod_managed/mod_managed.cpp +++ b/src/mod/languages/mod_managed/mod_managed.cpp @@ -26,6 +26,7 @@ * Michael Giagnocavo * David Brazier * Jeff Lenk + * Artur Kraev * * mod_mono.cpp -- FreeSWITCH mod_mono main class * @@ -73,14 +74,14 @@ typedef int (*runFunction)(const char *data, void *sessionPtr); typedef int (*executeFunction)(const char *cmd, void *stream, void *Event); typedef int (*executeBackgroundFunction)(const char* cmd); typedef int (*reloadFunction)(const char* cmd); -typedef int (*listFunction)(const char* cmd); +typedef int (*listFunction)(const char *cmd, void *stream, void *Event); static runFunction runDelegate; static executeFunction executeDelegate; static executeBackgroundFunction executeBackgroundDelegate; static reloadFunction reloadDelegate; static listFunction listDelegate; -SWITCH_MOD_DECLARE_NONSTD(void) InitManagedDelegates(runFunction run, executeFunction execute, executeBackgroundFunction executeBackground, reloadFunction reload, listFunction list) +SWITCH_MOD_DECLARE_NONSTD(void) InitManagedDelegates(runFunction run, executeFunction execute, executeBackgroundFunction executeBackground, reloadFunction reload, listFunction list) { runDelegate = run; executeDelegate = execute; @@ -451,7 +452,7 @@ SWITCH_STANDARD_API(managedlist_api_function) #ifndef _MANAGED mono_thread_attach(globals.domain); #endif - listDelegate(cmd); + listDelegate(cmd, stream, stream->param_event); #ifndef _MANAGED mono_thread_detach(mono_thread_current()); #endif diff --git a/src/mod/legacy/languages/mod_lua/freeswitch_lua.cpp b/src/mod/legacy/languages/mod_lua/freeswitch_lua.cpp index efef9679e7..39076e6225 100644 --- a/src/mod/legacy/languages/mod_lua/freeswitch_lua.cpp +++ b/src/mod/legacy/languages/mod_lua/freeswitch_lua.cpp @@ -394,9 +394,9 @@ bool Dbh::test_reactive(char *test_sql, char *drop_sql, char *reactive_sql) if (switch_cache_db_test_reactive(dbh, test_sql, drop_sql, reactive_sql) == SWITCH_TRUE) { return true; } + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "DBH NOT Connected.\n"); } - - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "DBH NOT Connected.\n"); return false; } diff --git a/src/mod/say/mod_say_es_ar/Makefile.am b/src/mod/say/mod_say_es_ar/Makefile.am new file mode 100644 index 0000000000..ca206db7c2 --- /dev/null +++ b/src/mod/say/mod_say_es_ar/Makefile.am @@ -0,0 +1,8 @@ +include $(top_srcdir)/build/modmake.rulesam +MODNAME=mod_say_es_ar + +mod_LTLIBRARIES = mod_say_es_ar.la +mod_say_es_ar_la_SOURCES = mod_say_es_ar.c +mod_say_es_ar_la_CFLAGS = $(AM_CFLAGS) +mod_say_es_ar_la_LIBADD = $(switch_builddir)/libfreeswitch.la +mod_say_es_ar_la_LDFLAGS = -avoid-version -module -no-undefined -shared diff --git a/src/mod/say/mod_say_es_ar/mod_say_es_ar.c b/src/mod/say/mod_say_es_ar/mod_say_es_ar.c new file mode 100644 index 0000000000..f2dcb9cdb9 --- /dev/null +++ b/src/mod/say/mod_say_es_ar/mod_say_es_ar.c @@ -0,0 +1,718 @@ +/* + * Copyright (c) 2007-2014, Anthony Minessale II + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of the original author; nor the names of any contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * 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): + * + * Anthony Minessale II + * Michael B. Murdock + * François Delawarde + * Joao Mesquita + * + * mod_say_es_ar.c -- Say for Spanish (Argentina) + * + */ + +#include +#include +#include + +SWITCH_MODULE_LOAD_FUNCTION(mod_say_es_ar_load); +SWITCH_MODULE_DEFINITION(mod_say_es_ar, mod_say_es_ar_load, NULL, NULL); + + +#define say_num(_sh, num, meth) { \ + char tmp[80]; \ + switch_status_t tstatus; \ + switch_say_method_t smeth = say_args->method; \ + switch_say_type_t stype = say_args->type; \ + say_args->type = SST_ITEMS; say_args->method = meth; \ + switch_snprintf(tmp, sizeof(tmp), "%u", (unsigned)num); \ + if ((tstatus = \ + es_say_general_count(_sh, tmp, say_args)) \ + != SWITCH_STATUS_SUCCESS) { \ + return tstatus; \ + } \ + say_args->method = smeth; say_args->type = stype; \ + } \ + + + +static switch_status_t play_group(switch_say_method_t method, switch_say_gender_t gender, int a, int b, int c, char *what, switch_say_file_handle_t *sh) +{ + + if (a) { + if (a == 1 && b == 0 && c == 0) { + switch_say_file(sh, "digits/hundred"); + } else { + switch_say_file(sh, "digits/%d00", a); + } + } + + if (b) { + if (method == SSM_COUNTED) { + /* Numeros no redondos es masculino siempre. */ + if (gender == SSG_FEMININE && c == 0) { + switch_say_file(sh, "digits/h-%d0_a", b); + + } else { + switch_say_file(sh, "digits/h-%d0", b); + } + } else { + /* Veinti */ + if (b == 2) { + switch_say_file(sh, "digits/%d0_i", b); + } else if(b == 1) { + switch_say_file(sh, "digits/%d%d", b, c); + } else { + switch_say_file(sh, "digits/%d0", b); + if (c > 0) { + switch_say_file(sh, "digits/y"); + } + } + } + } + + if (c && b != 1) { + if (method == SSM_COUNTED) { + if (gender == SSG_FEMININE) { + switch_say_file(sh, "digits/h-%d_a", c); + } else { + switch_say_file(sh, "digits/h-%d", c); + } + } else { + if (c == 1) { + if (gender == SSG_NEUTER) { + switch_say_file(sh, "digits/%d_n", c); + } else if (gender == SSG_FEMININE) { + switch_say_file(sh, "digits/%d_a", c); + } else { + switch_say_file(sh, "digits/%d", c); + } + } else { + switch_say_file(sh, "digits/%d", c); + } + } + } + + if (what && (a || b || c)) { + switch_say_file(sh, what); + } + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t es_say_general_count(switch_say_file_handle_t *sh, char *tosay, switch_say_args_t *say_args) +{ + int in; + int x = 0; + int places[9] = { 0 }; + char sbuf[128] = ""; + switch_status_t status; + + if (say_args->method == SSM_ITERATED) { + if ((tosay = switch_strip_commas(tosay, sbuf, sizeof(sbuf)-1))) { + char *p; + for (p = tosay; p && *p; p++) { + char *n_p = p+1; + switch_say_file(sh, "digits/%c", *p); + if (n_p && *n_p) { + switch_say_file(sh, "silence_stream://100"); + } + } + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Parse Error!\n"); + return SWITCH_STATUS_GENERR; + } + return SWITCH_STATUS_SUCCESS; + } + + if (!(tosay = switch_strip_commas(tosay, sbuf, sizeof(sbuf)-1)) || strlen(tosay) > 9) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Parse Error!\n"); + return SWITCH_STATUS_GENERR; + } + + in = atoi(tosay); + + if (in != 0) { + for (x = 8; x >= 0; x--) { + int num = (int) pow(10, x); + if ((places[(uint32_t) x] = in / num)) { + in -= places[(uint32_t) x] * num; + } + } + + + switch (say_args->method) { + case SSM_PRONOUNCED_YEAR: + { + int num = atoi(tosay); + int a = num / 100; + int b = num % 100; + + if (!b || !(a % 10)) { + say_num(sh, num, SSM_PRONOUNCED); + return SWITCH_STATUS_SUCCESS; + } + + say_num(sh, a, SSM_PRONOUNCED); + say_num(sh, b, SSM_PRONOUNCED); + + return SWITCH_STATUS_SUCCESS; + } + break; + case SSM_COUNTED: + case SSM_PRONOUNCED: + if ((status = play_group(SSM_PRONOUNCED, say_args->gender, places[8], places[7], places[6], "digits/million", sh)) != SWITCH_STATUS_SUCCESS) { + return status; + } + if ((status = play_group(SSM_PRONOUNCED, say_args->gender, places[5], places[4], places[3], "digits/thousand", sh)) != SWITCH_STATUS_SUCCESS) { + return status; + } + if ((status = play_group(say_args->method, say_args->gender, places[2], places[1], places[0], NULL, sh)) != SWITCH_STATUS_SUCCESS) { + return status; + } + break; + default: + break; + } + } else { + switch_say_file(sh, "digits/0"); + } + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t es_say_time(switch_say_file_handle_t *sh, char *tosay, switch_say_args_t *say_args) +{ + int32_t t; + switch_time_t target = 0, target_now = 0; + switch_time_exp_t tm, tm_now; + uint8_t say_date = 0, say_time = 0, say_year = 0, say_month = 0, say_dow = 0, say_day = 0, say_yesterday = 0, say_today = 0; + const char *tz = NULL; + + tz = switch_say_file_handle_get_variable(sh, "timezone"); + + if (say_args->type == SST_TIME_MEASUREMENT) { + int64_t hours = 0; + int64_t minutes = 0; + int64_t seconds = 0; + int64_t r = 0; + + if (strchr(tosay, ':')) { + char *tme = strdup(tosay); + char *p; + + if ((p = strrchr(tme, ':'))) { + *p++ = '\0'; + seconds = atoi(p); + if ((p = strchr(tme, ':'))) { + *p++ = '\0'; + minutes = atoi(p); + hours = atoi(tme); + } else { + minutes = atoi(tme); + } + } + free(tme); + } else { + if ((seconds = atol(tosay)) <= 0) { + seconds = (int64_t) switch_epoch_time_now(NULL); + } + + if (seconds >= 60) { + minutes = seconds / 60; + r = seconds % 60; + seconds = r; + } + + if (minutes >= 60) { + hours = minutes / 60; + r = minutes % 60; + minutes = r; + } + } + + if (hours) { + say_num(sh, hours, SSM_PRONOUNCED); + if (hours == 1) { + switch_say_file(sh, "time/hour"); + } else { + switch_say_file(sh, "time/hours"); + } + } else { + switch_say_file(sh, "digits/0"); + switch_say_file(sh, "time/hours"); + } + + if (minutes) { + say_num(sh, minutes, SSM_PRONOUNCED); + if (minutes == 1) { + switch_say_file(sh, "time/minute"); + } else { + switch_say_file(sh, "time/minutes"); + } + } else { + switch_say_file(sh, "digits/0"); + switch_say_file(sh, "time/minutes"); + } + + if (seconds) { + say_num(sh, seconds, SSM_PRONOUNCED); + if (seconds == 1) { + switch_say_file(sh, "time/second"); + } else { + switch_say_file(sh, "time/seconds"); + } + } else { + switch_say_file(sh, "digits/0"); + switch_say_file(sh, "time/seconds"); + } + + return SWITCH_STATUS_SUCCESS; + } + + if ((t = atol(tosay)) > 0) { + target = switch_time_make(t, 0); + target_now = switch_micro_time_now(); + } else { + target = switch_micro_time_now(); + target_now = switch_micro_time_now(); + } + + if (tz) { + int check = atoi(tz); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Timezone is [%s]\n", tz); + if (check) { + switch_time_exp_tz(&tm, target, check); + switch_time_exp_tz(&tm_now, target_now, check); + } else { + switch_time_exp_tz_name(tz, &tm, target); + switch_time_exp_tz_name(tz, &tm_now, target_now); + } + } else { + switch_time_exp_lt(&tm, target); + switch_time_exp_lt(&tm_now, target_now); + } + + switch (say_args->type) { + case SST_CURRENT_DATE_TIME: + say_date = say_time = 1; + break; + case SST_CURRENT_DATE: + say_date = 1; + break; + case SST_CURRENT_TIME: + say_time = 1; + break; + case SST_SHORT_DATE_TIME: + say_time = 1; + //Time is in the future + if ((tm.tm_year > tm_now.tm_year) || + (tm.tm_year == tm_now.tm_year && tm.tm_mon > tm_now.tm_mon) || + (tm.tm_year == tm_now.tm_year && tm.tm_mon == tm_now.tm_mon && tm.tm_mday > tm_now.tm_mday)) + { + say_date = 1; + break; + } + //Time is today or earlier + if (tm.tm_year != tm_now.tm_year) { + say_date = 1; + break; + } + if (tm.tm_yday == tm_now.tm_yday) { + say_today = 1; + break; + } + if (tm.tm_yday == tm_now.tm_yday - 1) { + say_yesterday = 1; + break; + } + if (tm.tm_yday >= tm_now.tm_yday - 5) { + say_dow = 1; + break; + } + if (tm.tm_mon != tm_now.tm_mon) { + say_month = say_day = say_dow = 1; + break; + } + + say_month = say_day = say_dow = 1; + + break; + default: + break; + } + + if (say_today) { + switch_say_file(sh, "time/today"); + } + if (say_yesterday) { + switch_say_file(sh, "time/yesterday"); + } + if (say_dow) { + switch_say_file(sh, "time/day-%d", tm.tm_wday); + } + + if (say_date) { + say_year = say_month = say_day = say_dow = 1; + say_today = say_yesterday = 0; + } + + if (say_day) { + if (tm.tm_mday == 1) { + say_num(sh, tm.tm_mday, SSM_COUNTED); + } else { + say_num(sh, tm.tm_mday, SSM_PRONOUNCED); + } + switch_say_file(sh, "time/de"); + } + if (say_month) { + switch_say_file(sh, "time/mon-%d", tm.tm_mon); + } + if (say_year) { + switch_say_file(sh, "time/de"); + say_num(sh, tm.tm_year + 1900, SSM_PRONOUNCED_YEAR); + } + + if (say_time) { + + if (say_date || say_today || say_yesterday || say_dow) { + switch_say_file(sh, "time/at"); + } + + + if (tm.tm_hour == 1) { + switch_say_file(sh, "digits/1"); + switch_say_file(sh, "time/hour"); + } else { + say_num(sh, tm.tm_hour, SSM_PRONOUNCED); + switch_say_file(sh, "time/hours"); + } + + if (tm.tm_min == 1) { + switch_say_file(sh, "digits/1_1a"); + switch_say_file(sh, "time/minute"); + } else { + say_num(sh, tm.tm_min, SSM_PRONOUNCED); + switch_say_file(sh, "time/minutes"); + } + + } + + return SWITCH_STATUS_SUCCESS; +} + + +static switch_status_t es_say_money(switch_say_file_handle_t *sh, char *tosay, switch_say_args_t *say_args) +{ + char sbuf[16] = ""; /* enough for 999,999,999,999.99 (w/o the commas or leading $) */ + char *dollars = NULL; + char *cents = NULL; + + if (strlen(tosay) > 15 || !switch_strip_nonnumerics(tosay, sbuf, sizeof(sbuf)-1)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Parse Error!\n"); + return SWITCH_STATUS_GENERR; + } + + dollars = sbuf; + + if ((cents = strchr(sbuf, '.'))) { + *cents++ = '\0'; + if (strlen(cents) > 2) { + cents[2] = '\0'; + } + } + + /* If positive sign - skip over" */ + if (sbuf[0] == '+') { + dollars++; + } + + /* If negative say "negative" */ + if (sbuf[0] == '-') { + switch_say_file(sh, "currency/negative"); + dollars++; + } + + /* Say dollar amount */ + es_say_general_count(sh, dollars, say_args); + if (atoi(dollars) == 1) { + switch_say_file(sh, "currency/dollar"); + } else { + switch_say_file(sh, "currency/dollars"); + } + + /* Say cents */ + if (cents) { + /* Say "and" */ + switch_say_file(sh, "currency/and"); + + es_say_general_count(sh, cents, say_args); + if (atoi(cents) == 1) { + switch_say_file(sh, "currency/cent"); + } else { + switch_say_file(sh, "currency/cents"); + } + } + + return SWITCH_STATUS_SUCCESS; +} + + +static switch_status_t say_ip(switch_say_file_handle_t *sh, + char *tosay, + switch_say_args_t *say_args) + +{ + char *a, *b, *c, *d; + switch_status_t status = SWITCH_STATUS_FALSE; + + if (!(a = strdup(tosay))) { + abort(); + } + + if (!(b = strchr(a, '.'))) { + goto end; + } + + *b++ = '\0'; + + if (!(c = strchr(b, '.'))) { + goto end; + } + + *c++ = '\0'; + + if (!(d = strchr(c, '.'))) { + goto end; + } + + *d++ = '\0'; + + say_num(sh, atoi(a), say_args->method); + switch_say_file(sh, "digits/dot"); + say_num(sh, atoi(b), say_args->method); + switch_say_file(sh, "digits/dot"); + say_num(sh, atoi(c), say_args->method); + switch_say_file(sh, "digits/dot"); + say_num(sh, atoi(d), say_args->method); + + end: + + free(a); + + return status; +} + + +static switch_status_t say_telephone_number(switch_say_file_handle_t *sh, char *tosay, switch_say_args_t *say_args) +{ + int silence = 0; + char *p; + + for (p = tosay; !zstr(p); p++) { + int a = tolower((int) *p); + if (a >= '0' && a <= '9') { + switch_say_file(sh, "digits/%c", a); + silence = 0; + } else if (a == '+' || (a >= 'a' && a <= 'z')) { + switch_say_file(sh, "ascii/%d", a); + silence = 0; + } else if (!silence) { + switch_say_file(sh, "silence_stream://100"); + silence = 1; + } + } + + return SWITCH_STATUS_SUCCESS; +} + + +static switch_status_t say_spell(switch_say_file_handle_t *sh, char *tosay, switch_say_args_t *say_args) +{ + char *p; + + for (p = tosay; p && *p; p++) { + int a = tolower((int) *p); + if (a >= '0' && a <= '9') { + switch_say_file(sh, "digits/%c", a); + } else { + if (say_args->type == SST_NAME_SPELLED) { + switch_say_file(sh, "ascii/%d", a); + } else if (say_args->type == SST_NAME_PHONETIC) { + switch_say_file(sh, "phonetic-ascii/%d", a); + } + } + } + + return SWITCH_STATUS_SUCCESS; +} + + +static switch_new_say_callback_t choose_callback(switch_say_args_t *say_args) +{ + switch_new_say_callback_t say_cb = NULL; + + switch (say_args->type) { + case SST_NUMBER: + case SST_ITEMS: + case SST_PERSONS: + case SST_MESSAGES: + say_cb = es_say_general_count; + break; + case SST_TIME_MEASUREMENT: + case SST_CURRENT_DATE: + case SST_CURRENT_TIME: + case SST_CURRENT_DATE_TIME: + case SST_SHORT_DATE_TIME: + say_cb = es_say_time; + break; + case SST_IP_ADDRESS: + say_cb = say_ip; + break; + case SST_NAME_SPELLED: + case SST_NAME_PHONETIC: + say_cb = say_spell; + break; + case SST_CURRENCY: + say_cb = es_say_money; + break; + case SST_TELEPHONE_NUMBER: + say_cb = say_telephone_number; + break; + default: + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unknown Say type=[%d]\n", say_args->type); + break; + } + + return say_cb; +} + + +static switch_status_t run_callback(switch_new_say_callback_t say_cb, char *tosay, switch_say_args_t *say_args, switch_core_session_t *session, char **rstr) +{ + switch_say_file_handle_t *sh; + switch_status_t status = SWITCH_STATUS_FALSE; + switch_event_t *var_event = NULL; + + if (session) { + switch_channel_t *channel = switch_core_session_get_channel(session); + switch_channel_get_variables(channel, &var_event); + } + + switch_say_file_handle_create(&sh, say_args->ext, &var_event); + + status = say_cb(sh, tosay, say_args); + + if ((*rstr = switch_say_file_handle_detach_path(sh))) { + status = SWITCH_STATUS_SUCCESS; + } + + switch_say_file_handle_destroy(&sh); + + return status; +} + + +static switch_status_t es_say(switch_core_session_t *session, char *tosay, switch_say_args_t *say_args, switch_input_args_t *args) +{ + + switch_new_say_callback_t say_cb = NULL; + char *string = NULL; + + switch_status_t status = SWITCH_STATUS_FALSE; + + say_cb = choose_callback(say_args); + + if (say_cb) { + status = run_callback(say_cb, tosay, say_args, session, &string); + if (session && string) { + status = switch_ivr_play_file(session, NULL, string, args); + } + + switch_safe_free(string); + } + + return status; +} + + +static switch_status_t es_say_string(switch_core_session_t *session, char *tosay, switch_say_args_t *say_args, char **rstr) +{ + + switch_new_say_callback_t say_cb = NULL; + char *string = NULL; + + switch_status_t status = SWITCH_STATUS_FALSE; + + say_cb = choose_callback(say_args); + + if (say_cb) { + status = run_callback(say_cb, tosay, say_args, session, &string); + if (string) { + status = SWITCH_STATUS_SUCCESS; + *rstr = string; + } + } + + return status; +} + +SWITCH_MODULE_LOAD_FUNCTION(mod_say_es_ar_load) +{ + switch_say_interface_t *say_interface; + /* connect my internal structure to the blank pointer passed to me */ + *module_interface = switch_loadable_module_create_module_interface(pool, modname); + say_interface = switch_loadable_module_create_interface(*module_interface, SWITCH_SAY_INTERFACE); + say_interface->interface_name = "es_ar"; + say_interface->say_function = es_say; + say_interface->say_string_function = es_say_string; + + /* indicate that the module should continue to be loaded */ + 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/xml_int/mod_xml_radius/mod_xml_radius.c b/src/mod/xml_int/mod_xml_radius/mod_xml_radius.c index bc75843800..94e127a12e 100644 --- a/src/mod/xml_int/mod_xml_radius/mod_xml_radius.c +++ b/src/mod/xml_int/mod_xml_radius/mod_xml_radius.c @@ -201,7 +201,7 @@ switch_status_t do_config() goto err; } } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Could not find 'auth_invite' section in config file.\n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Could not find 'auth_reg' section in config file.\n"); } if ((tmp = switch_xml_child(cfg, "global")) != NULL ) { @@ -741,7 +741,7 @@ switch_xml_t mod_xml_radius_auth_reg(switch_event_t *params) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: starting registration authentication\n"); } - if ( mod_xml_radius_new_handle(&new_handle, globals.auth_invite_configs) != SWITCH_STATUS_SUCCESS ) { + if ( mod_xml_radius_new_handle(&new_handle, globals.auth_reg_configs) != SWITCH_STATUS_SUCCESS ) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to load radius handle for registration authentication\n"); goto err; } @@ -849,7 +849,7 @@ static switch_xml_t mod_xml_radius_directory_search(const char *section, const c switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: starting authentication\n"); switch_event_serialize(params, &event_buf, SWITCH_TRUE); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Event: %s \n", event_buf); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Section: %s \nTag: %s\nKey_name: %s\nKey_value: %s\n", + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "\nSection: %s \nTag: %s\nKey_name: %s\nKey_value: %s\n", section, tag_name, key_name, key_value); } @@ -1087,7 +1087,7 @@ SWITCH_STANDARD_APP(radius_auth_handle) temp = NULL; if ( result != 0 ) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: Failed to authenticate\n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: Failed to authenticate, authentication result: %d \n", result); goto err; } @@ -1169,7 +1169,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_xml_radius_load) return SWITCH_STATUS_TERM; } - if ( globals.auth_invite_configs ) { + if ( globals.auth_invite_configs && globals.auth_reg_configs ) { status = switch_xml_bind_search_function(mod_xml_radius_directory_search, switch_xml_parse_section_string("directory"), NULL); } diff --git a/src/switch_channel.c b/src/switch_channel.c index 7fae7f16a2..3b96dcdc4d 100644 --- a/src/switch_channel.c +++ b/src/switch_channel.c @@ -4303,7 +4303,6 @@ SWITCH_DECLARE(switch_status_t) switch_channel_set_timestamps(switch_channel_t * switch_safe_free(substituted); substituted = switch_string_replace(substituted ? substituted : dtstr, replace, X); - printf("WTF [%s][%s]\n", replace, substituted); pcre_free_substring(replace); } } diff --git a/src/switch_core.c b/src/switch_core.c index bf07f46451..b23a35b542 100644 --- a/src/switch_core.c +++ b/src/switch_core.c @@ -1,3 +1,4 @@ + /* * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application * Copyright (C) 2005-2014, Anthony Minessale II @@ -1300,6 +1301,12 @@ SWITCH_DECLARE(void) switch_load_network_lists(switch_bool_t reload) switch_core_hash_init(&IP_LIST.hash); + tmp_name = "rfc6598.auto"; + switch_network_list_create(&rfc_list, tmp_name, SWITCH_FALSE, IP_LIST.pool); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Created ip list %s default (deny)\n", tmp_name); + switch_network_list_add_cidr(rfc_list, "100.64.0.0/10", SWITCH_TRUE); + switch_core_hash_insert(IP_LIST.hash, tmp_name, rfc_list); + tmp_name = "rfc1918.auto"; switch_network_list_create(&rfc_list, tmp_name, SWITCH_FALSE, IP_LIST.pool); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Created ip list %s default (deny)\n", tmp_name); @@ -1327,6 +1334,7 @@ SWITCH_DECLARE(void) switch_load_network_lists(switch_bool_t reload) switch_network_list_add_cidr(rfc_list, "10.0.0.0/8", SWITCH_TRUE); switch_network_list_add_cidr(rfc_list, "172.16.0.0/12", SWITCH_TRUE); switch_network_list_add_cidr(rfc_list, "192.168.0.0/16", SWITCH_TRUE); + switch_network_list_add_cidr(rfc_list, "100.64.0.0/10", SWITCH_TRUE); switch_core_hash_insert(IP_LIST.hash, tmp_name, rfc_list); tmp_name = "loopback.auto"; @@ -1551,6 +1559,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_thread_set_cpu_affinity(int cpu) } +#ifdef ENABLE_ZRTP static void switch_core_set_serial(void) { char buf[13] = ""; @@ -1596,7 +1605,7 @@ static void switch_core_set_serial(void) switch_core_set_variable("switch_serial", buf); } - +#endif SWITCH_DECLARE(int) switch_core_test_flag(int flag) { @@ -1740,8 +1749,9 @@ SWITCH_DECLARE(switch_status_t) switch_core_init(switch_core_flag_t flags, switc switch_core_set_variable("certs_dir", SWITCH_GLOBAL_dirs.certs_dir); switch_core_set_variable("storage_dir", SWITCH_GLOBAL_dirs.storage_dir); switch_core_set_variable("cache_dir", SWITCH_GLOBAL_dirs.cache_dir); +#ifdef ENABLE_ZRTP switch_core_set_serial(); - +#endif switch_console_init(runtime.memory_pool); switch_event_init(runtime.memory_pool); switch_channel_global_init(runtime.memory_pool); @@ -1972,6 +1982,12 @@ static void switch_load_core_config(const char *file) runtime.core_db_inner_pre_trans_execute = switch_core_strdup(runtime.memory_pool, val); } else if (!strcasecmp(var, "core-db-inner-post-trans-execute") && !zstr(val)) { runtime.core_db_inner_post_trans_execute = switch_core_strdup(runtime.memory_pool, val); + } else if (!strcasecmp(var, "dialplan-timestamps")) { + if (switch_true(val)) { + switch_set_flag((&runtime), SCF_DIALPLAN_TIMESTAMPS); + } else { + switch_clear_flag((&runtime), SCF_DIALPLAN_TIMESTAMPS); + } } else if (!strcasecmp(var, "mailer-app") && !zstr(val)) { runtime.mailer_app = switch_core_strdup(runtime.memory_pool, val); } else if (!strcasecmp(var, "mailer-app-args") && val) { diff --git a/src/switch_core_media.c b/src/switch_core_media.c index 32956df273..1c7c369474 100644 --- a/src/switch_core_media.c +++ b/src/switch_core_media.c @@ -235,7 +235,7 @@ SWITCH_DECLARE(int) switch_core_media_crypto_keylen(switch_rtp_crypto_key_type_t static int get_channels(const char *name, int dft) { - if (!switch_true(switch_core_get_variable("NDLB_broken_opus_sdp")) && !strcasecmp(name, "opus")) { + if (!zstr(name) && !switch_true(switch_core_get_variable("NDLB_broken_opus_sdp")) && !strcasecmp(name, "opus")) { return 2; /* IKR???*/ } @@ -3827,7 +3827,7 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s switch_snprintf(tmp, sizeof(tmp), "%d", a_engine->cur_payload_map->recv_pt); switch_channel_set_variable(session->channel, "rtp_audio_recv_pt", tmp); - if (switch_core_codec_ready(&a_engine->read_codec)) { + if (switch_core_codec_ready(&a_engine->read_codec) && strcasecmp(matches[0].imp->iananame, a_engine->read_codec.implementation->iananame)) { a_engine->reset_codec = 1; } @@ -4071,7 +4071,7 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s switch_channel_set_variable(session->channel, "rtp_video_recv_pt", tmp); if (!match && vmatch) match = 1; - if (switch_core_codec_ready(&v_engine->read_codec)) { + if (switch_core_codec_ready(&v_engine->read_codec) && strcasecmp(matches[0].imp->iananame, v_engine->read_codec.implementation->iananame)) { v_engine->reset_codec = 1; } @@ -4375,7 +4375,10 @@ static switch_status_t start_video_thread(switch_core_session_t *session) switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "%s Starting Video thread\n", switch_core_session_get_name(session)); - switch_rtp_set_default_payload(v_engine->rtp_session, v_engine->cur_payload_map->agreed_pt); + if (v_engine->rtp_session) { + switch_rtp_set_default_payload(v_engine->rtp_session, v_engine->cur_payload_map->agreed_pt); + } + v_engine->mh.session = session; switch_threadattr_create(&thd_attr, pool); switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE); @@ -4388,7 +4391,10 @@ static switch_status_t start_video_thread(switch_core_session_t *session) return SWITCH_STATUS_SUCCESS; } - +SWITCH_DECLARE(switch_status_t) switch_core_media_start_video_thread(switch_core_session_t *session) +{ + return start_video_thread(session); +} //? #define RA_PTR_LEN 512 @@ -4940,7 +4946,13 @@ SWITCH_DECLARE(void) switch_core_session_wake_video_thread(switch_core_session_t v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO]; - if (!v_engine->rtp_session) { + if ((!smh->mparams->external_video_source) && (!v_engine->rtp_session)) { + return; + } + + if (!v_engine->mh.cond_mutex) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Channel %s has no cond?\n", + switch_channel_get_name(session->channel)); return; } diff --git a/src/switch_core_session.c b/src/switch_core_session.c index c5f1eaa718..a3728234e1 100644 --- a/src/switch_core_session.c +++ b/src/switch_core_session.c @@ -2811,8 +2811,13 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_exec(switch_core_session_t * } - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, "EXECUTE %s %s(%s)\n", + if ( switch_core_test_flag(SCF_DIALPLAN_TIMESTAMPS) ) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "EXECUTE %s %s(%s)\n", switch_channel_get_name(session->channel), app, switch_str_nil(expanded)); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, "EXECUTE %s %s(%s)\n", + switch_channel_get_name(session->channel), app, switch_str_nil(expanded)); + } if ((var = switch_channel_get_variable(session->channel, "verbose_presence")) && switch_true(var)) { char *myarg = NULL; diff --git a/src/switch_core_sqldb.c b/src/switch_core_sqldb.c index 31e835e760..508b68643d 100644 --- a/src/switch_core_sqldb.c +++ b/src/switch_core_sqldb.c @@ -1267,20 +1267,38 @@ SWITCH_DECLARE(switch_status_t) switch_cache_db_execute_sql_callback_err(switch_ return status; } +/*! + * \brief Performs test_sql and if it fails performs drop_sql and reactive_sql. + * + * If auto-clear-sql is disabled, then this function will do nothing and it is + * assumed that the queries are not needed. If auto-create-schemas is disabled, + * then just test_sql is executed, but drop_sql and reactive_sql are not. + * + * Otherwise, test_sql gets executed. If that succeeds, then there is nothing to + * do. Otherwise drop_sql is executed (its result is ignored) and then finally + * reactive_sql is executed. + * + * \return If auto-create-schemas is enabled, SWITCH_TRUE is returned if + * test_sql succeeds, SWITCH_FALSE otherwise. If reactive_sql is executed + * successfully SWITCH_TRUE is returned, otherwise SWITCH_FALSE is returned. + */ SWITCH_DECLARE(switch_bool_t) switch_cache_db_test_reactive(switch_cache_db_handle_t *dbh, const char *test_sql, const char *drop_sql, const char *reactive_sql) { - char *errmsg; switch_bool_t r = SWITCH_TRUE; switch_mutex_t *io_mutex = dbh->io_mutex; + switch_assert(test_sql != NULL); + switch_assert(reactive_sql != NULL); + if (!switch_test_flag((&runtime), SCF_CLEAR_SQL)) { return SWITCH_TRUE; } if (!switch_test_flag((&runtime), SCF_AUTO_SCHEMAS)) { - switch_cache_db_execute_sql(dbh, (char *)test_sql, NULL); - return SWITCH_TRUE; + switch_status_t status = switch_cache_db_execute_sql(dbh, (char *)test_sql, NULL); + + return (status == SWITCH_STATUS_SUCCESS) ? SWITCH_TRUE : SWITCH_FALSE; } if (io_mutex) switch_mutex_lock(io_mutex); @@ -1289,49 +1307,48 @@ SWITCH_DECLARE(switch_bool_t) switch_cache_db_test_reactive(switch_cache_db_hand case SCDB_TYPE_PGSQL: { if (switch_pgsql_handle_exec(dbh->native_handle.pgsql_dbh, test_sql, NULL) != SWITCH_PGSQL_SUCCESS) { - r = SWITCH_FALSE; if (drop_sql) { switch_pgsql_handle_exec(dbh->native_handle.pgsql_dbh, drop_sql, NULL); } - switch_pgsql_handle_exec(dbh->native_handle.pgsql_dbh, reactive_sql, NULL); + r = switch_pgsql_handle_exec(dbh->native_handle.pgsql_dbh, reactive_sql, NULL) == SWITCH_PGSQL_SUCCESS; } } break; case SCDB_TYPE_ODBC: { if (switch_odbc_handle_exec(dbh->native_handle.odbc_dbh, test_sql, NULL, NULL) != SWITCH_ODBC_SUCCESS) { - r = SWITCH_FALSE; if (drop_sql) { switch_odbc_handle_exec(dbh->native_handle.odbc_dbh, drop_sql, NULL, NULL); } - switch_odbc_handle_exec(dbh->native_handle.odbc_dbh, reactive_sql, NULL, NULL); + r = switch_odbc_handle_exec(dbh->native_handle.odbc_dbh, reactive_sql, NULL, NULL) == SWITCH_ODBC_SUCCESS; } } break; case SCDB_TYPE_CORE_DB: { - if (test_sql) { - switch_core_db_exec(dbh->native_handle.core_db_dbh, test_sql, NULL, NULL, &errmsg); + char *errmsg = NULL; + switch_core_db_exec(dbh->native_handle.core_db_dbh, test_sql, NULL, NULL, &errmsg); + if (errmsg) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SQL ERR [%s]\n[%s]\nAuto Generating Table!\n", errmsg, test_sql); + switch_core_db_free(errmsg); + errmsg = NULL; + if (drop_sql) { + switch_core_db_exec(dbh->native_handle.core_db_dbh, drop_sql, NULL, NULL, &errmsg); + } if (errmsg) { - r = SWITCH_FALSE; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SQL ERR [%s]\n[%s]\nAuto Generating Table!\n", errmsg, test_sql); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Ignoring SQL ERR [%s]\n[%s]\n", errmsg, drop_sql); switch_core_db_free(errmsg); errmsg = NULL; - if (drop_sql) { - switch_core_db_exec(dbh->native_handle.core_db_dbh, drop_sql, NULL, NULL, &errmsg); - } - if (errmsg) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SQL ERR [%s]\n[%s]\n", errmsg, drop_sql); - switch_core_db_free(errmsg); - errmsg = NULL; - } - switch_core_db_exec(dbh->native_handle.core_db_dbh, reactive_sql, NULL, NULL, &errmsg); - if (errmsg) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SQL ERR [%s]\n[%s]\n", errmsg, reactive_sql); - switch_core_db_free(errmsg); - errmsg = NULL; - } + } + switch_core_db_exec(dbh->native_handle.core_db_dbh, reactive_sql, NULL, NULL, &errmsg); + if (errmsg) { + r = SWITCH_FALSE; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SQL ERR [%s]\n[%s]\n", errmsg, reactive_sql); + switch_core_db_free(errmsg); + errmsg = NULL; + } else { + r = SWITCH_TRUE; } } } diff --git a/src/switch_ivr_async.c b/src/switch_ivr_async.c index dcea776c83..1b209ae196 100644 --- a/src/switch_ivr_async.c +++ b/src/switch_ivr_async.c @@ -1088,17 +1088,17 @@ static void send_record_stop_event(switch_channel_t *channel, switch_codec_imple { switch_event_t *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)); + if (rh->fh) { + switch_channel_set_variable_printf(channel, "record_samples", "%d", rh->fh->samples_out); + 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)); + } } - if (!zstr(rh->completion_cause)) { switch_channel_set_variable_printf(channel, "record_completion_cause", "%s", rh->completion_cause); } - 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); diff --git a/src/switch_stun.c b/src/switch_stun.c index 55f8a65eac..b29c48d325 100644 --- a/src/switch_stun.c +++ b/src/switch_stun.c @@ -129,9 +129,7 @@ SWITCH_DECLARE(switch_stun_packet_t *) switch_stun_packet_parse(uint8_t *buf, ui packet = (switch_stun_packet_t *) buf; packet->header.type = ntohs(packet->header.type); packet->header.length = ntohs(packet->header.length); - if (packet->header.length > (bytes_left -= 20)) - return NULL; - + if (packet->header.length > (bytes_left -= 20)) return NULL; /* * Check packet type (RFC3489(bis?) values) diff --git a/src/switch_utils.c b/src/switch_utils.c index 3cde97a127..444333ec12 100644 --- a/src/switch_utils.c +++ b/src/switch_utils.c @@ -2567,6 +2567,12 @@ SWITCH_DECLARE(int) switch_wait_sock(switch_os_socket_t sock, uint32_t ms, switc s = poll(pfds, 1, ms); + if (s < 0) { + if (switch_errno_is_break(switch_errno())) { + s = 0; + } + } + if (s < 0) { r = s; } else if (s > 0) { @@ -2645,6 +2651,12 @@ SWITCH_DECLARE(int) switch_wait_socklist(switch_waitlist_t *waitlist, uint32_t l s = poll(pfds, len, ms); + if (s < 0) { + if (switch_errno_is_break(switch_errno())) { + s = 0; + } + } + if (s < 0) { r = s; } else if (s > 0) { @@ -2758,6 +2770,12 @@ SWITCH_DECLARE(int) switch_wait_sock(switch_os_socket_t sock, uint32_t ms, switc s = select(sock + 1, (flags & SWITCH_POLL_READ) ? rfds : NULL, (flags & SWITCH_POLL_WRITE) ? wfds : NULL, (flags & SWITCH_POLL_ERROR) ? efds : NULL, &tv); + if (s < 0) { + if (switch_errno_is_break(switch_errno())) { + s = 0; + } + } + if (s < 0) { r = s; } else if (s > 0) { @@ -2858,6 +2876,12 @@ SWITCH_DECLARE(int) switch_wait_socklist(switch_waitlist_t *waitlist, uint32_t l s = select(max_fd + 1, (flags & SWITCH_POLL_READ) ? rfds : NULL, (flags & SWITCH_POLL_WRITE) ? wfds : NULL, (flags & SWITCH_POLL_ERROR) ? efds : NULL, &tv); + if (s < 0) { + if (switch_errno_is_break(switch_errno())) { + s = 0; + } + } + if (s < 0) { r = s; } else if (s > 0) { diff --git a/support-d/fscore_pb b/support-d/fscore_pb index 80fd022fdf..c1c932d185 100755 --- a/support-d/fscore_pb +++ b/support-d/fscore_pb @@ -87,7 +87,8 @@ fi post_cmd="" command -v wget >/dev/null 2>&1 if [ $? -eq 0 ]; then - post_cmd="wget --output-file=/dev/null --output-document=/tmp/fscore_pb.tmp/pb_out --http-user=pastebin --http-password=freeswitch http://pastebin.freeswitch.org --post-file=$post_file" + post_cmd="wget --output-file=/dev/null --output-document=/tmp/fscore_pb.tmp/pb_out --http-user=pastebin --http-password=freeswitch https://pastebin.freeswitch.org --post-file=$post_file" + echo -n "paste=Send&remember=0&poster=$user&format=none&expiry=f&code2=" > $post_file fi if [ -z "$post_cmd" ]; then @@ -102,17 +103,15 @@ if [ -z "$post_cmd" ]; then exit 255 fi -if [[ "$post_cmd" == wget* ]]; then - echo -n "paste=Send&remember=0&poster=$user&format=none&expiry=f&code2=" > $post_file -fi - echo "Gathering Data Please Wait........." +UNAME=`uname`; + #Linux -if [ $(uname) == "Linux" ]; then +if [ "${UNAME}" = "Linux" ]; then echo "LSB RELEASE:" >> $post_file echo $line >> $post_file - if [ -f /etc/redhat-release ] ; then + if [ -f /etc/redhat-release ]; then cat /etc/redhat-release >> $post_file else lsb_release -a >> $post_file @@ -122,7 +121,7 @@ if [ $(uname) == "Linux" ]; then echo $line >> $post_file cat /proc/cpuinfo >> $post_file #Mac -elif [ $(uname) == "Darwin" ]; then +elif [ "${UNAME}" = "Darwin" ]; then system_profiler SPSoftwareDataType SPHardwareDataType >> $post_file fi;