Merge "chan_iax2: Prevent deadlock between hangup and sending lagrq/ping"
authorMark Michelson <mmichelson@digium.com>
Wed, 10 Jun 2015 17:06:02 +0000 (12:06 -0500)
committerGerrit Code Review <gerrit2@gerrit.digium.api>
Wed, 10 Jun 2015 17:06:02 +0000 (12:06 -0500)
390 files changed:
.gitignore
CHANGES
CREDITS
Makefile
Makefile.moddir_rules
Makefile.rules
UPGRADE.txt
addons/chan_mobile.c
addons/chan_ooh323.c
addons/res_config_mysql.c
apps/app_adsiprog.c
apps/app_alarmreceiver.c
apps/app_amd.c
apps/app_celgenuserevent.c
apps/app_fax.c
apps/app_followme.c
apps/app_getcpeid.c
apps/app_meetme.c
apps/app_minivm.c
apps/app_playback.c
apps/app_queue.c
apps/app_speech_utils.c
apps/app_stack.c
apps/app_stasis.c
apps/app_voicemail.c
apps/confbridge/conf_config_parser.c
autoconf/ast_check_raii.m4 [new file with mode: 0644]
autoconf/ast_check_strsep_array_bounds.m4 [new file with mode: 0644]
autoconf/ast_gcc_attribute.m4
build_tools/cflags.xml
build_tools/get_moduleinfo
build_tools/make_buildopts_h
cdr/cdr_adaptive_odbc.c
cdr/cdr_csv.c
cdr/cdr_custom.c
cdr/cdr_manager.c
cdr/cdr_odbc.c
cdr/cdr_pgsql.c
cdr/cdr_radius.c
cdr/cdr_tds.c
cel/cel_custom.c
cel/cel_odbc.c
cel/cel_pgsql.c
channels/chan_alsa.c
channels/chan_bridge_media.c
channels/chan_console.c
channels/chan_dahdi.c
channels/chan_iax2.c
channels/chan_mgcp.c
channels/chan_motif.c
channels/chan_pjsip.c
channels/chan_sip.c
channels/chan_skinny.c
channels/chan_unistim.c
channels/chan_vpb.cc
channels/dahdi/bridge_native_dahdi.c
channels/dahdi/bridge_native_dahdi.h
channels/sig_pri.c
channels/sig_pri.h
channels/sip/dialplan_functions.c
codecs/codec_adpcm.c
codecs/codec_alaw.c
codecs/codec_dahdi.c
codecs/codec_g722.c
codecs/codec_g726.c
codecs/codec_gsm.c
codecs/codec_lpc10.c
codecs/codec_speex.c
codecs/codec_ulaw.c
codecs/gsm/Makefile
codecs/lpc10/lpcini.c
configs/basic-pbx/extensions.conf
configs/samples/asterisk.conf.sample
configs/samples/cdr.conf.sample
configs/samples/cdr_adaptive_odbc.conf.sample
configs/samples/cdr_odbc.conf.sample
configs/samples/cel_pgsql.conf.sample
configs/samples/chan_dahdi.conf.sample
configs/samples/extensions_minivm.conf.sample
configs/samples/pjsip.conf.sample
configs/samples/sip.conf.sample
configure
configure.ac
contrib/Makefile
contrib/ast-db-manage/config/versions/31cd4f4891ec_add_auto_dtmf_mode.py
contrib/editors/asterisk.vim
contrib/scripts/clang-scan-build [new file with mode: 0755]
contrib/scripts/get_mp3_source.sh
contrib/scripts/refcounter.py
doc/.gitignore
doc/asterisk-ng-doxygen.in [moved from contrib/asterisk-ng-doxygen with 100% similarity]
doc/asterisk.8
funcs/func_aes.c
funcs/func_curl.c
funcs/func_dialplan.c
funcs/func_odbc.c
funcs/func_periodic_hook.c
funcs/func_pjsip_contact.c
include/asterisk.h
include/asterisk/app.h
include/asterisk/astmm.h
include/asterisk/astobj2.h
include/asterisk/audiohook.h
include/asterisk/autoconfig.h.in
include/asterisk/bridge_technology.h
include/asterisk/bucket.h
include/asterisk/channel.h
include/asterisk/cli.h
include/asterisk/codec.h
include/asterisk/config.h
include/asterisk/data.h
include/asterisk/event.h
include/asterisk/format.h
include/asterisk/format_cache.h
include/asterisk/format_cap.h
include/asterisk/http_websocket.h
include/asterisk/manager.h
include/asterisk/mod_format.h
include/asterisk/module.h
include/asterisk/monitor.h
include/asterisk/options.h
include/asterisk/parking.h
include/asterisk/pbx.h
include/asterisk/res_fax.h
include/asterisk/res_pjsip.h
include/asterisk/res_pjsip_pubsub.h
include/asterisk/rtp_engine.h
include/asterisk/sem.h
include/asterisk/sip_api.h
include/asterisk/slin.h
include/asterisk/sorcery.h
include/asterisk/stasis.h
include/asterisk/stasis_endpoints.h
include/asterisk/stasis_test.h
include/asterisk/strings.h
include/asterisk/tcptls.h
include/asterisk/test.h
include/asterisk/timing.h
include/asterisk/translate.h
include/asterisk/utils.h
include/asterisk/vector.h
main/.gitignore
main/Makefile
main/acl.c
main/ast_expr2.c
main/ast_expr2.fl
main/ast_expr2.y
main/ast_expr2f.c
main/asterisk.c
main/astmm.c
main/astobj2.c
main/astobj2_container.c
main/astobj2_container_private.h
main/astobj2_hash.c
main/astobj2_private.h
main/astobj2_rbtree.c
main/audiohook.c
main/bridge_basic.c
main/cdr.c
main/channel.c
main/channel_internal_api.c
main/cli.c
main/config.c
main/dns_query_set.c
main/dns_srv.c
main/event.c
main/features.c
main/file.c
main/format.c
main/format_cache.c
main/format_cap.c
main/hashtab.c
main/libasteriskssl.c
main/loader.c
main/logger.c
main/manager.c
main/manager_channels.c
main/manager_endpoints.c
main/message.c
main/parking.c
main/pbx.c
main/presencestate.c
main/rtp_engine.c
main/sdp_srtp.c
main/security_events.c
main/sorcery.c
main/stasis.c
main/stasis_channels.c
main/stasis_endpoints.c
main/tcptls.c
main/term.c
main/test.c
main/utils.c
makeopts.in
menuselect/configure
pbx/pbx_ael.c
pbx/pbx_config.c
pbx/pbx_dundi.c
pbx/pbx_lua.c
pbx/pbx_spool.c
res/ael/ael.flex
res/ael/ael.tab.c
res/ael/ael.y
res/ael/ael_lex.c
res/ael/pval.c
res/ari/ari_model_validators.c
res/ari/resource_bridges.c
res/ari/resource_channels.c
res/ari/resource_device_states.c
res/ari/resource_events.c
res/ari/resource_events.h
res/ari/resource_mailboxes.c
res/ari/resource_playbacks.c
res/ari/resource_recordings.c
res/parking/parking_applications.c
res/parking/parking_bridge_features.c
res/parking/parking_manager.c
res/parking/res_parking.h
res/res_adsi.c
res/res_ael_share.c
res/res_agi.c
res/res_ari.c
res/res_ari_applications.c
res/res_ari_asterisk.c
res/res_ari_bridges.c
res/res_ari_channels.c
res/res_ari_device_states.c
res/res_ari_endpoints.c
res/res_ari_events.c
res/res_ari_mailboxes.c
res/res_ari_model.c
res/res_ari_playbacks.c
res/res_ari_recordings.c
res/res_ari_sounds.c
res/res_calendar.c
res/res_calendar_caldav.c
res/res_calendar_exchange.c
res/res_calendar_icalendar.c
res/res_chan_stats.c
res/res_clialiases.c
res/res_clioriginate.c
res/res_config_curl.c
res/res_config_odbc.c
res/res_config_pgsql.c
res/res_config_sqlite.c
res/res_convert.c
res/res_corosync.c
res/res_crypto.c
res/res_curl.c
res/res_fax.c
res/res_fax_spandsp.c
res/res_hep.c
res/res_hep_pjsip.c
res/res_hep_rtcp.c
res/res_http_websocket.c
res/res_manager_devicestate.c
res/res_manager_presencestate.c
res/res_monitor.c
res/res_musiconhold.c
res/res_mwi_external_ami.c
res/res_odbc.c
res/res_parking.c
res/res_phoneprov.c
res/res_pjsip.c
res/res_pjsip/include/res_pjsip_private.h
res/res_pjsip/location.c
res/res_pjsip/pjsip_configuration.c
res/res_pjsip/pjsip_options.c
res/res_pjsip/pjsip_outbound_auth.c [deleted file]
res/res_pjsip/presence_xml.c
res/res_pjsip_acl.c
res/res_pjsip_authenticator_digest.c
res/res_pjsip_caller_id.c
res/res_pjsip_config_wizard.c
res/res_pjsip_dialog_info_body_generator.c
res/res_pjsip_diversion.c
res/res_pjsip_dlg_options.c
res/res_pjsip_dtmf_info.c
res/res_pjsip_endpoint_identifier_anonymous.c
res/res_pjsip_endpoint_identifier_ip.c
res/res_pjsip_endpoint_identifier_user.c
res/res_pjsip_exten_state.c
res/res_pjsip_header_funcs.c
res/res_pjsip_keepalive.c
res/res_pjsip_log_forwarder.c
res/res_pjsip_logger.c
res/res_pjsip_messaging.c
res/res_pjsip_multihomed.c
res/res_pjsip_mwi.c
res/res_pjsip_mwi_body_generator.c
res/res_pjsip_nat.c
res/res_pjsip_notify.c
res/res_pjsip_one_touch_record_info.c
res/res_pjsip_outbound_authenticator_digest.c
res/res_pjsip_outbound_publish.c
res/res_pjsip_outbound_registration.c
res/res_pjsip_path.c
res/res_pjsip_phoneprov_provider.c
res/res_pjsip_pidf_body_generator.c
res/res_pjsip_pidf_digium_body_supplement.c
res/res_pjsip_pidf_eyebeam_body_supplement.c
res/res_pjsip_publish_asterisk.c
res/res_pjsip_pubsub.c
res/res_pjsip_pubsub.exports.in
res/res_pjsip_refer.c
res/res_pjsip_registrar.c
res/res_pjsip_registrar_expire.c
res/res_pjsip_rfc3326.c
res/res_pjsip_sdp_rtp.c
res/res_pjsip_send_to_voicemail.c
res/res_pjsip_session.c
res/res_pjsip_sips_contact.c
res/res_pjsip_t38.c
res/res_pjsip_transport_websocket.c
res/res_pjsip_xpidf_body_generator.c
res/res_pktccops.c
res/res_resolver_unbound.c
res/res_rtp_asterisk.c
res/res_security_log.c
res/res_smdi.c
res/res_snmp.c
res/res_sorcery_config.c
res/res_sorcery_memory_cache.c [new file with mode: 0644]
res/res_speech.c
res/res_stasis.c
res/res_stasis_answer.c
res/res_stasis_device_state.c
res/res_stasis_mailbox.c
res/res_stasis_playback.c
res/res_stasis_recording.c
res/res_stasis_snoop.c
res/res_stasis_test.c
res/res_statsd.c
res/res_stun_monitor.c
res/res_timing_dahdi.c
res/res_timing_kqueue.c
res/res_timing_pthread.c
res/res_timing_timerfd.c
res/res_xmpp.c
res/snmp/agent.c
res/stasis/app.c
res/stasis/control.c
rest-api-templates/ari_model_validators.c.mustache
rest-api-templates/ari_resource.c.mustache
rest-api-templates/ari_resource.h.mustache
rest-api-templates/res_ari_resource.c.mustache
rest-api/api-docs/applications.json
rest-api/api-docs/asterisk.json
rest-api/api-docs/bridges.json
rest-api/api-docs/channels.json
rest-api/api-docs/deviceStates.json
rest-api/api-docs/endpoints.json
rest-api/api-docs/events.json
rest-api/api-docs/mailboxes.json
rest-api/api-docs/playbacks.json
rest-api/api-docs/recordings.json
rest-api/api-docs/sounds.json
sounds/Makefile
sounds/sounds.xml
tests/test_ari.c
tests/test_astobj2_weaken.c
tests/test_config.c
tests/test_dns_query_set.c
tests/test_endpoints.c
tests/test_gosub.c
tests/test_json.c
tests/test_message.c
tests/test_optional_api.c
tests/test_pbx.c
tests/test_res_stasis.c
tests/test_sorcery.c
tests/test_sorcery_memory_cache_thrash.c [new file with mode: 0644]
tests/test_stasis.c
tests/test_stasis_channels.c
tests/test_stasis_endpoints.c
tests/test_strings.c
tests/test_vector.c [new file with mode: 0644]
utils/.gitignore
utils/Makefile
utils/ael_main.c
utils/astman.c
utils/check_expr.c
utils/clicompat.c
utils/conf2ael.c
utils/extconf.c
utils/frame.c
utils/frame.h
utils/muted.c
utils/smsq.c
utils/streamplayer.c

index c240644..0281e10 100644 (file)
@@ -29,3 +29,8 @@ makeopts.embed_rules
 menuselect-tree
 *.sha1
 *.pyc
+*.gcno
+*.gcda
+latex
+doxygen.log
+
diff --git a/CHANGES b/CHANGES
index 94ed559..281d059 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -33,6 +33,20 @@ SMS
    providers to not log SMS content.
 
 
+CDRs
+------------------
+cdr_odbc
+------------------
+ * Added a new configuration option, "newcdrcolumns", which enables use of the
+   post-1.8 CDR columns 'peeraccount', 'linkedid', and 'sequence'.
+
+------------------
+cdr_csv
+------------------
+ * Added a new configuration option, "newcdrcolumns", which enables use of the
+   post-1.8 CDR columns 'peeraccount', 'linkedid', and 'sequence'.
+
+
 Channel Drivers
 ------------------
 
@@ -40,6 +54,9 @@ chan_dahdi
 ------------------
  * The CALLERID(ani2) value for incoming calls is now populated in featdmf
    signaling mode.  The information was previously discarded.
+ * Added the force_restart_unavailable_chans compatibility option.  When
+   enabled it causes Asterisk to restart the ISDN B channel if an outgoing
+   call receives cause 44 (Requested channel not available).
 
 chan_iax2
 ------------------
@@ -87,6 +104,16 @@ Core
    for DNS functionality. Modules that use this functionality will require that
    a DNS resolver module is loaded and available.
 
+ * Modified processing of command-line options to first parse only what
+   is necessary to read asterisk.conf. Once asterisk.conf is fully loaded,
+   the remaining options are processed.  The -X option now applies to
+   asterisk.conf only.  To enable #exec for other config files you must
+   set execincludes=yes in asterisk.conf.  Any other option set on the
+   command-line will now override the equivalent setting from asterisk.conf.
+
+ * The TLS core in Asterisk now supports X.509 certificate subject alternative
+   names. This way one X.509 certificate can be used for hosts that can be
+   reached under multiple DNS names or for multiple hosts.
 
 Functions
 ------------------
@@ -133,8 +160,31 @@ CEL Backends
 
 cel_pgsql
 ------------------
-* Added a new option, 'usegmtime', which causes timestamps in CEL events
-  to be logged in GMT.
+ * Added a new option, 'usegmtime', which causes timestamps in CEL events
+   to be logged in GMT.
+
+ * Added support to set schema where located the table cel. This settings is
+   configurable for cel_pgsql via the 'schema' in configuration file
+   cel_pgsql.conf.
+
+CDR Backends
+------------------
+
+cdr_adaptive_odbc
+------------------
+ * Added the ability to set the character to quote identifiers. This
+   allows adding the character at the start and end of table and column
+   names. This setting is configurable for cdr_adaptive_odbc via the
+   quoted_identifiers in configuration file cdr_adaptive_odbc.conf.
+
+------------------------------------------------------------------------------
+--- Functionality changes from Asterisk 13.4.0 to Asterisk 13.5.0 ------------
+------------------------------------------------------------------------------
+
+AMI
+------------------
+ * A new ContactStatus event has been added that reflects res_pjsip contact
+   lifecycle changes:  Created, Removed, Reachable, Unreachable, Unknown.
 
 ------------------------------------------------------------------------------
 --- Functionality changes from Asterisk 13.3.0 to Asterisk 13.4.0 ------------
@@ -286,10 +336,10 @@ Core Transfers
 
 The features.conf general section has three new configurable options:
     * transferdialattempts
-       * transferretrysound
-       * transferinvalidsound
+    * transferretrysound
+    * transferinvalidsound
 For more information on what these options do, see the Asterisk wiki:
-       https://wiki.asterisk.org/wiki/x/W4fAAQ
+ https://wiki.asterisk.org/wiki/x/W4fAAQ
 
 Channel Drivers
 ------------------
diff --git a/CREDITS b/CREDITS
index 6560976..af8b656 100644 (file)
--- a/CREDITS
+++ b/CREDITS
                (dialog-info), QUEUE_EXISTS function, device state provider
                architecture, multiparking (together with mvanbaak), meetme and
                parking device states, MiniVM - the small voicemail system,
+               RTP improvements, RTCP enhancements, DTMF timing fixes,
                many documentation updates/corrections, and many bug fixes.
                oej(AT)edvina.net, http://edvina.net
 
index 15e21b6..f6a3d1f 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -260,10 +260,10 @@ MOD_SUBDIRS_MENUSELECT_TREE:=$(MOD_SUBDIRS:%=%-menuselect-tree)
 
 ifneq ($(findstring darwin,$(OSARCH)),)
   _ASTCFLAGS+=-D__Darwin__ -mmacosx-version-min=10.6
-  _SOLINK=-mmacosx-version-min=10.6 -Xlinker -undefined -Xlinker dynamic_lookup
+  _SOLINK=-mmacosx-version-min=10.6 -Wl,-undefined,dynamic_lookup
   _SOLINK+=/usr/lib/bundle1.o
   SOLINK=-bundle $(_SOLINK)
-  DYLINK=-Xlinker -dylib $(_SOLINK)
+  DYLINK=-Wl,-dylib $(_SOLINK)
   _ASTLDFLAGS+=-L/usr/local/lib
 else
 # These are used for all but Darwin
@@ -429,6 +429,8 @@ _clean:
        rm -f doc/core-en_US.xml
        rm -f doc/full-en_US.xml
        rm -f doc/rest-api/*.wiki
+       rm -f doxygen.log
+       rm -rf latex
        rm -f rest-api-templates/*.pyc
        @$(MAKE) -C menuselect clean
        cp -f .cleancount .lastclean
@@ -445,6 +447,7 @@ distclean: $(SUBDIRS_DIST_CLEAN) _clean
        rm -f include/asterisk/autoconfig.h
        rm -f include/asterisk/buildopts.h
        rm -rf doc/api
+       rm -f doc/asterisk-ng-doxygen
        rm -f build_tools/menuselect-deps
 
 datafiles: _all doc/core-en_US.xml
@@ -763,7 +766,8 @@ webvmail:
        @echo " +-------------------------------------------+"
 
 progdocs:
-       # Note, Makefile conditionals must not be tabbed out. Wasted hours with that.
+# Note, Makefile conditionals must not be tabbed out. Wasted hours with that.
+       @cp doc/asterisk-ng-doxygen.in doc/asterisk-ng-doxygen
 ifeq ($(DOXYGEN),:)
        @echo "Doxygen is not installed.  Please install and re-run the configuration script."
 else
@@ -771,20 +775,20 @@ ifeq ($(DOT),:)
        @echo "DOT is not installed. Doxygen will not produce any diagrams. Please install and re-run the configuration script."
 else
        # Enable DOT
-       @echo "HAVE_DOT = YES" >> contrib/asterisk-ng-doxygen
+       @echo "HAVE_DOT = YES" >> doc/asterisk-ng-doxygen
 endif
        # Set Doxygen PROJECT_NUMBER variable
 ifneq ($(ASTERISKVERSION),UNKNOWN__and_probably_unsupported)
-       @echo "PROJECT_NUMBER = $(ASTERISKVERSION)" >> contrib/asterisk-ng-doxygen
+       @echo "PROJECT_NUMBER = $(ASTERISKVERSION)" >> doc/asterisk-ng-doxygen
 else
        echo "Asterisk Version is unknown, not configuring Doxygen PROJECT_NUMBER."
 endif
-       # Validate Doxygen Configuration
-       @doxygen -u contrib/asterisk-ng-doxygen
+       # Validate and auto-update local copy
+       @doxygen -u doc/asterisk-ng-doxygen
        # Run Doxygen
-       @doxygen contrib/asterisk-ng-doxygen
+       @doxygen doc/asterisk-ng-doxygen
        # Remove configuration backup file
-       @rm -f contrib/asterisk-ng-doxygen.bak
+       @rm -f doc/asterisk-ng-doxygen.bak
 endif
 
 install-logrotate:
@@ -937,7 +941,7 @@ nmenuselect: menuselect/nmenuselect menuselect-tree menuselect.makeopts
        -@menuselect/nmenuselect menuselect.makeopts && (echo "menuselect changes saved!"; rm -f channels/h323/Makefile.ast main/asterisk) || echo "menuselect changes NOT saved!"
 
 # options for make in menuselect/
-MAKE_MENUSELECT=CC="$(CC)" CXX="$(CXX)" LD="" AR="" RANLIB="" \
+MAKE_MENUSELECT=CC="$(BUILD_CC)" CXX="$(CXX)" LD="" AR="" RANLIB="" \
                CFLAGS="$(BUILD_CFLAGS)" LDFLAGS="$(BUILD_LDFLAGS)" \
                $(MAKE) -C menuselect CONFIGURE_SILENT="--silent"
 
@@ -982,6 +986,7 @@ ifeq ($(PYTHON),:)
        @echo "--------------------------------------------------------------------------"
        @false
 else
+       @$(INSTALL) -d doc/rest-api
        $(PYTHON) rest-api-templates/make_ari_stubs.py \
                rest-api/resources.json .
 endif
index 673580d..e702282 100644 (file)
@@ -60,12 +60,19 @@ endif
 # is used to collect the required flags for a module... which can
 # then be used any place they are required.
 
-MOD_ASTCFLAGS=-DAST_MODULE=\"$(1)\" $(MENUSELECT_OPTS_$(1):%=-D%) $(foreach dep,$(MENUSELECT_DEPENDS_$(1)),$(value $(dep)_INCLUDE))
+MOD_ASTCFLAGS=\
+       -DAST_MODULE=\"$(1)\" \
+       -DAST_MODULE_SELF_SYM=__internal_$(1)_self \
+       $(MENUSELECT_OPTS_$(1):%=-D%) \
+       $(foreach dep,$(MENUSELECT_DEPENDS_$(1)),$(value $(dep)_INCLUDE))
 
 define MOD_ADD_SOURCE
 $$(if $$(filter $(1),$$(EMBEDDED_MODS)),modules.link,$(1).so): $$(subst $(3),$(5),$(2))
 $$(subst $(3),$(5),$(2)): _ASTCFLAGS+=$$(call MOD_ASTCFLAGS,$(1))
 .$(1).moduleinfo: MODULEINFO_EXTRA_OUTPUT=" $$(addprefix $$(SUBDIR)/,$$(subst $(3),$(5),$(2)) $$(subst $(3),$(4),$(2)))"
+# The use of wildcard ensures that 'make menuselect' will not fail for modules that
+# require additional source downloads.
+.$(1).moduleinfo: $(wildcard $(2))
 
 clean:: clean-$(1)$(3)
 
@@ -148,12 +155,12 @@ dist-clean::
 
 .%.moduleinfo: %.c
        @echo "<member name=\"$*\" displayname=\"$(shell $(GREP) -e AST_MODULE_INFO $< | head -n 1 | cut -d '"' -f 2)\" remove_on_change=\"$(SUBDIR)/$*.o $(SUBDIR)/$*.i $(SUBDIR)/$*.so$(MODULEINFO_EXTRA_OUTPUT)\">" > $@
-       $(AWK) -f $(ASTTOPDIR)/build_tools/get_moduleinfo $< >> $@
+       $(AWK) -f $(ASTTOPDIR)/build_tools/get_moduleinfo $^ >> $@
        echo "</member>" >> $@
 
 .%.moduleinfo: %.cc
        @echo "<member name=\"$*\" displayname=\"$(shell $(GREP) -e AST_MODULE_INFO $< | head -n 1 | cut -d '"' -f 2)\" remove_on_change=\"$(SUBDIR)/$*.oo $(SUBDIR)/$*.ii $(SUBDIR)/$*.so$(MODULEINFO_EXTRA_OUTPUT)\">" > $@
-       $(AWK) -f $(ASTTOPDIR)/build_tools/get_moduleinfo $< >> $@
+       $(AWK) -f $(ASTTOPDIR)/build_tools/get_moduleinfo $^ >> $@
        echo "</member>" >> $@
 
 .moduleinfo:: $(addsuffix .moduleinfo,$(addprefix .,$(sort $(ALL_C_MODS) $(ALL_CC_MODS))))
index a24cc72..a274c95 100644 (file)
@@ -65,6 +65,11 @@ endif
 CC_CFLAGS=$(PTHREAD_CFLAGS) $(_ASTCFLAGS) $(ASTCFLAGS)
 CXX_CFLAGS=$(PTHREAD_CFLAGS) $(filter-out -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations $(AST_DECLARATION_AFTER_STATEMENT),$(_ASTCFLAGS) $(ASTCFLAGS))
 
+# Clang -Werror warning suppressions
+ifeq ($(C_COMPILER_FAMILY),clang)
+       CC_CFLAGS+=-Wno-unused-value -Wno-parentheses-equality
+endif
+
 ifeq ($(GNU_LD),1)
 SO_SUPPRESS_SYMBOLS=-Wl,--version-script,$(subst .so,.exports,$@),--warn-common
 ifneq ($(wildcard $(subst .so,.dynamics,$@)),)
index 8a349f0..91d9edc 100644 (file)
@@ -32,6 +32,16 @@ chan_dahdi:
    Caller-ID detection.
 
 Core:
+ - The REF_DEBUG compiler flag is now used to enable refdebug by default.
+   The setting can be overridden in asterisk.conf by setting refdebug in
+   the options category.  No recompile is required to enable/disable it.
+
+ - Modified processing of command-line options to first parse only what
+   is necessary to read asterisk.conf. Once asterisk.conf is fully loaded,
+   the remaining options are processed.  The -X option now applies to
+   asterisk.conf only.  To enable #exec for other config files you must
+   set execincludes=yes in asterisk.conf.  Any other option set on the
+   command-line will now override the equivalent setting from asterisk.conf.
 
 AMI:
  - The 'ModuleCheck' Action's Version key will no longer show the module
@@ -46,5 +56,13 @@ Logging:
  - The first callid created is now 1 instead of 0.  The value 0
    is now reserved to represent a lack of callid.
 
+AMI:
+ - The Command action now sends the output from the CLI command as a series
+   of Output headers for each line instead of as a block of text with the
+   --END COMMAND-- delimiter to match the output from other actions.
+
+   Commands that fail to execute (no such command, invalid syntax etc.) now
+   return an Error response instead of Success.
+
 ===========================================================
 ===========================================================
index 4535798..26056f4 100644 (file)
@@ -4754,8 +4754,8 @@ e_cleanup:
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Bluetooth Mobile Device Channel Driver",
-               .support_level = AST_MODULE_SUPPORT_EXTENDED,
-               .load = load_module,
-               .unload = unload_module,
-               .load_pri = AST_MODPRI_CHANNEL_DRIVER,
+       .support_level = AST_MODULE_SUPPORT_EXTENDED,
+       .load = load_module,
+       .unload = unload_module,
+       .load_pri = AST_MODPRI_CHANNEL_DRIVER,
 );
index da63f03..58db56f 100644 (file)
@@ -5188,9 +5188,9 @@ void ast_ooh323c_exit()
 #endif
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Objective Systems H323 Channel",
-               .support_level = AST_MODULE_SUPPORT_EXTENDED,
-                       .load = load_module,
-                       .unload = unload_module,
-                       .reload = reload_module,
-                       .load_pri = AST_MODPRI_CHANNEL_DRIVER
-                       );
+       .support_level = AST_MODULE_SUPPORT_EXTENDED,
+       .load = load_module,
+       .unload = unload_module,
+       .reload = reload_module,
+       .load_pri = AST_MODPRI_CHANNEL_DRIVER
+);
index 299fe56..a805cb4 100644 (file)
@@ -1202,38 +1202,44 @@ static int require_mysql(const char *database, const char *tablename, va_list ap
                                                        PICK_WHICH_ALTER_ACTION(bigint)
                                                }
                                        }
-                               } else if (strncmp(column->type, "float", 5) == 0 && !ast_rq_is_int(type) && type != RQ_FLOAT) {
-                                       if (table->database->requirements == RQ_WARN) {
-                                               ast_log(LOG_WARNING, "Realtime table %s@%s: Column %s cannot be a %s\n", tablename, database, column->name, column->type);
-                                               res = -1;
-                                       } else if (table->database->requirements == RQ_CREATECLOSE && modify_mysql(database, tablename, column, type, size) == 0) {
-                                               table_altered = 1;
-                                       } else if (table->database->requirements == RQ_CREATECHAR && modify_mysql(database, tablename, column, RQ_CHAR, size) == 0) {
-                                               table_altered = 1;
-                                       } else {
-                                               res = -1;
+                               } else if (strncmp(column->type, "float", 5) == 0) {
+                                       if (!ast_rq_is_int(type) && type != RQ_FLOAT) {
+                                               if (table->database->requirements == RQ_WARN) {
+                                                       ast_log(LOG_WARNING, "Realtime table %s@%s: Column %s cannot be a %s\n", tablename, database, column->name, column->type);
+                                                       res = -1;
+                                               } else if (table->database->requirements == RQ_CREATECLOSE && modify_mysql(database, tablename, column, type, size) == 0) {
+                                                       table_altered = 1;
+                                               } else if (table->database->requirements == RQ_CREATECHAR && modify_mysql(database, tablename, column, RQ_CHAR, size) == 0) {
+                                                       table_altered = 1;
+                                               } else {
+                                                       res = -1;
+                                               }
                                        }
-                               } else if ((strncmp(column->type, "datetime", 8) == 0 || strncmp(column->type, "timestamp", 9) == 0) && type != RQ_DATETIME) {
-                                       if (table->database->requirements == RQ_WARN) {
-                                               ast_log(LOG_WARNING, "Realtime table %s@%s: Column %s cannot be a %s\n", tablename, database, column->name, column->type);
-                                               res = -1;
-                                       } else if (table->database->requirements == RQ_CREATECLOSE && modify_mysql(database, tablename, column, type, size) == 0) {
-                                               table_altered = 1;
-                                       } else if (table->database->requirements == RQ_CREATECHAR && modify_mysql(database, tablename, column, RQ_CHAR, size) == 0) {
-                                               table_altered = 1;
-                                       } else {
-                                               res = -1;
+                               } else if (strncmp(column->type, "datetime", 8) == 0 || strncmp(column->type, "timestamp", 9) == 0) {
+                                       if (type != RQ_DATETIME) {
+                                               if (table->database->requirements == RQ_WARN) {
+                                                       ast_log(LOG_WARNING, "Realtime table %s@%s: Column %s cannot be a %s\n", tablename, database, column->name, column->type);
+                                                       res = -1;
+                                               } else if (table->database->requirements == RQ_CREATECLOSE && modify_mysql(database, tablename, column, type, size) == 0) {
+                                                       table_altered = 1;
+                                               } else if (table->database->requirements == RQ_CREATECHAR && modify_mysql(database, tablename, column, RQ_CHAR, size) == 0) {
+                                                       table_altered = 1;
+                                               } else {
+                                                       res = -1;
+                                               }
                                        }
-                               } else if ((strncmp(column->type, "date", 4) == 0) && type != RQ_DATE) {
-                                       if (table->database->requirements == RQ_WARN) {
-                                               ast_log(LOG_WARNING, "Realtime table %s@%s: Column %s cannot be a %s\n", tablename, database, column->name, column->type);
-                                               res = -1;
-                                       } else if (table->database->requirements == RQ_CREATECLOSE && modify_mysql(database, tablename, column, type, size) == 0) {
-                                               table_altered = 1;
-                                       } else if (table->database->requirements == RQ_CREATECHAR && modify_mysql(database, tablename, column, RQ_CHAR, size) == 0) {
-                                               table_altered = 1;
-                                       } else {
-                                               res = -1;
+                               } else if (strncmp(column->type, "date", 4) == 0) {
+                                       if (type != RQ_DATE) {
+                                               if (table->database->requirements == RQ_WARN) {
+                                                       ast_log(LOG_WARNING, "Realtime table %s@%s: Column %s cannot be a %s\n", tablename, database, column->name, column->type);
+                                                       res = -1;
+                                               } else if (table->database->requirements == RQ_CREATECLOSE && modify_mysql(database, tablename, column, type, size) == 0) {
+                                                       table_altered = 1;
+                                               } else if (table->database->requirements == RQ_CREATECHAR && modify_mysql(database, tablename, column, RQ_CHAR, size) == 0) {
+                                                       table_altered = 1;
+                                               } else {
+                                                       res = -1;
+                                               }
                                        }
                                } else { /* Other, possibly unsupported types? */
                                        if (table->database->requirements == RQ_WARN) {
@@ -1748,10 +1754,10 @@ static char *handle_cli_realtime_mysql_status(struct ast_cli_entry *e, int cmd,
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "MySQL RealTime Configuration Driver",
-               .support_level = AST_MODULE_SUPPORT_EXTENDED,
-               .load = load_module,
-               .unload = unload_module,
-               .reload = reload,
-               .load_pri = AST_MODPRI_REALTIME_DRIVER,
-               );
+       .support_level = AST_MODULE_SUPPORT_EXTENDED,
+       .load = load_module,
+       .unload = unload_module,
+       .reload = reload,
+       .load_pri = AST_MODPRI_REALTIME_DRIVER,
+);
 
index 7f5f3e6..3f3d11c 100644 (file)
@@ -1612,8 +1612,8 @@ static int load_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Asterisk ADSI Programming Application",
-               .support_level = AST_MODULE_SUPPORT_EXTENDED,
-               .load = load_module,
-               .unload = unload_module,
-               .nonoptreq = "res_adsi",
-               );
+       .support_level = AST_MODULE_SUPPORT_EXTENDED,
+       .load = load_module,
+       .unload = unload_module,
+       .nonoptreq = "res_adsi",
+);
index d5a0188..ace4df1 100644 (file)
@@ -995,8 +995,8 @@ static int reload(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Alarm Receiver for Asterisk",
-               .support_level = AST_MODULE_SUPPORT_EXTENDED,
-               .load = load_module,
-               .unload = unload_module,
-               .reload = reload,
+       .support_level = AST_MODULE_SUPPORT_EXTENDED,
+       .load = load_module,
+       .unload = unload_module,
+       .reload = reload,
 );
index ee5dd6f..ee421b6 100644 (file)
@@ -528,8 +528,8 @@ static int reload(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Answering Machine Detection Application",
-               .support_level = AST_MODULE_SUPPORT_EXTENDED,
-               .load = load_module,
-               .unload = unload_module,
-               .reload = reload,
+       .support_level = AST_MODULE_SUPPORT_EXTENDED,
+       .load = load_module,
+       .unload = unload_module,
+       .reload = reload,
 );
index fff4954..b98cd67 100644 (file)
@@ -102,7 +102,7 @@ static int load_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Generate an User-Defined CEL event",
-               .support_level = AST_MODULE_SUPPORT_CORE,
-                               .load = load_module,
-                               .unload = unload_module,
-       );
+       .support_level = AST_MODULE_SUPPORT_CORE,
+       .load = load_module,
+       .unload = unload_module,
+);
index ff323df..d6e9b4d 100644 (file)
@@ -996,9 +996,9 @@ static int load_module(void)
 
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Simple FAX Application",
-               .support_level = AST_MODULE_SUPPORT_EXTENDED,
-               .load = load_module,
-               .unload = unload_module,
-               );
+       .support_level = AST_MODULE_SUPPORT_EXTENDED,
+       .load = load_module,
+       .unload = unload_module,
+);
 
 
index 5fd5d15..d2000fd 100644 (file)
@@ -1582,8 +1582,8 @@ static int reload(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Find-Me/Follow-Me Application",
-               .support_level = AST_MODULE_SUPPORT_CORE,
-               .load = load_module,
-               .unload = unload_module,
-               .reload = reload,
-              );
+       .support_level = AST_MODULE_SUPPORT_CORE,
+       .load = load_module,
+       .unload = unload_module,
+       .reload = reload,
+);
index 7e457fb..c896f9e 100644 (file)
@@ -139,8 +139,8 @@ static int load_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Get ADSI CPE ID",
-               .support_level = AST_MODULE_SUPPORT_EXTENDED,
-               .load = load_module,
-               .unload = unload_module,
-               .nonoptreq = "res_adsi",
-               );
+       .support_level = AST_MODULE_SUPPORT_EXTENDED,
+       .load = load_module,
+       .unload = unload_module,
+       .nonoptreq = "res_adsi",
+);
index ba83ead..0c339d6 100644 (file)
@@ -7539,14 +7539,13 @@ static int sla_build_trunk(struct ast_config *cfg, const char *cat)
        ao2_unlock(trunk);
 
        if (!ast_strlen_zero(trunk->autocontext)) {
-               struct ast_context *context;
-               context = ast_context_find_or_create(NULL, NULL, trunk->autocontext, sla_registrar);
-               if (!context) {
+               if (!ast_context_find_or_create(NULL, NULL, trunk->autocontext, sla_registrar)) {
                        ast_log(LOG_ERROR, "Failed to automatically find or create "
                                "context '%s' for SLA!\n", trunk->autocontext);
                        return -1;
                }
-               if (ast_add_extension2(context, 0 /* don't replace */, "s", 1,
+
+               if (ast_add_extension(trunk->autocontext, 0 /* don't replace */, "s", 1,
                        NULL, NULL, slatrunk_app, ast_strdup(trunk->name), ast_free_ptr, sla_registrar)) {
                        ast_log(LOG_ERROR, "Failed to automatically create extension "
                                "for trunk '%s'!\n", trunk->name);
@@ -7715,17 +7714,16 @@ static int sla_build_station(struct ast_config *cfg, const char *cat)
        ao2_unlock(station);
 
        if (!ast_strlen_zero(station->autocontext)) {
-               struct ast_context *context;
                struct sla_trunk_ref *trunk_ref;
-               context = ast_context_find_or_create(NULL, NULL, station->autocontext, sla_registrar);
-               if (!context) {
+
+               if (!ast_context_find_or_create(NULL, NULL, station->autocontext, sla_registrar)) {
                        ast_log(LOG_ERROR, "Failed to automatically find or create "
                                "context '%s' for SLA!\n", station->autocontext);
                        return -1;
                }
                /* The extension for when the handset goes off-hook.
                 * exten => station1,1,SLAStation(station1) */
-               if (ast_add_extension2(context, 0 /* don't replace */, station->name, 1,
+               if (ast_add_extension(station->autocontext, 0 /* don't replace */, station->name, 1,
                        NULL, NULL, slastation_app, ast_strdup(station->name), ast_free_ptr, sla_registrar)) {
                        ast_log(LOG_ERROR, "Failed to automatically create extension "
                                "for trunk '%s'!\n", station->name);
@@ -7738,7 +7736,7 @@ static int sla_build_station(struct ast_config *cfg, const char *cat)
                        snprintf(hint, sizeof(hint), "SLA:%s", exten);
                        /* Extension for this line button 
                         * exten => station1_line1,1,SLAStation(station1_line1) */
-                       if (ast_add_extension2(context, 0 /* don't replace */, exten, 1,
+                       if (ast_add_extension(station->autocontext, 0 /* don't replace */, exten, 1,
                                NULL, NULL, slastation_app, ast_strdup(exten), ast_free_ptr, sla_registrar)) {
                                ast_log(LOG_ERROR, "Failed to automatically create extension "
                                        "for trunk '%s'!\n", station->name);
@@ -7746,7 +7744,7 @@ static int sla_build_station(struct ast_config *cfg, const char *cat)
                        }
                        /* Hint for this line button 
                         * exten => station1_line1,hint,SLA:station1_line1 */
-                       if (ast_add_extension2(context, 0 /* don't replace */, exten, PRIORITY_HINT,
+                       if (ast_add_extension(station->autocontext, 0 /* don't replace */, exten, PRIORITY_HINT,
                                NULL, NULL, hint, NULL, NULL, sla_registrar)) {
                                ast_log(LOG_ERROR, "Failed to automatically create hint "
                                        "for trunk '%s'!\n", station->name);
@@ -8271,10 +8269,10 @@ static int reload(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "MeetMe conference bridge",
-               .support_level = AST_MODULE_SUPPORT_EXTENDED,
-               .load = load_module,
-               .unload = unload_module,
-               .reload = reload,
-               .load_pri = AST_MODPRI_DEVSTATE_PROVIDER,
-              );
+       .support_level = AST_MODULE_SUPPORT_EXTENDED,
+       .load = load_module,
+       .unload = unload_module,
+       .reload = reload,
+       .load_pri = AST_MODPRI_DEVSTATE_PROVIDER,
+);
 
index b8a1ceb..4b1c4b5 100644 (file)
@@ -3561,8 +3561,8 @@ static int unload_module(void)
 
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Mini VoiceMail (A minimal Voicemail e-mail System)",
-               .support_level = AST_MODULE_SUPPORT_EXTENDED,
-               .load = load_module,
-               .unload = unload_module,
-               .reload = reload,
-               );
+       .support_level = AST_MODULE_SUPPORT_EXTENDED,
+       .load = load_module,
+       .unload = unload_module,
+       .reload = reload,
+);
index 4b9eb15..2875ec2 100644 (file)
@@ -490,7 +490,9 @@ static int playback_exec(struct ast_channel *chan, const char *data)
                                ast_stopstream(chan);
                        }
                        if (res) {
-                               ast_log(LOG_WARNING, "Playback failed on %s for %s\n", ast_channel_name(chan), (char *)data);
+                               if (!ast_check_hangup(chan)) {
+                                       ast_log(LOG_WARNING, "Playback failed on %s for %s\n", ast_channel_name(chan), (char *)data);
+                               }
                                res = 0;
                                mres = 1;
                        }
@@ -570,8 +572,8 @@ static int load_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Sound File Playback Application",
-               .support_level = AST_MODULE_SUPPORT_CORE,
-               .load = load_module,
-               .unload = unload_module,
-               .reload = reload,
-              );
+       .support_level = AST_MODULE_SUPPORT_CORE,
+       .load = load_module,
+       .unload = unload_module,
+       .reload = reload,
+);
index 0b8204c..d04080c 100644 (file)
@@ -1814,49 +1814,26 @@ static void queue_member_follower_removal(struct call_queue *queue, struct membe
        ao2_callback(queue->members, OBJ_NODATA | OBJ_MULTIPLE, queue_member_decrement_followers, &pos);
 }
 
-#ifdef REF_DEBUG
 #define queue_ref(q)                           _queue_ref(q, "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
 #define queue_unref(q)                         _queue_unref(q, "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
 #define queue_t_ref(q, tag)                    _queue_ref(q, tag, __FILE__, __LINE__, __PRETTY_FUNCTION__)
 #define queue_t_unref(q, tag)          _queue_unref(q, tag, __FILE__, __LINE__, __PRETTY_FUNCTION__)
-#define queues_t_link(c, q, tag)       __ao2_link_debug(c, q, 0, tag, __FILE__, __LINE__, __PRETTY_FUNCTION__)
-#define queues_t_unlink(c, q, tag)     __ao2_unlink_debug(c, q, 0, tag, __FILE__, __LINE__, __PRETTY_FUNCTION__)
-
-static inline struct call_queue *_queue_ref(struct call_queue *q, const char *tag, const char *file, int line, const char *filename)
-{
-       __ao2_ref_debug(q, 1, tag, file, line, filename);
-       return q;
-}
-
-static inline struct call_queue *_queue_unref(struct call_queue *q, const char *tag, const char *file, int line, const char *filename)
-{
-       if (q) {
-               __ao2_ref_debug(q, -1, tag, file, line, filename);
-       }
-       return NULL;
-}
-
-#else
-
-#define queue_t_ref(q, tag)                    queue_ref(q)
-#define queue_t_unref(q, tag)          queue_unref(q)
 #define queues_t_link(c, q, tag)       ao2_t_link(c, q, tag)
 #define queues_t_unlink(c, q, tag)     ao2_t_unlink(c, q, tag)
 
-static inline struct call_queue *queue_ref(struct call_queue *q)
+static inline struct call_queue *_queue_ref(struct call_queue *q, const char *tag, const char *file, int line, const char *filename)
 {
-       ao2_ref(q, 1);
+       __ao2_ref(q, 1, tag, file, line, filename);
        return q;
 }
 
-static inline struct call_queue *queue_unref(struct call_queue *q)
+static inline struct call_queue *_queue_unref(struct call_queue *q, const char *tag, const char *file, int line, const char *filename)
 {
        if (q) {
-               ao2_ref(q, -1);
+               __ao2_ref(q, -1, tag, file, line, filename);
        }
        return NULL;
 }
-#endif
 
 /*! \brief Set variables of queue */
 static void set_queue_variables(struct call_queue *q, struct ast_channel *chan)
@@ -7858,7 +7835,8 @@ check_turns:
                        record_abandoned(&qe);
                        reason = QUEUE_TIMEOUT;
                        res = 0;
-                       ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
+                       ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITWITHTIMEOUT",
+                               "%d|%d|%ld", qe.pos, qe.opos, (long) (time(NULL) - qe.start));
                        break;
                }
 
@@ -7887,7 +7865,8 @@ check_turns:
                /* exit after 'timeout' cycle if 'n' option enabled */
                if (noption && tries >= ao2_container_count(qe.parent->members)) {
                        ast_verb(3, "Exiting on time-out cycle\n");
-                       ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
+                       ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITWITHTIMEOUT",
+                               "%d|%d|%ld", qe.pos, qe.opos, (long) (time(NULL) - qe.start));
                        record_abandoned(&qe);
                        reason = QUEUE_TIMEOUT;
                        res = 0;
@@ -10933,11 +10912,11 @@ static struct member *find_member_by_queuename_and_interface(const char *queuena
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "True Call Queueing",
-               .support_level = AST_MODULE_SUPPORT_CORE,
-               .load = load_module,
-               .unload = unload_module,
-               .reload = reload,
-               .load_pri = AST_MODPRI_DEVSTATE_CONSUMER,
-               .nonoptreq = "res_monitor",
-              );
+       .support_level = AST_MODULE_SUPPORT_CORE,
+       .load = load_module,
+       .unload = unload_module,
+       .reload = reload,
+       .load_pri = AST_MODPRI_DEVSTATE_CONSUMER,
+       .nonoptreq = "res_monitor",
+);
 
index 5b44d14..7c34dca 100644 (file)
@@ -1002,8 +1002,8 @@ static int load_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Dialplan Speech Applications",
-               .support_level = AST_MODULE_SUPPORT_CORE,
-               .load = load_module,
-               .unload = unload_module,
-               .nonoptreq = "res_speech",
-               );
+       .support_level = AST_MODULE_SUPPORT_CORE,
+       .load = load_module,
+       .unload = unload_module,
+       .nonoptreq = "res_speech",
+);
index 2d440ab..be8abbf 100644 (file)
@@ -1318,9 +1318,9 @@ static int load_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT | AST_MODFLAG_LOAD_ORDER, "Dialplan subroutines (Gosub, Return, etc)",
-               .support_level = AST_MODULE_SUPPORT_CORE,
-               .load = load_module,
-               .unload = unload_module,
-               .load_pri = AST_MODPRI_APP_DEPEND,
-               .nonoptreq = "res_agi",
-               );
+       .support_level = AST_MODULE_SUPPORT_CORE,
+       .load = load_module,
+       .unload = unload_module,
+       .load_pri = AST_MODPRI_APP_DEPEND,
+       .nonoptreq = "res_agi",
+);
index 22e8342..aa77a0d 100644 (file)
@@ -141,4 +141,4 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Stasis dialplan applicat
        .load = load_module,
        .unload = unload_module,
        .nonoptreq = "res_stasis",
-       );
+);
index 532275e..f2f7bad 100644 (file)
@@ -617,6 +617,7 @@ static AST_LIST_HEAD_STATIC(vmstates, vmstate);
 #define VM_MESSAGEWRAP   (1 << 17)  /*!< Wrap around from the last message to the first, and vice-versa */
 #define VM_FWDURGAUTO    (1 << 18)  /*!< Autoset of Urgent flag on forwarded Urgent messages set globally */
 #define ERROR_LOCK_PATH  -100
+#define ERROR_MAX_MSGS   -101
 #define OPERATOR_EXIT     300
 
 enum vm_box {
@@ -7093,7 +7094,7 @@ static int save_to_folder(struct ast_vm_user *vmu, struct vm_state *vms, int msg
        } else {
                if (x >= vmu->maxmsg) {
                        ast_unlock_path(ddir);
-                       return -1;
+                       return ERROR_MAX_MSGS;
                }
        }
        make_file(sfn, sizeof(sfn), dir, msg);
@@ -8918,7 +8919,7 @@ static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
                } else if ((!strcasecmp(vms->curbox, "INBOX") || !strcasecmp(vms->curbox, "Urgent")) && vms->heard[x] && ast_test_flag(vmu, VM_MOVEHEARD) && !vms->deleted[x]) {
                        /* Move to old folder before deleting */
                        res = save_to_folder(vmu, vms, x, 1, NULL, 0);
-                       if (res == ERROR_LOCK_PATH) {
+                       if (res == ERROR_LOCK_PATH || res == ERROR_MAX_MSGS) {
                                /* If save failed do not delete the message */
                                ast_log(AST_LOG_WARNING, "Save failed.  Not moving message: %s.\n", res == ERROR_LOCK_PATH ? "unable to lock path" : "destination folder full");
                                vms->deleted[x] = 0;
@@ -16116,9 +16117,9 @@ play2_msg_cleanup:
  */
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, tdesc,
-               .support_level = AST_MODULE_SUPPORT_CORE,
-               .load = load_module,
-               .unload = unload_module,
-               .reload = reload,
-               .nonoptreq = "res_adsi,res_smdi",
-               );
+       .support_level = AST_MODULE_SUPPORT_CORE,
+       .load = load_module,
+       .unload = unload_module,
+       .reload = reload,
+       .nonoptreq = "res_adsi,res_smdi",
+);
index d3ffcb8..7fcc700 100644 (file)
@@ -963,12 +963,17 @@ static const struct ast_datastore_info confbridge_datastore = {
        .type = "confbridge",
        .destroy = func_confbridge_destroy_cb
 };
+
 int func_confbridge_helper(struct ast_channel *chan, const char *cmd, char *data, const char *value)
 {
        struct ast_datastore *datastore;
        struct func_confbridge_data *b_data;
        char *parse;
        struct ast_variable tmpvar = { 0, };
+       struct ast_variable template = {
+               .name = "template",
+               .file = "CONFBRIDGE"
+       };
        AST_DECLARE_APP_ARGS(args,
                AST_APP_ARG(type);
                AST_APP_ARG(option);
@@ -1041,7 +1046,14 @@ int func_confbridge_helper(struct ast_channel *chan, const char *cmd, char *data
                                ast_datastore_free(datastore);
                        }
                        return 0;
-               } else if (!aco_process_var(&bridge_type, "dialplan", &tmpvar, &b_data->b_profile)) {
+               }
+
+               if (b_data && !b_data->b_usable && strcasecmp(args.option, "template")) {
+                       template.value = DEFAULT_BRIDGE_PROFILE;
+                       aco_process_var(&bridge_type, "dialplan", &template, &b_data->b_profile);
+               }
+
+               if (!aco_process_var(&bridge_type, "dialplan", &tmpvar, &b_data->b_profile)) {
                        b_data->b_usable = 1;
                        return 0;
                }
@@ -1051,7 +1063,14 @@ int func_confbridge_helper(struct ast_channel *chan, const char *cmd, char *data
                        user_profile_destructor(&b_data->u_profile);
                        memset(&b_data->u_profile, 0, sizeof(b_data->u_profile));
                        return 0;
-               } else if (!aco_process_var(&user_type, "dialplan", &tmpvar, &b_data->u_profile)) {
+               }
+
+               if (b_data && !b_data->u_usable && strcasecmp(args.option, "template")) {
+                       template.value = DEFAULT_USER_PROFILE;
+                       aco_process_var(&user_type, "dialplan", &template, &b_data->u_profile);
+               }
+
+               if (!aco_process_var(&user_type, "dialplan", &tmpvar, &b_data->u_profile)) {
                        b_data->u_usable = 1;
                        return 0;
                }
@@ -1067,7 +1086,14 @@ int func_confbridge_helper(struct ast_channel *chan, const char *cmd, char *data
                                ast_datastore_free(datastore);
                        }
                        return 0;
-               } else if (!aco_process_var(&menu_type, "dialplan", &tmpvar, b_data->menu)) {
+               }
+
+               if (b_data && !b_data->m_usable && strcasecmp(args.option, "template")) {
+                       template.value = DEFAULT_MENU_PROFILE;
+                       aco_process_var(&menu_type, "dialplan", &template, &b_data->menu);
+               }
+
+               if (!aco_process_var(&menu_type, "dialplan", &tmpvar, b_data->menu)) {
                        b_data->m_usable = 1;
                        return 0;
                }
diff --git a/autoconf/ast_check_raii.m4 b/autoconf/ast_check_raii.m4
new file mode 100644 (file)
index 0000000..e39a43d
--- /dev/null
@@ -0,0 +1,56 @@
+dnl check RAII requirements
+dnl
+dnl gcc / llvm-gcc: -fnested-functions
+dnl clang : -fblocks / -fblocks and -lBlocksRuntime"
+AC_DEFUN([AST_CHECK_RAII], [
+       AC_MSG_CHECKING([for RAII support])
+       AST_C_COMPILER_FAMILY=""
+       AC_LINK_IFELSE(
+               [AC_LANG_PROGRAM([], [
+                       int main() {
+                               #if defined(__clang__)
+                               choke
+                               #endif
+                               return 0;
+                       }
+                       ])
+               ],[
+                       dnl Nested functions required for RAII implementation
+                       AC_MSG_CHECKING(for gcc -fnested-functions)
+                       AC_COMPILE_IFELSE(
+                               dnl Prototype needed due to http://gcc.gnu.org/bugzilla/show_bug.cgi?id=36774
+                               [
+                                       AC_LANG_PROGRAM([], [auto void foo(void); void foo(void) {}])
+                               ],[
+                                       AST_NESTED_FUNCTIONS=""
+                                       AC_MSG_RESULT(no)
+                               ],[
+                                       AST_NESTED_FUNCTIONS="-fnested-functions"
+                                       AC_MSG_RESULT(yes)
+                               ]
+                       )
+                       AC_SUBST(AST_NESTED_FUNCTIONS)
+                       AST_C_COMPILER_FAMILY="gcc"
+               ],[
+                       AC_MSG_CHECKING(for clang -fblocks)
+                       if test "`echo "int main(){return ^{return 42;}();}" | ${CC} -o /dev/null -fblocks -x c - 2>&1`" = ""; then
+                               AST_CLANG_BLOCKS_LIBS=""
+                               AST_CLANG_BLOCKS="-Wno-unknown-warning-option -fblocks"
+                               AC_MSG_RESULT(yes)
+                       elif test "`echo "int main(){return ^{return 42;}();}" | ${CC} -o /dev/null -fblocks -x c -lBlocksRuntime - 2>&1`" = ""; then
+                               AST_CLANG_BLOCKS_LIBS="-lBlocksRuntime"
+                               AST_CLANG_BLOCKS="-fblocks"
+                               AC_MSG_RESULT(yes)
+                       else
+                               AC_MSG_ERROR([BlocksRuntime is required for clang, please install libblocksruntime])
+                       fi
+                       AC_SUBST(AST_CLANG_BLOCKS_LIBS)
+                       AC_SUBST(AST_CLANG_BLOCKS)
+                       AST_C_COMPILER_FAMILY="clang"
+               ]
+       )
+       if test -z "${AST_C_COMPILER_FAMILY}"; then
+               AC_MSG_ERROR([Compiler ${CC} not supported. Mminimum required gcc-4.3 / llvm-gcc-4.3 / clang-3.3 + libblocksruntime-dev])
+       fi
+       AC_SUBST(AST_C_COMPILER_FAMILY)
+])
diff --git a/autoconf/ast_check_strsep_array_bounds.m4 b/autoconf/ast_check_strsep_array_bounds.m4
new file mode 100644 (file)
index 0000000..47a41e5
--- /dev/null
@@ -0,0 +1,81 @@
+dnl macro AST_CHECK_STRSEP_ARRAY_BOUNDS0
+dnl
+dnl The optimized strcmp and strsep macro's in
+dnl /usr/include/xxx-linux-gnu/bits/string2.h produce a warning (-Warray-bounds)
+dnl when compiled with clang (+ -O1), when the delimiter parameter is
+dnl passed in as a char *, instead of the expected char[]
+dnl
+dnl Instead of replacing all occurrences of strsep and strcmp, looking like:
+dnl xxx_name = strsep(&rest, ",");
+dnl
+dnl with:
+dnl char delimiters[] = ",";
+dnl xxx_name = strsep(&rest, delimiters);
+dnl
+dnl to get around this warning, without having to suppress the warning completely.
+dnl This macro detects the warning and force these 'optimizations' to be
+dnl switched off (Clang already has a set of builtin optimizers which should result
+dnl in good performance for these type of functions).
+dnl
+dnl When the issue is detected it will add a define to autoconfig.h which will prevent
+dnl bits/string2.h from replacing the standard implementation of strsep/strcmp with it's
+dnl macro optimized version. bits/string.h checks these defines before inserting it's
+dnl replacements.
+dnl
+dnl When bits/string2.h get's fixed in the future, this macro should be able to
+dnl detect the new behaviour, and when no warning is generated, it will use the optimize
+dnl version from bits/string2.h
+dnl
+dnl
+dnl See 'define __strcmp_gc(s1, s2, l2) in bits/string2.h'
+dnl
+dnl llvm-comment: Normally, this array-bounds warning are suppressed for macros, so that
+dnl unused paths like the one that accesses __s1[3] are not warned about.  But if you
+dnl preprocess manually, and feed the result to another instance of clang, it will warn
+dnl about all the possible forks of this particular if statement.
+dnl
+dnl Instead of switching of this optimization, another solution would be to run the pre-
+dnl processing step with -frewrite-includes, which should preserve enough information
+dnl so that clang should still be able to suppress the diagnostic at the compile step
+dnl later on.
+dnl
+dnl See also "https://llvm.org/bugs/show_bug.cgi?id=20144"
+dnl See also "https://llvm.org/bugs/show_bug.cgi?id=11536"
+dnl
+AC_DEFUN([AST_CHECK_STRSEP_ARRAY_BOUNDS], [
+       AC_MSG_CHECKING([for clang strsep/strcmp optimization])
+       save_CFLAGS="$CFLAGS"
+       CFLAGS="$CFLAGS -O1 -Werror=array-bounds"
+       AC_COMPILE_IFELSE(
+               [
+                       AC_LANG_SOURCE([
+                               #include <stdio.h>
+                               #include <string.h>
+
+                               /* fails with clang and -O1 */
+                               void test_strsep_strcmp (void) {
+                                       char *haystackstr = "test1,test2";
+                                       char *outstr;
+                                       if (!strcmp(haystackstr, ",")) {
+                                               printf("fail\n");
+                                       }
+                                       if ((outstr = strsep(&haystackstr, ","))) {
+                                               printf("fail:%s\n", outstr);
+                                       }
+                               }
+                               int main(int argc, char *argv[]) {
+                                       test_strsep_strcmp();
+                                       return 0;
+                               }
+                       ])
+               ],[
+                       AC_MSG_RESULT(no)
+               ],[
+                       dnl setting this define in autoconfig.h will prevent bits/string2.h from replacing the standard implementation of strsep/strcmp
+                       AC_DEFINE([_HAVE_STRING_ARCH_strcmp], 1, [Prevent clang array-bounds warning by not using strcmp from bits/string2.h])
+                       AC_DEFINE([_HAVE_STRING_ARCH_strsep], 1, [Prevent clang array-bounds warning by not using strsep from bits/string2.h])
+                       AC_MSG_RESULT([prevent use of __string2_1bptr_p / strsep / strcmp from bits/string2.h])
+               ]
+       )
+       CFLAGS="$save_CFLAGS"
+])
index bceaa28..4ade814 100644 (file)
@@ -20,7 +20,7 @@ AC_COMPILE_IFELSE(
 )
 else
 AC_COMPILE_IFELSE(
-       [AC_LANG_PROGRAM([$3 void __attribute__(($2)) *test(void *muffin, ...) {return (void *) 0;}],
+       [AC_LANG_PROGRAM([$3 void __attribute__(($2)) *test(void *muffin, ...) ;],
                        [])],
        AC_MSG_RESULT(yes)
        m4_ifval([$4],$4=1)
index 1a2e78f..b91cf5a 100644 (file)
@@ -5,7 +5,7 @@
                <member name="DEBUG_THREADS" displayname="Enable Thread Debugging">
                        <support_level>core</support_level>
                </member>
-               <member name="REF_DEBUG" displayname="Enable reference count debugging">
+               <member name="REF_DEBUG" displayname="Enable reference count debugging by default">
                        <support_level>extended</support_level>
                </member>
                <member name="AO2_DEBUG" displayname="Enable internal Astobj2 debugging">
index 92bc7e9..e4e72bb 100644 (file)
@@ -1,3 +1,4 @@
-/\/\*\*\* MODULEINFO/ {printit=1; next}
-/\*\*\*\// {if (printit) exit}
+/\/\*\*\* +MODULEINFO/ {printit=1; next}
+/<support_level>/ {if (gotsupportlevel) { next }; gotsupportlevel=1}
+/\*\*\*\// {printit=0}
 /.*/ {if (printit) print}
index 55d08ba..c96e508 100755 (executable)
@@ -10,27 +10,38 @@ cat << END
  */
 
 END
+
+if ${GREP} "AST_DEVMODE" makeopts | ${GREP} -q "yes"
+then
+       echo "#define AST_DEVMODE 1"
+       BUILDOPTS="AST_DEVMODE"
+fi
+
 TMP=`${GREP} -e "^MENUSELECT_CFLAGS" menuselect.makeopts | sed 's/MENUSELECT_CFLAGS\=//g' | sed 's/-D//g'`
 for x in ${TMP}; do
        echo "#define ${x} 1"
+       if test "${x}" = "DONT_OPTIMIZE" \
+                       -o "${x}" = "BETTER_BACKTRACES" \
+                       -o "${x}" = "LOTS_OF_SPANS" \
+                       -o "${x}" = "BUILD_NATIVE" \
+                       -o "${x}" = "REF_DEBUG" \
+                       -o "${x}" = "AO2_DEBUG" \
+                       -o "${x}" = "REBUILD_PARSERS" \
+                       -o "${x}" = "RADIO_RELAX" \
+                       -o "${x}" = "DEBUG_SCHEDULER" \
+                       -o "${x}" = "DETECT_DEADLOCKS" \
+                       -o "${x}" = "DUMP_SCHEDULER" ; then
+               # These aren't ABI affecting options, keep them out of AST_BUILDOPTS
+               continue
+       fi
        if test "x${BUILDOPTS}" != "x" ; then
                BUILDOPTS="${BUILDOPTS}, ${x}"
        else
                BUILDOPTS="${x}"
        fi
 done
-TMP=`${GREP} -e "^MENUSELECT_BUILD_DEPS" menuselect.makeopts | sed 's/MENUSELECT_BUILD_DEPS\=//g'`
-for x in ${TMP}; do
-       x2=`echo ${x} | tr a-z A-Z`
-       echo "#define AST_MODULE_${x2} 1"
-done
-if ${GREP} "AST_DEVMODE" makeopts | ${GREP} -q "yes"
-then
-       echo "#define AST_DEVMODE 1"
-       TMP="${TMP} AST_DEVMODE"
-fi
 
-BUILDSUM=`echo ${TMP} | ${MD5} | cut -c1-32`
+BUILDSUM=`echo ${BUILDOPTS} | ${MD5} | cut -c1-32`
 
 echo "#define AST_BUILDOPT_SUM \"${BUILDSUM}\""
 echo "#define AST_BUILDOPTS \"${BUILDOPTS}\""
index 22f7d79..f276959 100644 (file)
@@ -82,6 +82,7 @@ struct tables {
        char *connection;
        char *table;
        char *schema;
+       char quoted_identifiers;
        unsigned int usegmtime:1;
        AST_LIST_HEAD_NOLOCK(odbc_columns, columns) columns;
        AST_RWLIST_ENTRY(tables) list;
@@ -101,6 +102,7 @@ static int load_config(void)
        char connection[40];
        char table[40];
        char schema[40];
+       char quoted_identifiers;
        int lenconnection, lentable, lenschema, usegmtime = 0;
        SQLLEN sqlptr;
        int res = 0;
@@ -149,6 +151,16 @@ static int load_config(void)
                ast_copy_string(schema, tmp, sizeof(schema));
                lenschema = strlen(schema);
 
+               if (ast_strlen_zero(tmp = ast_variable_retrieve(cfg, catg, "quoted_identifiers"))) {
+                       tmp = "";
+               }
+               quoted_identifiers = tmp[0];
+               if (strlen(tmp) > 1) {
+                       ast_log(LOG_ERROR, "The quoted_identifiers setting only accepts a single character,"
+                               " while a value of '%s' was provided. This option has been disabled as a result.\n", tmp);
+                       quoted_identifiers = '\0';
+               }
+
                res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
                if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
                        ast_log(LOG_WARNING, "SQL Alloc Handle failed on connection '%s'!\n", connection);
@@ -164,7 +176,7 @@ static int load_config(void)
                        continue;
                }
 
-               tableptr = ast_calloc(sizeof(char), sizeof(*tableptr) + lenconnection + 1 + lentable + 1 + lenschema + 1);
+               tableptr = ast_calloc(sizeof(char), sizeof(*tableptr) + lenconnection + 1 + lentable + 1 + lenschema + 1 + 1);
                if (!tableptr) {
                        ast_log(LOG_ERROR, "Out of memory creating entry for table '%s' on connection '%s'%s%s%s\n", table, connection,
                                lenschema ? " (schema '" : "", lenschema ? schema : "", lenschema ? "')" : "");
@@ -181,6 +193,7 @@ static int load_config(void)
                ast_copy_string(tableptr->connection, connection, lenconnection + 1);
                ast_copy_string(tableptr->table, table, lentable + 1);
                ast_copy_string(tableptr->schema, schema, lenschema + 1);
+               tableptr->quoted_identifiers = quoted_identifiers;
 
                ast_verb(3, "Found adaptive CDR table %s@%s.\n", tableptr->table, tableptr->connection);
 
@@ -382,6 +395,8 @@ static int odbc_log(struct ast_cdr *cdr)
        char colbuf[1024], *colptr;
        SQLHSTMT stmt = NULL;
        SQLLEN rows = 0;
+       char *separator;
+       int quoted = 0;
 
        if (!sql || !sql2) {
                if (sql)
@@ -399,11 +414,27 @@ static int odbc_log(struct ast_cdr *cdr)
        }
 
        AST_LIST_TRAVERSE(&odbc_tables, tableptr, list) {
-               int first = 1;
+               separator = "";
+
+               if (tableptr->quoted_identifiers != '\0'){
+                       quoted = 1;
+               }
+
                if (ast_strlen_zero(tableptr->schema)) {
-                       ast_str_set(&sql, 0, "INSERT INTO %s (", tableptr->table);
+                       if (quoted) {
+                               ast_str_set(&sql, 0, "INSERT INTO %c%s%c (",
+                                       tableptr->quoted_identifiers, tableptr->table, tableptr->quoted_identifiers );
+                       }else{
+                               ast_str_set(&sql, 0, "INSERT INTO %s (", tableptr->table);
+                       }
                } else {
-                       ast_str_set(&sql, 0, "INSERT INTO %s.%s (", tableptr->schema, tableptr->table);
+                       if (quoted) {
+                               ast_str_set(&sql, 0, "INSERT INTO %c%s%c.%c%s%c (",
+                                               tableptr->quoted_identifiers, tableptr->schema, tableptr->quoted_identifiers,
+                                               tableptr->quoted_identifiers, tableptr->table,  tableptr->quoted_identifiers);
+                       }else{
+                               ast_str_set(&sql, 0, "INSERT INTO %s.%s (", tableptr->schema, tableptr->table);
+                       }
                }
                ast_str_set(&sql2, 0, " VALUES (");
 
@@ -484,11 +515,10 @@ static int odbc_log(struct ast_cdr *cdr)
                                                }
                                        }
 
-                                       ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
                                        LENGTHEN_BUF2(strlen(colptr));
 
                                        /* Encode value, with escaping */
-                                       ast_str_append(&sql2, 0, "%s'", first ? "" : ",");
+                                       ast_str_append(&sql2, 0, "%s'", separator);
                                        for (tmp = colptr; *tmp; tmp++) {
                                                if (*tmp == '\'') {
                                                        ast_str_append(&sql2, 0, "''");
@@ -520,9 +550,8 @@ static int odbc_log(struct ast_cdr *cdr)
                                                        year += 2000;
                                                }
 
-                                               ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
                                                LENGTHEN_BUF2(17);
-                                               ast_str_append(&sql2, 0, "%s{ d '%04d-%02d-%02d' }", first ? "" : ",", year, month, day);
+                                               ast_str_append(&sql2, 0, "%s{ d '%04d-%02d-%02d' }", separator, year, month, day);
                                        }
                                        break;
                                case SQL_TYPE_TIME:
@@ -537,9 +566,8 @@ static int odbc_log(struct ast_cdr *cdr)
                                                        continue;
                                                }
 
-                                               ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
                                                LENGTHEN_BUF2(15);
-                                               ast_str_append(&sql2, 0, "%s{ t '%02d:%02d:%02d' }", first ? "" : ",", hour, minute, second);
+                                               ast_str_append(&sql2, 0, "%s{ t '%02d:%02d:%02d' }", separator, hour, minute, second);
                                        }
                                        break;
                                case SQL_TYPE_TIMESTAMP:
@@ -566,9 +594,8 @@ static int odbc_log(struct ast_cdr *cdr)
                                                        year += 2000;
                                                }
 
-                                               ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
                                                LENGTHEN_BUF2(26);
-                                               ast_str_append(&sql2, 0, "%s{ ts '%04d-%02d-%02d %02d:%02d:%02d' }", first ? "" : ",", year, month, day, hour, minute, second);
+                                               ast_str_append(&sql2, 0, "%s{ ts '%04d-%02d-%02d %02d:%02d:%02d' }", separator, year, month, day, hour, minute, second);
                                        }
                                        break;
                                case SQL_INTEGER:
@@ -581,9 +608,8 @@ static int odbc_log(struct ast_cdr *cdr)
                                                        continue;
                                                }
 
-                                               ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
                                                LENGTHEN_BUF2(12);
-                                               ast_str_append(&sql2, 0, "%s%d", first ? "" : ",", integer);
+                                               ast_str_append(&sql2, 0, "%s%d", separator, integer);
                                        }
                                        break;
                                case SQL_BIGINT:
@@ -596,9 +622,8 @@ static int odbc_log(struct ast_cdr *cdr)
                                                        continue;
                                                }
 
-                                               ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
                                                LENGTHEN_BUF2(24);
-                                               ast_str_append(&sql2, 0, "%s%lld", first ? "" : ",", integer);
+                                               ast_str_append(&sql2, 0, "%s%lld", separator, integer);
                                        }
                                        break;
                                case SQL_SMALLINT:
@@ -611,9 +636,8 @@ static int odbc_log(struct ast_cdr *cdr)
                                                        continue;
                                                }
 
-                                               ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
                                                LENGTHEN_BUF2(6);
-                                               ast_str_append(&sql2, 0, "%s%d", first ? "" : ",", integer);
+                                               ast_str_append(&sql2, 0, "%s%d", separator, integer);
                                        }
                                        break;
                                case SQL_TINYINT:
@@ -626,9 +650,8 @@ static int odbc_log(struct ast_cdr *cdr)
                                                        continue;
                                                }
 
-                                               ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
                                                LENGTHEN_BUF2(4);
-                                               ast_str_append(&sql2, 0, "%s%d", first ? "" : ",", integer);
+                                               ast_str_append(&sql2, 0, "%s%d", separator, integer);
                                        }
                                        break;
                                case SQL_BIT:
@@ -643,9 +666,8 @@ static int odbc_log(struct ast_cdr *cdr)
                                                if (integer != 0)
                                                        integer = 1;
 
-                                               ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
                                                LENGTHEN_BUF2(2);
-                                               ast_str_append(&sql2, 0, "%s%d", first ? "" : ",", integer);
+                                               ast_str_append(&sql2, 0, "%s%d", separator, integer);
                                        }
                                        break;
                                case SQL_NUMERIC:
@@ -676,9 +698,8 @@ static int odbc_log(struct ast_cdr *cdr)
                                                        continue;
                                                }
 
-                                               ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
                                                LENGTHEN_BUF2(entry->decimals);
-                                               ast_str_append(&sql2, 0, "%s%*.*lf", first ? "" : ",", entry->decimals, entry->radix, number);
+                                               ast_str_append(&sql2, 0, "%s%*.*lf", separator, entry->decimals, entry->radix, number);
                                        }
                                        break;
                                case SQL_FLOAT:
@@ -710,16 +731,20 @@ static int odbc_log(struct ast_cdr *cdr)
                                                        continue;
                                                }
 
-                                               ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
                                                LENGTHEN_BUF2(entry->decimals);
-                                               ast_str_append(&sql2, 0, "%s%lf", first ? "" : ",", number);
+                                               ast_str_append(&sql2, 0, "%s%lf", separator, number);
                                        }
                                        break;
                                default:
                                        ast_log(LOG_WARNING, "Column type %d (field '%s:%s:%s') is unsupported at this time.\n", entry->type, tableptr->connection, tableptr->table, entry->name);
                                        continue;
                                }
-                               first = 0;
+                               if (quoted) {
+                                       ast_str_append(&sql, 0, "%s%s", separator, entry->name);
+                               } else {
+                                       ast_str_append(&sql, 0, "%s%c%s%c", separator, tableptr->quoted_identifiers, entry->name, tableptr->quoted_identifiers);
+                               }
+                               separator = ", ";
                        } else if (entry->filtervalue
                                && ((!entry->negatefiltervalue && entry->filtervalue[0] != '\0')
                                        || (entry->negatefiltervalue && entry->filtervalue[0] == '\0'))) {
index 944f98a..2877a6b 100644 (file)
@@ -58,7 +58,9 @@ static int accountlogs = 1;
 static int loguniqueid = 0;
 static int loguserfield = 0;
 static int loaded = 0;
+static int newcdrcolumns = 0;
 static const char config[] = "cdr.conf";
+static char file_csv_master[PATH_MAX];
 
 /* #define CSV_LOGUNIQUEID 1 */
 /* #define CSV_LOGUSERFIELD 1 */
@@ -93,8 +95,7 @@ static const char config[] = "cdr.conf";
 
 static char *name = "csv";
 
-AST_MUTEX_DEFINE_STATIC(mf_lock);
-AST_MUTEX_DEFINE_STATIC(acf_lock);
+AST_MUTEX_DEFINE_STATIC(f_lock);
 
 static int load_config(int reload)
 {
@@ -113,12 +114,19 @@ static int load_config(int reload)
        usegmtime = 0;
        loguniqueid = 0;
        loguserfield = 0;
+       newcdrcolumns = 0;
 
        if (!(v = ast_variable_browse(cfg, "csv"))) {
                ast_config_destroy(cfg);
                return 0;
        }
 
+       /* compute the location of the csv master file */
+       ast_mutex_lock(&f_lock);
+       snprintf(file_csv_master, sizeof(file_csv_master),
+               "%s/%s/%s", ast_config_AST_LOG_DIR, CSV_LOG_DIR, CSV_MASTER);
+       ast_mutex_unlock(&f_lock);
+
        for (; v; v = v->next) {
                if (!strcasecmp(v->name, "usegmtime")) {
                        usegmtime = ast_true(v->value);
@@ -129,7 +137,10 @@ static int load_config(int reload)
                        loguniqueid = ast_true(v->value);
                } else if (!strcasecmp(v->name, "loguserfield")) {
                        loguserfield = ast_true(v->value);
+               } else if (!strcasecmp(v->name, "newcdrcolumns")) {
+                       newcdrcolumns = ast_true(v->value);
                }
+
        }
        ast_config_destroy(cfg);
        return 1;
@@ -240,7 +251,12 @@ static int build_csv_record(char *buf, size_t bufsize, struct ast_cdr *cdr)
                append_string(buf, cdr->uniqueid, bufsize);
        /* append the user field */
        if(loguserfield)
-               append_string(buf, cdr->userfield,bufsize);
+               append_string(buf, cdr->userfield, bufsize);
+       if (newcdrcolumns) {
+               append_string(buf, cdr->peeraccount, bufsize);
+               append_string(buf, cdr->linkedid, bufsize);
+               append_int(buf, cdr->sequence, bufsize);
+       }
        /* If we hit the end of our buffer, log an error */
        if (strlen(buf) < bufsize - 5) {
                /* Trim off trailing comma */
@@ -251,65 +267,53 @@ static int build_csv_record(char *buf, size_t bufsize, struct ast_cdr *cdr)
        return -1;
 }
 
-static int writefile(char *s, char *acc)
+static int writefile(char *s, char *file_path)
 {
-       char tmp[PATH_MAX];
        FILE *f;
-
-       if (strchr(acc, '/') || (acc[0] == '.')) {
-               ast_log(LOG_WARNING, "Account code '%s' insecure for writing file\n", acc);
-               return -1;
-       }
-
-       snprintf(tmp, sizeof(tmp), "%s/%s/%s.csv", ast_config_AST_LOG_DIR,CSV_LOG_DIR, acc);
-
-       ast_mutex_lock(&acf_lock);
-       if (!(f = fopen(tmp, "a"))) {
-               ast_mutex_unlock(&acf_lock);
-               ast_log(LOG_ERROR, "Unable to open file %s : %s\n", tmp, strerror(errno));
+       /* because of the absolutely unconditional need for the
+          highest reliability possible in writing billing records,
+          we open write and close the log file each time */
+       if (!(f = fopen(file_path, "a"))) {
+               ast_log(LOG_ERROR, "Unable to open file %s : %s\n", file_path, strerror(errno));
                return -1;
        }
        fputs(s, f);
-       fflush(f);
+       fflush(f); /* be particularly anal here */
        fclose(f);
-       ast_mutex_unlock(&acf_lock);
 
        return 0;
 }
 
 
+static int writefile_account(char *s, char *acc)
+{
+       char file_account[PATH_MAX];
+       if (strchr(acc, '/') || (acc[0] == '.')) {
+               ast_log(LOG_WARNING, "Account code '%s' insecure for writing file\n", acc);
+               return -1;
+       }
+       snprintf(file_account, sizeof(file_account), "%s/%s/%s.csv", ast_config_AST_LOG_DIR,CSV_LOG_DIR, acc);
+       return writefile(s, file_account);
+}
+
 static int csv_log(struct ast_cdr *cdr)
 {
-       FILE *mf = NULL;
        /* Make sure we have a big enough buf */
        char buf[1024];
-       char csvmaster[PATH_MAX];
-       snprintf(csvmaster, sizeof(csvmaster),"%s/%s/%s", ast_config_AST_LOG_DIR, CSV_LOG_DIR, CSV_MASTER);
        if (build_csv_record(buf, sizeof(buf), cdr)) {
                ast_log(LOG_WARNING, "Unable to create CSV record in %d bytes.  CDR not recorded!\n", (int)sizeof(buf));
                return 0;
        }
 
-       /* because of the absolutely unconditional need for the
-          highest reliability possible in writing billing records,
-          we open write and close the log file each time */
-       ast_mutex_lock(&mf_lock);
-       if ((mf = fopen(csvmaster, "a"))) {
-               fputs(buf, mf);
-               fflush(mf); /* be particularly anal here */
-               fclose(mf);
-               mf = NULL;
-               ast_mutex_unlock(&mf_lock);
-       } else {
-               ast_mutex_unlock(&mf_lock);
-               ast_log(LOG_ERROR, "Unable to re-open master file %s : %s\n", csvmaster, strerror(errno));
-       }
+       ast_mutex_lock(&f_lock);
+       if (writefile(buf, file_csv_master))
+               ast_log(LOG_WARNING, "Unable to write CSV record to master '%s' : %s\n", file_csv_master, strerror(errno));
 
        if (accountlogs && !ast_strlen_zero(cdr->accountcode)) {
-               if (writefile(buf, cdr->accountcode))
+               if (writefile_account(buf, cdr->accountcode))
                        ast_log(LOG_WARNING, "Unable to write CSV record to account file '%s' : %s\n", cdr->accountcode, strerror(errno));
        }
-
+       ast_mutex_unlock(&f_lock);
        return 0;
 }
 
@@ -353,9 +357,9 @@ static int reload(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Comma Separated Values CDR Backend",
-               .support_level = AST_MODULE_SUPPORT_EXTENDED,
-               .load = load_module,
-               .unload = unload_module,
-               .reload = reload,
-               .load_pri = AST_MODPRI_CDR_DRIVER,
-              );
+       .support_level = AST_MODULE_SUPPORT_EXTENDED,
+       .load = load_module,
+       .unload = unload_module,
+       .reload = reload,
+       .load_pri = AST_MODPRI_CDR_DRIVER,
+);
index 2c4d8b7..24cb834 100644 (file)
@@ -226,10 +226,10 @@ static int reload(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Customizable Comma Separated Values CDR Backend",
-               .support_level = AST_MODULE_SUPPORT_CORE,
-               .load = load_module,
-               .unload = unload_module,
-               .reload = reload,
-               .load_pri = AST_MODPRI_CDR_DRIVER,
-              );
+       .support_level = AST_MODULE_SUPPORT_CORE,
+       .load = load_module,
+       .unload = unload_module,
+       .reload = reload,
+       .load_pri = AST_MODPRI_CDR_DRIVER,
+);
 
index 4a079ae..ef9d63e 100644 (file)
@@ -368,9 +368,9 @@ static int reload(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Asterisk Manager Interface CDR Backend",
-               .support_level = AST_MODULE_SUPPORT_CORE,
-               .load = load_module,
-               .unload = unload_module,
-               .reload = reload,
-               .load_pri = AST_MODPRI_CDR_DRIVER,
-              );
+       .support_level = AST_MODULE_SUPPORT_CORE,
+       .load = load_module,
+       .unload = unload_module,
+       .reload = reload,
+       .load_pri = AST_MODPRI_CDR_DRIVER,
+);
index 8f326f9..5fddb7b 100644 (file)
@@ -64,6 +64,7 @@ enum {
        CONFIG_DISPOSITIONSTRING = 1 << 2,
        CONFIG_HRTIME =            1 << 3,
        CONFIG_REGISTERED =        1 << 4,
+       CONFIG_NEWCDRCOLUMNS =     1 << 5,
 };
 
 static struct ast_flags config = { 0 };
@@ -72,23 +73,29 @@ static SQLHSTMT execute_cb(struct odbc_obj *obj, void *data)
 {
        struct ast_cdr *cdr = data;
        SQLRETURN ODBC_res;
-       char sqlcmd[2048] = "", timestr[128];
+       char sqlcmd[2048] = "", timestr[128], new_columns[120] = "", new_values[7] = "";
        struct ast_tm tm;
        SQLHSTMT stmt;
+       int i = 0;
 
        ast_localtime(&cdr->start, &tm, ast_test_flag(&config, CONFIG_USEGMTIME) ? "GMT" : NULL);
        ast_strftime(timestr, sizeof(timestr), DATE_FORMAT, &tm);
 
+       if (ast_test_flag(&config, CONFIG_NEWCDRCOLUMNS)) {
+               snprintf(new_columns, sizeof(new_columns), "%s", ",peeraccount,linkedid,sequence");
+               snprintf(new_values, sizeof(new_values), "%s", ",?,?,?");
+       }
+
        if (ast_test_flag(&config, CONFIG_LOGUNIQUEID)) {
                snprintf(sqlcmd,sizeof(sqlcmd),"INSERT INTO %s "
                "(calldate,clid,src,dst,dcontext,channel,dstchannel,lastapp,"
-               "lastdata,duration,billsec,disposition,amaflags,accountcode,uniqueid,userfield) "
-               "VALUES ({ts '%s'},?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", table, timestr);
+               "lastdata,duration,billsec,disposition,amaflags,accountcode,uniqueid,userfield%s) "
+               "VALUES ({ts '%s'},?,?,?,?,?,?,?,?,?,?,?,?,?,?,?%s)", table, new_columns, timestr, new_values);
        } else {
                snprintf(sqlcmd,sizeof(sqlcmd),"INSERT INTO %s "
                "(calldate,clid,src,dst,dcontext,channel,dstchannel,lastapp,lastdata,"
-               "duration,billsec,disposition,amaflags,accountcode) "
-               "VALUES ({ts '%s'},?,?,?,?,?,?,?,?,?,?,?,?,?)", table, timestr);
+               "duration,billsec,disposition,amaflags,accountcode%s) "
+               "VALUES ({ts '%s'},?,?,?,?,?,?,?,?,?,?,?,?,?%s)", table, new_columns, timestr, new_values);
        }
 
        ODBC_res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
@@ -134,9 +141,17 @@ static SQLHSTMT execute_cb(struct odbc_obj *obj, void *data)
        SQLBindParameter(stmt, 12, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->amaflags, 0, NULL);
        SQLBindParameter(stmt, 13, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->accountcode), 0, cdr->accountcode, 0, NULL);
 
+       i = 14;
        if (ast_test_flag(&config, CONFIG_LOGUNIQUEID)) {
                SQLBindParameter(stmt, 14, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->uniqueid), 0, cdr->uniqueid, 0, NULL);
                SQLBindParameter(stmt, 15, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->userfield), 0, cdr->userfield, 0, NULL);
+               i = 16;
+       }
+
+       if (ast_test_flag(&config, CONFIG_NEWCDRCOLUMNS)) {
+               SQLBindParameter(stmt, i, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->peeraccount), 0, cdr->peeraccount, 0, NULL);
+               SQLBindParameter(stmt, i + 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->linkedid), 0, cdr->linkedid, 0, NULL);
+               SQLBindParameter(stmt, i + 2, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->sequence, 0, NULL);
        }
 
        ODBC_res = SQLExecDirect(stmt, (unsigned char *)sqlcmd, SQL_NTS);
@@ -260,6 +275,13 @@ static int odbc_load_module(int reload)
                                ast_set_flag(&config, CONFIG_REGISTERED);
                        }
                }
+               if (((tmp = ast_variable_retrieve(cfg, "global", "newcdrcolumns"))) && ast_true(tmp)) {
+                       ast_set_flag(&config, CONFIG_NEWCDRCOLUMNS);
+                       ast_debug(1, "cdr_odbc: Add new cdr columns\n");
+               } else {
+                       ast_clear_flag(&config, CONFIG_NEWCDRCOLUMNS);
+                       ast_debug(1, "cdr_odbc: Not add new cdr columns\n");
+               }
        } while (0);
 
        if (ast_test_flag(&config, CONFIG_REGISTERED) && (!cfg || dsn == NULL || table == NULL)) {
@@ -302,9 +324,9 @@ static int reload(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "ODBC CDR Backend",
-               .support_level = AST_MODULE_SUPPORT_EXTENDED,
-               .load = load_module,
-               .unload = unload_module,
-               .reload = reload,
-               .load_pri = AST_MODPRI_CDR_DRIVER,
-              );
+       .support_level = AST_MODULE_SUPPORT_EXTENDED,
+       .load = load_module,
+       .unload = unload_module,
+       .reload = reload,
+       .load_pri = AST_MODPRI_CDR_DRIVER,
+);
index 310411c..8dc49e1 100644 (file)
@@ -75,6 +75,7 @@ static char *encoding;
 static char *tz;
 
 static int connected = 0;
+/* Optimization to reduce number of memory allocations */
 static int maxsize = 512, maxsize2 = 512;
 static time_t connect_time = 0;
 static int totalrecords = 0;
@@ -247,7 +248,7 @@ static int pgsql_log(struct ast_cdr *cdr)
                struct columns *cur;
                struct ast_str *sql = ast_str_create(maxsize), *sql2 = ast_str_create(maxsize2);
                char buf[257], escapebuf[513], *value;
-               int first = 1;
+               char *separator = "";
 
                if (!sql || !sql2) {
                        ast_free(sql);
@@ -269,86 +270,86 @@ static int pgsql_log(struct ast_cdr *cdr)
                                if (cur->notnull && !cur->hasdefault) {
                                        /* Field is NOT NULL (but no default), must include it anyway */
                                        LENGTHEN_BUF1(strlen(cur->name) + 2);
-                                       ast_str_append(&sql, 0, "%s\"%s\"", first ? "" : ",", cur->name);
+                                       ast_str_append(&sql, 0, "%s\"%s\"", separator, cur->name);
                                        LENGTHEN_BUF2(3);
-                                       ast_str_append(&sql2, 0, "%s''", first ? "" : ",");
-                                       first = 0;
+                                       ast_str_append(&sql2, 0, "%s''", separator);
+                                       separator = ", ";
                                }
                                continue;
                        }
 
                        LENGTHEN_BUF1(strlen(cur->name) + 2);
-                       ast_str_append(&sql, 0, "%s\"%s\"", first ? "" : ",", cur->name);
+                       ast_str_append(&sql, 0, "%s\"%s\"", separator, cur->name);
 
                        if (strcmp(cur->name, "start") == 0 || strcmp(cur->name, "calldate") == 0) {
                                if (strncmp(cur->type, "int", 3) == 0) {
                                        LENGTHEN_BUF2(13);
-                                       ast_str_append(&sql2, 0, "%s%ld", first ? "" : ",", (long) cdr->start.tv_sec);
+                                       ast_str_append(&sql2, 0, "%s%ld", separator, (long) cdr->start.tv_sec);
                                } else if (strncmp(cur->type, "float", 5) == 0) {
                                        LENGTHEN_BUF2(31);
-                                       ast_str_append(&sql2, 0, "%s%f", first ? "" : ",", (double)cdr->start.tv_sec + (double)cdr->start.tv_usec / 1000000.0);
+                                       ast_str_append(&sql2, 0, "%s%f", separator, (double)cdr->start.tv_sec + (double)cdr->start.tv_usec / 1000000.0);
                                } else {
                                        /* char, hopefully */
                                        LENGTHEN_BUF2(31);
                                        ast_localtime(&cdr->start, &tm, tz);
                                        ast_strftime(buf, sizeof(buf), DATE_FORMAT, &tm);
-                                       ast_str_append(&sql2, 0, "%s%s", first ? "" : ",", buf);
+                                       ast_str_append(&sql2, 0, "%s%s", separator, buf);
                                }
                        } else if (strcmp(cur->name, "answer") == 0) {
                                if (strncmp(cur->type, "int", 3) == 0) {
                                        LENGTHEN_BUF2(13);
-                                       ast_str_append(&sql2, 0, "%s%ld", first ? "" : ",", (long) cdr->answer.tv_sec);
+                                       ast_str_append(&sql2, 0, "%s%ld", separator, (long) cdr->answer.tv_sec);
                                } else if (strncmp(cur->type, "float", 5) == 0) {
                                        LENGTHEN_BUF2(31);
-                                       ast_str_append(&sql2, 0, "%s%f", first ? "" : ",", (double)cdr->answer.tv_sec + (double)cdr->answer.tv_usec / 1000000.0);
+                                       ast_str_append(&sql2, 0, "%s%f", separator, (double)cdr->answer.tv_sec + (double)cdr->answer.tv_usec / 1000000.0);
                                } else {
                                        /* char, hopefully */
                                        LENGTHEN_BUF2(31);
                                        ast_localtime(&cdr->answer, &tm, tz);
                                        ast_strftime(buf, sizeof(buf), DATE_FORMAT, &tm);
-                                       ast_str_append(&sql2, 0, "%s%s", first ? "" : ",", buf);
+                                       ast_str_append(&sql2, 0, "%s%s", separator, buf);
                                }
                        } else if (strcmp(cur->name, "end") == 0) {
                                if (strncmp(cur->type, "int", 3) == 0) {
                                        LENGTHEN_BUF2(13);
-                                       ast_str_append(&sql2, 0, "%s%ld", first ? "" : ",", (long) cdr->end.tv_sec);
+                                       ast_str_append(&sql2, 0, "%s%ld", separator, (long) cdr->end.tv_sec);
                                } else if (strncmp(cur->type, "float", 5) == 0) {
                                        LENGTHEN_BUF2(31);
-                                       ast_str_append(&sql2, 0, "%s%f", first ? "" : ",", (double)cdr->end.tv_sec + (double)cdr->end.tv_usec / 1000000.0);
+                                       ast_str_append(&sql2, 0, "%s%f", separator, (double)cdr->end.tv_sec + (double)cdr->end.tv_usec / 1000000.0);
                                } else {
                                        /* char, hopefully */
                                        LENGTHEN_BUF2(31);
                                        ast_localtime(&cdr->end, &tm, tz);
                                        ast_strftime(buf, sizeof(buf), DATE_FORMAT, &tm);
-                                       ast_str_append(&sql2, 0, "%s%s", first ? "" : ",", buf);
+                                       ast_str_append(&sql2, 0, "%s%s", separator, buf);
                                }
                        } else if (strcmp(cur->name, "duration") == 0 || strcmp(cur->name, "billsec") == 0) {
                                if (cur->type[0] == 'i') {
                                        /* Get integer, no need to escape anything */
                                        ast_cdr_format_var(cdr, cur->name, &value, buf, sizeof(buf), 0);
                                        LENGTHEN_BUF2(13);
-                                       ast_str_append(&sql2, 0, "%s%s", first ? "" : ",", value);
+                                       ast_str_append(&sql2, 0, "%s%s", separator, value);
                                } else if (strncmp(cur->type, "float", 5) == 0) {
                                        struct timeval *when = cur->name[0] == 'd' ? &cdr->start : ast_tvzero(cdr->answer) ? &cdr->end : &cdr->answer;
                                        LENGTHEN_BUF2(31);
-                                       ast_str_append(&sql2, 0, "%s%f", first ? "" : ",", (double) (ast_tvdiff_us(cdr->end, *when) / 1000000.0));
+                                       ast_str_append(&sql2, 0, "%s%f", separator, (double) (ast_tvdiff_us(cdr->end, *when) / 1000000.0));
                                } else {
                                        /* Char field, probably */
                                        struct timeval *when = cur->name[0] == 'd' ? &cdr->start : ast_tvzero(cdr->answer) ? &cdr->end : &cdr->answer;
                                        LENGTHEN_BUF2(31);
-                                       ast_str_append(&sql2, 0, "%s'%f'", first ? "" : ",", (double) (ast_tvdiff_us(cdr->end, *when) / 1000000.0));
+                                       ast_str_append(&sql2, 0, "%s'%f'", separator, (double) (ast_tvdiff_us(cdr->end, *when) / 1000000.0));
                                }
                        } else if (strcmp(cur->name, "disposition") == 0 || strcmp(cur->name, "amaflags") == 0) {
                                if (strncmp(cur->type, "int", 3) == 0) {
                                        /* Integer, no need to escape anything */
                                        ast_cdr_format_var(cdr, cur->name, &value, buf, sizeof(buf), 1);
                                        LENGTHEN_BUF2(13);
-                                       ast_str_append(&sql2, 0, "%s%s", first ? "" : ",", value);
+                                       ast_str_append(&sql2, 0, "%s%s", separator, value);
                                } else {
                                        /* Although this is a char field, there are no special characters in the values for these fields */
                                        ast_cdr_format_var(cdr, cur->name, &value, buf, sizeof(buf), 0);
                                        LENGTHEN_BUF2(31);
-                                       ast_str_append(&sql2, 0, "%s'%s'", first ? "" : ",", value);
+                                       ast_str_append(&sql2, 0, "%s'%s'", separator, value);
                                }
                        } else {
                                /* Arbitrary field, could be anything */
@@ -357,19 +358,19 @@ static int pgsql_log(struct ast_cdr *cdr)
                                        long long whatever;
                                        if (value && sscanf(value, "%30lld", &whatever) == 1) {
                                                LENGTHEN_BUF2(26);
-                                               ast_str_append(&sql2, 0, "%s%lld", first ? "" : ",", whatever);
+                                               ast_str_append(&sql2, 0, "%s%lld", separator, whatever);
                                        } else {
                                                LENGTHEN_BUF2(2);
-                                               ast_str_append(&sql2, 0, "%s0", first ? "" : ",");
+                                               ast_str_append(&sql2, 0, "%s0", separator);
                                        }
                                } else if (strncmp(cur->type, "float", 5) == 0) {
                                        long double whatever;
                                        if (value && sscanf(value, "%30Lf", &whatever) == 1) {
                                                LENGTHEN_BUF2(51);
-                                               ast_str_append(&sql2, 0, "%s%30Lf", first ? "" : ",", whatever);
+                                               ast_str_append(&sql2, 0, "%s%30Lf", separator, whatever);
                                        } else {
                                                LENGTHEN_BUF2(2);
-                                               ast_str_append(&sql2, 0, "%s0", first ? "" : ",");
+                                               ast_str_append(&sql2, 0, "%s0", separator);
                                        }
                                /* XXX Might want to handle dates, times, and other misc fields here XXX */
                                } else {
@@ -378,10 +379,10 @@ static int pgsql_log(struct ast_cdr *cdr)
                                        else
                                                escapebuf[0] = '\0';
                                        LENGTHEN_BUF2(strlen(escapebuf) + 3);
-                                       ast_str_append(&sql2, 0, "%s'%s'", first ? "" : ",", escapebuf);
+                                       ast_str_append(&sql2, 0, "%s'%s'", separator, escapebuf);
                                }
                        }
-                       first = 0;
+                       separator = ", ";
                }
 
                LENGTHEN_BUF1(ast_str_strlen(sql2) + 2);
@@ -453,6 +454,15 @@ static int pgsql_log(struct ast_cdr *cdr)
                        records++;
                }
                PQclear(result);
+
+               /* Next time, just allocate buffers that are that big to start with. */
+               if (ast_str_strlen(sql) > maxsize) {
+                       maxsize = ast_str_strlen(sql);
+               }
+               if (ast_str_strlen(sql2) > maxsize2) {
+                       maxsize2 = ast_str_strlen(sql2);
+               }
+
                ast_free(sql);
                ast_free(sql2);
        }
@@ -670,42 +680,20 @@ static int config_module(int reload)
                version = PQserverVersion(conn);
 
                if (version >= 70300) {
-                       char *schemaname, *tablename;
+                       char *schemaname, *tablename, *tmp_schemaname, *tmp_tablename;
                        if (strchr(table, '.')) {
-                               schemaname = ast_strdupa(table);
-                               tablename = strchr(schemaname, '.');
-                               *tablename++ = '\0';
+                               tmp_schemaname = ast_strdupa(table);
+                               tmp_tablename = strchr(tmp_schemaname, '.');
+                               *tmp_tablename++ = '\0';
                        } else {
-                               schemaname = "";
-                               tablename = table;
+                               tmp_schemaname = "";
+                               tmp_tablename = table;
                        }
+                       tablename = ast_alloca(strlen(tmp_tablename) * 2 + 1);
+                       PQescapeStringConn(conn, tablename, tmp_tablename, strlen(tmp_tablename), NULL);
 
-                       /* Escape special characters in schemaname */
-                       if (strchr(schemaname, '\\') || strchr(schemaname, '\'')) {
-                               char *tmp = schemaname, *ptr;
-
-                               ptr = schemaname = ast_alloca(strlen(tmp) * 2 + 1);
-                               for (; *tmp; tmp++) {
-                                       if (strchr("\\'", *tmp)) {
-                                               *ptr++ = *tmp;
-                                       }
-                                       *ptr++ = *tmp;
-                               }
-                               *ptr = '\0';
-                       }
-                       /* Escape special characters in tablename */
-                       if (strchr(tablename, '\\') || strchr(tablename, '\'')) {
-                               char *tmp = tablename, *ptr;
-
-                               ptr = tablename = ast_alloca(strlen(tmp) * 2 + 1);
-                               for (; *tmp; tmp++) {
-                                       if (strchr("\\'", *tmp)) {
-                                               *ptr++ = *tmp;
-                                       }
-                                       *ptr++ = *tmp;
-                               }
-                               *ptr = '\0';
-                       }
+                       schemaname = ast_alloca(strlen(tmp_schemaname) * 2 + 1);
+                       PQescapeStringConn(conn, schemaname, tmp_schemaname, strlen(tmp_schemaname), NULL);
 
                        snprintf(sqlcmd, sizeof(sqlcmd), "SELECT a.attname, t.typname, a.attlen, a.attnotnull, d.adsrc, a.atttypmod FROM (((pg_catalog.pg_class c INNER JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace AND c.relname = '%s' AND n.nspname = %s%s%s) INNER JOIN pg_catalog.pg_attribute a ON (NOT a.attisdropped) AND a.attnum > 0 AND a.attrelid = c.oid) INNER JOIN pg_catalog.pg_type t ON t.oid = a.atttypid) LEFT OUTER JOIN pg_attrdef d ON a.atthasdef AND d.adrelid = a.attrelid AND d.adnum = a.attnum ORDER BY n.nspname, c.relname, attnum",
                                tablename,
@@ -801,9 +789,9 @@ static int reload(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PostgreSQL CDR Backend",
-               .support_level = AST_MODULE_SUPPORT_EXTENDED,
-               .load = load_module,
-               .unload = unload_module,
-               .reload = reload,
-               .load_pri = AST_MODPRI_CDR_DRIVER,
-              );
+       .support_level = AST_MODULE_SUPPORT_EXTENDED,
+       .load = load_module,
+       .unload = unload_module,
+       .reload = reload,
+       .load_pri = AST_MODPRI_CDR_DRIVER,
+);
index d954265..e1a639c 100644 (file)
@@ -301,8 +301,8 @@ static int load_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "RADIUS CDR Backend",
-               .support_level = AST_MODULE_SUPPORT_EXTENDED,
-               .load = load_module,
-               .unload = unload_module,
-               .load_pri = AST_MODPRI_CDR_DRIVER,
-       );
+       .support_level = AST_MODULE_SUPPORT_EXTENDED,
+       .load = load_module,
+       .unload = unload_module,
+       .load_pri = AST_MODPRI_CDR_DRIVER,
+);
index c71abd0..6dabeff 100644 (file)
@@ -632,9 +632,9 @@ static int unload_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "FreeTDS CDR Backend",
-               .support_level = AST_MODULE_SUPPORT_EXTENDED,
-               .load = load_module,
-               .unload = unload_module,
-               .reload = reload,
-               .load_pri = AST_MODPRI_CDR_DRIVER,
-              );
+       .support_level = AST_MODULE_SUPPORT_EXTENDED,
+       .load = load_module,
+       .unload = unload_module,
+       .reload = reload,
+       .load_pri = AST_MODPRI_CDR_DRIVER,
+);
index 0c55e49..f6377fc 100644 (file)
@@ -222,5 +222,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Customizable Comma Se
        .unload = unload_module,
        .reload = reload,
        .load_pri = AST_MODPRI_CDR_DRIVER,
-       );
+);
 
index 4803444..2d8408b 100644 (file)
@@ -402,7 +402,7 @@ static void odbc_log(struct ast_event *event)
        }
 
        AST_LIST_TRAVERSE(&odbc_tables, tableptr, list) {
-               int first = 1;
+               char *separator = "";
                ast_str_set(&sql, 0, "INSERT INTO %s (", tableptr->table);
                ast_str_set(&sql2, 0, " VALUES (");
 
@@ -536,11 +536,11 @@ static void odbc_log(struct ast_event *event)
                                                }
                                        }
 
-                                       ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
+                                       ast_str_append(&sql, 0, "%s%s", separator, entry->name);
                                        LENGTHEN_BUF2(strlen(colptr));
 
                                        /* Encode value, with escaping */
-                                       ast_str_append(&sql2, 0, "%s'", first ? "" : ",");
+                                       ast_str_append(&sql2, 0, "%s'", separator);
                                        for (tmp = colptr; *tmp; tmp++) {
                                                if (*tmp == '\'') {
                                                        ast_str_append(&sql2, 0, "''");
@@ -580,9 +580,9 @@ static void odbc_log(struct ast_event *event)
                                                        }
                                                }
 
-                                               ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
+                                               ast_str_append(&sql, 0, "%s%s", separator, entry->name);
                                                LENGTHEN_BUF2(17);
-                                               ast_str_append(&sql2, 0, "%s{d '%04d-%02d-%02d'}", first ? "" : ",", year, month, day);
+                                               ast_str_append(&sql2, 0, "%s{d '%04d-%02d-%02d'}", separator, year, month, day);
                                        }
                                        break;
                                case SQL_TYPE_TIME:
@@ -605,9 +605,9 @@ static void odbc_log(struct ast_event *event)
                                                        }
                                                }
 
-                                               ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
+                                               ast_str_append(&sql, 0, "%s%s", separator, entry->name);
                                                LENGTHEN_BUF2(15);
-                                               ast_str_append(&sql2, 0, "%s{t '%02d:%02d:%02d'}", first ? "" : ",", hour, minute, second);
+                                               ast_str_append(&sql2, 0, "%s{t '%02d:%02d:%02d'}", separator, hour, minute, second);
                                        }
                                        break;
                                case SQL_TYPE_TIMESTAMP:
@@ -646,9 +646,9 @@ static void odbc_log(struct ast_event *event)
                                                        }
                                                }
 
-                                               ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
+                                               ast_str_append(&sql, 0, "%s%s", separator, entry->name);
                                                LENGTHEN_BUF2(27);
-                                               ast_str_append(&sql2, 0, "%s{ts '%04d-%02d-%02d %02d:%02d:%02d.%d'}", first ? "" : ",", year, month, day, hour, minute, second, fraction);
+                                               ast_str_append(&sql2, 0, "%s{ts '%04d-%02d-%02d %02d:%02d:%02d.%d'}", separator, year, month, day, hour, minute, second, fraction);
                                        }
                                        break;
                                case SQL_INTEGER:
@@ -659,9 +659,9 @@ static void odbc_log(struct ast_event *event)
                                                        continue;
                                                }
 
-                                               ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
+                                               ast_str_append(&sql, 0, "%s%s", separator, entry->name);
                                                LENGTHEN_BUF2(12);
-                                               ast_str_append(&sql2, 0, "%s%d", first ? "" : ",", integer);
+                                               ast_str_append(&sql2, 0, "%s%d", separator, integer);
                                        }
                                        break;
                                case SQL_BIGINT:
@@ -673,9 +673,9 @@ static void odbc_log(struct ast_event *event)
                                                        continue;
                                                }
 
-                                               ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
+                                               ast_str_append(&sql, 0, "%s%s", separator, entry->name);
                                                LENGTHEN_BUF2(24);
-                                               ast_str_append(&sql2, 0, "%s%lld", first ? "" : ",", integer);
+                                               ast_str_append(&sql2, 0, "%s%lld", separator, integer);
                                        }
                                        break;
                                case SQL_SMALLINT:
@@ -686,9 +686,9 @@ static void odbc_log(struct ast_event *event)
                                                        continue;
                                                }
 
-                                               ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
+                                               ast_str_append(&sql, 0, "%s%s", separator, entry->name);
                                                LENGTHEN_BUF2(7);
-                                               ast_str_append(&sql2, 0, "%s%d", first ? "" : ",", integer);
+                                               ast_str_append(&sql2, 0, "%s%d", separator, integer);
                                        }
                                        break;
                                case SQL_TINYINT:
@@ -699,9 +699,9 @@ static void odbc_log(struct ast_event *event)
                                                        continue;
                                                }
 
-                                               ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
+                                               ast_str_append(&sql, 0, "%s%s", separator, entry->name);
                                                LENGTHEN_BUF2(4);
-                                               ast_str_append(&sql2, 0, "%s%d", first ? "" : ",", integer);
+                                               ast_str_append(&sql2, 0, "%s%d", separator, integer);
                                        }
                                        break;
                                case SQL_BIT:
@@ -714,9 +714,9 @@ static void odbc_log(struct ast_event *event)
                                                if (integer != 0)
                                                        integer = 1;
 
-                                               ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
+                                               ast_str_append(&sql, 0, "%s%s", separator, entry->name);
                                                LENGTHEN_BUF2(2);
-                                               ast_str_append(&sql2, 0, "%s%d", first ? "" : ",", integer);
+                                               ast_str_append(&sql2, 0, "%s%d", separator, integer);
                                        }
                                        break;
                                case SQL_NUMERIC:
@@ -728,9 +728,9 @@ static void odbc_log(struct ast_event *event)
                                                        continue;
                                                }
 
-                                               ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
+                                               ast_str_append(&sql, 0, "%s%s", separator, entry->name);
                                                LENGTHEN_BUF2(entry->decimals + 2);
-                                               ast_str_append(&sql2, 0, "%s%*.*lf", first ? "" : ",", entry->decimals, entry->radix, number);
+                                               ast_str_append(&sql2, 0, "%s%*.*lf", separator, entry->decimals, entry->radix, number);
                                        }
                                        break;
                                case SQL_FLOAT:
@@ -743,16 +743,16 @@ static void odbc_log(struct ast_event *event)
                                                        continue;
                                                }
 
-                                               ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
+                                               ast_str_append(&sql, 0, "%s%s", separator, entry->name);
                                                LENGTHEN_BUF2(entry->decimals);
-                                               ast_str_append(&sql2, 0, "%s%lf", first ? "" : ",", number);
+                                               ast_str_append(&sql2, 0, "%s%lf", separator, number);
                                        }
                                        break;
                                default:
                                        ast_log(LOG_WARNING, "Column type %d (field '%s:%s:%s') is unsupported at this time.\n", entry->type, tableptr->connection, tableptr->table, entry->name);
                                        continue;
                                }
-                               first = 0;
+                               separator = ", ";
                        }
                }
 
index 2d7f0df..f495947 100644 (file)
@@ -60,6 +60,8 @@ ASTERISK_REGISTER_FILE()
 
 #define PGSQL_BACKEND_NAME "CEL PGSQL backend"
 
+#define PGSQL_MIN_VERSION_SCHEMA 70300
+
 static char *config = "cel_pgsql.conf";
 
 static char *pghostname;
@@ -69,8 +71,10 @@ static char *pgpassword;
 static char *pgappname;
 static char *pgdbport;
 static char *table;
+static char *schema;
 
 static int connected = 0;
+/* Optimization to reduce number of memory allocations */
 static int maxsize = 512, maxsize2 = 512;
 static int usegmtime = 0;
 
@@ -201,7 +205,7 @@ static void pgsql_log(struct ast_event *event)
                AST_RWLIST_RDLOCK(&psql_columns);
                AST_RWLIST_TRAVERSE(&psql_columns, cur, list) {
                        LENGTHEN_BUF1(strlen(cur->name) + 2);
-                       ast_str_append(&sql, 0, "%s\"%s\"", first ? "" : ",", cur->name);
+                       ast_str_append(&sql, 0, "%s\"%s\"", SEP, cur->name);
 
                        if (strcmp(cur->name, "eventtime") == 0) {
                                if (strncmp(cur->type, "int", 3) == 0) {
@@ -372,6 +376,14 @@ static void pgsql_log(struct ast_event *event)
                }
                PQclear(result);
 
+               /* Next time, just allocate buffers that are that big to start with. */
+               if (ast_str_strlen(sql) > maxsize) {
+                       maxsize = ast_str_strlen(sql);
+               }
+               if (ast_str_strlen(sql2) > maxsize2) {
+                       maxsize2 = ast_str_strlen(sql2);
+               }
+
 ast_log_cleanup:
                ast_free(sql);
                ast_free(sql2);
@@ -418,6 +430,10 @@ static int my_unload_module(void)
                ast_free(table);
                table = NULL;
        }
+       if (schema) {
+               ast_free(schema);
+               schema = NULL;
+       }
        while ((current = AST_RWLIST_REMOVE_HEAD(&psql_columns, list))) {
                ast_free(current);
        }
@@ -521,6 +537,16 @@ static int process_my_load_module(struct ast_config *cfg)
        } else {
                usegmtime = 0;
        }
+       if (!(tmp = ast_variable_retrieve(cfg, "global", "schema"))) {
+               tmp = "";
+       }
+       if (schema) {
+               ast_free(schema);
+       }
+       if (!(schema = ast_strdup(tmp))) {
+               ast_log(LOG_WARNING,"PostgreSQL Ran out of memory copying schema info\n");
+               return AST_MODULE_LOAD_DECLINE;
+       }
        if (option_debug) {
                if (ast_strlen_zero(pghostname)) {
                        ast_debug(3, "cel_pgsql: using default unix socket\n");
@@ -538,23 +564,50 @@ static int process_my_load_module(struct ast_config *cfg)
 
        pgsql_reconnect();
        if (PQstatus(conn) != CONNECTION_BAD) {
-               char sqlcmd[512];
-               char *fname, *ftype, *flen, *fnotnull, *fdef;
-               char *tableptr;
-               int i, rows;
+               char sqlcmd[768];
+               char *fname, *ftype, *flen, *fnotnull, *fdef, *tablename, *tmp_tablename;
+               int i, rows, version;
 
                ast_debug(1, "Successfully connected to PostgreSQL database.\n");
                connected = 1;
 
+               version = PQserverVersion(conn);
                /* Remove any schema name from the table */
-               if ((tableptr = strrchr(table, '.'))) {
-                       tableptr++;
+               if ((tmp_tablename = strrchr(table, '.'))) {
+                       tmp_tablename++;
                } else {
-                       tableptr = table;
+                       tmp_tablename = table;
+               }
+               tablename = ast_alloca(strlen(tmp_tablename) * 2 + 1);
+               PQescapeStringConn(conn, tablename, tmp_tablename, strlen(tmp_tablename), NULL);
+               if (version >= PGSQL_MIN_VERSION_SCHEMA) {
+                       char *schemaname;
+                       int lenschema;
+                       lenschema = strlen(schema);
+                       schemaname = ast_alloca(lenschema * 2 + 1);
+                       PQescapeStringConn(conn, schemaname, schema, lenschema, NULL);
+
+                       snprintf(sqlcmd, sizeof(sqlcmd),
+                       "SELECT a.attname, t.typname, a.attlen, a.attnotnull, d.adsrc, a.atttypmod "
+                       "FROM (((pg_catalog.pg_class c INNER JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace "
+                                "AND c.relname = '%s' AND n.nspname = %s%s%s) "
+                              "INNER JOIN pg_catalog.pg_attribute a ON ("
+                                  "NOT a.attisdropped) AND a.attnum > 0 AND a.attrelid = c.oid) "
+                           "INNER JOIN pg_catalog.pg_type t ON t.oid = a.atttypid) "
+                       "LEFT OUTER JOIN pg_attrdef d ON a.atthasdef AND d.adrelid = a.attrelid "
+                         "AND d.adnum = a.attnum "
+                       "ORDER BY n.nspname, c.relname, attnum",
+                               tablename,
+                               lenschema == 0 ? "" : "'", lenschema == 0 ? "current_schema()" : schemaname, lenschema == 0 ? "" : "'");
+               } else {
+                       snprintf(sqlcmd, sizeof(sqlcmd),
+                       "SELECT a.attname, t.typname, a.attlen, a.attnotnull, d.adsrc, a.atttypmod "
+                       "FROM pg_class c, pg_type t, pg_attribute a "
+                       "LEFT OUTER JOIN pg_attrdef d ON a.atthasdef AND d.adrelid = a.attrelid "
+                       "AND d.adnum = a.attnum WHERE c.oid = a.attrelid AND a.atttypid = t.oid "
+                       "AND (a.attnum > 0) AND c.relname = '%s' ORDER BY c.relname, attnum", tablename);
                }
-
                /* Query the columns */
-               snprintf(sqlcmd, sizeof(sqlcmd), "select a.attname, t.typname, a.attlen, a.attnotnull, d.adsrc from pg_class c, pg_type t, pg_attribute a left outer join pg_attrdef d on a.atthasdef and d.adrelid = a.attrelid and d.adnum = a.attnum where c.oid = a.attrelid and a.atttypid = t.oid and (a.attnum > 0) and c.relname = '%s' order by c.relname, attnum", tableptr);
                result = PQexec(conn, sqlcmd);
                if (PQresultStatus(result) != PGRES_TUPLES_OK) {
                        pgerror = PQresultErrorMessage(result);
index 7559363..9441800 100644 (file)
@@ -1046,8 +1046,8 @@ static int unload_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "ALSA Console Channel Driver",
-               .support_level = AST_MODULE_SUPPORT_EXTENDED,
-               .load = load_module,
-               .unload = unload_module,
-               .load_pri = AST_MODPRI_CHANNEL_DRIVER,
-       );
+       .support_level = AST_MODULE_SUPPORT_EXTENDED,
+       .load = load_module,
+       .unload = unload_module,
+       .load_pri = AST_MODPRI_CHANNEL_DRIVER,
+);
index 0a3468a..8e177ae 100644 (file)
@@ -216,6 +216,6 @@ static int load_module(void)
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Bridge Media Channel Driver",
        .support_level = AST_MODULE_SUPPORT_CORE,
-    .load = load_module,
-    .unload = unload_module,
+       .load = load_module,
+       .unload = unload_module,
 );
index 4fc538b..a8dbc97 100644 (file)
@@ -1578,9 +1578,9 @@ static int reload(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Console Channel Driver",
-               .support_level = AST_MODULE_SUPPORT_EXTENDED,
-               .load = load_module,
-               .unload = unload_module,
-               .reload = reload,
-               .load_pri = AST_MODPRI_CHANNEL_DRIVER,
+       .support_level = AST_MODULE_SUPPORT_EXTENDED,
+       .load = load_module,
+       .unload = unload_module,
+       .reload = reload,
+       .load_pri = AST_MODPRI_CHANNEL_DRIVER,
 );
index b7df2b8..fe61309 100644 (file)
@@ -600,14 +600,6 @@ static int restart_monitor(void);
 
 static int dahdi_sendtext(struct ast_channel *c, const char *text);
 
-static void mwi_event_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
-{
-       /* This module does not handle MWI in an event-based manner.  However, it
-        * subscribes to MWI for each mailbox that is configured so that the core
-        * knows that we care about it.  Then, chan_dahdi will get the MWI from the
-        * event cache instead of checking the mailbox directly. */
-}
-
 /*! \brief Avoid the silly dahdi_getevent which ignores a bunch of events */
 static inline int dahdi_get_event(int fd)
 {
@@ -12346,6 +12338,7 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
 #if defined(HAVE_PRI_MCID)
                                                pris[span].pri.mcid_send = conf->pri.pri.mcid_send;
 #endif /* defined(HAVE_PRI_MCID) */
+                                               pris[span].pri.force_restart_unavailable_chans = conf->pri.pri.force_restart_unavailable_chans;
 #if defined(HAVE_PRI_DATETIME_SEND)
                                                pris[span].pri.datetime_send = conf->pri.pri.datetime_send;
 #endif /* defined(HAVE_PRI_DATETIME_SEND) */
@@ -12592,7 +12585,11 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
 
                        mailbox_specific_topic = ast_mwi_topic(tmp->mailbox);
                        if (mailbox_specific_topic) {
-                               tmp->mwi_event_sub = stasis_subscribe_pool(mailbox_specific_topic, mwi_event_cb, NULL);
+                               /* This module does not handle MWI in an event-based manner.  However, it
+                                * subscribes to MWI for each mailbox that is configured so that the core
+                                * knows that we care about it.  Then, chan_dahdi will get the MWI from the
+                                * event cache instead of checking the mailbox directly. */
+                               tmp->mwi_event_sub = stasis_subscribe_pool(mailbox_specific_topic, stasis_subscription_cb_noop, NULL);
                        }
                }
 #ifdef HAVE_DAHDI_LINEREVERSE_VMWI
@@ -18258,6 +18255,8 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
                                else
                                        ast_log(LOG_WARNING, "'%s' is not a valid reset interval, should be >= 60 seconds or 'never' at line %d.\n",
                                                v->value, v->lineno);
+                       } else if (!strcasecmp(v->name, "force_restart_unavailable_chans")) {
+                               confp->pri.pri.force_restart_unavailable_chans = ast_true(v->value);
                        } else if (!strcasecmp(v->name, "minunused")) {
                                confp->pri.pri.minunused = atoi(v->value);
                        } else if (!strcasecmp(v->name, "minidle")) {
@@ -19516,7 +19515,7 @@ static int load_module(void)
        ast_format_cap_append(dahdi_tech.capabilities, ast_format_ulaw, 0);
        ast_format_cap_append(dahdi_tech.capabilities, ast_format_alaw, 0);
 
-       if (dahdi_native_load(ast_module_info->self, &dahdi_tech)) {
+       if (dahdi_native_load(&dahdi_tech)) {
                ao2_ref(dahdi_tech.capabilities, -1);
                return AST_MODULE_LOAD_FAILURE;
        }
@@ -19750,4 +19749,4 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, tdesc,
        .reload = reload,
        .load_pri = AST_MODPRI_CHANNEL_DRIVER,
        .nonoptreq = "res_smdi",
-       );
+);
index efdcb13..da6bec7 100644 (file)
@@ -433,37 +433,37 @@ struct iax2_context {
 };
 
 
-#define        IAX_HASCALLERID         (uint64_t)(1 << 0)    /*!< CallerID has been specified */
-#define IAX_DELME               (uint64_t)(1 << 1)    /*!< Needs to be deleted */
-#define IAX_TEMPONLY            (uint64_t)(1 << 2)    /*!< Temporary (realtime) */
-#define IAX_TRUNK               (uint64_t)(1 << 3)    /*!< Treat as a trunk */
-#define IAX_NOTRANSFER          (uint64_t)(1 << 4)    /*!< Don't native bridge */
-#define IAX_USEJITTERBUF        (uint64_t)(1 << 5)    /*!< Use jitter buffer */
-#define IAX_DYNAMIC             (uint64_t)(1 << 6)    /*!< dynamic peer */
-#define IAX_SENDANI             (uint64_t)(1 << 7)    /*!< Send ANI along with CallerID */
-#define IAX_RTSAVE_SYSNAME      (uint64_t)(1 << 8)    /*!< Save Systname on Realtime Updates */
-#define IAX_ALREADYGONE         (uint64_t)(1 << 9)    /*!< Already disconnected */
-#define IAX_PROVISION           (uint64_t)(1 << 10)   /*!< This is a provisioning request */
-#define IAX_QUELCH              (uint64_t)(1 << 11)   /*!< Whether or not we quelch audio */
-#define IAX_ENCRYPTED           (uint64_t)(1 << 12)   /*!< Whether we should assume encrypted tx/rx */
-#define IAX_KEYPOPULATED        (uint64_t)(1 << 13)   /*!< Whether we have a key populated */
-#define IAX_CODEC_USER_FIRST    (uint64_t)(1 << 14)   /*!< are we willing to let the other guy choose the codec? */
-#define IAX_CODEC_NOPREFS       (uint64_t)(1 << 15)   /*!< Force old behaviour by turning off prefs */
-#define IAX_CODEC_NOCAP         (uint64_t)(1 << 16)   /*!< only consider requested format and ignore capabilities*/
-#define IAX_RTCACHEFRIENDS      (uint64_t)(1 << 17)   /*!< let realtime stay till your reload */
-#define IAX_RTUPDATE            (uint64_t)(1 << 18)   /*!< Send a realtime update */
-#define IAX_RTAUTOCLEAR         (uint64_t)(1 << 19)   /*!< erase me on expire */
-#define IAX_RTIGNOREREGEXPIRE   (uint64_t)(1 << 21)   /*!< When using realtime, ignore registration expiration */
-#define IAX_TRUNKTIMESTAMPS     (uint64_t)(1 << 22)   /*!< Send trunk timestamps */
-#define IAX_TRANSFERMEDIA       (uint64_t)(1 << 23)   /*!< When doing IAX2 transfers, transfer media only */
-#define IAX_MAXAUTHREQ          (uint64_t)(1 << 24)   /*!< Maximum outstanding AUTHREQ restriction is in place */
-#define IAX_DELAYPBXSTART       (uint64_t)(1 << 25)   /*!< Don't start a PBX on the channel until the peer sends us a response, so that we've achieved a three-way handshake with them before sending voice or anything else */
-#define IAX_ALLOWFWDOWNLOAD     (uint64_t)(1 << 26)   /*!< Allow the FWDOWNL command? */
-#define IAX_IMMEDIATE           (uint64_t)(1 << 27)   /*!< Allow immediate off-hook to extension s */
-#define IAX_SENDCONNECTEDLINE   (uint64_t)(1 << 28)   /*!< Allow sending of connected line updates */
-#define IAX_RECVCONNECTEDLINE   (uint64_t)(1 << 29)   /*!< Allow receiving of connected line updates */
-#define IAX_FORCE_ENCRYPT       (uint64_t)(1 << 30)   /*!< Forces call encryption, if encryption not possible hangup */
-#define IAX_SHRINKCALLERID      (uint64_t)(1 << 31)   /*!< Turn on and off caller id shrinking */
+#define IAX_HASCALLERID         (uint64_t)(1LLU << 0)    /*!< CallerID has been specified */
+#define IAX_DELME               (uint64_t)(1LLU << 1)    /*!< Needs to be deleted */
+#define IAX_TEMPONLY            (uint64_t)(1LLU << 2)    /*!< Temporary (realtime) */
+#define IAX_TRUNK               (uint64_t)(1LLU << 3)    /*!< Treat as a trunk */
+#define IAX_NOTRANSFER          (uint64_t)(1LLU << 4)    /*!< Don't native bridge */
+#define IAX_USEJITTERBUF        (uint64_t)(1LLU << 5)    /*!< Use jitter buffer */
+#define IAX_DYNAMIC             (uint64_t)(1LLU << 6)    /*!< dynamic peer */
+#define IAX_SENDANI             (uint64_t)(1LLU << 7)    /*!< Send ANI along with CallerID */
+#define IAX_RTSAVE_SYSNAME      (uint64_t)(1LLU << 8)    /*!< Save Systname on Realtime Updates */
+#define IAX_ALREADYGONE         (uint64_t)(1LLU << 9)    /*!< Already disconnected */
+#define IAX_PROVISION           (uint64_t)(1LLU << 10)   /*!< This is a provisioning request */
+#define IAX_QUELCH              (uint64_t)(1LLU << 11)   /*!< Whether or not we quelch audio */
+#define IAX_ENCRYPTED           (uint64_t)(1LLU << 12)   /*!< Whether we should assume encrypted tx/rx */
+#define IAX_KEYPOPULATED        (uint64_t)(1LLU << 13)   /*!< Whether we have a key populated */
+#define IAX_CODEC_USER_FIRST    (uint64_t)(1LLU << 14)   /*!< are we willing to let the other guy choose the codec? */
+#define IAX_CODEC_NOPREFS       (uint64_t)(1LLU << 15)   /*!< Force old behaviour by turning off prefs */
+#define IAX_CODEC_NOCAP         (uint64_t)(1LLU << 16)   /*!< only consider requested format and ignore capabilities*/
+#define IAX_RTCACHEFRIENDS      (uint64_t)(1LLU << 17)   /*!< let realtime stay till your reload */
+#define IAX_RTUPDATE            (uint64_t)(1LLU << 18)   /*!< Send a realtime update */
+#define IAX_RTAUTOCLEAR         (uint64_t)(1LLU << 19)   /*!< erase me on expire */
+#define IAX_RTIGNOREREGEXPIRE   (uint64_t)(1LLU << 21)   /*!< When using realtime, ignore registration expiration */
+#define IAX_TRUNKTIMESTAMPS     (uint64_t)(1LLU << 22)   /*!< Send trunk timestamps */
+#define IAX_TRANSFERMEDIA       (uint64_t)(1LLU << 23)   /*!< When doing IAX2 transfers, transfer media only */
+#define IAX_MAXAUTHREQ          (uint64_t)(1LLU << 24)   /*!< Maximum outstanding AUTHREQ restriction is in place */
+#define IAX_DELAYPBXSTART       (uint64_t)(1LLU << 25)   /*!< Don't start a PBX on the channel until the peer sends us a response, so that we've achieved a three-way handshake with them before sending voice or anything else */
+#define IAX_ALLOWFWDOWNLOAD     (uint64_t)(1LLU << 26)   /*!< Allow the FWDOWNL command? */
+#define IAX_IMMEDIATE           (uint64_t)(1LLU << 27)   /*!< Allow immediate off-hook to extension s */
+#define IAX_SENDCONNECTEDLINE   (uint64_t)(1LLU << 28)   /*!< Allow sending of connected line updates */
+#define IAX_RECVCONNECTEDLINE   (uint64_t)(1LLU << 29)   /*!< Allow receiving of connected line updates */
+#define IAX_FORCE_ENCRYPT       (uint64_t)(1LLU << 30)   /*!< Forces call encryption, if encryption not possible hangup */
+#define IAX_SHRINKCALLERID      (uint64_t)(1LLU << 31)   /*!< Turn on and off caller id shrinking */
 static int global_rtautoclear = 120;
 
 static int reload_config(int forced_reload);
@@ -1430,13 +1430,6 @@ static int iax2_is_control_frame_allowed(int subtype)
        return is_allowed;
 }
 
-static void mwi_event_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
-{
-       /* The MWI subscriptions exist just so the core knows we care about those
-        * mailboxes.  However, we just grab the events out of the cache when it
-        * is time to send MWI, since it is only sent with a REGACK. */
-}
-
 static void network_change_stasis_subscribe(void)
 {
        if (!network_change_sub) {
@@ -13051,7 +13044,10 @@ static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, st
 
                mailbox_specific_topic = ast_mwi_topic(peer->mailbox);
                if (mailbox_specific_topic) {
-                       peer->mwi_event_sub = stasis_subscribe_pool(mailbox_specific_topic, mwi_event_cb, NULL);
+                       /* The MWI subscriptions exist just so the core knows we care about those
+                        * mailboxes.  However, we just grab the events out of the cache when it
+                        * is time to send MWI, since it is only sent with a REGACK. */
+                       peer->mwi_event_sub = stasis_subscribe_pool(mailbox_specific_topic, stasis_subscription_cb_noop, NULL);
                }
        }
 
@@ -13787,6 +13783,7 @@ static int set_config(const char *config_file, int reload, int forced)
                } else if (!strcasecmp(v->name, "calltokenoptional")) {
                        if (add_calltoken_ignore(v->value)) {
                                ast_log(LOG_WARNING, "Invalid calltokenoptional address range - '%s' line %d\n", v->value, v->lineno);
+                               return -1;
                        }
                } else if (!strcasecmp(v->name, "calltokenexpiration")) {
                        int temp = -1;
@@ -14670,7 +14667,6 @@ static void cleanup_thread_list(void *head)
 
 static int __unload_module(void)
 {
-       struct ast_context *con;
        int x;
 
        network_change_stasis_unsubscribe();
@@ -14747,9 +14743,7 @@ static int __unload_module(void)
        sched = NULL;
        ao2_ref(peercnts, -1);
 
-       con = ast_context_find(regcontext);
-       if (con)
-               ast_context_destroy(con, "IAX2");
+       ast_context_destroy_by_name(regcontext, "IAX2");
        ast_unload_realtime("iaxpeers");
 
        ao2_ref(iax2_tech.capabilities, -1);
@@ -15190,10 +15184,10 @@ static int load_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Inter Asterisk eXchange (Ver 2)",
-               .support_level = AST_MODULE_SUPPORT_CORE,
-               .load = load_module,
-               .unload = unload_module,
-               .reload = reload,
-               .load_pri = AST_MODPRI_CHANNEL_DRIVER,
-               .nonoptreq = "res_crypto",
-               );
+       .support_level = AST_MODULE_SUPPORT_CORE,
+       .load = load_module,
+       .unload = unload_module,
+       .reload = reload,
+       .load_pri = AST_MODPRI_CHANNEL_DRIVER,
+       .nonoptreq = "res_crypto",
+);
index 602d38d..16d3c65 100644 (file)
@@ -489,14 +489,6 @@ static struct ast_channel_tech mgcp_tech = {
        .func_channel_read = acf_channel_read,
 };
 
-static void mwi_event_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
-{
-       /* This module does not handle MWI in an event-based manner.  However, it
-        * subscribes to MWI for each mailbox that is configured so that the core
-        * knows that we care about it.  Then, chan_mgcp will get the MWI from the
-        * event cache instead of checking the mailbox directly. */
-}
-
 static int has_voicemail(struct mgcp_endpoint *p)
 {
        int new_msgs;
@@ -4104,7 +4096,19 @@ static struct mgcp_gateway *build_gateway(char *cat, struct ast_variable *v)
                        ast_sockaddr_to_sin(&tmp, &gw->defaddr);
                } else if (!strcasecmp(v->name, "permit") ||
                        !strcasecmp(v->name, "deny")) {
-                       gw->ha = ast_append_ha(v->name, v->value, gw->ha, NULL);
+                       int acl_error = 0;
+                       gw->ha = ast_append_ha(v->name, v->value, gw->ha, &acl_error);
+                       if (acl_error) {
+                               ast_log(LOG_ERROR, "Invalid ACL '%s' specified for MGCP gateway '%s' on line %d. Not creating.\n",
+                                               v->value, cat, v->lineno);
+                               if (!gw_reload) {
+                                       ast_mutex_destroy(&gw->msgs_lock);
+                                       ast_free(gw);
+                               } else {
+                                       gw->delme = 1;
+                               }
+                               return NULL;
+                       }
                } else if (!strcasecmp(v->name, "port")) {
                        gw->addr.sin_port = htons(atoi(v->value));
                } else if (!strcasecmp(v->name, "context")) {
@@ -4237,7 +4241,11 @@ static struct mgcp_gateway *build_gateway(char *cat, struct ast_variable *v)
 
                                        mailbox_specific_topic = ast_mwi_topic(e->mailbox);
                                        if (mailbox_specific_topic) {
-                                               e->mwi_event_sub = stasis_subscribe_pool(mailbox_specific_topic, mwi_event_cb, NULL);
+                                               /* This module does not handle MWI in an event-based manner.  However, it
+                                                * subscribes to MWI for each mailbox that is configured so that the core
+                                                * knows that we care about it.  Then, chan_mgcp will get the MWI from the
+                                                * event cache instead of checking the mailbox directly. */
+                                               e->mwi_event_sub = stasis_subscribe_pool(mailbox_specific_topic, stasis_subscription_cb_noop, NULL);
                                        }
                                }
                                snprintf(e->rqnt_ident, sizeof(e->rqnt_ident), "%08lx", (unsigned long)ast_random());
@@ -5013,10 +5021,10 @@ static int unload_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Media Gateway Control Protocol (MGCP)",
-               .support_level = AST_MODULE_SUPPORT_EXTENDED,
-               .load = load_module,
-               .unload = unload_module,
-               .reload = reload,
-               .load_pri = AST_MODPRI_CHANNEL_DRIVER,
-               .nonoptreq = "res_pktccops",
-              );
+       .support_level = AST_MODULE_SUPPORT_EXTENDED,
+       .load = load_module,
+       .unload = unload_module,
+       .reload = reload,
+       .load_pri = AST_MODPRI_CHANNEL_DRIVER,
+       .nonoptreq = "res_pktccops",
+);
index 05c6944..0851bf0 100644 (file)
@@ -2819,9 +2819,9 @@ static int unload_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Motif Jingle Channel Driver",
-               .support_level = AST_MODULE_SUPPORT_CORE,
-               .load = load_module,
-               .unload = unload_module,
-               .reload = reload,
-               .load_pri = AST_MODPRI_CHANNEL_DRIVER,
-              );
+       .support_level = AST_MODULE_SUPPORT_CORE,
+       .load = load_module,
+       .unload = unload_module,
+       .reload = reload,
+       .load_pri = AST_MODPRI_CHANNEL_DRIVER,
+);
index 07dd1b7..14ba4a2 100644 (file)
@@ -1864,6 +1864,7 @@ static int request(void *obj)
        if (ast_strlen_zero(endpoint_name)) {
                ast_log(LOG_ERROR, "Unable to create PJSIP channel with empty endpoint name\n");
                req_data->cause = AST_CAUSE_CHANNEL_UNACCEPTABLE;
+               return -1;
        } else if (!(endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", endpoint_name))) {
                ast_log(LOG_ERROR, "Unable to create PJSIP channel - endpoint '%s' was not found\n", endpoint_name);
                req_data->cause = AST_CAUSE_NO_ROUTE_DESTINATION;
@@ -2421,8 +2422,8 @@ static int unload_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Channel Driver",
-               .support_level = AST_MODULE_SUPPORT_CORE,
-               .load = load_module,
-               .unload = unload_module,
-               .load_pri = AST_MODPRI_CHANNEL_DRIVER,
-              );
+       .support_level = AST_MODULE_SUPPORT_CORE,
+       .load = load_module,
+       .unload = unload_module,
+       .load_pri = AST_MODPRI_CHANNEL_DRIVER,
+);
index 3ee92da..1d58a84 100644 (file)
@@ -254,7 +254,6 @@ ASTERISK_REGISTER_FILE()
 #include "asterisk/astobj2.h"
 #include "asterisk/dnsmgr.h"
 #include "asterisk/devicestate.h"
-#include "asterisk/monitor.h"
 #include "asterisk/netsock2.h"
 #include "asterisk/localtime.h"
 #include "asterisk/abstract_jb.h"
@@ -5009,7 +5008,7 @@ static void register_peer_exten(struct sip_peer *peer, int onoff)
 static void destroy_mailbox(struct sip_mailbox *mailbox)
 {
        if (mailbox->event_sub) {
-               mailbox->event_sub = stasis_unsubscribe(mailbox->event_sub);
+               mailbox->event_sub = stasis_unsubscribe_and_join(mailbox->event_sub);
        }
        ast_free(mailbox);
 }
@@ -8599,9 +8598,9 @@ struct sip_pvt *__sip_alloc(ast_string_field callid, struct ast_sockaddr *addr,
 {
        struct sip_pvt *p;
 
-       p = __ao2_alloc_debug(sizeof(*p), sip_destroy_fn,
+       p = __ao2_alloc(sizeof(*p), sip_destroy_fn,
                AO2_ALLOC_OPT_LOCK_MUTEX, "allocate a dialog(pvt) struct",
-               file, line, func, 1);
+               file, line, func);
        if (!p) {
                return NULL;
        }
@@ -9178,7 +9177,7 @@ static struct sip_pvt *__find_call(struct sip_request *req, struct ast_sockaddr
                struct sip_pvt tmp_dialog = {
                        .callid = callid,
                };
-               sip_pvt_ptr = __ao2_find_debug(dialogs, &tmp_dialog, OBJ_POINTER,
+               sip_pvt_ptr = __ao2_find(dialogs, &tmp_dialog, OBJ_POINTER,
                        "find_call in dialogs", file, line, func);
                if (sip_pvt_ptr) {  /* well, if we don't find it-- what IS in there? */
                        /* Found the call */
@@ -9193,7 +9192,7 @@ static struct sip_pvt *__find_call(struct sip_request *req, struct ast_sockaddr
                struct sip_pvt *fork_pvt = NULL;
                struct match_req_args args = { 0, };
                int found;
-               struct ao2_iterator *iterator = __ao2_callback_debug(dialogs,
+               struct ao2_iterator *iterator = __ao2_callback(dialogs,
                        OBJ_POINTER | OBJ_MULTIPLE,
                        dialog_find_multiple,
                        &tmp_dialog,
@@ -9243,7 +9242,7 @@ static struct sip_pvt *__find_call(struct sip_request *req, struct ast_sockaddr
                                /* This is likely a forked Request that somehow resulted in us receiving multiple parts of the fork.
                                * RFC 3261 section 8.2.2.2, Indicate that we want to merge requests by sending a 482 response. */
                                transmit_response_using_temp(callid, addr, 1, intended_method, req, "482 (Loop Detected)");
-                               __ao2_ref_debug(sip_pvt_ptr, -1, "pvt did not match incoming SIP msg, unref from search.",
+                               __ao2_ref(sip_pvt_ptr, -1, "pvt did not match incoming SIP msg, unref from search.",
                                        file, line, func);
                                ao2_iterator_destroy(iterator);
                                dialog_unref(fork_pvt, "unref fork_pvt");
@@ -9255,7 +9254,7 @@ static struct sip_pvt *__find_call(struct sip_request *req, struct ast_sockaddr
                                /* fall through */
                        case SIP_REQ_NOT_MATCH:
                        default:
-                               __ao2_ref_debug(sip_pvt_ptr, -1, "pvt did not match incoming SIP msg, unref from search",
+                               __ao2_ref(sip_pvt_ptr, -1, "pvt did not match incoming SIP msg, unref from search",
                                        file, line, func);
                                break;
                        }
@@ -19741,8 +19740,7 @@ static void cleanup_stale_contexts(char *new, char *old)
                        }
 
                }
-               if (stalecontext)
-                       ast_context_destroy(ast_context_find(stalecontext), "SIP");
+               ast_context_destroy_by_name(stalecontext, "SIP");
        }
 }
 
@@ -30609,7 +30607,9 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str
                                        ast_append_acl(v->name, v->value, &peer->acl, &ha_error, &acl_change_subscription_needed);
                                }
                                if (ha_error) {
-                                       ast_log(LOG_ERROR, "Bad ACL entry in configuration line %d : %s\n", v->lineno, v->value);
+                                       ast_log(LOG_ERROR, "Bad ACL entry in configuration line %d : %s. Deleting peer\n", v->lineno, v->value);
+                                       sip_unref_peer(peer, "Removing peer due to bad ACL configuration");
+                                       return NULL;
                                }
                        } else if (!strcasecmp(v->name, "contactpermit") || !strcasecmp(v->name, "contactdeny") || !strcasecmp(v->name, "contactacl")) {
                                int ha_error = 0;
@@ -30617,13 +30617,17 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str
                                        ast_append_acl(v->name + 7, v->value, &peer->contactacl, &ha_error, &acl_change_subscription_needed);
                                }
                                if (ha_error) {
-                                       ast_log(LOG_ERROR, "Bad ACL entry in configuration line %d : %s\n", v->lineno, v->value);
+                                       ast_log(LOG_ERROR, "Bad ACL entry in configuration line %d : %s. Deleting peer\n", v->lineno, v->value);
+                                       sip_unref_peer(peer, "Removing peer due to bad contact ACL configuration");
+                                       return NULL;
                                }
                        } else if (!strcasecmp(v->name, "directmediapermit") || !strcasecmp(v->name, "directmediadeny") || !strcasecmp(v->name, "directmediaacl")) {
                                int ha_error = 0;
                                ast_append_acl(v->name + 11, v->value, &peer->directmediaacl, &ha_error, &acl_change_subscription_needed);
                                if (ha_error) {
-                                       ast_log(LOG_ERROR, "Bad directmedia ACL entry in configuration line %d : %s\n", v->lineno, v->value);
+                                       ast_log(LOG_ERROR, "Bad directmedia ACL entry in configuration line %d : %s. Deleting peer\n", v->lineno, v->value);
+                                       sip_unref_peer(peer, "Removing peer due to bad direct media ACL configuration");
+                                       return NULL;
                                }
                        } else if (!strcasecmp(v->name, "port")) {
                                peer->portinuri = 1;
@@ -31567,7 +31571,8 @@ static int reload_config(enum channelreloadreason reason)
                        int ha_error = 0;
                        ast_append_acl(v->name + 7, v->value, &sip_cfg.contact_acl, &ha_error, &acl_change_subscription_needed);
                        if (ha_error) {
-                               ast_log(LOG_ERROR, "Bad ACL entry in configuration line %d : %s\n", v->lineno, v->value);
+                               ast_log(LOG_ERROR, "Bad ACL entry in configuration line %d : %s. Failing to load chan_sip.so\n", v->lineno, v->value);
+                               return -1;
                        }
                } else if (!strcasecmp(v->name, "rtautoclear")) {
                        int i = atoi(v->value);
@@ -34544,7 +34549,6 @@ static int unload_module(void)
 {
        struct sip_pvt *p;
        struct sip_threadinfo *th;
-       struct ast_context *con;
        struct ao2_iterator i;
        int wait_count;
 
@@ -34724,10 +34728,7 @@ static int unload_module(void)
        close(sipsock);
        io_context_destroy(io);
        ast_sched_context_destroy(sched);
-       con = ast_context_find(used_context);
-       if (con) {
-               ast_context_destroy(con, "SIP");
-       }
+       ast_context_destroy_by_name(used_context, "SIP");
        ast_unload_realtime("sipregs");
        ast_unload_realtime("sippeers");
        ast_cc_monitor_unregister(&sip_cc_monitor_callbacks);
@@ -34752,10 +34753,10 @@ static int unload_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Session Initiation Protocol (SIP)",
-               .support_level = AST_MODULE_SUPPORT_CORE,
-               .load = load_module,
-               .unload = unload_module,
-               .reload = reload,
-               .load_pri = AST_MODPRI_CHANNEL_DRIVER,
-               .nonoptreq = "res_crypto,res_http_websocket",
-              );
+       .support_level = AST_MODULE_SUPPORT_CORE,
+       .load = load_module,
+       .unload = unload_module,
+       .reload = reload,
+       .load_pri = AST_MODPRI_CHANNEL_DRIVER,
+       .nonoptreq = "res_crypto,res_http_websocket",
+);
index 06878fb..08629fd 100644 (file)
@@ -2198,8 +2198,7 @@ static void cleanup_stale_contexts(char *new, char *old)
                        }
 
                }
-               if (stalecontext)
-                       ast_context_destroy(ast_context_find(stalecontext), "Skinny");
+               ast_context_destroy_by_name(stalecontext, "Skinny");
        }
 }
 
@@ -7488,6 +7487,7 @@ static void *skinny_session(void *data)
        struct skinnysession *s = data;
 
        int dlen = 0;
+       int eventmessage = 0;
        struct pollfd fds[1];
 
        if (!s) {
@@ -7544,7 +7544,8 @@ static void *skinny_session(void *data)
                                break;
                        }
 
-                       if (letohl(req->e) < 0) {
+                       eventmessage = letohl(req->e);
+                       if (eventmessage < 0) {
                                ast_log(LOG_ERROR, "Event Message is NULL from socket %d, This is bad\n", s->fd);
                                break;
                        }
@@ -8042,7 +8043,14 @@ static void config_parse_variables(int type, void *item, struct ast_variable *vp
                        }
                } else if (!strcasecmp(v->name, "permit") || !strcasecmp(v->name, "deny")) {
                        if (type & (TYPE_DEVICE)) {
-                               CDEV->ha = ast_append_ha(v->name, v->value, CDEV->ha, NULL);
+                               int acl_error = 0;
+
+                               CDEV->ha = ast_append_ha(v->name, v->value, CDEV->ha, &acl_error);
+                               if (acl_error) {
+                                       ast_log(LOG_ERROR, "Invalid ACL '%s' on line '%d'. Deleting device\n",
+                                                       v->value, v->lineno);
+                                       CDEV->prune = 1;
+                               }
                                continue;
                        }
                } else if (!strcasecmp(v->name, "allow")) {
@@ -8708,7 +8716,6 @@ static int unload_module(void)
        struct skinny_device *d;
        struct skinny_line *l;
        struct skinny_subchannel *sub;
-       struct ast_context *con;
        pthread_t tempthread;
 
        ast_rtp_glue_unregister(&skinny_rtp_glue);
@@ -8747,7 +8754,7 @@ static int unload_module(void)
                                skinny_unlocksub(sub);
                        }
                        if (l->mwi_event_sub) {
-                               l->mwi_event_sub = stasis_unsubscribe(l->mwi_event_sub);
+                               l->mwi_event_sub = stasis_unsubscribe_and_join(l->mwi_event_sub);
                        }
                        ast_mutex_unlock(&l->lock);
                        unregister_exten(l);
@@ -8769,9 +8776,7 @@ static int unload_module(void)
                ast_sched_context_destroy(sched);
        }
 
-       con = ast_context_find(used_context);
-       if (con)
-               ast_context_destroy(con, "Skinny");
+       ast_context_destroy_by_name(used_context, "Skinny");
 
        ao2_ref(default_cap, -1);
        return 0;
@@ -8784,9 +8789,9 @@ static int reload(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Skinny Client Control Protocol (Skinny)",
-               .support_level = AST_MODULE_SUPPORT_EXTENDED,
-               .load = load_module,
-               .unload = unload_module,
-               .reload = reload,
-               .load_pri = AST_MODPRI_CHANNEL_DRIVER,
+       .support_level = AST_MODULE_SUPPORT_EXTENDED,
+       .load = load_module,
+       .unload = unload_module,
+       .reload = reload,
+       .load_pri = AST_MODPRI_CHANNEL_DRIVER,
 );
index 4379aa5..a3c0ffd 100644 (file)
@@ -6395,6 +6395,85 @@ static struct unistim_line *find_line_by_number(struct unistim_device *d, const
        return ret;
 }
 
+static void delete_device(struct unistim_device *d)
+{
+       struct unistim_line *l;
+       struct unistim_subchannel *sub;
+       struct unistimsession *s;
+
+       if (unistimdebug) {
+               ast_verb(0, "Removing device '%s'\n", d->name);
+       }
+       AST_LIST_LOCK(&d->subs);
+       AST_LIST_TRAVERSE_SAFE_BEGIN(&d->subs, sub, list){
+               if (sub->subtype == SUB_REAL) {
+                       if (sub->owner) {
+                               ast_log(LOG_WARNING,
+                                               "Device '%s' was not deleted : a call is in progress. Try again later.\n",
+                                               d->name);
+                               AST_LIST_UNLOCK(&d->subs);
+                               return;
+                       }
+               }
+               if (sub->subtype == SUB_THREEWAY) {
+                       ast_log(LOG_WARNING,
+                                       "Device '%s' with threeway call subchannels allocated, aborting.\n",
+                                       d->name);
+                       AST_LIST_UNLOCK(&d->subs);
+                       return;
+               }
+               AST_LIST_REMOVE_CURRENT(list);
+               ast_mutex_destroy(&sub->lock);
+               ast_free(sub);
+       }
+       AST_LIST_TRAVERSE_SAFE_END
+       AST_LIST_UNLOCK(&d->subs);
+
+
+       AST_LIST_LOCK(&d->lines);
+       AST_LIST_TRAVERSE_SAFE_BEGIN(&d->lines, l, list){
+               AST_LIST_REMOVE_CURRENT(list);
+               ast_mutex_destroy(&l->lock);
+               unistim_line_destroy(l);
+       }
+       AST_LIST_TRAVERSE_SAFE_END
+       AST_LIST_UNLOCK(&d->lines);
+
+       if (d->session) {
+               if (sessions == d->session) {
+                       sessions = d->session->next;
+               } else {
+                       s = sessions;
+                       while (s) {
+                               if (s->next == d->session) {
+                                       s->next = d->session->next;
+                                       break;
+                               }
+                               s = s->next;
+                       }
+               }
+               ast_mutex_destroy(&d->session->lock);
+               ast_free(d->session);
+       }
+       if (devices == d) {
+               devices = d->next;
+       } else {
+               struct unistim_device *d2 = devices;
+               while (d2) {
+                       if (d2->next == d) {
+                               d2->next = d->next;
+                               break;
+                       }
+                       d2 = d2->next;
+               }
+       }
+       if (d->tz) {
+               d->tz = ast_tone_zone_unref(d->tz);
+       }
+       ast_mutex_destroy(&d->lock);
+       ast_free(d);
+}
+
 static struct unistim_device *build_device(const char *cat, const struct ast_variable *v)
 {
        struct unistim_device *d;
@@ -6486,7 +6565,14 @@ static struct unistim_device *build_device(const char *cat, const struct ast_var
                } else if (!strcasecmp(v->name, "tn")) {
                        ast_copy_string(d->extension_number, v->value, sizeof(d->extension_number));
                } else if (!strcasecmp(v->name, "permit") || !strcasecmp(v->name, "deny")) {
-                       d->ha = ast_append_ha(v->name, v->value, d->ha, NULL);
+                       int acl_error = 0;
+                       d->ha = ast_append_ha(v->name, v->value, d->ha, &acl_error);
+                       if (acl_error) {
+                               ast_log(LOG_ERROR, "Invalid ACL '%s' specified for device '%s' on line %d. Deleting device\n",
+                                               v->value, cat, v->lineno);
+                               delete_device(d);
+                               return NULL;
+                       }
                } else if (!strcasecmp(v->name, "context")) {
                        ast_copy_string(d->context, v->value, sizeof(d->context));
                } else if (!strcasecmp(v->name, "maintext0")) {
@@ -6853,85 +6939,7 @@ static int reload_config(void)
        d = devices;
        while (d) {
                if (d->to_delete) {
-                       struct unistim_line *l;
-                       struct unistim_subchannel *sub;
-
-                       if (unistimdebug) {
-                               ast_verb(0, "Removing device '%s'\n", d->name);
-                       }
-                       AST_LIST_LOCK(&d->subs);
-                       AST_LIST_TRAVERSE_SAFE_BEGIN(&d->subs, sub, list){
-                               if (sub->subtype == SUB_REAL) {
-                                       if (!sub) {
-                                               ast_log(LOG_ERROR, "Device '%s' without a subchannel !, aborting\n",
-                                                               d->name);
-                                               ast_config_destroy(cfg);
-                                               return 0;
-                                       }
-                                       if (sub->owner) {
-                                               ast_log(LOG_WARNING,
-                                                               "Device '%s' was not deleted : a call is in progress. Try again later.\n",
-                                                               d->name);
-                                               d = d->next;
-                                               continue;
-                                       }
-                               }
-                               if (sub->subtype == SUB_THREEWAY) {
-                                       ast_log(LOG_WARNING,
-                                                       "Device '%s' with threeway call subchannels allocated, aborting.\n",
-                                                       d->name);
-                                       break;
-                               }
-                               AST_LIST_REMOVE_CURRENT(list);
-                               ast_mutex_destroy(&sub->lock);
-                               ast_free(sub);
-                       }
-                       AST_LIST_TRAVERSE_SAFE_END
-                       AST_LIST_UNLOCK(&d->subs);
-
-
-                       AST_LIST_LOCK(&d->lines);
-                       AST_LIST_TRAVERSE_SAFE_BEGIN(&d->lines, l, list){
-                               AST_LIST_REMOVE_CURRENT(list);
-                               ast_mutex_destroy(&l->lock);
-                               unistim_line_destroy(l);
-                       }
-                       AST_LIST_TRAVERSE_SAFE_END
-                       AST_LIST_UNLOCK(&d->lines);
-
-                       if (d->session) {
-                               if (sessions == d->session) {
-                                       sessions = d->session->next;
-                               } else {
-                                       s = sessions;
-                                       while (s) {
-                                               if (s->next == d->session) {
-                                                       s->next = d->session->next;
-                                                       break;
-                                               }
-                                               s = s->next;
-                                       }
-                               }
-                               ast_mutex_destroy(&d->session->lock);
-                               ast_free(d->session);
-                       }
-                       if (devices == d) {
-                               devices = d->next;
-                       } else {
-                               struct unistim_device *d2 = devices;
-                               while (d2) {
-                                       if (d2->next == d) {
-                                               d2->next = d->next;
-                                               break;
-                                       }
-                                       d2 = d2->next;
-                               }
-                       }
-                       if (d->tz) {
-                               d->tz = ast_tone_zone_unref(d->tz);
-                       }
-                       ast_mutex_destroy(&d->lock);
-                       ast_free(d);
+                       delete_device(d);
                        d = devices;
                        continue;
                }
@@ -7170,7 +7178,7 @@ int reload(void)
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "UNISTIM Protocol (USTM)",
        .support_level = AST_MODULE_SUPPORT_EXTENDED,
-    .load = load_module,
-    .unload = unload_module,
-    .reload = reload,
+       .load = load_module,
+       .unload = unload_module,
+       .reload = reload,
 );
index 6a9e9a6..16a66b9 100644 (file)
@@ -59,7 +59,7 @@ extern "C" {
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+ASTERISK_REGISTER_FILE()
 
 #include "asterisk/lock.h"
 #include "asterisk/utils.h"
index d67cb5c..234228b 100644 (file)
@@ -903,11 +903,11 @@ void dahdi_native_unload(void)
  * \retval 0 on success.
  * \retval -1 on error.
  */
-int dahdi_native_load(struct ast_module *mod, const struct ast_channel_tech *tech)
+int dahdi_native_load(const struct ast_channel_tech *tech)
 {
        dahdi_tech = tech;
 
-       if (__ast_bridge_technology_register(&native_bridge, mod)) {
+       if (ast_bridge_technology_register(&native_bridge)) {
                dahdi_native_unload();
                return -1;
        }
index 91e8d16..6362a6f 100644 (file)
@@ -36,7 +36,7 @@ extern "C" {
 /* ------------------------------------------------------------------- */
 
 void dahdi_native_unload(void);
-int dahdi_native_load(struct ast_module *mod, const struct ast_channel_tech *tech);
+int dahdi_native_load(const struct ast_channel_tech *tech);
 
 /* ------------------------------------------------------------------- */
 
index a7cc3d7..b009c45 100644 (file)
  */
 //#define ALWAYS_PICK_CHANNEL  1
 
-/*!
- * Define to force a RESTART on a channel that returns a cause
- * code of PRI_CAUSE_REQUESTED_CHAN_UNAVAIL(44).  If the cause
- * is because of a stuck channel on the peer and the channel is
- * always the next channel we pick for an outgoing call then
- * this can help.
- */
-#define FORCE_RESTART_UNAVAIL_CHANS            1
-
 #if defined(HAVE_PRI_CCSS)
 struct sig_pri_cc_agent_prv {
        /*! Asterisk span D channel control structure. */
@@ -1376,10 +1367,9 @@ static void sig_pri_queue_unhold(struct sig_pri_span *pri, int chanpos)
 static void pri_queue_control(struct sig_pri_span *pri, int chanpos, int subclass)
 {
        struct ast_frame f = {AST_FRAME_CONTROL, };
-       struct sig_pri_chan *p = pri->pvts[chanpos];
 
        if (sig_pri_callbacks.queue_control) {
-               sig_pri_callbacks.queue_control(p->chan_pvt, subclass);
+               sig_pri_callbacks.queue_control(pri->pvts[chanpos]->chan_pvt, subclass);
        }
 
        f.subclass.integer = subclass;
@@ -1388,6 +1378,31 @@ static void pri_queue_control(struct sig_pri_span *pri, int chanpos, int subclas
 
 /*!
  * \internal
+ * \brief Queue a request to hangup control frame onto the owner channel.
+ *
+ * \param pri PRI span control structure.
+ * \param chanpos Channel position in the span.
+ *
+ * \note Assumes the pri->lock is already obtained.
+ * \note Assumes the sig_pri_lock_private(pri->pvts[chanpos]) is already obtained.
+ *
+ * \return Nothing
+ */
+static void sig_pri_queue_hangup(struct sig_pri_span *pri, int chanpos)
+{
+       if (sig_pri_callbacks.queue_control) {
+               sig_pri_callbacks.queue_control(pri->pvts[chanpos]->chan_pvt, AST_CONTROL_HANGUP);
+       }
+
+       sig_pri_lock_owner(pri, chanpos);
+       if (pri->pvts[chanpos]->owner) {
+               ast_queue_hangup(pri->pvts[chanpos]->owner);
+               ast_channel_unlock(pri->pvts[chanpos]->owner);
+       }
+}
+
+/*!
+ * \internal
  * \brief Queue a PVT_CAUSE_CODE frame onto the owner channel.
  * \since 11
  *
@@ -4035,14 +4050,14 @@ static void sig_pri_send_aoce_termination_request(struct sig_pri_span *pri, int
        }
 
        if (!(decoded = ast_aoc_create(AST_AOC_REQUEST, 0, AST_AOC_REQUEST_E))) {
-               ast_softhangup_nolock(pvt->owner, AST_SOFTHANGUP_DEV);
+               ast_queue_hangup(pvt->owner);
                goto cleanup_termination_request;
        }
 
        ast_aoc_set_termination_request(decoded);
 
        if (!(encoded = ast_aoc_encode(decoded, &encoded_size, pvt->owner))) {
-               ast_softhangup_nolock(pvt->owner, AST_SOFTHANGUP_DEV);
+               ast_queue_hangup(pvt->owner);
                goto cleanup_termination_request;
        }
 
@@ -4051,7 +4066,7 @@ static void sig_pri_send_aoce_termination_request(struct sig_pri_span *pri, int
        whentohangup.tv_sec = ms / 1000;
 
        if (ast_queue_control_data(pvt->owner, AST_CONTROL_AOC, encoded, encoded_size)) {
-               ast_softhangup_nolock(pvt->owner, AST_SOFTHANGUP_DEV);
+               ast_queue_hangup(pvt->owner);
                goto cleanup_termination_request;
        }
 
@@ -4295,43 +4310,6 @@ static void sig_pri_handle_cis_subcmds(struct sig_pri_span *pri, int event_id,
        }
 }
 
-#if defined(HAVE_PRI_AOC_EVENTS)
-/*!
- * \internal
- * \brief detect if AOC-S subcmd is present.
- * \since 1.8
- *
- * \param subcmds Subcommands to process if any. (Could be NULL).
- *
- * \note Knowing whether or not an AOC-E subcmd is present on certain
- * PRI hangup events is necessary to determine what method to use to hangup
- * the ast_channel.  If an AOC-E subcmd just came in, then a new AOC-E was queued
- * on the ast_channel.  If a soft hangup is used, the AOC-E msg will never make it
- * across the bridge, but if a AST_CONTROL_HANGUP frame is queued behind it
- * we can ensure the AOC-E frame makes it to it's destination before the hangup
- * frame is read.
- *
- *
- * \retval 0 AOC-E is not present in subcmd list
- * \retval 1 AOC-E is present in subcmd list
- */
-static int detect_aoc_e_subcmd(const struct pri_subcommands *subcmds)
-{
-       int i;
-
-       if (!subcmds) {
-               return 0;
-       }
-       for (i = 0; i < subcmds->counter_subcmd; ++i) {
-               const struct pri_subcommand *subcmd = &subcmds->subcmd[i];
-               if (subcmd->cmd == PRI_SUBCMD_AOC_E) {
-                       return 1;
-               }
-       }
-       return 0;
-}
-#endif /* defined(HAVE_PRI_AOC_EVENTS) */
-
 /*!
  * \internal
  * \brief Handle the call associated PRI subcommand events.
@@ -6567,9 +6545,8 @@ static void *pri_dchannel(void *vpri)
                                                                pri->pvts[chanpos]->call = NULL;
                                                        }
                                                }
-                                               /* Force soft hangup if appropriate */
-                                               if (pri->pvts[chanpos]->owner)
-                                                       ast_channel_softhangup_internal_flag_add(pri->pvts[chanpos]->owner, AST_SOFTHANGUP_DEV);
+                                               /* Force hangup if appropriate */
+                                               sig_pri_queue_hangup(pri, chanpos);
                                                sig_pri_unlock_private(pri->pvts[chanpos]);
                                        }
                                } else {
@@ -6581,8 +6558,8 @@ static void *pri_dchannel(void *vpri)
                                                                pri_destroycall(pri->pri, pri->pvts[x]->call);
                                                                pri->pvts[x]->call = NULL;
                                                        }
-                                                       if (pri->pvts[x]->owner)
-                                                               ast_channel_softhangup_internal_flag_add(pri->pvts[x]->owner, AST_SOFTHANGUP_DEV);
+                                                       /* Force hangup if appropriate */
+                                                       sig_pri_queue_hangup(pri, x);
                                                        sig_pri_unlock_private(pri->pvts[x]);
                                                }
                                }
@@ -7113,10 +7090,11 @@ static void *pri_dchannel(void *vpri)
                                                break;
                                        }
                                        if (pri->pvts[chanpos]->owner) {
-                                               int do_hangup = 0;
-
                                                snprintf(cause_str, sizeof(cause_str), "PRI PRI_EVENT_HANGUP (%d)", e->hangup.cause);
                                                pri_queue_pvt_cause_data(pri, chanpos, cause_str, e->hangup.cause);
+                                       }
+                                       if (pri->pvts[chanpos]->owner) {
+                                               int do_hangup = 0;
 
                                                /* Queue a BUSY instead of a hangup if our cause is appropriate */
                                                ast_channel_hangupcause_set(pri->pvts[chanpos]->owner, e->hangup.cause);
@@ -7154,17 +7132,7 @@ static void *pri_dchannel(void *vpri)
                                                }
 
                                                if (do_hangup) {
-#if defined(HAVE_PRI_AOC_EVENTS)
-                                                       if (detect_aoc_e_subcmd(e->hangup.subcmds)) {
-                                                               /* If a AOC-E msg was sent during the release, we must use a
-                                                                * AST_CONTROL_HANGUP frame to guarantee that frame gets read before hangup */
-                                                               pri_queue_control(pri, chanpos, AST_CONTROL_HANGUP);
-                                                       } else {
-                                                               ast_channel_softhangup_internal_flag_add(pri->pvts[chanpos]->owner, AST_SOFTHANGUP_DEV);
-                                                       }
-#else
-                                                       ast_channel_softhangup_internal_flag_add(pri->pvts[chanpos]->owner, AST_SOFTHANGUP_DEV);
-#endif /* defined(HAVE_PRI_AOC_EVENTS) */
+                                                       sig_pri_queue_hangup(pri, chanpos);
                                                }
                                        } else {
                                                /*
@@ -7182,9 +7150,9 @@ static void *pri_dchannel(void *vpri)
                                        pri_hangup(pri->pri, pri->pvts[chanpos]->call, e->hangup.cause);
                                        pri->pvts[chanpos]->call = NULL;
                                }
-#if defined(FORCE_RESTART_UNAVAIL_CHANS)
                                if (e->hangup.cause == PRI_CAUSE_REQUESTED_CHAN_UNAVAIL
                                        && pri->sig != SIG_BRI_PTMP && !pri->resetting
+                                       && pri->force_restart_unavailable_chans
                                        && pri->pvts[chanpos]->resetting == SIG_PRI_RESET_IDLE) {
                                        ast_verb(3,
                                                "Span %d: Forcing restart of channel %d/%d since channel reported in use\n",
@@ -7193,7 +7161,6 @@ static void *pri_dchannel(void *vpri)
                                        pri->pvts[chanpos]->resetting = SIG_PRI_RESET_ACTIVE;
                                        pri_reset(pri->pri, PVT_TO_CHANNEL(pri->pvts[chanpos]));
                                }
-#endif /* defined(FORCE_RESTART_UNAVAIL_CHANS) */
                                if (e->hangup.aoc_units > -1)
                                        ast_verb(3, "Channel %d/%d, span %d received AOC-E charging %d unit%s\n",
                                                pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span, (int)e->hangup.aoc_units, (e->hangup.aoc_units == 1) ? "" : "s");
@@ -7268,10 +7235,11 @@ static void *pri_dchannel(void *vpri)
                                        break;
                                }
                                if (pri->pvts[chanpos]->owner) {
-                                       int do_hangup = 0;
-
                                        snprintf(cause_str, sizeof(cause_str), "PRI PRI_EVENT_HANGUP_REQ (%d)", e->hangup.cause);
                                        pri_queue_pvt_cause_data(pri, chanpos, cause_str, e->hangup.cause);
+                               }
+                               if (pri->pvts[chanpos]->owner) {
+                                       int do_hangup = 0;
 
                                        ast_channel_hangupcause_set(pri->pvts[chanpos]->owner, e->hangup.cause);
                                        switch (ast_channel_state(pri->pvts[chanpos]->owner)) {
@@ -7314,16 +7282,11 @@ static void *pri_dchannel(void *vpri)
                                                        && ast_channel_is_bridged(pri->pvts[chanpos]->owner)) {
                                                        sig_pri_send_aoce_termination_request(pri, chanpos,
                                                                pri_get_timer(pri->pri, PRI_TIMER_T305) / 2);
-                                               } else if (detect_aoc_e_subcmd(e->hangup.subcmds)) {
-                                                       /* If a AOC-E msg was sent during the Disconnect, we must use a AST_CONTROL_HANGUP frame
-                                                        * to guarantee that frame gets read before hangup */
-                                                       pri_queue_control(pri, chanpos, AST_CONTROL_HANGUP);
-                                               } else {
-                                                       ast_channel_softhangup_internal_flag_add(pri->pvts[chanpos]->owner, AST_SOFTHANGUP_DEV);
-                                               }
-#else
-                                               ast_channel_softhangup_internal_flag_add(pri->pvts[chanpos]->owner, AST_SOFTHANGUP_DEV);
+                                               } else
 #endif /* defined(HAVE_PRI_AOC_EVENTS) */
+                                               {
+                                                       sig_pri_queue_hangup(pri, chanpos);
+                                               }
                                        }
                                        ast_verb(3, "Span %d: Channel %d/%d got hangup request, cause %d\n",
                                                pri->span, pri->pvts[chanpos]->logicalspan,
@@ -7336,9 +7299,9 @@ static void *pri_dchannel(void *vpri)
                                        pri_hangup(pri->pri, pri->pvts[chanpos]->call, e->hangup.cause);
                                        pri->pvts[chanpos]->call = NULL;
                                }
-#if defined(FORCE_RESTART_UNAVAIL_CHANS)
                                if (e->hangup.cause == PRI_CAUSE_REQUESTED_CHAN_UNAVAIL
                                        && pri->sig != SIG_BRI_PTMP && !pri->resetting
+                                       && pri->force_restart_unavailable_chans
                                        && pri->pvts[chanpos]->resetting == SIG_PRI_RESET_IDLE) {
                                        ast_verb(3,
                                                "Span %d: Forcing restart of channel %d/%d since channel reported in use\n",
@@ -7347,7 +7310,6 @@ static void *pri_dchannel(void *vpri)
                                        pri->pvts[chanpos]->resetting = SIG_PRI_RESET_ACTIVE;
                                        pri_reset(pri->pri, PVT_TO_CHANNEL(pri->pvts[chanpos]));
                                }
-#endif /* defined(FORCE_RESTART_UNAVAIL_CHANS) */
 
 #ifdef SUPPORT_USERUSER
                                if (!ast_strlen_zero(e->hangup.useruserinfo)) {
@@ -8619,16 +8581,18 @@ int sig_pri_indicate(struct sig_pri_chan *p, struct ast_channel *chan, int condi
                                        if (p->pri->aoc_passthrough_flag & SIG_PRI_AOC_GRANT_E) {
                                                sig_pri_aoc_e_from_ast(p, decoded);
                                        }
-                                       /* if hangup was delayed for this AOC-E msg, waiting_for_aoc
+                                       /*
+                                        * If hangup was delayed for this AOC-E msg, waiting_for_aoc
                                         * will be set.  A hangup is already occuring via a timeout during
                                         * this delay.  Instead of waiting for that timeout to occur, go ahead
-                                        * and initiate the softhangup since the delay is no longer necessary */
+                                        * and initiate the hangup since the delay is no longer necessary.
+                                        */
                                        if (p->waiting_for_aoce) {
                                                p->waiting_for_aoce = 0;
                                                ast_debug(1,
                                                        "Received final AOC-E msg, continue with hangup on %s\n",
                                                        ast_channel_name(chan));
-                                               ast_softhangup_nolock(chan, AST_SOFTHANGUP_DEV);
+                                               ast_queue_hangup(chan);
                                        }
                                        break;
                                case AST_AOC_REQUEST:
@@ -9014,7 +8978,7 @@ void sig_pri_stop_pri(struct sig_pri_span *pri)
 #if defined(HAVE_PRI_MWI)
        for (idx = 0; idx < ARRAY_LEN(pri->mbox); ++idx) {
                if (pri->mbox[idx].sub) {
-                       pri->mbox[idx].sub = stasis_unsubscribe(pri->mbox[idx].sub);
+                       pri->mbox[idx].sub = stasis_unsubscribe_and_join(pri->mbox[idx].sub);
                }
        }
 #endif /* defined(HAVE_PRI_MWI) */
diff --git