Compare commits

...

No commits in common. "master" and "old-master-svn" have entirely different histories.

349 changed files with 2356 additions and 13013 deletions

29
.gitignore vendored
View File

@ -1,29 +0,0 @@
*.cache
Makefile
YateLocal*
configure
config.*
*-stamp
yatepaths.h
yateversn.h
yateiss.inc
run
yate.spec
yate
yate-config
yate-config.in
yate.pc
core*
yate.core*
*.o
*.a
*.so
*.so.*
*.yate
*.orig
*~
.*.swp
*.log
*.out
*.csv
*.tsv

View File

@ -81,10 +81,6 @@ DOCGEN := $(DOCGEN_D)
APIDOCS := apidocs
endif
GIT_TAG := $(shell LANG=C LC_MESSAGES=C git tag 2>/dev/null | tail -1)
GIT_HASH := $(shell LANG=C LC_MESSAGES=C git rev-list -n1 HEAD 2>/dev/null)
.PHONY: all everything debug ddebug xdebug ndebug
all: engine modules clients ilibs
@ -295,9 +291,9 @@ uninstall uninstall-root:
install-root uninstall-root: LDCONFIG:=ldconfig
.PHONY: snapshot tarball rpm srpm rpm-tag srpm-tag rpm-head srpm-head revision check-gittag
.PHONY: snapshot tarball rpm srpm revision
snapshot tarball: check-topdir revision clean windows apidocs
@if [ $@ = snapshot ]; then ver="`date '+GIT-%Y%m%d'`"; else ver="@PACKAGE_VERSION@-@PACKAGE_STATUS@@PACKAGE_RELEASE@"; fi ; \
@if [ $@ = snapshot ]; then ver="`date '+SVN-%Y%m%d'`"; else ver="@PACKAGE_VERSION@-@PACKAGE_STATUS@@PACKAGE_RELEASE@"; fi ; \
wd=`pwd|sed 's,^.*/,,'`; \
mkdir -p packing/tarballs; cd ..; \
echo $$wd/tar-exclude >$$wd/tar-exclude; \
@ -311,8 +307,6 @@ snapshot tarball: check-topdir revision clean windows apidocs
find $$wd -name .svn >>$$wd/tar-exclude; \
find $$wd -name CVS >>$$wd/tar-exclude; \
find $$wd -name .cvsignore >>$$wd/tar-exclude; \
find $$wd -name .gitignore >>$$wd/tar-exclude; \
find $$wd -name .git >>$$wd/tar-exclude; \
else \
echo "$$wd/packing/rpm/yate.spec" >>$$wd/tar-exclude; \
fi ; \
@ -329,47 +323,15 @@ snapshot tarball: check-topdir revision clean windows apidocs
$$wd; \
rm $$wd/tar-exclude
# rpm and sprm will check that head is at the last tag
rpm: check-gittag tarball
rpm: tarball
rpmbuild -tb $(RPMOPT) packing/tarballs/@PACKAGE_TARNAME@-@PACKAGE_VERSION@-@PACKAGE_STATUS@@PACKAGE_RELEASE@.tar.gz
srpm: check-gittag tarball
srpm: tarball
rpmbuild -ta $(RPMOPT) packing/tarballs/@PACKAGE_TARNAME@-@PACKAGE_VERSION@-@PACKAGE_STATUS@@PACKAGE_RELEASE@.tar.gz
#build rpm/srpm with tag in revision number
rpm-tag: check-gittag tarball
rpmbuild -tb --define 'revision $(GIT_TAG)git' $(RPMOPT) packing/tarballs/@PACKAGE_TARNAME@-@PACKAGE_VERSION@-@PACKAGE_STATUS@@PACKAGE_RELEASE@.tar.gz
srpm-tag: check-gittag tarball
rpmbuild -ta --define 'revision $(GIT_TAG)git' $(RPMOPT) packing/tarballs/@PACKAGE_TARNAME@-@PACKAGE_VERSION@-@PACKAGE_STATUS@@PACKAGE_RELEASE@.tar.gz
# build packages from GIT HEAD
rpm-head: tarball
rpmbuild -tb --define 'revision $(GIT_HASH)git' $(RPMOPT) packing/tarballs/@PACKAGE_TARNAME@-@PACKAGE_VERSION@-@PACKAGE_STATUS@@PACKAGE_RELEASE@.tar.gz
srpm-head: tarball
rpmbuild -ta --define 'revision $(GIT_HASH)git' $(RPMOPT) packing/tarballs/@PACKAGE_TARNAME@-@PACKAGE_VERSION@-@PACKAGE_STATUS@@PACKAGE_RELEASE@.tar.gz
check-gittag revision: check-topdir
@tag_hash=""; \
if [ "" != "$(GIT_TAG)" ]; then \
tag_hash=`LANG=C LC_MESSAGES=C git rev-list -n1 $(GIT_TAG) 2>/dev/null`; \
elif [ $@ = check-gittag ]; then \
echo "No available GIT tag"; \
exit 1; \
fi; \
if [ "x$(GIT_HASH)" != "x$$tag_hash" ]; then \
if [ $@ = check-gittag ]; then \
echo "Current commit hash $(GIT_HASH) different from expected hash for tag $(GIT_TAG) ($$tag_hash)"; \
exit 1; \
fi; \
tag=""; \
fi; \
test -z "$(GIT_TAG)" || echo "$(GIT_TAG)" > packing/revision.txt ; \
test -z "$(GIT_HASH)" || echo "$(GIT_HASH)" > packing/git_commit.txt
revision: check-topdir
@-rev=`LANG=C LC_MESSAGES=C svn info 2>/dev/null | sed -n 's,^Last Changed Rev: *,,p'`; \
test -z "$$rev" || echo "$$rev" > packing/revision.txt
%.o: @srcdir@/%.cpp $(MKDEPS) @srcdir@/yatengine.h
$(COMPILE) -c $<

11
clients/.gitignore vendored
View File

@ -1,11 +0,0 @@
Makefile
YateLocal*
.xvpics
core*
yate-*
*.o
*.a
*.so
*.orig
*~
.*.swp

View File

@ -5,7 +5,7 @@
* A Qt-4 based universal telephony client
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2023 Null Team
* Copyright (C) 2004-2014 Null Team
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing

View File

@ -1,9 +0,0 @@
Makefile
YateLocal.mak
core*
*.moc
*.o
*.a
*.orig
*~
.*.swp

View File

@ -5,7 +5,7 @@
* A Qt-4 based universal telephony client
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2023 Null Team
* Copyright (C) 2004-2014 Null Team
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing

View File

@ -5,7 +5,7 @@
* A Qt-4 based universal telephony client
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2023 Null Team
* Copyright (C) 2004-2014 Null Team
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing

8
conf.d/.gitignore vendored
View File

@ -1,8 +0,0 @@
*.bind
Makefile
YateLocal.mak
core*
*.conf
*.orig
*~
.*.swp

View File

@ -39,13 +39,6 @@
; Default true
; sips: Boolean. Use SIPS URI for register/contact. Transport defaults to TLS if enabled
;
; For TCP SIP HEP3 capturing, setup the following parameters:
; capture_filter: Boolean, default false. Enable it if you want HEP3 capture of packets
; capture_agent: String, mandatory if capture_filter is set to true. Name of capture
; capture_server: String, mandatory if capture_filter is set to true. Name of HEP3 server where to send packets
; capture_compress: Boolean, default false. Set to true to compress captured packets
; If not set, capture settings will default to SIP global capture settings.
;
; NOTE: Default port is 5060 for udp/tcp and 5061 for tls
;
; Jabber:

View File

@ -1,52 +0,0 @@
; each section starting with 'server' configures a connection
; to a HEP3 server
; The string after 'server' is the server name
[server hep_server]
; enable: boolean: True to enable this connection. False to disable it
; This setting is applicable on reload.
;enable=yes
; auth_key: string: Authentication key string. If not set, it will look at
; value of auth_key_hex.
; This setting is applicable on reload.
;auth_key=
; auth_key_hex: Hexified string: Authentication key in hexadecimal octet string.
; If auth_key is not set and neither is this, authentication key will not be set
; in HEP3 packets.
; This setting is applicable on reload.
;auth_key_hex=
; capture_id: unsigned 4 byte integer: HEP3 Capture agent ID for this connection
; This setting is applicable on reload.
;capture_id=0
; compress: boolean: Compress HEP3 packet payload
; This setting can be overridden by entities that request a HEP3 capture
; for its own instance.
;compress=false
; socket_type: keyword (udp, tcp). Type of socket to create for communication
; with this server.
; Not applicable on reload.
;socket_type=udp
; remote_host: destination IPv4 address, mandatory to set. IPv4 address of the
; server where to send HEP3 packets
; Not applicable on reload.
;remote_host=
; remote_port: destination port, mandatory to set. Port where to send HEP3 packets
; Not applicable on reload.
;remote_port=
; local_host: local IPv4 address, mandatory to set. IPv4 address to use for
; sending HEP3 packets
; Not applicable on reload.
;local_host=
; remote_port: source port, mandatory to set. Port to use for sending HEP3 packets
; Not applicable on reload.
;local_port=

View File

@ -74,46 +74,3 @@ eliza=eliza.js
; These scripts are loaded only after the engine and modules have initialized, immediately
; after the dispatching of the "engine.start" message.
; The names must be unique and different from any in the [scripts] section.
[handlers]
; Install singleton message handlers
; These handlers are running using a separate context for each handled message
;
; Description:
; name=filename,callback,priority,trackname,parameters_prefix,filter,context,script_name
;
; Parameters (optional, unless otherwise specified):
; name: Required. Name of the message to handle
; Names starting with 'handlerparam:' are ignored
; filename: Required. Script to load
; callback: Required. Callback function. Function is required to be present in script code
; priority: Handler priority. Default: 100
; trackname: Track name to be put in handled message 'handlers' parameter
; parameters_prefix: Prefix for handler parameters specified in separate section parameters
; filter: Message handler filter.
; Format: filter_param=filter_value. Ignored if 'filter_param' is empty.
; filter_value starting with '^' char is handled as regular expression
; context: String to be passed to callback function
; script_name: Name of the script. Used internally for debug purposes. Use 'script_file_name' if empty
;
; Notes:
; - The following parameters are used to identify a handler:
; name,filename,callback,priority,trackname,filter,context,script_name
; An existing handler whose identity changed (not found in config) is removed at reload
; - Multiple handlers for the same message may be installed
; handlerparam:<parameters_prefix>:<param_name>: string: Configure a parameters for a handler
; Some of these parameters may be set in message handler description also (ignored here if so)
; They may be configured here since they may contain ',' in their contents
; Parameters:
; debug: string: Script debug (e.g. 'level 10'). This parameter is applied on reload
; context: string: Context to be passed to callback function
; filter: string: Message handler filter. See handler description for format
; track_priority: boolean: Add priority to tracked name. Default: true
; load_extensions: boolean: Load extension in script context when a message is handled
; This parameter is applied on reload
; Default: [general] 'auto_extensions'
; keep_old_on_fail: boolean: Keep old code if failed to parse the new one
; This parameter is used when handler is re-loaded and script changed
; Default: [general] 'keep_old_on_fail'

View File

@ -53,9 +53,3 @@
; poolsize: int: Number of connections to establish for this account
; Minimum number of connections is 1
;poolsize=1
; warn_query_duration: integer: Warn if query duration (database query and result fetch)
; exceeds this value (in milliseconds)
; This parameter is applied on reload and can be overridden in query database message
; Minium allowed interval is 50
;warn_query_duration=0

View File

@ -148,14 +148,10 @@
[extra]
; This section allows installing handlers for any message name.
; Each line must be of the form:
; message.name=priority[,[paramname][,context][,filter_param][,filter_match]]]
; message.name=priority[,[paramname][,context]]
; For each handler create a corresponding [context] or [message.name] section
; in which implement handling for that specific message. If paramname is not
; set you will need to match parameters explicitely or set a new match string.
; For filters, filter_param is the name of the parameter you want to match.
; filter_match is the value that filter_param parameter has to match. It can be
; an exact value to match or a regular expression. For regular expressions,
; filter_match must start with the character '^'.
; Examples:
; engine.command=90
; call.execute=120,callto

View File

@ -21,13 +21,9 @@
; If empty it will match all messages
; Example for a filter matching all chan.Anything messages and engine.halt:
; filter=^\(chan\.\|engine\.halt$\)
;filter=
;filter
; timer: boolean: True to sniff engine.timer messages, false otherwise
;timer=false
; max_buf_size: integer: Maximum admitted length of an encoded message.
; If encoded message length exceeds this length, message will not be sniffed
; Acceptable range is 2048 .. 65507
;max_buf_size=2048

View File

@ -110,18 +110,16 @@
; filtersniff: regexp: Default filter to apply to message sniffer at initialization
; If empty it will match all messages except engine.timer which is never displayed
; Example for a filter matching all chan.Anything messages and engine.halt:
; filtersniff=^\(chan\.\|engine\.halt\)$
; filtersniff=^\(chan\.\|engine\.halt$\)
;filtersniff=
; agesniff: float: Display only messages whose age or delay is higher than this value
; This is a floating point number in seconds (1.5 means 1500msec)
;agesniff=0
; filtersniffparams: string: Default parameter(s) filter to apply to message sniffer at initialization
; If empty it will not attempt to match message parameters
; Format: [any] [negated] param1=value1 [param2=value2 ...]
; any: message matches if at least one configured parameter matches
; negated: message matches if list does not match
; Format: [any] param1=value1 [param2=value2 ...]
; 'any' indicates that message matches if at least one configured parameter matches
; Value to match is handled as regexp. It may end with '^' to revert match (i.e. matches if regexp don't match)
; Value may be empty. In this case the parameter matches if missing in message or present with empty value
; Example for a filter matching messages with empty route_type or route_type=call
@ -130,16 +128,6 @@
; filtersniffparams=any caller=^123$ called=^123$
;filtersniffparams=
; msgsniff:<NAME>: string: Add a message sniffer rule
; <NAME> is optional. If missing the rule is handled as the one set using filtersniff/agesniff/filtersniffparams
; This parameter may be repeated with different <NAME> value to add multiple rules
; A rule will replace a previously defined rule with the same name
; Format: [filter=[value]] [age=[value]] [params [any negated] [name=value]]
; Examples:
; msgsniff:=filter=^\(chan\.\) age=0.5 params id=^sip/
; msgsniff:extra=filter=^\(call\.cdr\)$ params any caller=123 called=^2
;msgsniff:<NAME>=
; trace_msg_time: boolean: Instruct message dispatcher to set message event(s) time (enqueue / dispatch)
;trace_msg_time=no
@ -241,19 +229,3 @@ h323chan.yate=yes
; dtmfdups: bool: Allow duplicate DTMFs (detected with different methods)
;dtmfdups=disable
[configuration]
; Options for Configuration files
; These parameters are handled on first load only (repeated parameters are ignored)
; This section should be the first handled section if you need to apply parameters on this file also
; max_depth: integer: Maximum file include depth
; Allowed interval: 3..10
;max_depth=3
; disable_include_silent: boolean: Disable silent include in Configuration files
; The '$includesilent' directives of configuration file will be handled as '$include' if this
; parameter is set to boolean true
; Same applies for '$includesectionsilent': handled as '$includesection'
;disable_include_silent=no

View File

@ -155,9 +155,6 @@
; OBSOLETE - please use "enable" in section [options]
;options=enable
; update: bool: Enable receiving UPDATE transactions (RFC 3311)
;update=disable
; prack: bool: Enable acknowledging provisional 1xx answers (RFC 3262)
;prack=disable
@ -250,15 +247,10 @@
; Defaults to enable
;honor_dtmf_detect=enable
; rfc2833: bool: Offer RFC2833 telephone-event 8KHz by default
; rfc2833: bool: Offer RFC2833 telephone-event by default
; A numeric payload >= 96 can be provided
;rfc2833=yes
; rfc2833_RATE: bool: Offer RFC2833 telephone-event for specific rate (non 8KHz) by default
; A numeric payload >= 96 can be provided
; Supported rates (parameters): rfc2833_16000, rfc2833_32000
;rfc2833_RATE=yes
; privacy: bool: Process and generate privacy related SIP headers
;privacy=disable
@ -268,9 +260,6 @@
; forward_sdp: bool: Include the raw SDP body to be used as-is for forwarding RTP
;forward_sdp=disable
; forward_gpmd: bool: Propagate GPMD even when not forwarding RTP
;forward_gpmd=disable
; rtp_start: bool: Start RTP when sending 200 on incoming instead of receiving ACK
;rtp_start=disable
@ -381,73 +370,12 @@
; If set this parameter must be less than 'tcp_keepalive'
;tcp_keepalive_first=0
; ssdp_prefix: string: Prefix to use when handling SDP session level parameters
; This parameter is used when setting them in yate messages or handling them from there
; This parameter is applied on reload
; Prefix used to set parsed SDP: <ssdp_prefix>_ (default: ssdp_)
; Prefix used to update from yate messages: o<ssdp_prefix>_ (default: ossdp_)
; When updated from yate messages the prefix must be set in 'ossdp-prefix' message parameter
;ssdp_prefix=ssdp
; initial_headers: boolean: Put all headers from initial requests in yate message
; Handled for incoming channel preroute, user (un)register and messages sent on SIP
; requests received outside a dialog
; This parameter is applied on reload
;initial_headers=no
; reinvite_wait_initial: boolean: Wait for answered initial transaction termination when need to send
; a re-INVITE and initial transaction was not terminated
; Applicable for the inbound call leg
; This parameter is handled when answer (200 OK) was sent to initial transaction
; If enabled the module will not send an UPDATE even if supported by remote
; This parameter can be overridden from routing
; This parameter is applied on reload
;reinvite_wait_initial=no
; mixed_provisional: boolean: Accept mixed (non)reliable provisional responses to initial transaction
; When enabled (default) the dialog will accept non reliable provisional messages
; after receiving a reliable one
; This parameter can be overridden from routing
; This parameter is applied on reload
;mixed_provisional=yes
; warn_bind_fail_delay: integer/string: Delay failed to bind debug message
; This parameter may be used when listener is going to bind on an IP which may become
; available later
; Values:
; integer: Delay in milliseconds. Interval: 500..60000
; 'start': Delay until engine starts (engine.start message is handled by module)
;warn_bind_fail_delay=0
; warn_no_default_udp_transport: boolean: Warn if there is not default UDP transport
; This parameter is applied on reload
;warn_no_default_udp_transport=yes
; capture_filter: boolean. Enable global HEP3 capture of SIP packets
; NOTE: This setting can be overridden by listener settings or by account settings
; in case of outgoing TCP connections.
; This setting applies on reload.
;capture_filter=false
; capture_agent: string, mandatory if capture_filter is set to true. Name of capture agent.
; NOTE: This setting can be overridden by listener settings or by account settings
; in case of outgoing TCP connections.
; This is for internal tracking.
;capture_agent=
; capture_server: string, mandatory if capture_filter is set to true.
; Name of HEP3 server where to send packets. The server with this name must be configured
; in HEP3 module configuration.
; NOTE: This setting can be overridden by listener settings or by account settings
; in case of outgoing TCP connections.
;capture_server=
; capture_compress: boolean. Set to true to compress captured packets.
; If not set, it will use the HEP server configuration 'compress' configured value.
; NOTE: This setting can be overridden by listener settings or by account settings
; in case of outgoing TCP connections.
;capture_compress=false
[options]
; Controls the behaviour for SIP options retrieval
@ -623,7 +551,6 @@
; The following parameters can be overridden from 'general' section:
; UDP: maxpkt, buffer
; TCP/TLS: tcp_maxpkt
; All: warn_bind_fail_delay
; type: keyword: Listener type
; Allowed values:
@ -688,21 +615,3 @@
; role: string: Role to be set in messages sent by connections using this listener
; This parameter is applied on reload
;role=
; capture_filter: boolean. Enable HEP3 capture of packets on this listener.
; NOTE: for outgoing TCP connections, these settings must be made in accfile.conf.
; This setting applies on reload.
;capture_filter=false
; capture_agent: string, mandatory if capture_filter is set to true. Name of capture agent
; This is for internal tracking.
;capture_agent=
; capture_server: string, mandatory if capture_filter is set to true.
; Name of HEP3 server where to send packets. The server with this name must be configured
; in HEP3 module configuration
;capture_server=
; capture_compress: boolean. Set to true to compress captured packets.
; If not set, it will use the HEP server configuration 'compress' configured value
;capture_compress=false

View File

@ -9,11 +9,8 @@ fi
PACKAGE_RELEASE="1"
PACKAGE_STATUS="devel"
PACKAGE_REVISION=`cd "$srcdir"; LANG=C LC_MESSAGES=C git rev-list -n 1 HEAD 2>/dev/null`
PACKAGE_REVISION=`cd "$srcdir"; LANG=C LC_MESSAGES=C svn info 2>/dev/null | sed -n 's,^Last Changed Rev: *,,p'`
test -z "$PACKAGE_REVISION" && PACKAGE_REVISION=`cat "$srcdir/packing/revision.txt" 2>/dev/null`
test -z "$PACKAGE_REVISION" && PACKAGE_REVISION=`cat "$srcdir/packing/git_commit.txt" 2>/dev/null`
PACKAGE_GIT_HASH=`cd "$srcdir"; LANG=C LC_MESSAGES=C git rev-list -n 1 HEAD 2>/dev/null`
test -z "$PACKAGE_REVISION" && PACKAGE_REVISION=`cat "$srcdir/packing/git_commit.txt" 2>/dev/null`
AC_ARG_WITH(status,AC_HELP_STRING([--with-status=NAME],[use NAME as package status]),[PACKAGE_STATUS=$withval])
PACKAGE_VERSION_MAJOR="${PACKAGE_VERSION%%.*}"
@ -28,7 +25,6 @@ AC_SUBST(PACKAGE_VERSION_RELEASE)
AC_SUBST(PACKAGE_RELEASE)
AC_SUBST(PACKAGE_STATUS)
AC_SUBST(PACKAGE_REVISION)
AC_SUBST(PACKAGE_GIT_HASH)
# We may need the host OS type but avoid the overhead of AC_CANONICAL_SYSTEM
AC_MSG_CHECKING([for local operating system type])
@ -313,25 +309,6 @@ MUTEX_HACK="$MUTEX_HACK -DHAVE_TIMEDWAIT"
fi
AC_MSG_RESULT([$have_sem_timedwait])
have_rd_timedlock=""
AC_CHECK_LIB([pthread], [pthread_rwlock_timedrdlock], [have_rd_timedlock="yes"])
if [[ "x$have_rd_timedlock" = "x" ]]; then
AC_CHECK_LIB([c], [pthread_rwlock_timedrdlock],[have_rd_timedlock="yes"])
fi
if [[ "x$have_rd_timedlock" = "xyes" ]]; then
MUTEX_HACK="$MUTEX_HACK -DHAVE_TIMEDRDLOCK"
fi
have_wr_timedlock=""
AC_CHECK_LIB([pthread], [pthread_rwlock_timedwrlock], [have_wr_timedlock="yes"])
if [[ "x$have_wr_timedlock" = "x" ]]; then
AC_CHECK_LIB([c], [pthread_rwlock_timedwrlock], [have_wr_timedlock="yes"])
fi
if [[ "x$have_rd_timedlock" = "xyes" ]]; then
MUTEX_HACK="$MUTEX_HACK -DHAVE_TIMEDWRLOCK"
fi
CFLAGS="$SAVE_CFLAGS"
LIBS="$SAVE_LIBS"
AC_LANG_RESTORE
@ -1204,7 +1181,7 @@ AC_SUBST(SPEEX_LIB)
HAVE_AMRNB=no
AMRNB_INC=""
AMRNB_LIB="-lopencore-amrnb"
AMRNB_LIB="-lamrnb"
AC_ARG_WITH(amrnb,AC_HELP_STRING([--with-amrnb=DIR],[use AMR-NB if available (default)]),[ac_cv_use_amrnb=$withval],[ac_cv_use_amrnb=/usr])
if [[ "x$ac_cv_use_amrnb" = "xstatic" ]]; then
ac_cv_use_amrnb=/usr
@ -1213,9 +1190,9 @@ fi
if [[ "x$ac_cv_use_amrnb" != "xno" ]]; then
AC_MSG_CHECKING([for AMR-NB in $ac_cv_use_amrnb])
local_lib="$ARCHLIB"
amrinc="$ac_cv_use_amrnb/include/opencore-amrnb"
test -f "$ac_cv_use_amrnb/$local_lib/libopencore-amrnb.so" || local_lib="lib"
if [[ -f "$ac_cv_use_amrnb/$local_lib/libopencore-amrnb.so" -a -f "$amrinc/interf_dec.h" ]]; then
amrinc="$ac_cv_use_amrnb/include/amrnb"
test -f "$ac_cv_use_amrnb/$local_lib/libamrnb.so" || local_lib="lib"
if [[ -f "$ac_cv_use_amrnb/$local_lib/libamrnb.so" -a -f "$amrinc/interf_rom.h" ]]; then
HAVE_AMRNB=yes
AMRNB_LIB="-L$ac_cv_use_amrnb/$local_lib $AMRNB_LIB"
AMRNB_INC="-I$amrinc"
@ -1824,7 +1801,7 @@ AC_SUBST(INSTALL_L)
INSTALL_D="install -D"
CFLAGS=`echo "$CFLAGS" | sed 's/\(^\| \+\)-g[[0-9]]*//' | sed 's/[[[:space:]]]\{2,\}/ /g'`
MODULE_CFLAGS="-fno-exceptions -fPIC $HAVE_GCC_FORMAT_CHECK $HAVE_BLOCK_RETURN $ATOMIC_OPS"
MODULE_CFLAGS="-fno-exceptions -fPIC $HAVE_GCC_FORMAT_CHECK $HAVE_BLOCK_RETURN"
MODULE_CPPFLAGS="$HAVE_NO_OVERLOAD_VIRT_WARN $RTTI_OPT $MODULE_CFLAGS"
MODULE_LDRELAX="-rdynamic -shared"
MODULE_SYMBOLS="-Wl,--retain-symbols-file,/dev/null"

4
docs/.gitignore vendored
View File

@ -1,4 +0,0 @@
core*
*.orig
*~
.*.swp

3
docs/api/.gitignore vendored
View File

@ -1,3 +0,0 @@
core*
*.*
*~

8
engine/.gitignore vendored
View File

@ -1,8 +0,0 @@
Makefile
YateLocal*
core*
*.o
*.a
*.orig
*~
.*.swp

View File

@ -3,7 +3,7 @@
* This file is part of the YATE Project http://YATE.null.ro
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2023 Null Team
* Copyright (C) 2004-2014 Null Team
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing

View File

@ -5,7 +5,7 @@
* Base64 data encoding and decoding
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2023 Null Team
* Copyright (C) 2004-2014 Null Team
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing

View File

@ -3,7 +3,7 @@
* This file is part of the YATE Project http://YATE.null.ro
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2023 Null Team
* Copyright (C) 2004-2014 Null Team
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing
@ -1333,17 +1333,28 @@ bool Module::setDebug(Message& msg, const String& target)
return false;
NamedCounter* counter = objectsCounter();
const String& line = msg[YSTRING("line")];
debugSet(line);
String str = line;
if (str.startSkip("level"))
;
else if (str == YSTRING("reset")) {
String str = msg.getValue("line");
if (str.startSkip("level")) {
int dbg = debugLevel();
str >> dbg;
if (str == "+") {
if (debugLevel() > dbg)
dbg = debugLevel();
}
else if (str == "-") {
if (debugLevel() < dbg)
dbg = debugLevel();
}
debugLevel(dbg);
}
else if (str == "reset") {
debugLevel(TelEngine::debugLevel());
debugEnabled(true);
if (counter)
counter->enable(getObjCounting());
}
else if (str.startSkip("objects")) {
bool dbg = (str == YSTRING("reset")) ? getObjCounting() : (counter && counter->enabled());
bool dbg = (str == "reset") ? getObjCounting() : (counter && counter->enabled());
str >> dbg;
if (counter)
counter->enable(dbg);

View File

@ -3,7 +3,7 @@
* This file is part of the YATE Project http://YATE.null.ro
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2023 Null Team
* Copyright (C) 2004-2014 Null Team
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing

View File

@ -3,7 +3,7 @@
* This file is part of the YATE Project http://YATE.null.ro
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2023 Null Team
* Copyright (C) 2004-2014 Null Team
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing

View File

@ -5,7 +5,7 @@
* Default client logic
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2023 Null Team
* Copyright (C) 2004-2014 Null Team
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing

View File

@ -3,7 +3,7 @@
* This file is part of the YATE Project http://YATE.null.ro
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2023 Null Team
* Copyright (C) 2004-2014 Null Team
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing

View File

@ -3,7 +3,7 @@
* This file is part of the YATE Project http://YATE.null.ro
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2023 Null Team
* Copyright (C) 2004-2020 Null Team
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing
@ -22,159 +22,10 @@
#include <stdio.h>
#include <string.h>
#define MAX_DEPTH 3
using namespace TelEngine;
static unsigned int s_maxDepth = 3;
static int s_disableIncludeSilent = -1;
class ConfigurationPrivate
{
public:
enum Include {
IncludeNone = 0,
Include = 1,
IncludeSilent = 2,
IncludeRequire = 3,
};
inline ConfigurationPrivate(Configuration& cfg, bool isMain)
: m_cfg(cfg), m_main(isMain)
{}
inline void addingParam(const String& sect, const String& name, const String& value) {
if (!m_main || sect != YSTRING("configuration"))
return;
if (s_maxDepthInit && name == YSTRING("max_depth")) {
s_maxDepthInit = false;
s_maxDepth = value.toInteger(3,0,3,10);
}
else if (s_disableIncludeSilent < 0 && name == YSTRING("disable_include_silent"))
s_disableIncludeSilent = value.toBoolean() ? 1 : 0;
}
inline bool prepareIncludeSection(const String& sect, String& s, const char* file, bool warn,
bool& ok) {
int inc = getIncludeSect(s);
if (!inc)
return false;
NamedList* nl = sect ? m_cfg.getSection(sect) : 0;
if (nl) {
nl->addParam("[]",s);
if (!m_includeSections.find(nl))
m_includeSections.append(nl)->setDelete(false);
XDebug(DebugAll,"Config '%s' prepared section '%s' include '%s' file='%s'",
m_cfg.safe(),sect.safe(),s.safe(),(file == m_cfg.c_str() ? "<same>" : file));
}
else {
if (inc == IncludeRequire)
ok = false;
if (getWarn(warn,inc == IncludeSilent)) {
String tmp;
if (file != m_cfg.c_str())
tmp.printf(" in included file '%s'",file);
Debug(DebugNote,"Config '%s' found '%s' outside any section%s",
m_cfg.safe(),s.safe(),tmp.safe());
}
}
return true;
}
inline void processIncludeSections(bool warn, bool& ok) {
for (ObjList* o = m_includeSections.skipNull(); o; o = o->skipNext()) {
ObjList stack;
processInclude(static_cast<NamedList*>(o->get()),stack,warn,ok);
}
}
inline bool getWarn(bool warn, bool silent)
{ return (warn && silent) ? (s_disableIncludeSilent > 0) : warn; }
static inline int getIncludeSect(String& buf, bool setName = false) {
if (buf.startsWith("$includesection",true))
{ if (setName) buf = buf.substr(16,buf.length() - 16); return Include; }
if (buf.startsWith("$includesectionsilent",true))
{ if (setName) buf = buf.substr(22,buf.length() - 22); return IncludeSilent; }
if (buf.startsWith("$requiresection",true))
{ if (setName) buf = buf.substr(16,buf.length() - 16); return IncludeRequire; }
return 0;
}
static bool s_maxDepthInit;
private:
void processInclude(NamedList* sect, ObjList& stack, bool warn, bool& ok);
Configuration& m_cfg;
bool m_main;
ObjList m_includeSections;
ObjList m_includeSectProcessed;
};
bool ConfigurationPrivate::s_maxDepthInit = true;
void ConfigurationPrivate::processInclude(NamedList* sect, ObjList& stack, bool warn, bool& ok)
{
if (!sect || m_includeSectProcessed.find(sect))
return;
stack.append(sect)->setDelete(false);
#ifdef XDEBUG
String tmp;
tmp.append(stack," -> ");
Debug(DebugInfo,"Config '%s' processing include section stack: %s",
m_cfg.safe(),tmp.safe());
#endif
for (ObjList* o = sect->paramList()->skipNull(); o;) {
NamedString* s = static_cast<NamedString*>(o->get());
int inc = 0;
if ('[' == s->name()[0] && ']' == s->name()[1])
inc = getIncludeSect(*s,true);
if (!inc) {
o = o->skipNext();
continue;
}
Engine::runParams().replaceParams(*s);
if (*s) {
String error;
if (!stack[*s]) {
// NOTE: We are adding current section to processed after processing it
// Handle already processed sections whithout checking for recursive include
NamedList* incSect = static_cast<NamedList*>(m_includeSectProcessed[*s]);
if (!incSect) {
incSect = m_cfg.getSection(*s);
if (incSect && incSect != sect)
processInclude(incSect,stack,warn,ok);
else
error = incSect ? "recursive include" : "not found";
}
if (!error) {
XDebug(DebugAll,"Config '%s' including section '%s' in '%s'",
m_cfg.safe(),incSect->safe(),sect->safe());
for (ObjList* p = incSect->paramList()->skipNull(); p; p = p->skipNext()) {
NamedString* ns = static_cast<NamedString*>(p->get());
o->insert(new NamedString(ns->name(),*ns));
// Update current element (replaced by insert)
o = o->next();
}
}
}
else {
error.append(stack," -> ");
error = "recursive include stack=" + error;
}
if (error) {
if (inc == IncludeRequire)
ok = false;
if (getWarn(warn,inc == IncludeSilent))
Debug(DebugNote,"Config '%s' not including section '%s' in '%s': %s",
m_cfg.safe(),s->safe(),sect->safe(),error.c_str());
}
}
o->remove();
o = o->skipNull();
if (o)
continue;
sect->paramList()->compact();
break;
}
stack.remove(sect,false);
m_includeSectProcessed.insert(sect)->setDelete(false);
}
// Text sort callback
static int textSort(GenObject* obj1, GenObject* obj2, void* context)
{
@ -189,12 +40,11 @@ static int textSort(GenObject* obj1, GenObject* obj2, void* context)
Configuration::Configuration()
: m_main(false)
{
}
Configuration::Configuration(const char* filename, bool warn)
: String(filename), m_main(false)
: String(filename)
{
load(warn);
}
@ -335,8 +185,7 @@ bool Configuration::load(bool warn)
m_sections.clear();
if (null())
return false;
ConfigurationPrivate priv(*this,m_main);
return loadFile(c_str(),"",0,warn,&priv);
return loadFile(c_str(),"",0,warn);
}
static inline char* cfgReadLine(FILE* f, char* buf, int rd,
@ -391,14 +240,12 @@ static inline char* cfgReadLine(FILE* f, char* buf, int rd,
return pc;
}
bool Configuration::loadFile(const char* file, String sect, unsigned int depth, bool warn, void* priv)
bool Configuration::loadFile(const char* file, String sect, unsigned int depth, bool warn)
{
ConfigurationPrivate& cfg = *(ConfigurationPrivate*)priv;
DDebug(DebugInfo,"Configuration::loadFile(\"%s\",[%s],%u,%s)",
file,sect.c_str(),depth,String::boolText(warn));
if (depth > s_maxDepth) {
Debug(DebugWarn,"Config '%s' refusing to load config file '%s' at include depth %u",
c_str(),file,depth);
if (depth > MAX_DEPTH) {
Debug(DebugWarn,"Refusing to open config file '%s' at include depth %u",file,depth);
return false;
}
FILE *f = ::fopen(file,"r");
@ -453,12 +300,8 @@ bool Configuration::loadFile(const char* file, String sect, unsigned int depth,
}
if (!enabled)
continue;
if (cfg.prepareIncludeSection(sect,s,file,warn,ok))
continue;
bool noerr = false;
bool silent = false;
if (s.startSkip("$require") || (noerr = s.startSkip("$include"))
|| (silent = noerr = s.startSkip("$includesilent"))) {
if (s.startSkip("$require") || (noerr = s.startSkip("$include"))) {
Engine::runParams().replaceParams(s);
String path;
if (!s.startsWith(Engine::pathSeparator())) {
@ -483,7 +326,6 @@ bool Configuration::loadFile(const char* file, String sect, unsigned int depth,
}
path << s;
ObjList files;
bool doWarn = cfg.getWarn(warn,silent);
if (File::listDirectory(path,0,&files)) {
path << Engine::pathSeparator();
DDebug(DebugAll,"Configuration loading up to %u files from '%s'",
@ -492,7 +334,7 @@ bool Configuration::loadFile(const char* file, String sect, unsigned int depth,
while (String* it = static_cast<String*>(files.remove(false))) {
if (!(it->startsWith(".") || it->endsWith("~")
|| it->endsWith(".bak") || it->endsWith(".tmp")))
ok = (loadFile(path + *it,sect,depth+1,doWarn,priv) || noerr) && ok;
ok = (loadFile(path + *it,sect,depth+1,warn) || noerr) && ok;
#ifdef DEBUG
else
Debug(DebugAll,"Configuration skipping over file '%s'",it->c_str());
@ -501,7 +343,7 @@ bool Configuration::loadFile(const char* file, String sect, unsigned int depth,
}
}
else
ok = (loadFile(path,sect,depth+1,doWarn,priv) || noerr) && ok;
ok = (loadFile(path,sect,depth+1,warn) || noerr) && ok;
continue;
}
Engine::runParams().replaceParams(s);
@ -529,20 +371,16 @@ bool Configuration::loadFile(const char* file, String sect, unsigned int depth,
break;
s += pc;
}
s.trimBlanks();
cfg.addingParam(sect,key,s);
addValue(sect,key,s);
addValue(sect,key,s.trimBlanks());
}
::fclose(f);
if (!depth)
cfg.processIncludeSections(warn,ok);
return ok;
}
if (warn) {
int err = errno;
if (depth)
Debug(DebugNote,"Config '%s' failed to open included config file '%s' (%d: %s)",
c_str(),file,err,strerror(err));
Debug(DebugNote,"Failed to open included config file '%s' (%d: %s)",
file,err,strerror(err));
else
Debug(DebugNote,"Failed to open config file '%s', using defaults (%d: %s)",
file,err,strerror(err));

View File

@ -3,7 +3,7 @@
* This file is part of the YATE Project http://YATE.null.ro
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2023 Null Team
* Copyright (C) 2004-2014 Null Team
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing
@ -77,14 +77,6 @@ static InitG711 s_initG711;
static const DataBlock s_empty;
static inline void* dbAlloc(unsigned int n, void* oldBuf = 0)
{
void* data = ::realloc(oldBuf,n);
if (!data)
Debug("DataBlock",DebugFail,"realloc(%u) returned NULL!",n);
return data;
}
const DataBlock& DataBlock::empty()
{
return s_empty;
@ -130,7 +122,6 @@ void* DataBlock::getObject(const String& name) const
void DataBlock::clear(bool deleteData)
{
m_length = 0;
m_allocated = 0;
if (m_data) {
void *data = m_data;
m_data = 0;
@ -139,91 +130,6 @@ void DataBlock::clear(bool deleteData)
}
}
// Change (insert or append data) the current block
bool DataBlock::change(unsigned int pos, const void* buf, unsigned int bufLen,
unsigned int extra, int extraVal, bool mayOverlap)
{
unsigned int addLen = (buf ? bufLen : 0) + extra;
if (!addLen)
return true;
XDebug("DataBlock",DebugAll,
"change(%u,%p,%u,%d,%d,%u) add_lenlen=%u m_data=%p m_length=%u allocated=%u [%p]",
pos,buf,bufLen,extra,extraVal,mayOverlap,addLen,m_data,m_length,m_allocated,this);
if (!(buf && bufLen)) {
buf = 0;
bufLen = 0;
}
if (pos > m_length)
pos = m_length;
unsigned int newLen = m_length + addLen;
void* data = 0;
unsigned int aLen = 0;
// Allocate a new buffer if input data may overlap with existing
bool overlap = buf && (mayOverlap || buf == m_data);
if (!m_data || overlap || newLen > m_allocated) {
aLen = allocLen(newLen);
// Append to existing: Realloc data. Avoid free
void* reallocAppend = (!overlap && pos == m_length) ? m_data : 0;
data = dbAlloc(aLen,reallocAppend);
if (!data)
return false;
if (reallocAppend)
clear(false);
else
copyData(data,m_data,m_length,pos,addLen);
}
else {
moveData(m_data,m_length,pos,addLen);
data = m_data;
}
if (bufLen)
::memcpy((uint8_t*)data + pos,buf,bufLen);
if (extra)
::memset((uint8_t*)data + pos + bufLen,extraVal,extra);
if (aLen)
assign(data,newLen,false,aLen);
else
m_length = newLen;
return true;
}
#define DB_CHANGE_UINT_FUNC \
unsigned int n = 0; \
if (lsb) { \
while (len--) { \
buf[n++] = (uint8_t)value; \
value = value >> 8; \
} \
} \
else { \
uint8_t sh = (len - 1) * 8; \
while (len--) { \
buf[n++] = (uint8_t)(value >> sh); \
sh -= 8; \
} \
} \
return change(pos,(const void*)buf,n,0,0,false)
bool DataBlock::change8(unsigned int pos, uint64_t value, unsigned int len, bool lsb)
{
if (!len)
return true;
if (len > 8)
len = 8;
uint8_t buf[8] = {0,0,0,0,0,0,0,0};
DB_CHANGE_UINT_FUNC;
}
bool DataBlock::change4(unsigned int pos, uint32_t value, unsigned int len, bool lsb)
{
if (!len)
return true;
if (len > 4)
len = 4;
uint8_t buf[4] = {0,0,0,0};
DB_CHANGE_UINT_FUNC;
}
DataBlock& DataBlock::assign(void* value, unsigned int len, bool copyData, unsigned int allocated)
{
if ((value != m_data) || (len != m_length)) {
@ -292,6 +198,76 @@ DataBlock& DataBlock::operator=(const DataBlock& value)
return *this;
}
void DataBlock::append(const DataBlock& value)
{
if (m_length) {
if (value.length()) {
unsigned int len = m_length+value.length();
if (len <= m_allocated) {
::memcpy(m_length+(char*)m_data,value.data(),value.length());
m_length = len;
return;
}
unsigned int aLen = allocLen(len);
void *data = ::malloc(aLen);
if (data) {
::memcpy(data,m_data,m_length);
::memcpy(m_length+(char*)data,value.data(),value.length());
assign(data,len,false,aLen);
}
else
Debug("DataBlock",DebugFail,"malloc(%d) returned NULL!",aLen);
}
}
else
assign(value.data(),value.length());
}
void DataBlock::append(const String& value)
{
if (m_length) {
if (value.length()) {
unsigned int len = m_length+value.length();
if (len <= m_allocated) {
::memcpy(m_length+(char*)m_data,value.safe(),value.length());
m_length = len;
return;
}
unsigned int aLen = allocLen(len);
void *data = ::malloc(aLen);
if (data) {
::memcpy(data,m_data,m_length);
::memcpy(m_length+(char*)data,value.safe(),value.length());
assign(data,len,false,aLen);
}
else
Debug("DataBlock",DebugFail,"malloc(%d) returned NULL!",aLen);
}
}
else
assign((void*)value.c_str(),value.length());
}
void DataBlock::insert(const DataBlock& value)
{
unsigned int vl = value.length();
if (m_length) {
if (vl) {
unsigned int len = m_length+vl;
void *data = ::malloc(len);
if (data) {
::memcpy(data,value.data(),vl);
::memcpy(vl+(char*)data,m_data,m_length);
assign(data,len,false);
}
else
Debug("DataBlock",DebugFail,"malloc(%d) returned NULL!",len);
}
}
else
assign(value.data(),vl);
}
unsigned int DataBlock::allocLen(unsigned int len) const
{
// allocate a multiple of 8 bytes
@ -390,24 +366,60 @@ inline signed char hexDecode(char c)
return -1;
}
static inline bool retResult(bool ok, int result, int* res)
{
if (res)
*res = result;
return ok;
}
// Change data from a hexadecimal string representation.
// Build this data block from a hexadecimal string representation.
// Each octet must be represented in the input string with 2 hexadecimal characters.
// If a separator is specified, the octets in input string must be separated using
// exactly 1 separator. Only 1 leading or 1 trailing separators are allowed
bool DataBlock::changeHex(unsigned int pos, const char* data, unsigned int len, char sep,
bool guessSep, bool emptyOk, int* res)
bool DataBlock::unHexify(const char* data, unsigned int len, char sep)
{
clear();
if (!(data && len))
return retResult(emptyOk,0,res);
return true;
if (!sep && guessSep && len > 2) {
// Calculate the destination buffer length
unsigned int n = 0;
if (!sep) {
if (0 != (len % 2))
return false;
n = len / 2;
}
else {
// Remove leading and trailing separators
if (data[0] == sep) {
data++;
len--;
}
if (len && data[len-1] == sep)
len--;
// No more leading and trailing separators allowed
if (2 != (len % 3))
return (bool)(len == 0);
n = (len + 1) / 3;
}
if (!n)
return true;
char* buf = (char*)::malloc(n);
unsigned int iBuf = 0;
for (unsigned int i = 0; i < len; i += (sep ? 3 : 2)) {
signed char c1 = hexDecode(data[i]);
signed char c2 = hexDecode(data[i+1]);
if (c1 == -1 || c2 == -1 || (sep && (iBuf != n - 1) && (sep != data[i+2])))
break;
buf[iBuf++] = (c1 << 4) | c2;
}
if (iBuf >= n)
assign(buf,n,false);
else
::free(buf);
return (iBuf >= n);
}
// This variant of unHexify automatically detects presence of separators
bool DataBlock::unHexify(const char* data, unsigned int len)
{
char sep = 0;
if (len > 2) {
const char* s = " :;.,-/|";
while (char c = *s++) {
unsigned int offs = 2;
@ -419,140 +431,38 @@ bool DataBlock::changeHex(unsigned int pos, const char* data, unsigned int len,
}
}
}
// Calculate the destination buffer length
unsigned int n = 0;
if (!sep) {
if (0 != (len % 2))
return retResult(false,-3,res);
n = len / 2;
}
else {
// Remove leading and trailing separators
if (data[0] == sep) {
data++;
len--;
}
if (len && data[len - 1] == sep)
len--;
// No more leading and trailing separators allowed
if (!len)
return retResult(emptyOk,0,res);
if (2 != (len % 3))
return retResult(false,-3,res);
n = (len + 1) / 3;
}
if (!n)
return retResult(emptyOk,0,res);
unsigned int newLen = m_length + n;
unsigned int aLen = allocLen(newLen);
void* newData = dbAlloc(aLen);
if (!newData)
return retResult(false,-1,res);
if (pos > m_length)
pos = m_length;
char* buf = (char*)newData + pos;
unsigned int iBuf = 0;
for (unsigned int i = 0; i < len; i += (sep ? 3 : 2)) {
signed char c1 = hexDecode(*data++);
signed char c2 = hexDecode(*data++);
if (c1 == -1 || c2 == -1 || (sep && (iBuf != n - 1) && (sep != *data++)))
break;
buf[iBuf++] = (c1 << 4) | c2;
}
if (iBuf < n) {
::free(newData);
return retResult(false,-2,res);
}
copyData(newData,m_data,m_length,pos,n);
assign(newData,newLen,false,aLen);
return retResult(true,n,res);
return unHexify(data,len,sep);
}
static inline bool dbIsEscape(char c, char extraEsc)
String DataBlock::sqlEscape(char extraEsc) const
{
return c == '\0' || c == '\r' || c == '\n' || c == '\\' || c == '\'' || c == extraEsc;
}
String& DataBlock::sqlEscape(String& str, const void* data, unsigned int len, char extraEsc)
{
if (!(data && len))
return str;
unsigned int useLen = len;
char* ds = (char*)data;
for (unsigned int i = 0; i < len; i++) {
if (dbIsEscape(*ds++,extraEsc))
useLen++;
unsigned int len = m_length;
unsigned int i;
for (i = 0; i < m_length; i++) {
char c = static_cast<char*>(m_data)[i];
if (c == '\0' || c == '\r' || c == '\n' || c == '\\' || c == '\'' || c == extraEsc)
len++;
}
// No escape needed ?
if (useLen == len)
return str.append((const char*)data,len);
unsigned int sLen = str.length();
str.append(' ',useLen);
char* d = ((char*)(str.c_str())) + sLen;
ds = (char*)data;
for (unsigned int i = 0; i < len; i++) {
char c = *ds++;
if (dbIsEscape(c,extraEsc)) {
String tmp(' ',len);
char* d = const_cast<char*>(tmp.c_str());
for (i = 0; i < m_length; i++) {
char c = static_cast<char*>(m_data)[i];
if (c == '\0' || c == '\r' || c == '\n' || c == '\\' || c == '\'' || c == extraEsc)
*d++ = '\\';
switch (c) {
case '\0':
c = '0';
break;
case '\r':
c = 'r';
break;
case '\n':
c = 'n';
break;
}
switch (c) {
case '\0':
c = '0';
break;
case '\r':
c = 'r';
break;
case '\n':
c = 'n';
break;
}
*d++ = c;
}
return str;
}
void DataBlock::moveData(void* buf, unsigned int len, unsigned int pos, unsigned int space)
{
if (!buf || pos >= len)
return;
unsigned int delta = pos + space;
if (!delta)
return;
uint8_t* src = (uint8_t*)buf;
uint8_t* dest = (uint8_t*)buf + delta;
if (pos) {
// Insert middle. Keep old data until pos. Copy the rest
len -= pos;
src += pos;
}
if (delta < len)
::memmove(dest,src,len);
else
::memcpy(dest,src,len);
}
void DataBlock::copyData(void* dest, const void* src, unsigned int len, unsigned int pos,
unsigned int space)
{
if (!(src && dest && len))
return;
uint8_t* d = (uint8_t*)dest;
const uint8_t* s = (const uint8_t*)src;
if (!pos)
// Data insert before existing, copy old data after it
::memcpy(d + space,s,len);
else if (pos == len)
// Data added to existing, copy old at start
::memcpy(d,s,len);
else if (space) {
// Insert middle
::memcpy(d,s,pos);
::memcpy(d + pos + space,s + pos,len - pos);
}
else
::memcpy(d,s,len);
return tmp;
}
/* vi: set ts=8 sw=4 sts=4 noet: */

View File

@ -3,7 +3,7 @@
* This file is part of the YATE Project http://YATE.null.ro
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2023 Null Team
* Copyright (C) 2004-2014 Null Team
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing

View File

@ -3,7 +3,7 @@
* This file is part of the YATE Project http://YATE.null.ro
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2023 Null Team
* Copyright (C) 2004-2020 Null Team
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing
@ -305,7 +305,6 @@ static int s_exit = -1;
unsigned int Engine::s_congestion = 0;
static Mutex s_congMutex(false,"Congestion");
static bool s_debug = true;
static NamedList s_debugInit("");
static bool s_capture = CAPTURE_EVENTS;
static int s_maxevents = 25;
static Mutex s_eventsMutex(false,"EventsList");
@ -544,35 +543,11 @@ bool EngineStatusHandler::received(Message &msg)
objects(msg.retValue(),details);
return true;
}
if (sel.startSkip("dispatcher")) {
bool byMsg = sel.startSkip("handlers");
if ((byMsg || sel.startSkip("handlers-trackname")) && sel) {
String str;
unsigned int count = 0;
unsigned int total = 0;
MessageDispatcher* d = Engine::dispatcher();
if (d) {
if (sel[0] == '^')
count = d->fillHandlersInfo(byMsg,Regexp(sel),details ? &str : 0,&total);
else
count = d->fillHandlersInfo(byMsg,sel,details ? &str : 0,&total);
}
msg.retValue()
<< "name=dispatcher,type=system,format=Priority|TrackName|Filtered;"
<< "handlers=" << total << ",count=" << count;
if (details)
msg.retValue() << ';' << str;
msg.retValue() << "\r\n";
return true;
}
return false;
}
return false;
}
msg.retValue() << "name=engine,type=system";
msg.retValue() << ",version=" << YATE_VERSION;
msg.retValue() << ",revision=" << YATE_REVISION;
msg.retValue() << ",githash=" << YATE_GIT_HASH;
msg.retValue() << ",nodename=" << Engine::nodeName();
msg.retValue() << ";plugins=" << plugins.count();
msg.retValue() << ",inuse=" << Engine::self()->usedPlugins();
@ -674,8 +649,6 @@ static const char s_runpOpt[] = " runparam name=value\r\n";
static const char s_runpMsg[] = "Add a new parameter to the Engine's runtime list\r\n";
static const char s_dispatcherOpt[] = " dispatcher {trace_msg_time|trace_msg_handler_time} <on|off>\r\n";
static const char s_dispatcherMsg[] = "Enable or disable dispatcher debugging options\r\n";
static const char s_dispatcherStatusOpt[] = " status dispatcher {handlers|handlers-trackname} <match>\r\n";
static const char s_dispatcherStatusMsg[] = "Show installed handlers by message name or track name. Matching value starting with ^ is handled as basic regular expression\r\n";
// get the base name of a module file
static String moduleBase(const String& fname)
@ -778,32 +751,27 @@ void completeModule(String& ret, const String& part, ObjList& mods, bool reload,
void EngineCommand::doCompletion(Message &msg, const String& partLine, const String& partWord)
{
if (partLine.null() || (partLine == YSTRING("help"))) {
completeOne(msg.retValue(),YSTRING("module"),partWord);
completeOne(msg.retValue(),YSTRING("events"),partWord);
completeOne(msg.retValue(),YSTRING("logview"),partWord);
completeOne(msg.retValue(),YSTRING("runparam"),partWord);
completeOne(msg.retValue(),YSTRING("dispatcher"),partWord);
completeOne(msg.retValue(),"module",partWord);
completeOne(msg.retValue(),"events",partWord);
completeOne(msg.retValue(),"logview",partWord);
completeOne(msg.retValue(),"runparam",partWord);
completeOne(msg.retValue(),"dispatcher",partWord);
}
else if (partLine == YSTRING("status")) {
completeOne(msg.retValue(),YSTRING("engine"),partWord);
completeOne(msg.retValue(),YSTRING("objects"),partWord);
completeOne(msg.retValue(),YSTRING("dispatcher"),partWord);
completeOne(msg.retValue(),"engine",partWord);
completeOne(msg.retValue(),"objects",partWord);
}
else if (partLine == YSTRING("status objects")) {
for (ObjList* l = getObjCounters().skipNull();l;l = l->skipNext())
completeOne(msg.retValue(),l->get()->toString(),partWord);
}
else if (partLine == YSTRING("status dispatcher")) {
completeOne(msg.retValue(),YSTRING("handlers"),partWord);
completeOne(msg.retValue(),YSTRING("handlers-trackname"),partWord);
}
else if (partLine == YSTRING("module")) {
completeOne(msg.retValue(),YSTRING("load"),partWord);
completeOne(msg.retValue(),"load",partWord);
if (!s_nounload) {
completeOne(msg.retValue(),YSTRING("unload"),partWord);
completeOne(msg.retValue(),YSTRING("reload"),partWord);
completeOne(msg.retValue(),"unload",partWord);
completeOne(msg.retValue(),"reload",partWord);
}
completeOne(msg.retValue(),YSTRING("list"),partWord);
completeOne(msg.retValue(),"list",partWord);
}
else if (partLine == YSTRING("module load"))
completeModule(msg.retValue(),partWord,Engine::self()->m_libs,false);
@ -828,29 +796,28 @@ void EngineCommand::doCompletion(Message &msg, const String& partLine, const Str
const EngineEventList* e = static_cast<const EngineEventList*>(l->get());
completeOne(msg.retValue(),e->toString(),partWord);
}
completeOne(msg.retValue(),YSTRING("log"),partWord);
completeOne(msg.retValue(),"log",partWord);
if (partLine == YSTRING("events"))
completeOne(msg.retValue(),YSTRING("clear"),partWord);
completeOne(msg.retValue(),"clear",partWord);
}
else if (partLine == YSTRING("dispatcher")) {
completeOne(msg.retValue(),YSTRING("trace_msg_time"),partWord);
completeOne(msg.retValue(),YSTRING("trace_msg_handler_time"),partWord);
completeOne(msg.retValue(),"trace_msg_time",partWord);
completeOne(msg.retValue(),"trace_msg_handler_time",partWord);
}
else if ((partLine == YSTRING("dispatcher trace_msg_time"))
|| (partLine == YSTRING("dispatcher trace_msg_handler_time"))) {
completeOne(msg.retValue(),YSTRING("on"),partWord);
completeOne(msg.retValue(),YSTRING("off"),partWord);
completeOne(msg.retValue(),"on",partWord);
completeOne(msg.retValue(),"off",partWord);
}
}
bool EngineCommand::received(Message &msg)
{
const String& l = msg[YSTRING("line")];
if (!l) {
String line = msg.getValue("line");
if (line.null()) {
doCompletion(msg,msg.getValue("partline"),msg.getValue("partword"));
return false;
}
String line = l;
if (line.startSkip("control")) {
int pos = line.find(' ');
String id = line.substr(0,pos).trimBlanks();
@ -914,19 +881,17 @@ bool EngineCommand::received(Message &msg)
}
return false;
}
if (line.startSkip("dispatcher")) {
bool traceMsgTime = line.startSkip("trace_msg_time");
if (traceMsgTime || line.startSkip("trace_msg_handler_time")) {
MessageDispatcher* d = Engine::dispatcher();
if (d) {
if (traceMsgTime)
d->traceTime(line.toBoolean());
else
d->traceHandlerTime(line.toBoolean());
return true;
}
}
return false;
if (line.startSkip("dispatcher trace_msg_time")) {
MessageDispatcher* d = Engine::dispatcher();
if (d)
d->traceTime(line.toBoolean());
return 0 != d;
}
if (line.startSkip("dispatcher trace_msg_handler_time")) {
MessageDispatcher* d = Engine::dispatcher();
if (d)
d->traceHandlerTime(line.toBoolean());
return 0 != d;
}
return false;
}
@ -1007,8 +972,7 @@ bool EngineHelp::received(Message &msg)
else if (line == YSTRING("runparam"))
msg.retValue() << s_runpOpt << s_runpMsg;
else if (line == YSTRING("dispatcher"))
msg.retValue() << s_dispatcherOpt << s_dispatcherMsg
<< s_dispatcherStatusOpt << s_dispatcherStatusMsg;
msg.retValue() << s_dispatcherOpt << s_dispatcherMsg;
else
return false;
return true;
@ -1619,7 +1583,7 @@ int Engine::engineInit()
#endif
CapturedEvent::capturing(s_capture);
s_cfg = configFile(s_cfgfile);
s_cfg.loadMain();
s_cfg.load();
s_capture = s_cfg.getBoolValue("general","startevents",s_capture);
CapturedEvent::capturing(s_capture);
if (s_capture && s_startMsg)
@ -1790,9 +1754,6 @@ int Engine::engineInit()
}
// Reload configuration file so conditionals will take into account runtime parameters
s_cfg.load();
NamedList* sect = s_cfg.getSection(YSTRING("debug"));
if (sect)
s_debugInit.copyParams(false,*sect);
vars = s_cfg.getSection("variables");
if (vars) {
unsigned int n = vars->length();
@ -1898,14 +1859,18 @@ int Engine::run()
if (s_debug) {
// one-time sending of debug setup messages
s_debug = false;
for (ObjList* o = s_debugInit.paramList()->skipNull(); o; o = o->skipNext()) {
const NamedString* str = static_cast<NamedString*>(o->get());
if (!(str->name() && *str))
continue;
Message* m = new Message("engine.debug");
m->addParam("module",str->name());
m->addParam("line",*str);
enqueue(m);
const NamedList* sect = s_cfg.getSection("debug");
if (sect) {
unsigned int n = sect->length();
for (unsigned int i = 0; i < n; i++) {
const NamedString* str = sect->getParam(i);
if (!(str && str->name() && *str))
continue;
Message* m = new Message("engine.debug");
m->addParam("module",str->name());
m->addParam("line",*str);
enqueue(m);
}
}
}
else if (s_capture) {
@ -2313,8 +2278,6 @@ void Engine::initPlugins()
for (; l; l = l->skipNext()) {
Plugin *p = static_cast<Plugin *>(l->get());
TempObjectCounter cnt(p->objectsCounter(),true);
if (s_debug)
p->debugSet(s_debugInit[p->toString()]);
p->initialize();
if (exiting()) {
Output("Initialization aborted, exiting...");
@ -2600,7 +2563,6 @@ void Engine::initLibrary(const String& line, String* output)
ENGINE_SET_VAL_BREAK('s',s_lateabrt,true);
ENGINE_INSTR_BREAK('m',setLockableWait());
ENGINE_INSTR_BREAK('d',Lockable::enableSafety());
ENGINE_INSTR_BREAK('r',RWLock::disableRWLock(true));
default:
unkArgs.append("-D" + String(*pc)," ");
}
@ -2939,9 +2901,6 @@ int Engine::main(int argc, const char** argv, const char** env, RunMode mode, En
case 'd':
Lockable::enableSafety();
break;
case 'r':
RWLock::disableRWLock(true);
break;
#ifdef RTLD_GLOBAL
case 'l':
s_localsymbol = true;

View File

@ -3,7 +3,7 @@
* This file is part of the YATE Project http://YATE.null.ro
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2023 Null Team
* Copyright (C) 2004-2014 Null Team
*
* Idea and initial implementation (as HashTable) by Maciek Kaminski
*

View File

@ -3,7 +3,7 @@
* This file is part of the YATE Project http://YATE.null.ro
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2013-2023 Null Team
* Copyright (C) 2013-2014 Null Team
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing

View File

@ -3,7 +3,7 @@
* This file is part of the YATE Project http://YATE.null.ro
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2023 Null Team
* Copyright (C) 2004-2014 Null Team
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing

View File

@ -115,7 +115,7 @@ Thread.o: @srcdir@/Thread.cpp $(MKDEPS) $(CINC)
$(COMPILE) @THREAD_KILL@ @THREAD_AFFINITY@ @HAVE_PRCTL@ -c $<
TelEngine.o: @srcdir@/TelEngine.cpp $(MKDEPS) $(CINC)
$(COMPILE) @HAVE_GMTOFF@ @HAVE_INT_TZ@ -c $<
$(COMPILE) @ATOMIC_OPS@ @HAVE_GMTOFF@ @HAVE_INT_TZ@ -c $<
Client.o: @srcdir@/Client.cpp $(MKDEPS) $(CLINC)
$(COMPILE) -c $<

View File

@ -3,7 +3,7 @@
* This file is part of the YATE Project http://YATE.null.ro
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2015-2023 Null Team
* Copyright (C) 2015 Null Team
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing
@ -57,14 +57,10 @@ static inline void unpackMsb8(uint8_t*& d, uint8_t val)
}
// Copy string, advance dest and src, return src
static inline const char* copyInc(char*& dest, const char* src, unsigned int n,
bool strLen = false)
static inline const char* copyInc(char*& dest, const char* src, unsigned int n)
{
if (n) {
if (strLen)
::strcpy(dest,src);
else
::strncpy(dest,src,n);
::strncpy(dest,src,n);
dest += n;
}
return src + n;
@ -104,11 +100,11 @@ String& RefStorage::dumpSplit(String& buf, const String& str, unsigned int lineL
const char* src = str.c_str();
src = copyInc(dest,src,firstLineLen);
for (; nFullLines; nFullLines--) {
copyInc(dest,linePrefix,linePrefLen,true);
copyInc(dest,linePrefix,linePrefLen);
src = copyInc(dest,src,lineLen);
}
if (lastLineLen) {
copyInc(dest,linePrefix,linePrefLen,true);
copyInc(dest,linePrefix,linePrefLen);
src = copyInc(dest,src,lastLineLen);
}
copyInc(dest,suffix,suffixLen);

View File

@ -3,7 +3,7 @@
* This file is part of the YATE Project http://YATE.null.ro
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2023 Null Team
* Copyright (C) 2004-2014 Null Team
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing
@ -237,8 +237,8 @@ int Message::commonDecode(const char* str, int offs)
MessageHandler::MessageHandler(const char* name, unsigned priority,
const char* trackName, bool addPriority)
: String(name),
m_trackName(trackName), m_trackNameOnly(trackName), m_priority(priority),
m_dispatcher(0), m_filter(0), m_counter(0)
m_trackName(trackName), m_priority(priority),
m_unsafe(0), m_dispatcher(0), m_filter(0), m_filterRegexp(0), m_counter(0)
{
DDebug(DebugAll,"MessageHandler::MessageHandler('%s',%u,'%s',%s) [%p]",
name,priority,trackName,String::boolText(addPriority),this);
@ -271,12 +271,9 @@ void MessageHandler::destruct()
void MessageHandler::safeNowInternal()
{
WLock lck(m_dispatcher ? &m_dispatcher->handlersLock() : 0);
Lock lock(m_dispatcher);
// when the unsafe counter reaches zero we're again safe to destroy
int v = --m_unsafe;
if (v < 0)
Debug(DebugFail,"MessageHandler(%s) unsafe=%d dispatcher=(%p) [%p]",
safe(),v,m_dispatcher,this);
m_unsafe--;
}
bool MessageHandler::receivedInternal(Message& msg)
@ -288,23 +285,19 @@ bool MessageHandler::receivedInternal(Message& msg)
void MessageHandler::setFilter(NamedString* filter)
{
Regexp* r = YOBJECT(Regexp,filter);
if (r)
setFilter(new MatchingItemRegexp(filter->name(),*r));
else if (filter)
setFilter(new MatchingItemString(filter->name(),*filter));
else
clearFilter();
TelEngine::destruct(filter);
clearFilter();
m_filter = filter;
m_filterRegexp = YOBJECT(Regexp,filter);
}
void MessageHandler::clearFilter()
{
if (!m_filter)
return;
MatchingItemBase* tmp = m_filter;
m_filter = 0;
TelEngine::destruct(tmp);
if (m_filter) {
NamedString* tmp = m_filter;
m_filter = 0;
m_filterRegexp = 0;
delete tmp;
}
}
@ -318,8 +311,8 @@ bool MessageRelay::receivedInternal(Message& msg)
MessageDispatcher::MessageDispatcher(const char* trackParam)
: m_handlersLock("DispatcherHandlers"), m_messagesLock("DispatcherMsgs"),
m_hooksLock("DispatcherHooks"),
: Mutex(false,"MessageDispatcher"),
m_hookMutex(false,"PostHooks"),
m_msgAppend(&m_messages), m_hookAppend(&m_hooks),
m_trackParam(trackParam), m_changes(0), m_warnTime(0),
m_enqueueCount(0), m_dequeueCount(0), m_dispatchCount(0),
@ -333,16 +326,9 @@ MessageDispatcher::MessageDispatcher(const char* trackParam)
MessageDispatcher::~MessageDispatcher()
{
XDebug(DebugInfo,"MessageDispatcher::~MessageDispatcher() [%p]",this);
lock();
clear();
}
void MessageDispatcher::clear()
{
WLock lck(m_handlersLock);
m_handlers.clear();
lck.acquire(m_hooksLock);
m_hookAppend = &m_hooks;
m_hooks.clear();
unlock();
}
bool MessageDispatcher::install(MessageHandler* handler)
@ -350,7 +336,7 @@ bool MessageDispatcher::install(MessageHandler* handler)
DDebug(DebugAll,"MessageDispatcher::install(%p)",handler);
if (!handler)
return false;
WLock lck(m_handlersLock);
Lock lock(this);
ObjList *l = m_handlers.find(handler);
if (l)
return false;
@ -386,7 +372,7 @@ bool MessageDispatcher::install(MessageHandler* handler)
bool MessageDispatcher::uninstall(MessageHandler* handler)
{
DDebug(DebugAll,"MessageDispatcher::uninstall(%p)",handler);
WLock lck(m_handlersLock);
lock();
handler = static_cast<MessageHandler *>(m_handlers.remove(handler,false));
if (handler) {
m_changes++;
@ -395,15 +381,16 @@ bool MessageDispatcher::uninstall(MessageHandler* handler)
handler,handler->c_str());
// wait until handler is again safe to destroy
do {
lck.drop();
unlock();
Thread::yield();
lck.acquire(m_handlersLock);
lock();
} while (handler->m_unsafe > 0);
}
if (handler->m_unsafe != 0)
Debug(DebugFail,"MessageHandler %p has unsafe=%d",handler,(int)handler->m_unsafe);
Debug(DebugFail,"MessageHandler %p has unsafe=%d",handler,handler->m_unsafe);
handler->m_dispatcher = 0;
}
unlock();
return (handler != 0);
}
@ -429,13 +416,19 @@ bool MessageDispatcher::dispatch(Message& msg)
unsigned int hTrackPos = 0;
bool hTrackTime = m_traceHandlerTime;
ObjList *l = &m_handlers;
RLock lck(m_handlersLock);
Lock mylock(this);
m_dispatchCount++;
for (; l; l=l->next()) {
MessageHandler *h = static_cast<MessageHandler*>(l->get());
if (h && (h->null() || *h == msg)) {
if (h->filter() && !h->filter()->matchListParam(msg))
continue;
if (h->filter()) {
if (h->filterRegexp()) {
if (!h->filterRegexp()->matches(msg.getValue(h->filter()->name())))
continue;
}
else if (*(h->filter()) != msg[h->filter()->name()])
continue;
}
if (counting)
Thread::setCurrentObjCounter(h->objectsCounter());
@ -454,7 +447,7 @@ bool MessageDispatcher::dispatch(Message& msg)
}
// mark handler as unsafe to destroy / uninstall
h->m_unsafe++;
lck.drop();
mylock.drop();
u_int64_t tm = (m_warnTime || hTrackTime) ? Time::now() : 0;
@ -463,7 +456,7 @@ bool MessageDispatcher::dispatch(Message& msg)
if (tm) {
tm = Time::now() - tm;
if (m_warnTime && tm > m_warnTime) {
lck.acquire(m_handlersLock);
mylock.acquire(this);
const char* name = (c == m_changes) ? h->trackName().c_str() : 0;
Debug(DebugInfo,"Message '%s' [%p] passed through %p%s%s%s in " FMT64U " usec",
msg.c_str(),&msg,h,
@ -489,7 +482,7 @@ bool MessageDispatcher::dispatch(Message& msg)
if (retv && !msg.broadcast())
break;
lck.acquire(m_handlersLock);
mylock.acquire(this);
if (c == m_changes)
continue;
// the handler list has changed - find again
@ -518,7 +511,7 @@ bool MessageDispatcher::dispatch(Message& msg)
break;
}
}
lck.drop();
mylock.drop();
if (counting)
Thread::setCurrentObjCounter(msg.getObjCounter());
msg.dispatched(retv);
@ -541,7 +534,7 @@ bool MessageDispatcher::dispatch(Message& msg)
}
}
lck.acquire(m_hooksLock);
m_hookMutex.lock();
if (m_hookHole && !m_hookCount) {
// compact the list, remove the holes
for (l = &m_hooks; l; l = l->next()) {
@ -559,16 +552,16 @@ bool MessageDispatcher::dispatch(Message& msg)
for (l = m_hooks.skipNull(); l; l = l->skipNext()) {
RefPointer<MessagePostHook> ph = static_cast<MessagePostHook*>(l->get());
if (ph) {
lck.drop();
m_hookMutex.unlock();
if (counting)
Thread::setCurrentObjCounter(ph->getObjCounter());
ph->dispatched(msg,retv);
ph = 0;
lck.acquire(m_hooksLock);
m_hookMutex.lock();
}
}
m_hookCount--;
lck.drop();
m_hookMutex.unlock();
if (counting)
Thread::setCurrentObjCounter(saved);
@ -577,7 +570,7 @@ bool MessageDispatcher::dispatch(Message& msg)
bool MessageDispatcher::enqueue(Message* msg)
{
WLock lck(m_messagesLock);
Lock lock(this);
if (!msg || m_messages.find(msg))
return false;
if (m_traceTime)
@ -591,17 +584,19 @@ bool MessageDispatcher::enqueue(Message* msg)
bool MessageDispatcher::dequeueOne()
{
WLock lck(m_messagesLock);
lock();
if (m_messages.next() == m_msgAppend)
m_msgAppend = &m_messages;
Message* msg = static_cast<Message *>(m_messages.remove(false));
if (msg) {
m_dequeueCount++;
uint64_t age = Time::now() - msg->msgTime();
if (age < 60000000)
m_msgAvgAge = (3 * m_msgAvgAge + age) >> 2;
}
unlock();
if (!msg)
return false;
m_dequeueCount++;
uint64_t age = Time::now() - msg->msgTime();
if (age < 60000000)
m_msgAvgAge = (3 * m_msgAvgAge + age) >> 2;
lck.drop();
dispatch(*msg);
msg->destruct();
return true;
@ -615,35 +610,35 @@ void MessageDispatcher::dequeue()
unsigned int MessageDispatcher::messageCount()
{
RLock lck(m_messagesLock);
Lock lock(this);
return (unsigned int)(m_enqueueCount - m_dequeueCount);
}
unsigned int MessageDispatcher::handlerCount()
{
RLock lck(m_handlersLock);
Lock lock(this);
return m_handlers.count();
}
unsigned int MessageDispatcher::postHookCount()
{
RLock lck(m_hooksLock);
Lock lock(m_hookMutex);
return m_hooks.count();
}
void MessageDispatcher::getStats(u_int64_t& enqueued, u_int64_t& dequeued, u_int64_t& dispatched, u_int64_t& queueMax)
{
RLock lck(m_messagesLock);
lock();
enqueued = m_enqueueCount;
dequeued = m_dequeueCount;
queueMax = m_queuedMax;
lck.acquire(m_handlersLock);
dispatched = m_dispatchCount;
queueMax = m_queuedMax;
unlock();
}
void MessageDispatcher::setHook(MessagePostHook* hook, bool remove)
{
WLock lck(m_hooksLock);
m_hookMutex.lock();
if (remove) {
// zero the hook, we'll compact it later when safe
ObjList* l = m_hooks.find(hook);
@ -654,30 +649,7 @@ void MessageDispatcher::setHook(MessagePostHook* hook, bool remove)
}
else
m_hookAppend = m_hookAppend->append(hook);
}
unsigned int MessageDispatcher::fillHandlersInfo(bool byName, const String& match,
String* details, unsigned int* total)
{
unsigned int n = 0;
unsigned int matched = 0;
String tmp;
RLock lck(m_handlersLock);
for (ObjList* o = m_handlers.skipNull(); o; o = o->skipNext()) {
n++;
MessageHandler *h = static_cast<MessageHandler*>(o->get());
if (!match.matches(byName ? (const String&)(*h): h->trackNameOnly()))
continue;
matched++;
if (!details)
continue;
tmp.printf("%s=%u|%s|%s",h->safe(),h->priority(),h->trackNameOnly().safe(),
h->filter() ? "yes" : "no");
details->append(tmp,",");
}
if (total)
*total = n;
return matched;
m_hookMutex.unlock();
}

View File

@ -3,7 +3,7 @@
* This file is part of the YATE Project http://YATE.null.ro
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2023 Null Team
* Copyright (C) 2004-2014 Null Team
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing

View File

@ -3,7 +3,7 @@
* This file is part of the YATE Project http://YATE.null.ro
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2023 Null Team
* Copyright (C) 2004-2014 Null Team
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing
@ -43,7 +43,6 @@ extern int pthread_mutexattr_settype(pthread_mutexattr_t *__attr, int __kind) __
typedef pthread_mutex_t HMUTEX;
typedef sem_t HSEMAPHORE;
typedef pthread_rwlock_t rwlock_t;
#endif /* ! _WINDOWS */
@ -56,32 +55,7 @@ typedef pthread_rwlock_t rwlock_t;
namespace TelEngine {
class LockablePrivateBase
{
public:
inline LockablePrivateBase(const char* name)
: m_name(name ? name : ""), m_owner(0), m_ownerName(0)
{}
inline const char* name() const
{ return m_name; }
inline Thread* owner() const
{ return m_owner; }
inline const char* ownerName() const
{ return m_ownerName; }
protected:
inline void setOwner(Thread* th = 0) {
m_owner = th;
m_ownerName = th ? th->name() : "";
}
private:
const char* m_name;
Thread* m_owner;
const char* m_ownerName;
};
class MutexPrivate : public LockablePrivateBase
{
class MutexPrivate {
public:
MutexPrivate(bool recursive, const char* name);
~MutexPrivate();
@ -91,6 +65,10 @@ public:
{ if (!--m_refcount) delete this; }
inline bool recursive() const
{ return m_recursive; }
inline const char* name() const
{ return m_name; }
inline const char* owner() const
{ return m_owner; }
bool locked() const
{ return (m_locked > 0); }
bool lock(long maxwait);
@ -103,6 +81,8 @@ private:
volatile unsigned int m_locked;
volatile unsigned int m_waiting;
bool m_recursive;
const char* m_name;
const char* m_owner;
};
class SemaphorePrivate {
@ -129,40 +109,6 @@ private:
const char* m_name;
};
class RWLockPrivate : public LockablePrivateBase
{
public:
RWLockPrivate(const char* name);
~RWLockPrivate();
inline void ref()
{ ++m_refcount; }
inline void deref()
{ if (!--m_refcount) delete this; }
inline Thread* owner() const
{ return m_nonRWLck ? m_nonRWLck->owner() : LockablePrivateBase::owner(); }
inline const char* ownerName() const
{ return m_nonRWLck ? m_nonRWLck->ownerName() : LockablePrivateBase::ownerName(); }
inline bool locked() const
{ return m_nonRWLck ? m_nonRWLck->locked() : (m_locked > 0); }
bool readLock(long maxWait = -1);
bool writeLock(long maxWwait = -1);
bool unlock();
static volatile int s_count;
static volatile int s_locks;
private:
#ifdef _WINDOWS
// we use m_nonRWLck
#else
rwlock_t m_lock;
#endif
MutexPrivate* m_nonRWLck;
int m_refcount;
unsigned int m_locked;
#ifndef ATOMIC_OPS
Mutex m_mutex;
#endif
};
class GlobalMutex {
public:
GlobalMutex();
@ -183,18 +129,11 @@ static GlobalMutex s_global;
static unsigned long s_maxwait = 0;
static bool s_unsafe = MUTEX_STATIC_UNSAFE;
static bool s_safety = false;
#ifdef _WINDOWS
static bool s_rwLockDisabled = true;
#else
static bool s_rwLockDisabled = false;
#endif
volatile int MutexPrivate::s_count = 0;
volatile int MutexPrivate::s_locks = 0;
volatile int SemaphorePrivate::s_count = 0;
volatile int SemaphorePrivate::s_locks = 0;
volatile int RWLockPrivate::s_count = 0;
volatile int RWLockPrivate::s_locks = 0;
bool GlobalMutex::s_init = true;
// WARNING!!!
@ -247,8 +186,8 @@ void GlobalMutex::unlock()
MutexPrivate::MutexPrivate(bool recursive, const char* name)
: LockablePrivateBase(name),
m_refcount(1), m_locked(0), m_waiting(0), m_recursive(recursive)
: m_refcount(1), m_locked(0), m_waiting(0), m_recursive(recursive),
m_name(name), m_owner(0)
{
GlobalMutex::lock();
s_count++;
@ -293,11 +232,11 @@ MutexPrivate::~MutexPrivate()
#endif
GlobalMutex::unlock();
if (m_locked || m_waiting)
Debug(DebugFail,"MutexPrivate '%s' owned by '%s' (%p) destroyed with %u locks, %u waiting [%p]",
name(),ownerName(),owner(),m_locked,m_waiting,this);
Debug(DebugFail,"MutexPrivate '%s' owned by '%s' destroyed with %u locks, %u waiting [%p]",
m_name,m_owner,m_locked,m_waiting,this);
else if (warn)
Debug(DebugCrit,"MutexPrivate '%s' owned by '%s' (%p) unlocked in destructor [%p]",
name(),ownerName(),owner(),this);
Debug(DebugCrit,"MutexPrivate '%s' owned by '%s' unlocked in destructor [%p]",
m_name,m_owner,this);
}
bool MutexPrivate::lock(long maxwait)
@ -368,16 +307,18 @@ bool MutexPrivate::lock(long maxwait)
if (safety)
s_locks++;
m_locked++;
setOwner(thr);
if (thr)
if (thr) {
thr->m_locks++;
m_owner = thr->name();
}
else
m_owner = 0;
}
if (safety)
GlobalMutex::unlock();
if (warn && !rval)
Debug(DebugFail,
"Thread '%s' could not lock mutex '%s' owned by '%s' (%p) waited by %u others for %lu usec!",
Thread::currentName(),name(),ownerName(),owner(),m_waiting,maxwait);
Debug(DebugFail,"Thread '%s' could not lock mutex '%s' owned by '%s' waited by %u others for %lu usec!",
Thread::currentName(),m_name,m_owner,m_waiting,maxwait);
return rval;
}
@ -393,10 +334,11 @@ bool MutexPrivate::unlock()
if (thr)
thr->m_locks--;
if (!--m_locked) {
if (thr != owner())
Debug(DebugFail,"MutexPrivate '%s' unlocked by '%s' (%p) but owned by '%s' (%p) [%p]",
name(),thr ? thr->name() : "",thr,ownerName(),owner(),this);
setOwner();
const char* tname = thr ? thr->name() : 0;
if (tname != m_owner)
Debug(DebugFail,"MutexPrivate '%s' unlocked by '%s' but owned by '%s' [%p]",
m_name,tname,m_owner,this);
m_owner = 0;
}
if (safety) {
int locks = --s_locks;
@ -413,10 +355,10 @@ bool MutexPrivate::unlock()
ok = s_unsafe || !::pthread_mutex_unlock(&m_mutex);
#endif
if (!ok)
Debug(DebugFail,"Failed to unlock mutex '%s' [%p]",name(),this);
Debug(DebugFail,"Failed to unlock mutex '%s' [%p]",m_name,this);
}
else
Debug(DebugFail,"MutexPrivate::unlock called on unlocked '%s' [%p]",name(),this);
Debug(DebugFail,"MutexPrivate::unlock called on unlocked '%s' [%p]",m_name,this);
if (safety)
GlobalMutex::unlock();
return ok;
@ -664,7 +606,7 @@ bool Mutex::locked() const
const char* Mutex::owner() const
{
return m_private ? m_private->ownerName() : static_cast<const char*>(0);
return m_private ? m_private->owner() : static_cast<const char*>(0);
}
int Mutex::count()
@ -827,376 +769,4 @@ void Lock2::drop()
mx1->unlock();
}
RWLockPrivate::RWLockPrivate(const char* name)
: LockablePrivateBase(name),
m_nonRWLck(0), m_refcount(1), m_locked(0)
#ifndef ATOMIC_OPS
, m_mutex(true,"RWLockPrivate")
#endif
{
if (s_rwLockDisabled) {
m_nonRWLck = new MutexPrivate(true,name);
return;
}
GlobalMutex::lock();
s_count++;
#ifdef _WINDOWS
// not implemented, uses m_nonRWLck
#else
::pthread_rwlock_init(&m_lock,0);
#endif
GlobalMutex::unlock();
}
RWLockPrivate::~RWLockPrivate()
{
if (m_nonRWLck) {
delete m_nonRWLck;
m_nonRWLck = 0;
return;
}
bool warn = false;
GlobalMutex::lock();
if (m_locked) {
warn = true;
--m_locked;
if (s_safety)
--s_locks;
#ifdef _WINDOWS
// not implemented, uses m_nonRWLck
#else
::pthread_rwlock_unlock(&m_lock);
#endif
}
s_count--;
#ifdef _WINDOWS
// not implemented, uses m_nonRWLck
#else
::pthread_rwlock_destroy(&m_lock);
#endif
GlobalMutex::unlock();
if (m_locked)
Debug(DebugFail,"RWLockPrivate '%s' owned by '%s' (%p) destroyed with %u locks [%p]",
name(),ownerName(),owner(),m_locked,this);
else if (warn)
Debug(DebugCrit,"RWLockPrivate '%s' owned by '%s' (%p) unlocked in destructor [%p]",
name(),ownerName(),owner(),this);
}
bool RWLockPrivate::readLock(long maxwait)
{
if (m_nonRWLck)
return m_nonRWLck->lock(maxwait);
int ret = -1;
bool warn = false;
if (s_maxwait && (maxwait < 0)) {
maxwait = (long)s_maxwait;
warn = true;
}
bool safety = s_safety;
if (safety)
GlobalMutex::lock();
Thread* thr = Thread::current();
if (thr)
thr->m_locking = true;
if (safety)
GlobalMutex::unlock();
#ifdef _WINDOWS
// not implemented, uses m_nonRWLck
#else
if (s_unsafe)
ret = 0;
if (maxwait < 0)
ret = ::pthread_rwlock_rdlock(&m_lock);
else if (!maxwait)
ret = ::pthread_rwlock_tryrdlock(&m_lock);
else {
u_int64_t t = Time::now() + maxwait;
#ifdef HAVE_TIMEDRDLOCK
struct timeval tv;
struct timespec ts;
Time::toTimeval(&tv,t);
ts.tv_sec = tv.tv_sec;
ts.tv_nsec = 1000 * tv.tv_usec;
ret = ::pthread_rwlock_timedrdlock(&m_lock,&ts);
#else
bool dead = false;
do {
if (!dead) {
dead = Thread::check(false);
// give up only if caller asked for a limited wait
if (dead && !warn)
break;
}
ret = ::pthread_rwlock_tryrdlock(&m_lock);
if (!ret)
break;
Thread::yield();
} while (t > Time::now());
#endif
}
#endif // _WINDOWS
if (safety)
GlobalMutex::lock();
if (thr)
thr->m_locking = false;
if (!ret) {
if (safety)
++s_locks;
#ifdef ATOMIC_OPS
#ifdef _WINDOWS
InterlockedIncrement((LONG*)&m_locked);
#else
__sync_add_and_fetch(&m_locked,1);
#endif
#else
m_mutex.lock();
++m_locked;
m_mutex.unlock();
#endif
if (thr)
++thr->m_locks;
}
if (safety)
GlobalMutex::unlock();
if (warn && ret)
Debug(DebugFail,"Thread '%s' could not lock for read RW lock '%s'"
" writing-owned by '%s' (%p) after waiting for %ld usec! [%p]",
Thread::currentName(),name(),ownerName(),owner(),maxwait,this);
return ret == 0;
}
bool RWLockPrivate::writeLock(long maxwait)
{
if (m_nonRWLck)
return m_nonRWLck->lock(maxwait);
int ret = -1;
bool warn = false;
if (s_maxwait && (maxwait < 0)) {
maxwait = (long)s_maxwait;
warn = true;
}
bool safety = s_safety;
if (safety)
GlobalMutex::lock();
Thread* thr = Thread::current();
if (thr)
thr->m_locking = true;
if (safety)
GlobalMutex::unlock();
#ifdef _WINDOWS
// not implemented, uses m_nonRWLck
#else
if (s_unsafe)
ret = 0;
if (maxwait < 0)
ret = ::pthread_rwlock_wrlock(&m_lock);
else if (!maxwait)
ret = ::pthread_rwlock_trywrlock(&m_lock);
else {
u_int64_t t = Time::now() + maxwait;
#ifdef HAVE_TIMEDWRLOCK
struct timeval tv;
struct timespec ts;
Time::toTimeval(&tv,t);
ts.tv_sec = tv.tv_sec;
ts.tv_nsec = 1000 * tv.tv_usec;
ret = ::pthread_rwlock_timedwrlock(&m_lock,&ts);
#else
bool dead = false;
do {
if (!dead) {
dead = Thread::check(false);
// give up only if caller asked for a limited wait
if (dead && !warn)
break;
}
ret = ::pthread_rwlock_trywrlock(&m_lock);
if (!ret)
break;
Thread::yield();
} while (t > Time::now());
#endif
}
#endif
if (safety)
GlobalMutex::lock();
if (thr)
thr->m_locking = false;
if (!ret) {
if (safety)
++s_locks;
#ifdef ATOMIC_OPS
#ifdef _WINDOWS
InterlockedIncrement((LONG*)&m_locked);
#else
__sync_add_and_fetch(&m_locked,1);
#endif
#else
m_mutex.lock();
++m_locked;
m_mutex.unlock();
#endif
setOwner(thr);
if (thr)
++thr->m_locks;
}
if (safety)
GlobalMutex::unlock();
if (warn && ret)
Debug(DebugFail,"Thread '%s' could not lock for write RW lock '%s'"
" writing-owned by '%s' (%p) after waiting for %ld usec! [%p]",
Thread::currentName(),name(),ownerName(),name(),maxwait,this);
return ret == 0;
}
bool RWLockPrivate::unlock()
{
if (m_nonRWLck)
return m_nonRWLck->unlock();
int ok = -1;
bool safety = s_safety;
if (safety)
GlobalMutex::lock();
if (m_locked) {
Thread* thr = Thread::current();
if (thr)
--thr->m_locks;
#ifdef ATOMIC_OPS
#ifdef _WINDOWS
int l = InterlockedDecrement((LONG*)&m_locked);
#else
int l = __sync_sub_and_fetch(&m_locked,1);
#endif
#else
m_mutex.lock();
int l = --m_locked;
m_mutex.unlock();
#endif
if (!l) {
if (owner() && owner() != thr)
Debug(DebugFail,"RWLockPrivate '%s' unlocked by '%s' (%p) but owned by '%s' (%p) [%p]",
name(),thr ? thr->name() : "",thr,ownerName(),owner(),this);
setOwner();
}
if (safety) {
int locks = --s_locks;
if (locks < 0) {
// this is very very bad - abort right now
abortOnBug(true);
s_locks = 0;
Debug(DebugFail,"RWLockPrivate::locks() is %d [%p]",locks,this);
}
}
#ifdef _WINDOWS
// not implemented, uses m_nonRWLck
#else
ok = s_unsafe ? 0 : ::pthread_rwlock_unlock(&m_lock);
#endif
if (ok)
Debug(DebugFail,"Thread '%s' failed to unlock RW lock '%s' owned by '%s' (%p) [%p]",
Thread::currentName(),name(),ownerName(),owner(),this);
}
else {
Debug(DebugFail,
"Thread '%s' could not unlock already unlocked RW lock '%s' writing-owned by '%s' (%p) [%p]",
Thread::currentName(),name(),ownerName(),owner(),this);
}
if (safety)
GlobalMutex::unlock();
return ok == 0;
}
/**
* class RWLock
*/
RWLock::RWLock(const char* name)
{
m_private = new RWLockPrivate(name ? name : "?");
}
RWLock::RWLock(const RWLock& original)
: Lockable(),
m_private(original.privDataCopy())
{
}
RWLock::~RWLock()
{
RWLockPrivate* priv = m_private;
m_private = 0;
if (priv)
priv->deref();
}
bool RWLock::readLock(long maxwait)
{
return m_private && m_private->readLock(maxwait);
}
bool RWLock::writeLock(long maxwait)
{
return m_private && m_private->writeLock(maxwait);
}
bool RWLock::unlock()
{
return m_private && m_private->unlock();
}
bool RWLock::locked() const
{
return m_private && m_private->locked();
}
void RWLock::disableRWLock(bool disable)
{
#ifdef _WINDOWS
// we disable RWLock usage as it is not implemented
s_rwLockDisabled = true;
#else
s_rwLockDisabled = disable;
#endif
}
RWLockPrivate* RWLock::privDataCopy() const
{
if (m_private)
m_private->ref();
return m_private;
}
RWLockPool::RWLockPool(unsigned int len, const char* name)
: m_name(0), m_data(0), m_length(len ? len : 1)
{
if (TelEngine::null(name))
name = "Pool";
m_name = new String[m_length];
m_data = new RWLock*[m_length];
for (unsigned int i = 0; i < m_length; i++) {
m_name[i] << name << "::" << (i + 1);
m_data[i] = new RWLock(m_name[i]);
}
}
RWLockPool::~RWLockPool()
{
if (m_data) {
for (unsigned int i = 0; i < m_length; i++)
delete m_data[i];
delete[] m_data;
}
if (m_name)
delete[] m_name;
}
/* vi: set ts=8 sw=4 sts=4 noet: */

View File

@ -3,7 +3,7 @@
* This file is part of the YATE Project http://YATE.null.ro
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2023 Null Team
* Copyright (C) 2004-2014 Null Team
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing
@ -18,7 +18,6 @@
*/
#include "yateclass.h"
#include "yatexml.h"
using namespace TelEngine;
@ -37,7 +36,11 @@ NamedList::NamedList(const char* name)
NamedList::NamedList(const NamedList& original)
: String(original)
{
copyParams(false,original);
ObjList* dest = &m_params;
for (const ObjList* l = original.m_params.skipNull(); l; l = l->skipNext()) {
const NamedString* p = static_cast<const NamedString*>(l->get());
dest = dest->append(new NamedString(p->name(),*p));
}
}
NamedList::NamedList(const char* name, const NamedList& original, const String& prefix)
@ -77,135 +80,30 @@ NamedList& NamedList::addParam(const char* name, const char* value, bool emptyOK
return *this;
}
NamedList& NamedList::setParam(NamedString* param)
NamedList& NamedList::setParam(const String& name, const char* value)
{
XDebug(DebugAll,"NamedList::setParam(%p) [%p]",param,this);
if (!param)
return *this;
ObjList* o = m_params.skipNull();
while (o) {
NamedString* s = static_cast<NamedString*>(o->get());
if (s->name() == param->name()) {
o->set(param);
XDebug(DebugInfo,"NamedList::setParam(\"%s\",\"%s\")",name.c_str(),value);
ObjList *p = m_params.skipNull();
while (p) {
NamedString *s = static_cast<NamedString*>(p->get());
if (s->name() == name) {
*s = value;
return *this;
}
ObjList* next = o->skipNext();
ObjList* next = p->skipNext();
if (next)
o = next;
p = next;
else
break;
}
if (o)
o->append(param);
if (p)
p->append(new NamedString(name,value));
else
m_params.append(param);
return *this;
m_params.append(new NamedString(name,value));
return *this;
}
static inline NamedString* nlSetParamCreate(NamedList& list, const String& name, ObjList*& append)
{
append = list.paramList()->skipNull();
while (append) {
NamedString* ns = static_cast<NamedString*>(append->get());
if (ns->name() == name) {
append = 0;
return ns;
}
ObjList* next = append->skipNext();
if (!next)
return new NamedString(name);
append = next;
}
append = list.paramList();
return new NamedString(name);
}
NamedList& NamedList::setParam(const String& name, unsigned int flags, const TokenDict* tokens,
bool unknownflag)
{
XDebug(DebugAll,"NamedList::setParam(%s) flags=%u tokens=%p unkFlag=%u [%p]",
name.safe(),flags,tokens,unknownflag,this);
ObjList* append = 0;
NamedString* ns = nlSetParamCreate(*this,name,append);
*static_cast<String*>(ns) = "";
ns->decodeFlags(flags,tokens,unknownflag);
if (append)
append->append(ns);
return *this;
}
NamedList& NamedList::setParam(const String& name, uint64_t flags, const TokenDict64* tokens,
bool unknownflag)
{
XDebug(DebugAll,"NamedList::setParam(%s) flags64=" FMT64U " tokens=%p unkFlag=%u [%p]",
name.safe(),flags,tokens,unknownflag,this);
ObjList* append = 0;
NamedString* ns = nlSetParamCreate(*this,name,append);
*static_cast<String*>(ns) = "";
ns->decodeFlags(flags,tokens,unknownflag);
if (append)
append->append(ns);
return *this;
}
NamedList& NamedList::setParamHex(const String& name, const void* buf, unsigned int len, char sep)
{
XDebug(DebugAll,"NamedList::setParamHex(%s,%p,%u,%c) [%p]",name.safe(),buf,len,sep,this);
ObjList* append = 0;
NamedString* ns = nlSetParamCreate(*this,name,append);
ns->hexify((void*)buf,len,sep);
if (append)
append->append(ns);
return *this;
}
template <class Obj> NamedList& nlSetParamValue(NamedList& list, const String& name, Obj& value)
{
ObjList* append = 0;
NamedString* ns = nlSetParamCreate(list,name,append);
*static_cast<String*>(ns) = value;
if (append)
append->append(ns);
return list;
}
NamedList& NamedList::setParam(const String& name, const char* value)
{
XDebug(DebugAll,"NamedList::setParam('%s','%s') [%p]",name.c_str(),value,this);
return nlSetParamValue(*this,name,value);
}
NamedList& NamedList::setParam(const String& name, int64_t value)
{
XDebug(DebugAll,"NamedList::setParam(%s) INT64=" FMT64 " [%p]",name.c_str(),value,this);
return nlSetParamValue(*this,name,value);
}
NamedList& NamedList::setParam(const String& name, uint64_t value)
{
XDebug(DebugAll,"NamedList::setParam(%s) UINT64=" FMT64U " [%p]",name.c_str(),value,this);
return nlSetParamValue(*this,name,value);
}
NamedList& NamedList::setParam(const String& name, int32_t value)
{
XDebug(DebugAll,"NamedList::setParam(%s) INT32=%d [%p]",name.c_str(),value,this);
return nlSetParamValue(*this,name,value);
}
NamedList& NamedList::setParam(const String& name, uint32_t value)
{
XDebug(DebugAll,"NamedList::setParam(%s) UINT32=%u [%p]",name.c_str(),value,this);
return nlSetParamValue(*this,name,value);
}
NamedList& NamedList::setParam(const String& name, double value)
{
XDebug(DebugAll,"NamedList::setParam(%s) DOUBLE=%f [%p]",name.c_str(),value,this);
return nlSetParamValue(*this,name,value);
}
NamedList& NamedList::clearParam(const String& name, char childSep, const String* value)
NamedList& NamedList::clearParam(const String& name, char childSep)
{
XDebug(DebugInfo,"NamedList::clearParam(\"%s\",'%.1s')",
name.c_str(),&childSep);
@ -215,8 +113,7 @@ NamedList& NamedList::clearParam(const String& name, char childSep, const String
ObjList *p = &m_params;
while (p) {
NamedString *s = static_cast<NamedString *>(p->get());
if (s && ((s->name() == name) || s->name().startsWith(tmp))
&& (!value || value->matches(*s)))
if (s && ((s->name() == name) || s->name().startsWith(tmp)))
p->remove();
else
p = p->next();
@ -257,37 +154,12 @@ NamedList& NamedList::copyParam(const NamedList& original, const String& name, c
return *this;
}
static inline NamedString* nlCopyParam(const NamedString& param)
NamedList& NamedList::copyParams(const NamedList& original)
{
NamedPointer* np = YOBJECT(NamedPointer,&param);
if (!(np && np->userData()))
return 0;
GenObject* ud = 0;
#define NP_COPY_PARAM_INTERNAL(Type) \
ud = YOBJECT(Type,np->userData()); \
if (ud) \
return new NamedPointer(np->name(),new Type(*(Type*)ud),*np)
NP_COPY_PARAM_INTERNAL(DataBlock);
NP_COPY_PARAM_INTERNAL(XmlElement);
#undef NP_COPY_PARAM_INTERNAL
return 0;
}
NamedList& NamedList::copyParams(bool replace, const NamedList& original, bool copyUserData)
{
XDebug(DebugInfo,"NamedList::copyParams(%p,%u) [%p]",&original,replace,this);
ObjList* append = replace ? 0 : &m_params;
XDebug(DebugInfo,"NamedList::copyParams(%p) [%p]",&original,this);
for (const ObjList* l = original.m_params.skipNull(); l; l = l->skipNext()) {
const NamedString* p = static_cast<const NamedString*>(l->get());
NamedString* ns = 0;
if (copyUserData)
ns = nlCopyParam(*p);
if (!ns)
ns = new NamedString(p->name(),*p);
if (append)
append = append->append(ns);
else
setParam(ns);
setParam(p->name(),*p);
}
return *this;
}

View File

@ -3,7 +3,7 @@
* This file is part of the YATE Project http://YATE.null.ro
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2023 Null Team
* Copyright (C) 2004-2014 Null Team
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing
@ -18,7 +18,6 @@
*/
#include "yateclass.h"
#include <string.h>
using namespace TelEngine;
@ -487,47 +486,6 @@ unsigned int ObjVector::assign(ObjList& list, bool move, unsigned int maxLen)
return maxLen;
}
static inline void clearObjVector(GenObject** objs, unsigned int len)
{
while (len--) {
TelEngine::destruct(*objs);
objs++;
}
}
unsigned int ObjVector::resize(unsigned int len, bool keepData)
{
if (!len) {
clear();
return length();
}
if (len == length()) {
if (!keepData) {
if (m_delete)
clearObjVector(m_objects,length());
::memset(m_objects,0,length() * sizeof(GenObject*));
}
return length();
}
GenObject** buf = new GenObject*[len];
if (!(keepData && length()))
::memset(buf,0,len * sizeof(GenObject*));
else if (len < length()) {
::memcpy(buf,m_objects,len * sizeof(GenObject*));
::memset(m_objects,0,len * sizeof(GenObject*));
}
else {
::memcpy(buf,m_objects,length() * sizeof(GenObject*));
::memset(m_objects,0,length() * sizeof(GenObject*));
if (len > length())
::memset(buf + length(),0,(len - length()) * sizeof(GenObject*));
}
clear();
m_objects = buf;
m_length = len;
return length();
}
unsigned int ObjVector::count() const
{
if (!m_objects)
@ -600,8 +558,10 @@ void ObjVector::clear()
unsigned int len = m_length;
m_length = 0;
m_objects = 0;
if (m_delete && objs)
clearObjVector(objs,len);
if (m_delete && objs) {
for (unsigned int i = 0; i < len; i++)
TelEngine::destruct(objs[i]);
}
delete[] objs;
}

View File

@ -3,7 +3,7 @@
* This file is part of the YATE Project http://YATE.null.ro
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2023 Null Team
* Copyright (C) 2004-2014 Null Team
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing

View File

@ -3,7 +3,7 @@
* This file is part of the YATE Project http://YATE.null.ro
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2023 Null Team
* Copyright (C) 2004-2014 Null Team
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing

View File

@ -3,7 +3,7 @@
* This file is part of the YATE Project http://YATE.null.ro
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2023 Null Team
* Copyright (C) 2004-2014 Null Team
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing
@ -231,8 +231,6 @@ const TokenDict SocketAddr::s_familyName[] = {
{0,0},
};
const char* SocketAddr::s_ifaceNameExtraEscape = ".:[]";
SocketAddr::SocketAddr(const struct sockaddr* addr, socklen_t len)
: m_address(0), m_length(0)
{
@ -267,9 +265,7 @@ void SocketAddr::clear()
{
m_length = 0;
m_host.clear();
m_iface.clear();
m_addr.clear();
m_addrFull.clear();
void* tmp = m_address;
m_address = 0;
if (tmp)
@ -436,15 +432,7 @@ bool SocketAddr::host(const String& name)
}
switch (family()) {
case AF_INET:
if (name.find('%') >= 0) {
String tmp, ifc;
splitIface(name,tmp,&ifc);
if (host(tmp)) {
iface(ifc,true);
return true;
}
}
else {
{
in_addr_t a = inet_addr(name);
if (a == INADDR_NONE) {
#ifdef HAVE_GHBN_R
@ -470,7 +458,6 @@ bool SocketAddr::host(const String& name)
}
if (a != INADDR_NONE) {
((struct sockaddr_in*)m_address)->sin_addr.s_addr = a;
m_iface.clear();
stringify();
return true;
}
@ -479,30 +466,25 @@ bool SocketAddr::host(const String& name)
#ifdef AF_INET6
case AF_INET6:
if (name.find('%') >= 0) {
String tmp, ifc;
splitIface(name,tmp,&ifc);
String tmp, iface;
splitIface(name,tmp,&iface);
if (!host(tmp))
break;
if (ifc && iface(ifc,true)) {
return false;
if (iface)
#ifndef _WINDOWS
scopeId(if_nametoindex(m_iface));
scopeId(if_nametoindex(iface));
#else
scopeId(m_iface.toInteger(0,0,0));
scopeId(iface.toInteger(0,0,0));
#endif
}
else
m_iface.clear();
return true;
}
#ifdef HAVE_PTON
if (inet_pton(family(),name,&((struct sockaddr_in6*)m_address)->sin6_addr) > 0) {
m_iface.clear();
stringify();
return true;
}
#endif
if (resolveIPv6(m_address,name)) {
m_iface.clear();
stringify();
return true;
}
@ -511,12 +493,11 @@ bool SocketAddr::host(const String& name)
#ifdef HAS_AF_UNIX
case AF_UNIX:
if (name.length() >= (UNIX_PATH_MAX-1))
break;
return false;
::strcpy(((struct sockaddr_un*)m_address)->sun_path,name.c_str());
stringify();
return true;
#endif
break;
}
return false;
}
@ -527,20 +508,15 @@ int SocketAddr::family(const String& addr)
if (!addr)
return Unknown;
bool ipv6 = false;
int percent = -1;
for (unsigned int i = 0; i < addr.length(); i++) {
if (addr[i] == '/')
return Unix;
if (addr[i] == ':')
ipv6 = true;
else if (percent < 0 && addr[i] == '%')
percent = i;
}
if (ipv6)
return IPv6;
if (!percent)
return Unknown;
in_addr_t a = percent < 0 ? inet_addr(addr) : inet_addr(addr.substr(0,percent));
in_addr_t a = inet_addr(addr);
if (a != INADDR_NONE || addr == YSTRING("255.255.255.255"))
return IPv4;
return Unknown;
@ -607,23 +583,13 @@ int SocketAddr::copyAddr(uint8_t* buf, struct sockaddr* addr)
}
// Append an address to a buffer
String& SocketAddr::appendAddr(String& buf, const String& addr, int family, const String& iface)
String& SocketAddr::appendAddr(String& buf, const String& addr, int family)
{
if (!addr)
return buf;
// Address already starts with [
if (addr[0] == '[') {
if (!iface)
return buf << addr;
char last = (addr[addr.length() - 1] == ']') ? ']' : 0;
if (last)
buf.append(addr.c_str(),addr.length() - 1);
else
buf << addr;
buf << '%';
escapeIface(buf,iface);
if (last)
buf << last;
buf << addr;
return buf;
}
if (family == Unknown) {
@ -635,19 +601,10 @@ String& SocketAddr::appendAddr(String& buf, const String& addr, int family, cons
family = IPv6;
}
}
if (!iface) {
if (family != IPv6)
return buf << addr;
return buf << '[' << addr << ']';
}
char last = (family != IPv6) ? 0 : ']';
if (last)
buf << '[' << addr << '%';
if (family != IPv6)
buf << addr;
else
buf << addr << '%';
escapeIface(buf,iface);
if (last)
buf << last;
buf << "[" << addr << "]";
return buf;
}
@ -683,8 +640,8 @@ void SocketAddr::splitIface(const String& buf, String& addr, String* iface)
}
else {
if (iface)
iface->assign(buf.c_str() + pos + 1,buf.length() - pos - 1);
addr.assign(buf.c_str(),pos);
*iface = buf.substr(pos + 1);
addr = buf.substr(0,pos);
}
}
@ -699,7 +656,7 @@ void SocketAddr::split(const String& buf, String& addr, int& port, bool portPres
if (buf[0] == '[') {
int p = buf.find(']',1);
if (p >= 1) {
if (buf[p + 1] == ':')
if (p < ((int)buf.length() - 1) && buf[p + 1] == ':')
port = buf.substr(p + 2).toInteger();
addr.assign(buf.c_str() + 1,p - 1);
return;
@ -740,22 +697,15 @@ void SocketAddr::stringify()
{
m_host.clear();
m_addr.clear();
m_addrFull.clear();
if (m_length && m_address)
stringify(m_host,m_address);
}
// Store host:port in m_addr
void SocketAddr::updateAddr(bool full) const
void SocketAddr::updateAddr() const
{
if (full) {
m_addrFull.clear();
appendTo(m_addrFull,host(),port(),family(),m_iface);
}
else {
m_addr.clear();
appendTo(m_addr,host(),port(),family());
}
m_addr.clear();
appendTo(m_addr,host(),port(),family());
}
int SocketAddr::port() const
@ -790,7 +740,6 @@ bool SocketAddr::port(int newport)
return false;
}
m_addr.clear();
m_addrFull.clear();
return true;
}
@ -1624,24 +1573,6 @@ bool File::listDirectory(const char* path, ObjList* dirs, ObjList* files, int* e
}
unsigned int Socket::s_features = 0
#ifdef IPPROTO_IPV6
| FProtoIpv6
#endif
#ifdef IPV6_V6ONLY
| FIpv6Only
#endif
#ifdef SO_BINDTODEVICE
| FBindToIface
#endif
#if defined(_WINDOWS) || defined(HAVE_POLL)
| FEfficientSelect
#endif
#ifdef SO_EXCLUSIVEADDRUSE
| FExclusiveAddrUse
#endif
;
Socket::Socket()
: m_handle(invalidHandle())
{
@ -1814,32 +1745,6 @@ bool Socket::bind(struct sockaddr* addr, socklen_t addrlen)
return checkError(::bind(m_handle,addr,addrlen));
}
bool Socket::bind(struct sockaddr* addr, socklen_t addrlen,
const char* iface, int ifLen)
{
if (iface && ifLen &&
!bindIface(iface,ifLen,addr ? addr->sa_family : SocketAddr::Unknown))
return false;
return bind(addr,addrlen);
}
bool Socket::bindIface(const char* name, int len, int family)
{
// IPv6 interface should be set in address header
if (!(name && len) || family == SocketAddr::IPv6)
return true;
#ifdef SO_BINDTODEVICE
if (len < 0)
len = strlen(name);
if (!setOption(SOL_SOCKET,SO_BINDTODEVICE,name,len))
return false;
#else
m_error = EINVAL;
return false;
#endif // SO_BINDTODEVICE
return true;
}
bool Socket::listen(unsigned int backlog)
{
if ((backlog == 0) || (backlog > SOMAXCONN))
@ -1979,19 +1884,6 @@ bool Socket::getPeerName(SocketAddr& addr)
return ok;
}
bool Socket::getBoundIface(String& buf)
{
#ifdef SO_BINDTODEVICE
char tmp[IF_NAMESIZE];
socklen_t len = IF_NAMESIZE;
if (getOption(SOL_SOCKET,SO_BINDTODEVICE,tmp,&len)) {
buf << tmp;
return true;
}
#endif
return false;
}
int Socket::sendTo(const void* buffer, int length, const struct sockaddr* addr, socklen_t adrlen, int flags)
{
if (!addr)
@ -2000,7 +1892,6 @@ int Socket::sendTo(const void* buffer, int length, const struct sockaddr* addr,
length = 0;
int res = ::sendto(m_handle,(const char*)buffer,length,flags,addr,adrlen);
checkError(res,true);
applyFilters(buffer,res,flags,addr,adrlen,false);
return res;
}
@ -2010,7 +1901,6 @@ int Socket::send(const void* buffer, int length, int flags)
length = 0;
int res = ::send(m_handle,(const char*)buffer,length,flags);
checkError(res,true);
applyFilters(buffer,res,flags,0,0,false);
return res;
}
@ -2023,7 +1913,6 @@ int Socket::writeData(const void* buffer, int length)
length = 0;
int res = ::write(m_handle,buffer,length);
checkError(res,true);
applyFilters(buffer,res,0,0,0,false);
return res;
#endif
}
@ -2073,7 +1962,6 @@ int Socket::readData(void* buffer, int length)
length = 0;
int res = ::read(m_handle,buffer,length);
checkError(res,true);
applyFilters(buffer,res,0);
return res;
#endif
}
@ -2333,18 +2221,12 @@ void Socket::removeFilter(SocketFilter* filter, bool delobj)
filter->m_socket = 0;
}
void Socket::clearFilters(bool del)
void Socket::clearFilters()
{
for (ObjList* l = m_filters.skipNull(); l; l = l->skipNext()) {
SocketFilter* filter = static_cast<SocketFilter*>(l->get());
filter->m_socket = 0;
}
m_filters.setDelete(del);
m_filters.clear();
}
bool Socket::applyFilters(const void* buffer, int length, int flags, const struct sockaddr* addr,
socklen_t adrlen, bool rx)
bool Socket::applyFilters(void* buffer, int length, int flags, const struct sockaddr* addr, socklen_t adrlen)
{
if ((length <= 0) || !buffer)
return false;
@ -2352,9 +2234,7 @@ bool Socket::applyFilters(const void* buffer, int length, int flags, const struc
adrlen = 0;
for (ObjList* l = &m_filters; l; l = l->next()) {
SocketFilter* filter = static_cast<SocketFilter*>(l->get());
if (filter &&
(rx ? filter->received(buffer, length, flags, addr, adrlen)
: filter->sent(buffer, length, flags, addr, adrlen)))
if (filter && filter->received(buffer,length,flags,addr,adrlen))
return true;
}
return false;

View File

@ -3,7 +3,7 @@
* This file is part of the YATE Project http://YATE.null.ro
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2023 Null Team
* Copyright (C) 2004-2014 Null Team
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing
@ -36,14 +36,6 @@
namespace TelEngine {
static inline char* strAlloc(unsigned int n, char* old = 0)
{
char* data = (char*)::realloc(old,n + 1);
if (!data)
Debug("String",DebugFail,"realloc(%u) returned NULL!",n + 1);
return data;
}
// String to regular integer conversion, takes into account overflows
static int strtoi(const char* nptr, char** endptr, int base)
{
@ -684,7 +676,7 @@ String& String::assign(char value, unsigned int repeat)
return *this;
}
String& String::hexify(const void* data, unsigned int len, char sep, bool upCase)
String& String::hexify(void* data, unsigned int len, char sep, bool upCase)
{
const char* hex = upCase ? "0123456789ABCDEF" : "0123456789abcdef";
if (data && len) {
@ -1263,35 +1255,6 @@ String& String::insert(unsigned int pos, const char* value, int len)
return *this;
}
// Insert characters in string into current string
String& String::insert(unsigned int pos, char value, unsigned int len)
{
if (!(value && len))
return *this;
if (pos > m_length)
pos = m_length;
unsigned int newLen = len + m_length;
char* data = strAlloc(newLen,pos < m_length ? 0 : m_string);
if (!data)
return *this;
if (m_string) {
if (!pos)
// Insert before existing, copy old data after it
::memcpy(data + len,m_string,m_length);
else if (pos == m_length)
// Data reallocated. Reset held pointer
m_string = 0;
else {
// Insert middle
::memcpy(data,m_string,pos);
::memcpy(data + pos + len,m_string + pos,m_length - pos);
}
}
::memset(data + pos,value,len);
return changeStringData(data,newLen);
}
static char* string_printf(unsigned int& length, const char* format, va_list& va)
{
if (TelEngine::null(format) || !length)
@ -1376,33 +1339,6 @@ String& String::printf(const char* format, ...)
return *this;
}
String& String::printfAppend(unsigned int length, const char* format, ...)
{
va_list va;
va_start(va,format);
char* buf = string_printf(length,format,va);
va_end(va);
if (buf) {
*this << buf;
::free(buf);
}
return *this;
}
String& String::printfAppend(const char* format, ...)
{
va_list va;
va_start(va,format);
unsigned int len = TelEngine::null(format) ? 0 : (128 + ::strlen(format));
char* buf = string_printf(len,format,va);
va_end(va);
if (buf) {
*this << buf;
::free(buf);
}
return *this;
}
String& String::appendFixed(unsigned int fixedLength, const char* str, unsigned int len, char fill, int align)
{
if (len == (unsigned int)-1)
@ -1758,147 +1694,71 @@ String String::sqlEscape(const char* str, char extraEsc)
return s;
}
static inline bool isUriNoEsc(char c, const char* noEsc)
{
return (c == ' ' || c == '+' || c == '?' || c == '&') && !(noEsc && ::strchr(noEsc,c));
}
static inline char isUriEscape(char c, char extraEsc, const char* noEsc)
{
if ((unsigned char)c < ' ' || c == '%' || c == extraEsc || isUriNoEsc(c,noEsc))
return c;
return 0;
}
static inline char isUriEscape(char c, const char* extraEsc, const char* noEsc)
{
if ((unsigned char)c < ' ' || c == '%' || (extraEsc && ::strchr(extraEsc,c))
|| isUriNoEsc(c,noEsc))
return c;
return 0;
}
static inline String& uriEscapeFunc(String& buf, const char* str, const char* noEsc,
char extraCh, const char* extraStr)
String String::uriEscape(const char* str, char extraEsc, const char* noEsc)
{
String s;
if (TelEngine::null(str))
return buf;
unsigned int escape = 0;
return s;
char c;
const char* strPtr = str;
if (extraStr) {
while ((c = *strPtr++)) {
if (isUriEscape(c,extraStr,noEsc))
escape++;
}
while ((c=*str++)) {
if ((unsigned char)c < ' ' || c == '%' || c == extraEsc ||
((c == ' ' || c == '+' || c == '?' || c == '&') && !(noEsc && ::strchr(noEsc,c))))
s << '%' << hexEncode(c >> 4) << hexEncode(c);
else
s += c;
}
else {
while ((c = *strPtr++)) {
if (isUriEscape(c,extraCh,noEsc))
escape++;
}
}
if (!escape)
return buf << str;
unsigned int oldLen = buf.length();
buf.append(' ',(escape * 2) + (strPtr - str - 1));
if (buf.length() == oldLen)
return buf;
char* dest = (char*)buf.c_str() + oldLen;
if (extraStr) {
while ((c = *str++)) {
if (isUriEscape(c,extraStr,noEsc)) {
*dest++ = '%';
*dest++ = hexEncode(c >> 4);
*dest++ = hexEncode(c);
}
else
*dest++ = c;
}
}
else {
while ((c = *str++)) {
if (isUriEscape(c,extraCh,noEsc)) {
*dest++ = '%';
*dest++ = hexEncode(c >> 4);
*dest++ = hexEncode(c);
}
else
*dest++ = c;
}
}
return buf;
return s;
}
String& String::uriEscapeTo(String& buf, const char* str, char extraEsc, const char* noEsc)
{
return uriEscapeFunc(buf,str,noEsc,extraEsc,0);
}
String& String::uriEscapeTo(String& buf, const char* str, const char* extraEsc, const char* noEsc)
{
return uriEscapeFunc(buf,str,noEsc,0,extraEsc);
}
String& String::uriUnescapeTo(String& buf, const char* str, bool setPartial, int* errptr)
String String::uriEscape(const char* str, const char* extraEsc, const char* noEsc)
{
String s;
if (TelEngine::null(str))
return buf;
return s;
char c;
bool unescape = false;
const char* pos = str;
while ((c = *pos++)) {
if ((unsigned char)c < ' ' || c == '%') {
unescape = true;
break;
}
while ((c=*str++)) {
if ((unsigned char)c < ' ' || c == '%' || (extraEsc && ::strchr(extraEsc,c)) ||
((c == ' ' || c == '+' || c == '?' || c == '&') && !(noEsc && ::strchr(noEsc,c))))
s << '%' << hexEncode(c >> 4) << hexEncode(c);
else
s += c;
}
int ePtr = -1;
if (unescape) {
char* newData = strAlloc(::strlen(str));
if (!newData) {
return s;
}
String String::uriUnescape(const char* str, int* errptr)
{
String s;
if (TelEngine::null(str))
return s;
const char *pos = str;
char c;
while ((c=*pos++)) {
if ((unsigned char)c < ' ') {
if (errptr)
*errptr = 0;
return buf;
*errptr = (pos-str) - 1;
return s;
}
char* set = newData;
pos = str;
while ((c = *pos++)) {
if ((unsigned char)c < ' ') {
ePtr = (pos - str) - 1;
break;
else if (c == '%') {
int hiNibble = hexDecode(*pos++);
if (hiNibble < 0) {
if (errptr)
*errptr = (pos-str) - 1;
return s;
}
if (c == '%') {
int hiNibble = hexDecode(*pos++);
if (hiNibble < 0) {
ePtr = (pos - str) - 1;
break;
}
int loNibble = hexDecode(*pos++);
if (loNibble < 0) {
ePtr = (pos - str) - 1;
break;
}
c = ((hiNibble << 4) | loNibble) & 0xff;
int loNibble = hexDecode(*pos++);
if (loNibble < 0) {
if (errptr)
*errptr = (pos-str) - 1;
return s;
}
*set++ = c;
c = ((hiNibble << 4) | loNibble) & 0xff;
}
if (ePtr < 0 || setPartial) {
*set = 0;
if (buf.c_str() != str)
buf << newData;
else
buf = newData;
}
::free(newData);
s += c;
}
else if (buf.c_str() != str)
buf << str;
else
buf = str;
if (errptr)
*errptr = ePtr;
return buf;
*errptr = -1;
return s;
}
unsigned int String::hash(const char* value, unsigned int h)
@ -2120,90 +1980,6 @@ const String* String::atom(const String*& str, const char* val)
return str;
}
static unsigned int c_find_str(bool start, const char* str, const char* what,
int lenStr, int lenWhat, bool caseInsensitive)
{
if (!lenStr || !lenWhat || TelEngine::null(str) || TelEngine::null(what))
return 0;
if (lenStr < 0)
lenStr = ::strlen(str);
if (lenWhat < 0)
lenWhat = ::strlen(what);
if (lenStr < lenWhat)
return 0;
if (!start)
str += lenStr - lenWhat - 1;
if (caseInsensitive) {
if (::strncasecmp(str,what,lenWhat))
return 0;
}
else if (::strncmp(str,what,lenWhat))
return 0;
return lenWhat;
}
unsigned int String::c_starts_with(const char* str, const char* what, int lenStr, int lenWhat,
bool caseInsensitive)
{
return c_find_str(true,str,what,lenStr,lenWhat,caseInsensitive);
}
unsigned int String::c_ends_with(const char* str, const char* what, int lenStr, int lenWhat,
bool caseInsensitive)
{
return c_find_str(false,str,what,lenStr,lenWhat,caseInsensitive);
}
unsigned int String::c_skip_chars(const char*& str, const char* what, int len, bool skipFound)
{
if (!len || TelEngine::null(str) || TelEngine::null(what))
return 0;
const char* orig = str;
if (skipFound) {
if (len < 0) {
if (what[1])
while (*str) {
if (!::strchr(what,*str))
break;
str++;
}
else
while (*str == *what)
str++;
}
else if (what[1])
while (len-- && *str) {
if (!::strchr(what,*str))
break;
str++;
}
else
while (len-- && *str == *what)
str++;
}
else if (len < 0) {
if (what[1])
while (*str) {
if (::strchr(what,*str))
break;
str++;
}
else
while (*str && *str != *what)
str++;
}
else if (what[1])
while (len-- && *str) {
if (::strchr(what,*str))
break;
str++;
}
else
while (len-- && *str && *str != *what)
str++;
return (unsigned int)(str - orig);
}
Regexp::Regexp()
: m_regexp(0), m_compile(true), m_flags(0)
@ -2440,348 +2216,4 @@ const String& String::decodeFlags(uint64_t flags, const TokenDict64* tokens, boo
return *this;
}
String& String::changeStringData(char* data, unsigned int len)
{
char* tmp = m_string;
if (data)
data[len] = 0;
m_string = data;
m_length = len;
if (tmp)
::free(tmp);
changed();
return *this;
}
//
// MatchingItemDump
//
static inline void addFlags(String& buf, const String& flags)
{
if (flags)
buf << '[' << flags << "] ";
}
static inline const char* miType(const MatchingItemBase* item)
{
if (!item)
return "";
if (item->itemList())
return "list";
if (item->itemString())
return "string";
if (item->itemRegexp())
return "regexp";
if (item->itemRandom())
return "random";
if (item->itemCustom())
return item->itemCustom()->type().safe("custom");
return "unknown";
}
static const TokenDict s_miDumpFlags[] = {
{"no_initial_list_desc", MatchingItemDump::NoInitialListDesc},
{0,0}
};
static inline String dumpIndent(const String& buf)
{
String s;
for (const char* ss = buf; (ss && *ss); ++ss)
if (*ss == '\r')
s << "\\r";
else if (*ss == '\n')
s << "\\n";
else
s << *ss;
return s;
}
void MatchingItemDump::init(const NamedList& params)
{
for (ObjList* o = params.paramList()->skipNull(); o; o = o->skipNext()) {
NamedString* ns = static_cast<NamedString*>(o->get());
if (ns->name() == YSTRING("flags"))
m_flags = ns->encodeFlags(s_miDumpFlags);
else if (ns->name() == YSTRING("rex_enclose"))
m_rexEnclose = (*ns)[0];
else if (ns->name() == YSTRING("str_enclose"))
m_strEnclose = (*ns)[0];
else if (ns->name() == YSTRING("name_value_sep"))
m_nameValueSep = *ns;
else if (ns->name() == YSTRING("prop_negated"))
m_negated = (*ns)[0];
else if (ns->name() == YSTRING("prop_caseinsensitive"))
m_caseInsentive = (*ns)[0];
else if (ns->name() == YSTRING("prop_rex_basic"))
m_regexpBasic = (*ns)[0];
else if (ns->name() == YSTRING("prop_rex_extended"))
m_regexpExtended = (*ns)[0];
}
}
String& MatchingItemDump::dumpValue(const MatchingItemBase* item, String& buf,
const String& indent, const String& origIndent, unsigned int depth) const
{
if (!item)
return buf;
String tmp;
// Done if already dumped (item implements dumpValue())
if (item->dumpValue(tmp,this,indent,origIndent,depth))
return buf << tmp;
XDebug("MatchingItemDump",DebugAll,
"dumpValue (%p) %s '%s' depth=%u indent='%s'/'%s' [%p]",
item,miType(item),item->name().safe(),depth,dumpIndent(indent).safe(),
dumpIndent(origIndent).safe(),this);
if (item->itemList()) {
for (unsigned int i = 0; i < item->itemList()->length(); ++i) {
String tmp;
buf << dump(item->itemList()->at(i),tmp,indent,origIndent,depth);
}
}
else {
const MatchingItemString* str = item->itemString();
const MatchingItemRegexp* rex = str ? 0 : item->itemRegexp();
String flags;
if (item->negated())
flags << m_negated;
if (str) {
if (str->caseInsensitive())
flags << m_caseInsentive;
addFlags(buf,flags);
buf << m_strEnclose << item->itemString()->value() << m_strEnclose;
}
else if (rex) {
if (rex->value().isCaseInsensitive())
flags << m_caseInsentive;
if (rex->value().isExtended())
flags << m_regexpExtended;
else
flags << m_regexpBasic;
addFlags(buf,flags);
buf << m_rexEnclose << item->itemRegexp()->value() << m_rexEnclose;
}
else {
addFlags(buf,flags);
if (item->itemRandom()) {
buf << "RANDOM " << item->itemRandom()->value();
if (item->itemRandom()->maxValue() == 100)
buf << '%';
else
buf << '/' << item->itemRandom()->maxValue();
}
else if (item->itemCustom())
buf << "<CUSTOM " << item->itemCustom()->type() << '>';
else
buf << "<UNKNOWN>";
}
}
XDebug("MatchingItemDump",DebugAll,"Dumped value (%p) '%s' [%p]\r\n-----\r\n%s\r\n-----",
item,item->name().safe(),this,buf.safe());
return buf;
}
String& MatchingItemDump::dump(const MatchingItemBase* item, String& buf,
const String& indent, const String& origIndent, unsigned int depth) const
{
if (!item)
return buf;
XDebug("MatchingItemDump",DebugAll,
"dump (%p) %s '%s' flags=0x%x depth=%u indent='%s'/'%s' [%p]",
item,miType(item),item->name().safe(),m_flags,depth,
dumpIndent(indent).safe(),dumpIndent(origIndent).safe(),this);
unsigned int oLen = buf.length();
item->dump(buf,this,indent,origIndent,depth);
// Done if already dumped (item implements dump())
if (oLen != buf.length())
return buf;
const MatchingItemList* list = item->itemList();
if (list) {
String tmp;
if (depth || 0 == (m_flags & NoInitialListDesc)) {
String flags;
if (list->negated())
flags.append("negated",",");
if (!list->matchAll())
flags.append("any",",");
if (flags)
flags.printf(" [%s]",flags.safe());
if (depth || flags || item->name())
tmp << item->name().safe("List") << ':' << flags;
}
// Nothing dumped at first level:
// print the rest of the list at same alignment
String newIndent = indent;
if (tmp) {
buf << indent << tmp;
newIndent += origIndent;
}
for (unsigned int i = 0; i < list->length(); ++i) {
tmp.clear();
buf << dump(list->at(i),tmp,newIndent,origIndent,depth + 1);
}
}
else {
String val;
dumpValue(item,val);
if (item->name() || val) {
buf << indent;
if (item->name())
buf << item->name() << m_nameValueSep.safe("=");
buf << val;
}
}
XDebug("MatchingItemDump",DebugAll,"Dumped (%p) '%s' [%p]\r\n-----\r\n%s\r\n-----",
item,item->name().safe(),this,buf.safe());
return buf;
}
//
// MatchingItemRegexp
//
MatchingItemRegexp* MatchingItemRegexp::build(const char* name, const String& str,
int negated, bool insensitive, bool extended, int fail)
{
Regexp rex(0,extended,insensitive);
if (str) {
if (negated >= 0)
rex.assign(str);
else {
unsigned int pos = str.length() - 1;
negated = (str[pos] == '^') ? 1 : 0;
if (negated)
rex.assign(str.substr(0,pos));
else
rex.assign(str);
}
}
else if (negated < 0)
negated = 0;
if (fail > 1) {
if (!rex.compile())
return 0;
}
else if (fail < 0 && !rex.c_str())
return 0;
return new MatchingItemRegexp(name,rex,negated);
}
//
// MatchingItemList
//
bool MatchingItemList::change(MatchingItemBase* item, int pos, bool ins, unsigned int overAlloc)
{
if (!item) {
unsigned int n = count();
if (ins || pos < 0 || pos >= (int)n)
return false;
// Remove
GenObject* gen = m_value.take(pos);
if (gen) {
for (; pos < (int)n; ++pos)
m_value.set(m_value.take(pos + 1),pos);
TelEngine::destruct(gen);
}
return true;
}
// Detect first free position
unsigned int firstFree = 0;
while (m_value.at(firstFree))
firstFree++;
if (firstFree >= m_value.length()) {
if (firstFree >= m_value.resize(m_value.length() + 1 + overAlloc,true)) {
TelEngine::destruct(item);
return false;
}
}
if (pos < 0 || pos >= (int)firstFree)
pos = firstFree;
else if (ins) {
for (; (int)firstFree > pos; --firstFree)
m_value.set(m_value.take(firstFree - 1),firstFree);
}
m_value.set(item,pos);
return true;
}
MatchingItemBase* MatchingItemList::copy() const
{
MatchingItemList* lst = new MatchingItemList(name(),matchAll(),negated());
if (length()) {
unsigned int overAlloc = length() - 1;
for (unsigned int i = 0; i < length(); ++i) {
const MatchingItemBase* it = at(i);
MatchingItemBase* item = it ? it->copy() : 0;
if (item) {
lst->append(item,overAlloc);
overAlloc = 0;
}
}
}
return lst;
}
static inline bool matchingListRun(const MatchingItemList& mil, MatchingParams* params,
const NamedList* list, const String& str = String::empty())
{
bool allMatch = mil.matchAll();
#ifdef XDEBUG
Debugger dbg(DebugAll,"MatchingItemList MATCHING",
" name='%s' all=%s negated=%s input='%s' params=(%p) [%p]",
mil.name().safe(),String::boolText(allMatch),String::boolText(mil.negated()),
list ? list->safe("list") : "<string>",params,&mil);
#endif
int pos = -1;
while (true) {
const MatchingItemBase* item = const_cast<MatchingItemBase*>(mil.at(++pos));
if (!item)
break;
bool ok = list ? item->matchListParam(*list,params) : item->matchString(str,params);
XDebug("MatchingItemList",DebugAll,"matched [%s] idx=%d (%p) '%s' type=%s [%p]",
String::boolText(ok),pos,item,item->name().safe(),miType(item),&mil);
// Matched: done if not all match (any match)
// Not matched: done if all match is required
if (ok) {
if (!allMatch)
return true;
}
else if (allMatch)
return false;
}
// End of list reached
// Empty list or match any: not matched
// Otherwise: matched
XDebug("MatchingItemList",DebugAll,"End of matching [%s] pos=%d [%p]",
String::boolText(pos && allMatch),pos,&mil);
return pos && allMatch;
}
bool MatchingItemList::runMatchString(const String& str, MatchingParams* params) const
{
return matchingListRun(*this,params,0,str);
}
bool MatchingItemList::runMatchListParam(const NamedList& list, MatchingParams* params) const
{
return matchingListRun(*this,params,&list);
}
MatchingItemBase* MatchingItemList::optimize(MatchingItemList* list)
{
if (!list || list->at(1))
return list;
MatchingItemBase* ret = static_cast<MatchingItemBase*>(list->m_value.take(0));
if (ret) {
// Reverse item (not)negated flag if list is negated to keep the same matching behaviour
if (list->negated())
ret->m_notNegated = !ret->m_notNegated;
}
TelEngine::destruct(list);
return ret;
}
/* vi: set ts=8 sw=4 sts=4 noet: */

View File

@ -3,7 +3,7 @@
* This file is part of the YATE Project http://YATE.null.ro
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2023 Null Team
* Copyright (C) 2004-2014 Null Team
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing
@ -104,15 +104,7 @@ namespace TelEngine {
#define DebugDef DebugNote
#define DebugMax DebugAll
#ifndef OUT_BUFFER_SIZE
#define OUT_BUFFER_SIZE 16384
#elif OUT_BUFFER_SIZE < 4096
#undef OUT_BUFFER_SIZE
#define OUT_BUFFER_SIZE 4096
#elif OUT_BUFFER_SIZE > 32768
#undef OUT_BUFFER_SIZE
#define OUT_BUFFER_SIZE 32768
#endif
#define OUT_BUFFER_SIZE 8192
#define OUT_HEADER_SIZE 112
// RefObject mutex pool array size
@ -692,31 +684,6 @@ void DebugEnabler::debugCopy(const DebugEnabler* original)
m_chain = 0;
}
void DebugEnabler::debugSet(const char* desc)
{
if (TelEngine::null(desc))
return;
String s(desc);
if (s.startSkip("level")) {
int dbg = debugLevel();
s >> dbg;
if (s == YSTRING("+")) {
if (debugLevel() > dbg)
dbg = debugLevel();
}
else if (s == YSTRING("-")) {
if (debugLevel() < dbg)
dbg = debugLevel();
}
debugLevel(dbg);
}
else if (s == YSTRING("reset")) {
debugLevel(TelEngine::debugLevel());
debugEnabled(true);
}
}
Debugger::Debugger(const char* name, const char* format, ...)
: m_name(name), m_level(DebugAll)
{
@ -1295,6 +1262,7 @@ ObjList& GenObject::getObjCounters()
return s_counters;
}
#ifndef ATOMIC_OPS
static MutexPool s_refMutex(REFOBJECT_MUTEX_COUNT,false,"RefObject");
#endif
@ -1432,6 +1400,58 @@ void RefPointerBase::assign(RefObject* oldptr, RefObject* newptr, void* pointer)
}
NamedCounter::NamedCounter(const String& name)
: String(name), m_count(0), m_enabled(getObjCounting()), m_mutex(0)
{
#ifndef ATOMIC_OPS
m_mutex = s_refMutex.mutex(this);
#endif
}
int NamedCounter::inc()
{
#ifdef ATOMIC_OPS
#ifdef _WINDOWS
return InterlockedIncrement((LONG*)&m_count);
#else
return __sync_add_and_fetch(&m_count,1);
#endif
#else
Lock lock(m_mutex);
return ++m_count;
#endif
}
int NamedCounter::dec()
{
#ifdef ATOMIC_OPS
#ifdef _WINDOWS
return InterlockedDecrement((LONG*)&m_count);
#else
return __sync_fetch_and_sub(&m_count,1);
#endif
#else
Lock lock(m_mutex);
return --m_count;
#endif
}
int NamedCounter::add(int val)
{
#ifdef ATOMIC_OPS
#ifdef _WINDOWS
return InterlockedExchangeAdd((LONG*)&m_count,(LONG)val);
#else
return __sync_add_and_fetch(&m_count,val);
#endif
#else
Lock lock(m_mutex);
m_count += val;
return m_count;
#endif
}
void SysUsage::init()
{
if (!s_startTime)
@ -1505,35 +1525,6 @@ double SysUsage::runTime(Type type)
#endif
}
//
// AtomicOp
//
#ifndef ATOMIC_OP_LOCK_COUNT
#define ATOMIC_OP_LOCK_COUNT 101
#endif
#ifdef YATOMIC_LOCK
static RWLockPool s_atomicLock(ATOMIC_OP_LOCK_COUNT,"AtomicOp");
#endif
AtomicOp::AtomicOp()
: m_lock(0)
{
#ifdef YATOMIC_LOCK
m_lock = s_atomicLock.lock(this);
#endif
}
bool AtomicOp::efficient()
{
#ifdef YATOMIC_LOCK
return false;
#else
return true;
#endif
}
};
/* vi: set ts=8 sw=4 sts=4 noet: */

View File

@ -3,7 +3,7 @@
* This file is part of the YATE Project http://YATE.null.ro
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2023 Null Team
* Copyright (C) 2004-2014 Null Team
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing

View File

@ -3,7 +3,7 @@
* This file is part of the YATE Project http://YATE.null.ro
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2023 Null Team
* Copyright (C) 2004-2014 Null Team
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing

View File

@ -3,7 +3,7 @@
* This file is part of the YATE Project http://YATE.null.ro
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2023 Null Team
* Copyright (C) 2004-2014 Null Team
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing
@ -1965,6 +1965,14 @@ unsigned int XmlElement::copyAttributes(NamedList& list, const String& prefix) c
return copy;
}
void XmlElement::setAttributes(NamedList& list, const String& prefix, bool skipPrefix)
{
if (prefix)
m_element.copySubParams(list,prefix,skipPrefix);
else
m_element.copyParams(list);
}
// Retrieve a namespace attribute. Search in parent or inherited for it
String* XmlElement::xmlnsAttribute(const String& name) const
{
@ -2278,7 +2286,7 @@ void XmlDoctype::toString(String& dump, const String& indent) const
*/
// Maximul number of predicates in step
#ifndef XPATH_MAX_PREDICATES
#define XPATH_MAX_PREDICATES 10
#define XPATH_MAX_PREDICATES 5
#endif
#ifdef XDEBUG
@ -2591,15 +2599,10 @@ protected:
class XPathEscapedString
{
YNOCOPY(XPathEscapedString);
public:
inline XPathEscapedString(String* str, bool literal = false)
: m_delimiter(0), m_esc(false), m_literal(literal), m_str(str)
{}
inline XPathEscapedString(const XPathEscapedString& other, String* str)
: m_delimiter(other.m_delimiter), m_esc(other.m_esc), m_literal(other.m_literal),
m_str(str)
{}
inline void setLiteral(bool on)
{ m_literal = on; }
inline char delimiter() const
@ -2642,12 +2645,6 @@ public:
}
protected:
inline void copy(const XPathEscapedString& other) {
m_delimiter = other.m_delimiter;
m_esc = other.m_esc;
m_literal = other.m_literal;
}
char m_delimiter; // Delimiter. Non 0 indicates data is used
bool m_esc; // String contains escaped chars
bool m_literal; // String is an XPATH literal
@ -2661,17 +2658,8 @@ public:
inline XPathString(bool literal = false)
: XPathEscapedString(this,literal)
{}
inline XPathString(const XPathString& other)
: String(*static_cast<const String*>(&other)),
XPathEscapedString(*static_cast<const XPathEscapedString*>(&other),this)
{}
inline String& dump(String& buf, bool escape = false) const
{ return dumpString(buf,escape); }
inline XPathString& operator=(const XPathString& other) {
String::assign(other.c_str());
XPathEscapedString::copy(other);
return *this;
}
};
// XPath regexp literal
@ -2682,12 +2670,6 @@ public:
: XPathEscapedString(this),
m_match(true)
{}
inline XPathRegexp(const XPathRegexp& other)
: Regexp(*static_cast<const Regexp*>(&other)),
XPathEscapedString(*static_cast<const XPathEscapedString*>(&other),this),
m_match(other.m_match),
m_flags(other.m_flags)
{}
inline bool matches(const char* value) const
{ return m_match == Regexp::matches(value); }
inline const XPathString& flags() const
@ -2723,15 +2705,6 @@ public:
}
return buf;
}
inline XPathRegexp& operator=(const XPathRegexp& other) {
String::assign(other.c_str());
Regexp::setFlags(other.isExtended(),other.isCaseInsensitive());
Regexp::assign(other.c_str());
m_match = other.m_match;
m_flags = other.m_flags;
XPathEscapedString::copy(other);
return *this;
}
protected:
bool m_match; // (Reverse) match
@ -2739,103 +2712,6 @@ protected:
};
namespace TelEngine {
class XPathStep;
class XPathNodeCheck
{
public:
enum Process {
Xml,
Attribute,
Text,
ChildText,
};
inline XPathNodeCheck(XPathStep* step, ObjList* resList)
: m_step(step), m_nameCheck(0), m_resList(resList),
m_type(Xml), m_index(0), m_count(0), m_next(0), m_nextChild(0)
{}
inline unsigned int index() const
{ return m_index; }
inline void setType(int t)
{ m_type = t; }
inline XmlElement* startXml(const XmlElement& xml, bool root = false) {
if (!root) {
m_next = xml.getChildren().skipNull();
return advanceXml();
}
m_count = 1;
return (!m_nameCheck || *m_nameCheck == xml.getTag()) ? (XmlElement*)&xml : 0;
}
inline XmlText* startText(const XmlElement& xml) {
m_nextChild = xml.getChildren().skipNull();
return advanceText();
}
inline NamedString* startAttr(const XmlElement& xml) {
m_next = xml.attributes().paramList()->skipNull();
return advanceAttr();
}
inline XmlElement* advanceXml()
{ return XmlFragment::getElement(m_next,m_nameCheck); }
inline XmlText* advanceText()
{ return XmlFragment::getText(m_nextChild); }
inline NamedString* advanceAttr() {
m_next = findAttr(m_next,m_nameCheck);
if (!m_next)
return 0;
ObjList* tmp = m_next;
m_next = m_next->skipNext();
return static_cast<NamedString*>(tmp->get());
}
inline void advanceIndex()
{ m_index++; }
inline int checkIndex(unsigned int idx) {
if (m_index == idx)
return XPathProcHandleStop;
return m_index < idx ? XPathProcCont : XPathProcStop;
}
inline int checkPosLast() {
if (Xml == m_type) {
if (m_count)
return checkIndex(m_count);
return procNotLastPos(XmlFragment::findElement(m_next,m_nameCheck,0));
}
if (Attribute == m_type)
return procNotLastPos(findAttr(m_next,m_nameCheck));
// Text process
if (ChildText == m_type && m_next) {
XmlElement* next = XmlFragment::findElement(m_next,0,0);
if (next && XmlFragment::findText(next->getChildren().skipNull()))
return XPathProcCont;
// No next element or next element has no text child. Check current element
}
return procNotLastPos(XmlFragment::findText(m_nextChild));
}
static inline int procNotLastPos(bool notLast)
{ return notLast ? XPathProcCont : XPathProcHandleStop; }
static inline ObjList* findAttr(ObjList* lst, const String* name) {
if (!(lst && name))
return lst;
for (; lst; lst = lst->skipNext()) {
if (*name == static_cast<NamedString*>(lst->get())->name())
return lst;
}
return 0;
}
XPathStep* m_step;
const String* m_nameCheck;
ObjList* m_resList;
protected:
int m_type;
unsigned int m_index;
unsigned int m_count;
ObjList* m_next; // Next item (Xml or Attribute)
ObjList* m_nextChild; // Next child (XML text)
};
class XPathPredicate
{
public:
@ -2849,8 +2725,6 @@ public:
XmlName = 0x10,
Attribute, // XML element attribute match
Child, // XML child match (presence or text),
Position = 0x20,
PosLast, // Node position in list: last item
};
// Operators
enum Opc {
@ -2863,10 +2737,6 @@ public:
inline XPathPredicate()
: m_type(0), m_opc(0)
{}
inline XPathPredicate(const XPathPredicate& other)
: m_type(other.m_type), m_opc(other.m_opc),
m_name(other.m_name), m_value(other.m_value), m_regexp(other.m_regexp)
{}
inline int type() const
{ return m_type; }
inline unsigned int opc() const
@ -2878,15 +2748,13 @@ public:
inline bool valid() const
{ return 0 != type(); }
inline bool isPosition() const
{ return 0 != (Position & type()); }
inline bool sameIndex(const XPathPredicate& other) const
{ return opc() == other.opc(); }
inline int check(XPathNodeCheck& data, const XmlElement* xml = 0,
const NamedString* attr = 0) const {
if (Index == m_type)
return data.checkIndex(m_opc);
if (PosLast == m_type)
return data.checkPosLast();
{ return Index == type(); }
inline int check(unsigned int index, const XmlElement* xml = 0, const NamedString* attr = 0) const {
if (Index == m_type) {
if (index == m_opc)
return XPathProcHandleStop;
return index < m_opc ? XPathProcCont : XPathProcStop;
}
if (Text == m_type || Child == m_type) {
const String* txt = xml ?
((Child == m_type) ? xml->childText(m_name) : &(xml->getText())) : 0;
@ -2954,14 +2822,6 @@ public:
m_value.dump(buf,escape);
}
}
inline XPathPredicate& operator=(const XPathPredicate& other) {
m_type = other.m_type;
m_opc = other.m_opc;
m_name = other.m_name;
m_value = other.m_value;
m_regexp = other.m_regexp;
return *this;
}
static inline const char* opcName(int opc)
{ return lookup(opc,s_opcAll); }
@ -3011,44 +2871,36 @@ const TokenDict XPathPredicate::s_typeName[] = {
{"attribute", Attribute},
{"child", Child},
{"text", Text},
{"last", PosLast},
{0,0},
};
typedef GenericVector<XPathPredicate> XPathPredicateVector;
class XPathPredicateList
{
public:
inline XPathPredicateList()
: m_predicates(2), m_indexPredicate(0), m_stopProc(false)
: m_indexPredicate(0), m_stopProc(false)
{}
inline XPathPredicateList(const XPathPredicateList& other)
: m_predicates(other.m_predicates), m_indexPredicate(0), m_stopProc(other.m_stopProc)
{
if (other.m_indexPredicate) {
const XPathPredicate* p = other.m_predicates.data();
for (unsigned int i = 0; i < other.m_predicates.length(); ++i, ++p)
if (p == other.m_indexPredicate) {
m_indexPredicate = m_predicates.data(i,1);
break;
}
}
}
inline int check(XPathNodeCheck& data, const XmlElement* xml = 0,
inline bool valid() const
{ return m_predicates[0].valid(); }
inline XPathPredicate* first()
{ return m_predicates; }
inline const XPathPredicate* first() const
{ return m_predicates; }
inline int check(unsigned int& index, const XmlElement* xml = 0,
const NamedString* attr = 0) const {
const XPathPredicate* f = m_predicates.first();
if (!f)
if (!valid())
return XPathProcHandleCont;
data.advanceIndex();
index++;
int rProc = XPathProcHandleCont;
if (!m_stopProc) {
// Always evalute predicates with position first. May lead to fast return
if (m_indexPredicate)
check(rProc,true,*m_indexPredicate,data,xml,attr);
for (unsigned int i = 0; rProc > 0 && i < m_predicates.length(); ++i, ++f) {
if (f != m_indexPredicate)
check(rProc,!(m_indexPredicate || i),*f,data,xml,attr);
check(rProc,true,*m_indexPredicate,index,xml,attr);
const XPathPredicate* f = first();
for (unsigned int i = 0; rProc > 0 && i < XPATH_MAX_PREDICATES && f->valid(); ++i, ++f) {
if (!f->isPosition())
check(rProc,!(m_indexPredicate || i),*f,index,xml,attr);
}
}
else
@ -3059,13 +2911,36 @@ public:
"Checked %s '%s' idx=%u. Predicate(s) not matched proc=%s",
(xml ? "xml" : (attr ? "attribute" : "???")),
(xml ? xml->tag() : ((attr ? attr->name().c_str() : ""))),
data.index(),lookup(rProc,s_xpathProcAct));
index,lookup(rProc,s_xpathProcAct));
#endif
return rProc;
}
inline bool check(int& rProc, bool first, const XPathPredicate& pred,
unsigned int index, const XmlElement* xml, const NamedString* attr) const {
#ifdef XPATH_XDEBUG_FIND
String tmp;
pred.dump(tmp) << " index=" << index;
#endif
if (first) {
rProc = pred.check(index,xml,attr);
#ifdef XPATH_XDEBUG_FIND
Debug("XPath",DebugAll,"Predicate %s check returned %s",
tmp.safe(),lookup(rProc,s_xpathProcAct));
#endif
}
else {
int proc = pred.check(index,xml,attr);
rProc = filterProc(rProc,proc);
#ifdef XPATH_XDEBUG_FIND
Debug("XPath",DebugAll,"Predicate %s check returned %s. Filtered: %s",
tmp.safe(),lookup(proc,s_xpathProcAct),lookup(rProc,s_xpathProcAct));
#endif
}
return rProc > 0;
}
inline String& dump(String& buf, bool escape = false) const {
const XPathPredicate* f = m_predicates.first();
for (unsigned int i = 0; i < m_predicates.length(); ++i, ++f)
const XPathPredicate* f = first();
for (unsigned int i = 0; i < XPATH_MAX_PREDICATES && f->valid(); ++i, ++f)
f->dump(buf,escape);
return buf;
}
@ -3090,34 +2965,9 @@ public:
return XPathProcCont;
}
XPathPredicateVector m_predicates; // Predicate expression(s)
XPathPredicate m_predicates[XPATH_MAX_PREDICATES]; // Predicate expression(s)
XPathPredicate* m_indexPredicate;
bool m_stopProc;
protected:
inline bool check(int& rProc, bool first, const XPathPredicate& pred,
XPathNodeCheck& data, const XmlElement* xml, const NamedString* attr) const {
#ifdef XPATH_XDEBUG_FIND
String tmp;
pred.dump(tmp) << " index=" << data.index();
#endif
if (first) {
rProc = pred.check(data,xml,attr);
#ifdef XPATH_XDEBUG_FIND
Debug("XPath",DebugAll,"Predicate %s check returned %s",
tmp.safe(),lookup(rProc,s_xpathProcAct));
#endif
}
else {
int proc = pred.check(data,xml,attr);
rProc = filterProc(rProc,proc);
#ifdef XPATH_XDEBUG_FIND
Debug("XPath",DebugAll,"Predicate %s check returned %s. Filtered: %s",
tmp.safe(),lookup(proc,s_xpathProcAct),lookup(rProc,s_xpathProcAct));
#endif
}
return rProc > 0;
}
};
namespace TelEngine {
@ -3145,7 +2995,7 @@ public:
{}
inline XPathStep(const XPathStep& other)
: String(other.c_str()),
m_nodeType(other.m_nodeType), m_predicates(other.m_predicates)
m_nodeType(other.m_nodeType)
{}
inline int nodeType() const
{ return m_nodeType; }
@ -3158,7 +3008,7 @@ public:
inline const String* valueMatch() const
{ return valueMatchAny() ? 0 : (const String*)this; }
inline const XPathPredicateList* predicates() const
{ return m_predicates.m_predicates.length() ? &m_predicates : 0; }
{ return m_predicates.valid() ? &m_predicates : 0; }
inline String& dump(String& buf, bool escape = false) {
switch (m_nodeType) {
case Xml:
@ -3176,6 +3026,17 @@ public:
}
return m_predicates.dump(buf,escape);
}
// Check if a given item should be added to result set
inline int checkHandle(const XPath* path, unsigned int& resultIdx,
const XmlElement* xml = 0, const NamedString* attr = 0,
const String& name = String::empty(), const String* nameCheck = 0) const {
if (nameCheck && name != *nameCheck) {
XPathDebugFind("XPath",DebugAll,"Checked %s '%s': not matched [%p]",
(xml ? "xml" : "attribute"),name.c_str(),path);
return XPathProcCont;
}
return m_predicates.check(resultIdx,xml,attr);
}
static inline bool matchAny(const char* buf, unsigned int len)
{ return 1 == len && '*' == *buf; }
@ -3228,17 +3089,20 @@ XPath::XPath(const char* value, unsigned int flags)
}
XPath::XPath(const XPath& other)
: m_flags(0),
m_status(NotParsed),
m_errorItem(0)
: String(other.c_str()),
m_flags(other.m_flags),
m_status(other.m_status),
m_errorItem(other.m_errorItem),
m_error(other.m_error)
{
XDebug(DebugAll,"XPath(%p) [%p]",&other,this);
copy(other,true);
XDebug(DebugAll,"XPath(%s,0x%x) [%p]",c_str(),m_flags,this);
ObjList* itAppend = &m_items;
for (ObjList* o = other.m_items.skipNull(); o; o = o->skipNext())
itAppend->append(new XPathStep(*static_cast<XPathStep*>(o->get())));
}
XPath::~XPath()
{
XDebug(DebugAll,"~XPath [%p]",this);
reset();
}
@ -3343,21 +3207,26 @@ int XPath::find(unsigned int& total, const XmlElement& src, const GenObject*& re
ObjList* lstAppend = list;
unsigned int n = 0;
bool stop = false;
XPathNodeCheck info(&it,list);
unsigned int resultIdx = 0;
while (true) {
if (it.isElementNode()) {
ObjList* o = 0;
XmlElement* x = 0;
if (absolute)
x = (XmlElement*)&src;
else {
o = src.getChildren().skipNull();
x = XmlFragment::getElement(o);
}
bool xmlReq = 0 != (what & FindXml);
// Last item but no XML/TEXT requested ?
if (!nextItem && !xmlReq && 0 == (what & FindText)) {
stop = true;
break;
}
info.setType(XPathNodeCheck::Xml);
info.m_nameCheck = it.valueMatch();
XPathNodeCheck infoText(0,list);
infoText.setType(XPathNodeCheck::Text);
for (XmlElement* x = info.startXml(src,absolute); x; x = info.advanceXml()) {
int proc = it.m_predicates.check(info,x);
const String* tag = it.valueMatch();
for ( ; x; x = XmlFragment::getElement(o)) {
int proc = it.checkHandle(this,resultIdx,x,0,x->getTag(),tag);
if (proc > 0) {
if (nextItem)
proc = XPathStep::filterProc(proc,find(n,*x,res,list,what,nextItem,step + 1));
@ -3368,7 +3237,7 @@ int XPath::find(unsigned int& total, const XmlElement& src, const GenObject*& re
}
else
// Last item pointing to an XML but XML was not requested
proc = XPathStep::filterProc(proc,getText(n,*x,res,infoText));
proc = XPathStep::filterProc(proc,getText(n,*x,0,resultIdx,res,list));
}
if (proc < 0 || XPathProcHandleStop == proc)
break;
@ -3376,7 +3245,7 @@ int XPath::find(unsigned int& total, const XmlElement& src, const GenObject*& re
break;
}
if (XPathStep::Text == it.m_nodeType || XPathStep::ChildText == it.m_nodeType) {
if (XPathStep::Text == it.m_nodeType || XPathStep::Text == it.m_nodeType) {
// No need to check anything if the requested result set contains other data
// type (non XML Text) or we have a next item
// If next item is present there is nothing there to match (XmlText has no attributes, children ...)
@ -3386,14 +3255,12 @@ int XPath::find(unsigned int& total, const XmlElement& src, const GenObject*& re
stop = true;
break;
}
if (XPathStep::Text == it.m_nodeType) {
info.setType(XPathNodeCheck::Text);
getText(n,src,res,info);
}
if (XPathStep::Text == it.m_nodeType)
getText(n,src,&it,resultIdx,res,list);
else {
info.setType(XPathNodeCheck::ChildText);
for (XmlElement* x = info.startXml(src); x; x = info.advanceXml()) {
int proc = getText(n,*x,res,info);
ObjList* o = src.getChildren().skipNull();
for (XmlElement* x = XmlFragment::getElement(o); x; x = XmlFragment::getElement(o)) {
int proc = getText(n,*x,&it,resultIdx,res,list);
if (proc < 0 || XPathProcHandleStop == proc)
break;
}
@ -3408,10 +3275,10 @@ int XPath::find(unsigned int& total, const XmlElement& src, const GenObject*& re
stop = true;
break;
}
info.setType(XPathNodeCheck::Attribute);
info.m_nameCheck = it.valueMatch();
for (NamedString* ns = info.startAttr(src); ns; ns = info.advanceAttr()) {
int proc = it.m_predicates.check(info,0,ns);
const String* name = it.valueMatch();
for (const ObjList* o = src.attributes().paramList()->skipNull(); o; o = o->skipNext()) {
NamedString* ns = static_cast<NamedString*>(o->get());
int proc = it.checkHandle(this,resultIdx,0,ns,ns->name(),name);
if (proc > 0) {
n++;
if (!xpathAddResult(this,ns,res,lstAppend))
@ -3438,19 +3305,20 @@ int XPath::find(unsigned int& total, const XmlElement& src, const GenObject*& re
return rProc;
}
int XPath::getText(unsigned int& total, const XmlElement& src, const GenObject*& res,
XPathNodeCheck& data) const
int XPath::getText(unsigned int& total, const XmlElement& src, const XPathStep* step,
unsigned int& resultIdx, const GenObject*& res, ObjList* list) const
{
XPathDebugFind("XPath",DebugAll,"Get text xml '%s' multi=%s step=(%p) [%p]",
src.getTag().c_str(),String::boolText(data.m_resList),data.m_step,this);
src.getTag().c_str(),String::boolText(list),step,this);
unsigned int n = 0;
int proc = XPathProcHandleCont;
for (XmlText* t = data.startText(src); t; t = data.advanceText()) {
if (data.m_step)
proc = data.m_step->m_predicates.check(data);
ObjList* o = src.getChildren().skipNull();
for (XmlText* t = XmlFragment::getText(o); t; t = XmlFragment::getText(o)) {
if (step)
proc = step->checkHandle(this,resultIdx);
if (proc > 0) {
n++;
if (!xpathAddResult(this,&t->getText(),res,data.m_resList))
if (!xpathAddResult(this,&t->getText(),res,list))
proc = XPathProcStop;
}
if (proc < 0 || XPathProcHandleStop == proc)
@ -3464,8 +3332,7 @@ int XPath::getText(unsigned int& total, const XmlElement& src, const GenObject*&
void XPath::changed()
{
if (FCopying != m_flags)
parsePath();
parsePath();
}
#define XPATH_SET_STATUS_BREAK(code,str) { setStatus(code,data.step(),str); break; }
@ -3598,7 +3465,8 @@ void XPath::parsePath()
prevStep = step;
}
for (unsigned int i = 0; ; ++i) {
XPathPredicate* p = step->m_predicates.first();
for (unsigned int i = 0; ; ++p, ++i) {
if (!data.strictParse)
data.skipBlanks();
if (data.isStepEnd())
@ -3610,14 +3478,10 @@ void XPath::parsePath()
}
if (i == XPATH_MAX_PREDICATES)
XPATH_SET_STATUS_BREAK(ERange,"Too many predicates");
XPathPredicateVector& predicates = step->m_predicates.m_predicates;
if (!predicates.resize(1 + predicates.length()))
XPATH_SET_STATUS_BREAK(ERange,"Memory allocation failure");
XPathPredicate* p = predicates.last();
if (!(parseStepPredicate(data,p) && checkStepPredicate(data,step,p))) {
predicates.removeLast(n);
if (!parseStepPredicate(data,p))
break;
if (!checkStepPredicate(data,step,p))
break;
}
}
if (m_status)
break;
@ -3687,6 +3551,7 @@ bool XPath::parseStepPredicate(XPathParseData& data, XPathPredicate* pred)
XPATH_SET_SYNTAX_RET("Predicate index value invalid or out of range");
pred->m_type = XPathPredicate::Index;
pred->m_opc = (unsigned int)val;
XPathDebugParse("XPath",DebugInfo,"Parsed predicate %u '%s' value=%u [%p]",
pred->type(),pred->typeName(),pred->opc(),this);
return true;
@ -3847,33 +3712,22 @@ bool XPath::parseStepPredicate(XPathParseData& data, XPathPredicate* pred)
case 0:
// Function not found. Check for selector type function
func = lookup(fn,XPathPredicate::s_typeName);
#define XPATH_PARSE_END_FUNC_DONE \
if (data.ended() || data != ')') \
XPATH_SET_SYNTAX_RET(tmp.printf("Expecting ')' after '%s' start",fn.c_str())); \
func = 0; \
selector.advance(); \
data.advance();
switch (func) {
case XPathPredicate::Text:
XPATH_PARSE_END_FUNC_DONE;
if (data.ended() || data != ')')
XPATH_SET_SYNTAX_RET("Expecting ')' after predicate input selector");
pred->m_type = XPathPredicate::Text;
break;
case XPathPredicate::PosLast:
XPATH_PARSE_END_FUNC_DONE;
// Skip now until predicate end: we don't expect anything else
XPATH_PARSE_STRICT_BLANK_PREDICATE;
if (!data.isPredicatedEnd())
tmp.printf("Expecting predicate end after position selector");
pred->m_type = XPathPredicate::PosLast;
func = 0;
selector.advance();
data.advance();
break;
default:
if (!func)
tmp.printf("Unknown function '%s' in predicate",fn.c_str());
else
if (func)
tmp.printf("Predicate function '%s' not implemented",fn.c_str());
else
tmp.printf("Unknown function '%s' in predicate",fn.c_str());
XPATH_SET_SYNTAX_RET(tmp);
}
#undef XPATH_PARSE_END_FUNC_DONE
break;
default:
tmp.printf("Predicate function '%s' not implemented",fn.c_str());
@ -4002,11 +3856,10 @@ bool XPath::checkStepPredicate(XPathParseData& data, XPathStep* step, XPathPredi
else {
if (data.strictParse)
XPATH_SET_STATUS_RET(ESemantic,"Repeated index predicate in step");
if (!pred->sameIndex(*(lst.m_indexPredicate))) {
if (pred->opc() != lst.m_indexPredicate->opc())
if (data.checkEmptyRes)
XPATH_SET_STATUS_RET(EEmptyResult,"Path step with different index value in predicate");
lst.m_stopProc = true;
}
}
}
else {
@ -4025,8 +3878,6 @@ bool XPath::checkStepPredicate(XPathParseData& data, XPathStep* step, XPathPredi
}
break;
case XPathPredicate::Index:
case XPathPredicate::Position:
case XPathPredicate::PosLast:
break;
default:
Debug("XPath",DebugStub,
@ -4107,22 +3958,4 @@ bool XPath::setStatus(unsigned int code, unsigned int itemIdx, const char* error
return false;
}
XPath& XPath::copy(const XPath& other, bool constr)
{
if (&other == this)
return *this;
if (!constr)
reset();
m_flags = FCopying;
String::assign(other.c_str()),
m_flags = other.m_flags;
m_status = other.m_status;
m_errorItem = other.m_errorItem;
m_error = other.m_error;
ObjList* itAppend = &m_items;
for (ObjList* o = other.m_items.skipNull(); o; o = o->skipNext())
itAppend->append(new XPathStep(*static_cast<XPathStep*>(o->get())));
return *this;
}
/* vi: set ts=8 sw=4 sts=4 noet: */

View File

@ -6,7 +6,7 @@
* Adapted for YATE by Paul Chitescu
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2023 Null Team
* Copyright (C) 2004-2014 Null Team
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing

View File

@ -9,7 +9,7 @@
* Adapted for YATE by Paul Chitescu
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2023 Null Team
* Copyright (C) 2004-2014 Null Team
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing

View File

@ -7,7 +7,7 @@
* Adapted for YATE by Paul Chitescu
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2013-2023 Null Team
* Copyright (C) 2013-2014 Null Team
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing

View File

@ -1,8 +0,0 @@
Makefile
YateLocal*
core*
*.o
*.a
*.orig
*~
.*.swp

View File

@ -5,7 +5,7 @@
* Classes for interfacing with Mac OS X API
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2023 Null Team
* Copyright (C) 2004-2014 Null Team
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing

View File

@ -3,7 +3,7 @@
* This file is part of the YATE Project http://YATE.null.ro
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2023 Null Team
* Copyright (C) 2004-2014 Null Team
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing

View File

@ -1,7 +0,0 @@
Makefile
core*
*.o
*.a
*.orig
*~
.*.swp

View File

@ -1,4 +0,0 @@
core*
*.orig
*~
.*.swp

View File

@ -1,7 +0,0 @@
Makefile
core*
*.o
*.a
*.orig
*~
.*.swp

View File

@ -1,7 +0,0 @@
Makefile
core*
*.o
*.a
*.orig
*~
.*.swp

View File

@ -1,6 +0,0 @@
core*
*.o
*.a
*.orig
*~
.*.swp

View File

@ -1,6 +0,0 @@
core*
*.o
*.a
*.orig
*~
.*.swp

View File

@ -1,6 +0,0 @@
core*
*.o
*.a
*.orig
*~
.*.swp

View File

@ -1,6 +0,0 @@
core*
*.o
*.a
*.orig
*~
.*.swp

View File

@ -1,6 +0,0 @@
core*
*.o
*.a
*.orig
*~
.*.swp

View File

@ -1,6 +0,0 @@
core*
*.o
*.a
*.orig
*~
.*.swp

View File

@ -1,6 +0,0 @@
core*
*.o
*.a
*.orig
*~
.*.swp

View File

@ -1,6 +0,0 @@
core*
*.o
*.a
*.orig
*~
.*.swp

View File

@ -1,6 +0,0 @@
core*
*.o
*.a
*.orig
*~
.*.swp

View File

@ -1,6 +0,0 @@
core*
*.o
*.a
*.orig
*~
.*.swp

View File

@ -1,6 +0,0 @@
core*
*.o
*.a
*.orig
*~
.*.swp

View File

@ -1,6 +0,0 @@
core*
*.o
*.a
*.orig
*~
.*.swp

View File

@ -1,6 +0,0 @@
core*
*.o
*.a
*.orig
*~
.*.swp

View File

@ -1,6 +0,0 @@
core*
*.o
*.a
*.orig
*~
.*.swp

View File

@ -1,8 +0,0 @@
Makefile
YateLocal.mak
core*
*.o
*.a
*.orig
*~
.*.swp

View File

@ -5,7 +5,7 @@
* ASN.1 Library
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2023 Null Team
* Copyright (C) 2004-2014 Null Team
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing

View File

@ -5,7 +5,7 @@
* ASN.1 Library
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2023 Null Team
* Copyright (C) 2004-2014 Null Team
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing

View File

@ -1,8 +0,0 @@
Makefile
YateLocal.mak
core*
*.o
*.a
*.orig
*~
.*.swp

View File

@ -4,7 +4,7 @@
* This file is part of the YATE Project http://YATE.null.ro
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2023 Null Team
* Copyright (C) 2004-2014 Null Team
* Author: Marian Podgoreanu
*
* This software is distributed under multiple licenses;

View File

@ -4,7 +4,7 @@
* This file is part of the YATE Project http://YATE.null.ro
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2023 Null Team
* Copyright (C) 2004-2014 Null Team
* Author: Marian Podgoreanu
*
* This software is distributed under multiple licenses;

View File

@ -4,7 +4,7 @@
* This file is part of the YATE Project http://YATE.null.ro
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2023 Null Team
* Copyright (C) 2004-2014 Null Team
* Author: Marian Podgoreanu
*
* This software is distributed under multiple licenses;

View File

@ -4,7 +4,7 @@
* This file is part of the YATE Project http://YATE.null.ro
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2023 Null Team
* Copyright (C) 2004-2014 Null Team
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing

View File

@ -1,8 +0,0 @@
Makefile
YateLocal.mak
core*
*.o
*.a
*.orig
*~
.*.swp

View File

@ -4,7 +4,7 @@
* This file is part of the YATE Project http://YATE.null.ro
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2023 Null Team
* Copyright (C) 2004-2014 Null Team
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing

View File

@ -4,7 +4,7 @@
* This file is part of the YATE Project http://YATE.null.ro
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2023 Null Team
* Copyright (C) 2004-2014 Null Team
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing

View File

@ -4,7 +4,7 @@
* This file is part of the YATE Project http://YATE.null.ro
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2023 Null Team
* Copyright (C) 2004-2014 Null Team
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing

View File

@ -4,7 +4,7 @@
* This file is part of the YATE Project http://YATE.null.ro
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2023 Null Team
* Copyright (C) 2004-2014 Null Team
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing

View File

@ -4,7 +4,7 @@
* This file is part of the YATE Project http://YATE.null.ro
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2023 Null Team
* Copyright (C) 2004-2014 Null Team
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing

View File

@ -4,7 +4,7 @@
* This file is part of the YATE Project http://YATE.null.ro
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2023 Null Team
* Copyright (C) 2004-2014 Null Team
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing

View File

@ -4,7 +4,7 @@
* This file is part of the YATE Project http://YATE.null.ro
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2023 Null Team
* Copyright (C) 2004-2014 Null Team
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing

View File

@ -4,7 +4,7 @@
* This file is part of the YATE Project http://YATE.null.ro
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2023 Null Team
* Copyright (C) 2004-2014 Null Team
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing

View File

@ -1,8 +0,0 @@
Makefile
YateLocal.mak
core*
*.o
*.a
*.orig
*~
.*.swp

View File

@ -4,7 +4,7 @@
* This file is part of the YATE Project http://YATE.null.ro
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2023 Null Team
* Copyright (C) 2004-2014 Null Team
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing

View File

@ -4,7 +4,7 @@
* This file is part of the YATE Project http://YATE.null.ro
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2023 Null Team
* Copyright (C) 2004-2014 Null Team
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing

View File

@ -4,7 +4,7 @@
* This file is part of the YATE Project http://YATE.null.ro
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2023 Null Team
* Copyright (C) 2004-2014 Null Team
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing
@ -30,10 +30,6 @@ using namespace TelEngine;
// Ensure response code string representation is 3 digit long
inline void setCode(String& dest, unsigned int code)
{
if (code >= 1000) {
dest = "999";
return;
}
char c[4];
sprintf(c,"%03u",code);
dest = c;

View File

@ -4,7 +4,7 @@
* This file is part of the YATE Project http://YATE.null.ro
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2023 Null Team
* Copyright (C) 2004-2014 Null Team
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing

View File

@ -4,7 +4,7 @@
* This file is part of the YATE Project http://YATE.null.ro
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2023 Null Team
* Copyright (C) 2004-2014 Null Team
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing

View File

@ -1,8 +0,0 @@
Makefile
YateLocal.mak
core*
*.o
*.a
*.orig
*~
.*.swp

View File

@ -5,7 +5,7 @@
* Yet Another Modem
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2023 Null Team
* Copyright (C) 2004-2014 Null Team
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing

View File

@ -5,7 +5,7 @@
* Yet Another Modem
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2023 Null Team
* Copyright (C) 2004-2014 Null Team
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing

View File

@ -5,7 +5,7 @@
* Yet Another Modem
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2023 Null Team
* Copyright (C) 2004-2014 Null Team
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing

Some files were not shown because too many files have changed in this diff Show More