aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
author(no author) <(no author)@f38db490-d61c-443f-a65b-d21fe96a405b>2005-11-21 16:53:51 +0000
committer(no author) <(no author)@f38db490-d61c-443f-a65b-d21fe96a405b>2005-11-21 16:53:51 +0000
commit0721731e93eb315ab19418b95fad8690417b8994 (patch)
tree84965a610f6ae7e51cd499f8bd89464f247db803
parent27a9c96742202c8188b53a0173649de479256b69 (diff)
This commit was manufactured by cvs2svn to create tag 'v1-0-10'.
git-svn-id: http://svn.digium.com/svn/asterisk/tags/v1-0-10@7178 f38db490-d61c-443f-a65b-d21fe96a405b
-rwxr-xr-xCREDITS2
-rwxr-xr-xChangeLog (renamed from CHANGES)273
-rwxr-xr-xMakefile60
-rwxr-xr-xREADME61
-rwxr-xr-xacl.c36
-rwxr-xr-xaesopt.h19
-rwxr-xr-xapp.c111
-rwxr-xr-xapps/app_alarmreceiver.c2
-rwxr-xr-xapps/app_chanisavail.c11
-rwxr-xr-xapps/app_controlplayback.c15
-rwxr-xr-xapps/app_cut.c4
-rwxr-xr-xapps/app_dial.c42
-rwxr-xr-xapps/app_disa.c22
-rwxr-xr-xapps/app_eval.c4
-rwxr-xr-xapps/app_festival.c7
-rwxr-xr-xapps/app_forkcdr.c7
-rwxr-xr-xapps/app_getcpeid.c10
-rwxr-xr-xapps/app_hasnewvoicemail.c28
-rwxr-xr-xapps/app_macro.c3
-rwxr-xr-xapps/app_meetme.c83
-rwxr-xr-xapps/app_parkandannounce.c4
-rwxr-xr-xapps/app_qcall.c2
-rwxr-xr-xapps/app_queue.c132
-rwxr-xr-xapps/app_random.c1
-rwxr-xr-xapps/app_read.c3
-rwxr-xr-xapps/app_record.c2
-rwxr-xr-xapps/app_sms.c14
-rwxr-xr-xapps/app_sql_postgres.c2
-rwxr-xr-xapps/app_test.c13
-rwxr-xr-xapps/app_userevent.c6
-rwxr-xr-xapps/app_voicemail.c442
-rwxr-xr-xapps/app_zapras.c27
-rwxr-xr-xast_expr.y68
-rwxr-xr-xasterisk.c79
-rwxr-xr-xastman/astman.c14
-rwxr-xr-xcallerid.c2
-rwxr-xr-xcdr.c11
-rwxr-xr-xcdr/cdr_csv.c8
-rwxr-xr-xcdr/cdr_odbc.c253
-rwxr-xr-xcdr/cdr_pgsql.c40
-rwxr-xr-xcdr/cdr_tds.c255
-rwxr-xr-xchannel.c55
-rwxr-xr-xchannels/chan_agent.c42
-rwxr-xr-xchannels/chan_alsa.c17
-rwxr-xr-xchannels/chan_h323.c28
-rwxr-xr-xchannels/chan_iax2.c179
-rwxr-xr-xchannels/chan_local.c40
-rwxr-xr-xchannels/chan_mgcp.c235
-rwxr-xr-xchannels/chan_modem.c15
-rwxr-xr-xchannels/chan_modem_bestdata.c6
-rwxr-xr-xchannels/chan_oss.c10
-rwxr-xr-xchannels/chan_phone.c32
-rwxr-xr-xchannels/chan_sip.c1178
-rwxr-xr-xchannels/chan_skinny.c29
-rwxr-xr-xchannels/chan_zap.c173
-rwxr-xr-xchannels/h323/.cvsignore1
-rwxr-xr-xchannels/h323/Makefile17
-rwxr-xr-xchannels/h323/ast_h323.cpp6
-rwxr-xr-xchannels/h323/chan_h323.h2
-rwxr-xr-xchannels/iax2-parser.c19
-rwxr-xr-xchannels/iax2.h2
-rwxr-xr-xcli.c206
-rwxr-xr-xcodecs/Makefile4
-rwxr-xr-xcodecs/gsm/Makefile14
-rwxr-xr-xconfig.c2
-rwxr-xr-xconfigs/agents.conf.sample4
-rwxr-xr-xconfigs/enum.conf.sample1
-rwxr-xr-xconfigs/extensions.conf.sample13
-rwxr-xr-xconfigs/iax.conf.sample3
-rwxr-xr-xconfigs/indications.conf.sample206
-rwxr-xr-xconfigs/logger.conf.sample7
-rwxr-xr-xconfigs/manager.conf.sample22
-rwxr-xr-xconfigs/meetme.conf.sample2
-rwxr-xr-xconfigs/modem.conf.sample2
-rwxr-xr-xconfigs/queues.conf.sample21
-rwxr-xr-xconfigs/rtp.conf.sample2
-rwxr-xr-xconfigs/sip.conf.sample21
-rwxr-xr-xconfigs/voicemail.conf.sample6
-rwxr-xr-xconfigs/zapata.conf.sample7
-rwxr-xr-xcontrib/README.festival17
-rwxr-xr-xcontrib/firmware/iax/iaxy.binbin39241 -> 39402 bytes
-rwxr-xr-xcontrib/scripts/astgenkey.8129
-rwxr-xr-xcontrib/scripts/autosupport155
-rwxr-xr-xcontrib/scripts/autosupport.841
-rwxr-xr-xcontrib/scripts/safe_asterisk.862
-rwxr-xr-xdb1-ast/hash/ndbm.c50
-rwxr-xr-xdlfcn.c2
-rwxr-xr-xdns.c1
-rwxr-xr-xdoc/README.cdr28
-rwxr-xr-xdoc/README.iax71
-rwxr-xr-xdoc/README.tds18
-rwxr-xr-xdoc/README.variables9
-rwxr-xr-xdoc/cdr.txt2
-rwxr-xr-xdsp.c13
-rwxr-xr-xenum.c47
-rwxr-xr-xfile.c38
-rwxr-xr-xformats/format_g726.c6
-rwxr-xr-xformats/format_g729.c8
-rwxr-xr-xformats/format_gsm.c6
-rwxr-xr-xformats/format_h263.c6
-rwxr-xr-xformats/format_ilbc.c6
-rwxr-xr-xformats/format_jpeg.c6
-rwxr-xr-xformats/format_pcm.c6
-rwxr-xr-xformats/format_pcm_alaw.c6
-rwxr-xr-xformats/format_sln.c7
-rwxr-xr-xformats/format_vox.c6
-rwxr-xr-xformats/format_wav.c7
-rwxr-xr-xformats/format_wav_gsm.c13
-rwxr-xr-xframe.c470
-rwxr-xr-xinclude/asterisk/acl.h1
-rwxr-xr-xinclude/asterisk/adsi.h2
-rwxr-xr-xinclude/asterisk/app.h9
-rwxr-xr-xinclude/asterisk/cdr.h2
-rwxr-xr-xinclude/asterisk/channel.h8
-rwxr-xr-xinclude/asterisk/endian.h59
-rwxr-xr-xinclude/asterisk/file.h8
-rwxr-xr-xinclude/asterisk/frame.h91
-rwxr-xr-xinclude/asterisk/io.h2
-rwxr-xr-xinclude/asterisk/lock.h10
-rwxr-xr-xinclude/asterisk/rtp.h3
-rwxr-xr-xinclude/asterisk/sched.h10
-rwxr-xr-xinclude/asterisk/utils.h2
-rwxr-xr-xinclude/asterisk/vmodem.h4
-rwxr-xr-xindications.c2
-rwxr-xr-xloader.c21
-rwxr-xr-xlogger.c66
-rwxr-xr-xmanager.c88
-rwxr-xr-xmd5.c12
-rwxr-xr-xpbx.c138
-rwxr-xr-xpbx/pbx_config.c15
-rwxr-xr-xpbx/pbx_spool.c5
-rwxr-xr-xredhat/asterisk.spec2
-rwxr-xr-xres/res_adsi.c50
-rwxr-xr-xres/res_agi.c31
-rwxr-xr-xres/res_config_odbc.c2
-rwxr-xr-xres/res_crypto.c3
-rwxr-xr-xres/res_features.c104
-rwxr-xr-xres/res_indications.c17
-rwxr-xr-xres/res_monitor.c96
-rwxr-xr-xres/res_musiconhold.c29
-rwxr-xr-xres/res_odbc.c112
-rwxr-xr-xres/res_osp.c30
-rwxr-xr-xrtp.c133
-rwxr-xr-xsay.c118
-rwxr-xr-xsched.c27
-rwxr-xr-xsounds.txt6
-rwxr-xr-xsounds/digits/minus.gsmbin0 -> 1518 bytes
-rwxr-xr-xsounds/hello-world.gsmbin0 -> 2838 bytes
-rwxr-xr-xsounds/vm-saveoper.gsmbin0 -> 16533 bytes
-rwxr-xr-xstdtime/localtime.c4
-rwxr-xr-xtdd.c2
-rwxr-xr-xutils.c2
-rwxr-xr-xutils/astman.c683
153 files changed, 5087 insertions, 2965 deletions
diff --git a/CREDITS b/CREDITS
index 8b36cfc3c..11552bdec 100755
--- a/CREDITS
+++ b/CREDITS
@@ -58,6 +58,8 @@ Thorsten Lockert - OpenBSD, FreeBSD ports, making MacOS X port run on 10.3,
bugs. tholo@sigmasoft.com
Brian West - ODBC support and Bug Marshaling
William Waites - syslog support, SIP NAT traversal for SIP-UA. ww@styx.org
+Rich Murphey - Porting to FreeBSD, NetBSD, OpenBSD, and Darwin.
+ rich@whiteoaklabs.com http://whiteoaklabs.com
=== OTHER CONTRIBUTIONS ===
John Todd - Monkey sounds and associated teletorture prompt
diff --git a/CHANGES b/ChangeLog
index 066275c0a..c8ca2cf67 100755
--- a/CHANGES
+++ b/ChangeLog
@@ -1,8 +1,279 @@
+ NOTE: Corrections or additions to the ChangeLog may be submitted to
+ http://bugs.digium.com. Documentation and formatting fixes are not
+ not listed here. A complete listing of changes is available through
+ the Asterisk-CVS mailing list hosted at http://lists.digium.com.
+
+Asterisk 1.0.10
+
+ -- chan_local
+ -- In releases 1.0.8 and 1.0.9, the Local channels that are created would
+ not be masqueraded into the new channel type. This has now been fixed.
+ -- chan_sip
+ -- The 'insecure' options have been changed to support matching peersby IP
+ only, not requiring authentication on incoming invites, or both. Before,
+ to not require authentication on incoming invites also required matching
+ peers based on IP only.
+ -- chan_zap
+ -- Before, call waiting could occur during the initial ringing on the line.
+ This has now been fixed.
+ -- app_disa
+ -- We will now not set the accountcode if one is not supplied.
+ -- app_meetme
+ -- If the first caller into a conference hangs up while being prompted for
+ the conference pin number, the conference will no longer be held open.
+ -- app_userevent
+ -- Events created with this application were indicated as a "call" event
+ instead of a "user" event. This made the "user" event permissions
+ not work correctly.
+ -- app_voicemail
+ -- When using the externpass option for voicemail, the password will be
+ immediately updated in memory as well, instead of having to wait for
+ the next time the configuration is reloaded.
+ -- app_zapras
+ -- We now ensure buffer policy is restored after RAS is done with a channel.
+ This could cause audio problems on the channel after zapras is done
+ with it.
+ -- res_agi
+ -- We now unmask the SIGHUP signal before executing an AGI script. This
+ fixes problems where some AGI scripts would continue running long after
+ the call is over.
+ -- extensions
+ -- A potential crash has been fixed when calling LEN() to get the length of
+ a string that was 80 characters or larger.
+ -- logger
+ -- The Asterisk logger will automatically detect when a log file needs to
+ be rotated. However, this feature could put Asterisk in a nasty loop
+ that would result in a crash.
+ -- general
+ -- Added man pages for astgenkey, autosupport, and safe_asterisk
+
+Asterisk 1.0.9
+
+ -- fix bug in callerid matching in the dialplan that was introduced in 1.0.8
+
+Asterisk 1.0.8
+
+ -- chan_zap
+ -- Asterisk will now also look in the regular context for the fax extension
+ while executing a macro. Previously, for this to work, the fax extension
+ would have to be included in the macro definition.
+ -- On some systems, ALERTING will be sent after PROCEEDING, so code has been
+ added to account for this case.
+ -- If no extension is specified on an overlap call, the 's' extension will
+ be used.
+ -- chan_sip
+ -- We no longer send a "to" tag on "100 Trying" messages, as it is
+ inappropriate to do so.
+ -- We now respond correctly to an invite for T.38 with a "488 Not acceptable
+ here"
+ -- We now discard saved tags on 401/407 responses in case the provider we're
+ talking to tries to pull a dirty trick on us and change it.
+ -- rtptimeout options will now be correctly set on a peer basis rather than
+ only global
+ -- chan_mgcp
+ -- Fixed setting of accountcode
+ -- Fixed where *67 to block callerid only worked for first call
+ -- chan_agent
+ -- We now will not pass audio until the agent has acked the call if the
+ configuration
+ is set up for the agent to do so.
+ -- chan_alsa
+ -- Fixed problems with the unloading of this module
+ -- res_agi
+ -- A fix has been added to prevent calls from being hung up when more than
+ one call is executing an AGI script calling the GET DATA command.
+ -- AGI scripts will now continue to run even if a file was not found with
+ the GET DATA command.
+ -- When calling SAY NUMBER with a number like 09, we will now say "nine"
+ instead of "zero"
+ -- app_dial
+ -- There was a problem where text frames would not be forwarded before the
+ channel has been answered.
+ -- app_disa
+ -- Fixed the timeout used when no password is set
+ -- app_queue
+ -- Distinctive ring has been fixed to work for queue members
+ -- rtp
+ -- Fixed a logic error when setting the "rtpchecksums" option
+ -- say.c
+ -- A problem has been fixed with saying the date in Spanish.
+ -- Makefile
+ -- A line was missing for the autosupport script that caused "make rpm" to
+ fail
+ -- format_wav_gsm
+ -- Fixed a problem with wav formatting that prevented files from being
+ played in some media players
+ -- pbx_spool
+ -- Fixed if the last line of text in a file for the call spool did not
+ contain a new line, it would not be processed
+ -- logger
+ -- Fixed the logger so that color escape sequences wouldn't be sent to the
+ logs
+ -- format_sln
+ -- A lot of changes were made to correctly handle signed linear format on
+ big endian machines
+ -- asterisk.conf
+ -- fix 'highpriority' option for asterisk.conf
+
+Asterisk 1.0.7
+
+ -- chan_sip
+ -- The fix for some codec availibility issues in 1.0.6 caused music on hold
+ problems, but has now been fixed.
+ -- chan_skinny
+ -- A check has been added to avoid a crash.
+ -- chan_iax2
+ -- A feature has been added to CVS head to have the option of sending
+ timestamps with trunk frames. It is not supported in 1.0, but a change
+ has been made so that it will at least not choke if sent trunk
+ timestamps.
+ -- app_voicemail
+ -- Some checks have been added to avoid a crash.
+ -- speex
+ -- The path /usr/include/speex has been added for a place to look for the
+ speex header.
+
+Asterisk 1.0.6
+
+ -- chan_iax2:
+ -- Fixed a bug dealing with a division by zero that could cause a crash
+ -- chan_sip:
+ -- Behavior was changed so that when a registration fails due to DNS
+ resolution issues, a retry will be attempted in 20 seconds.
+ -- Peer settings were not reset to null values when reloading the
+ configuration file. Behavior has been changed so that these values are
+ now cleared.
+ -- 'restrictcid' now properly works on MySQL peers.
+ -- Only use the default callerid if it has been specified.
+ -- Asterisk was not sending the same From: line in SIP messages during
+ certain times. Fixed to make sure it stays the same. This makes some
+ providers happier, to a working state.
+ -- Certain circumstances involving a blank callerid caused asterisk to
+ segmentation fault.
+ -- There was a problem incorrectly matching codec availablity when global
+ preferences were different from that of the user. To fix this,
+ processing of SDP data has been moved to after determining who the call
+ is coming from.
+ -- Asterisk would run out of RTP ports while waiting for SUBSCRIBE's to
+ expire even though an RTP port isn't needed in this case. This has been
+ fixed by releasing the ports early.
+ -- chan_zap:
+ -- During a certain scenario when using flash and '#' transfers you would
+ hear the other person and the music they were hearing. This has been
+ fixed.
+ -- A fix for a compilation issue with gcc4 was added.
+ -- chan_modem_bestdata:
+ -- A fix for a compilation issue with gcc4 was added.
+ -- format_g729:
+ -- Treat a 10-byte read as an end of file indication instead of an error.
+ Some G729 encoders like to put 10-bytes at the end to indicate this.
+ -- res_features:
+ -- During certain situations when parking a call, both endpoints would get
+ musiconhold. This has been fixed so the individual who parked the call
+ will hear the digits and not musiconhold.
+ -- app_dial:
+ -- DIALEDPEERNUMBER is now being set, so if you attempted to use it in the
+ past and failed, it should work now.
+ -- A callerid change caused many headaches, this has been reversed to the
+ original 1.0 behavior.
+ -- A crash caused with the combination of the 'g' option and # transfer was
+ fixed.
+ -- app_voicemail:
+ -- If two people hit the voicemail system at the same time, and were leaving
+ a message the second message was overwriting the first. This has been
+ fixed so that each one is distinct and will not overwrite eachother.
+ -- cdr_tds:
+ -- If the server you were using was going down, it had the potential to
+ bring your asterisk server down with it. Extra stuff has been added so
+ as to bring in more error/connection checking.
+ -- cdr_pgsql:
+ -- This will now attempt to reconnect after a connection problem.
+ -- IAXY firmware:
+ -- This has been updated to version 23. It includes a fix for lost
+ registrations.
+ -- internals
+ -- Behavior was changed for 'show codec <number>' to make it more intuitive.
+ -- DNS failures and asterisk do not get along too well, this is not totally
+ the case anymore.
+ -- Asterisk will now handle DNS failures at startup more gracefully, and
+ won't crash and burn
+ -- Choosing to append to a wave file would render the outputted wave file
+ corrupt. Appending now works again.
+ -- If you failed to define certain keys, asterisk had the potential to crash
+ when seeing if you had used them.
+ -- Attempting to use such things as ${EXTEN:-1} gave a wrong return value.
+ However, this was never a documented feature...
+
+Asterisk 1.0.5
+
+ -- chan_zap
+ -- fix a callerid bug introduced in 1.0.4
+ -- app_queue
+ -- fix some penalty behavior
+
+Asterisk 1.0.4
+
+ -- general
+ -- fix memory leak evident with extensive use of variables
+ -- update IAXy firmware to version 22
+ -- enable some special write protection
+ -- enable outbound DTMF
+ -- fix seg fault with incorrect usage of SetVar
+ -- other minor fixes including typos and doc updates
+ -- chan_sip
+ -- fix codecs to not be case sensitive
+ -- Re-use auth credentials
+ -- fix MWI when using type=friend
+ -- fix global NAT option
+ -- chan_agent / chan_local
+ -- fix incorrect use count
+ -- chan_zap
+ -- Allow CID rings to be configured in zapata.conf
+ -- no more patching needed for UK CID
+ -- app_macro
+ -- allow Macros to exit with '*' or '#' like regular extension processing
+ -- app_voicemail
+ -- don't allow '#' as a password
+ -- add option to save voicemail before going to the operator
+ -- fix global operator=yes
+ -- app_read
+ -- return 0 instead of -1 if user enters nothing
+ -- res_agi
+ -- don't exit AGI when file not found to stream
+ -- send script parameter when using FastAGI
+
+Asterisk 1.0.3
+
+ -- chan_zap
+ -- fix seg fault when doing *0 to flash a trunk
+ -- rtp
+ -- seg fault fix
+ -- chan_sip
+ -- fix to prevent seg fault when attempting a transfer
+ -- fix bug with supervised transfers
+ -- fix codec preferences
+ -- chan_h323
+ -- fix compilation problem
+ -- chan_iax2
+ -- avoid a deadlock related to a static config of a BUNCH of peers
+ -- cdr_pgsql
+ -- fix memory leak when reading config
+ -- Numerous other minor bug fixes
+
+Asterisk 1.0.2
+
+ -- Major bugfix release
+
+Asterisk 1.0.1
+
+ -- Added AGI over TCP support
+ -- Add ability to purge callers from queue if no agents are logged in
-- Fix inband PRI indication detection
-- Fix for MGCP - always request digits if no RTP stream
-- Fixed seg fault for ast_control_streamfile
- -- Added AGI over TCP support
-- Make pick-up extension configurable via features.conf
+ -- Numerous other bug fixes
+
Asterisk 1.0.0
-- Use Q.931 standard cause codes for asterisk cause codes
-- Bug fixes from the bug tracker
diff --git a/Makefile b/Makefile
index 5a6a51c49..080735805 100755
--- a/Makefile
+++ b/Makefile
@@ -38,6 +38,7 @@ OPTIONS+=$(shell if $(CC) -mcpu=v8 -S -o /dev/null -xc /dev/null >/dev/null 2>&1
OPTIONS+=-fomit-frame-pointer
endif
+MPG123TARG=linux
endif
ifeq ($(findstring BSD,${OSARCH}),BSD)
@@ -138,15 +139,17 @@ CFLAGS+=$(shell if [ -f /usr/include/osp/osp.h ]; then echo "-DOSP_SUPPORT -I/us
ifeq (${OSARCH},FreeBSD)
OSVERSION=$(shell make -V OSVERSION -f /usr/share/mk/bsd.port.subdir.mk)
-CFLAGS+=$(if ${OSVERSION}<500016,-D_THREAD_SAFE)
-LIBS+=$(if ${OSVERSION}<502102,-lc_r,-pthread)
+CFLAGS+=$(shell if test ${OSVERSION} -lt 500016 ; then echo "-D_THREAD_SAFE"; fi)
+LIBS+=$(shell if test ${OSVERSION} -lt 502102 ; then echo "-lc_r"; else echo "-pthread"; fi)
INCLUDE+=-I/usr/local/include
CFLAGS+=$(shell if [ -d /usr/local/include/spandsp ]; then echo "-I/usr/local/include/spandsp"; fi)
+MPG123TARG=freebsd
endif # FreeBSD
ifeq (${OSARCH},NetBSD)
CFLAGS+=-pthread
-INCLUDE+=-I/usr/local/include
+INCLUDE+=-I/usr/local/include -I/usr/pkg/include
+MPG123TARG=netbsd
endif
ifeq (${OSARCH},OpenBSD)
@@ -197,7 +200,7 @@ ifeq (${OSARCH},FreeBSD)
LIBS+=-lcrypto
endif
ifeq (${OSARCH},NetBSD)
-LIBS+=-lpthread -lcrypto -lm -L/usr/local/lib -lncurses
+LIBS+=-lpthread -lcrypto -lm -L/usr/local/lib -L/usr/pkg/lib -lncurses
endif
ifeq (${OSARCH},OpenBSD)
LIBS=-lcrypto -lpthread -lm -lncurses
@@ -211,14 +214,25 @@ OBJS=io.o sched.o logger.o frame.o loader.o config.o channel.o \
astmm.o enum.o srv.o dns.o aescrypt.o aestab.o aeskey.o \
utils.o
ifeq (${OSARCH},Darwin)
-OBJS+=poll.o dlfcn.o
ASTLINK=-Wl,-dynamic
SOLINK=-dynamic -bundle -undefined suppress -force_flat_namespace
+OBJS+= poll.o
+CFLAGS+=-DPOLLCOMPAT
else
ASTLINK=-Wl,-E
SOLINK=-shared -Xlinker -x
endif
+ifeq ($(wildcard $(CROSS_COMPILE_TARGET)/usr/include/sys/poll.h),)
+ OBJS+= poll.o
+ CFLAGS+=-DPOLLCOMPAT
+endif
+
+ifeq ($(wildcard $(CROSS_COMPILE_TARGET)/usr/include/dlfcn.h),)
+ OBJS+= dhfcn.o
+ CFLAGS+=-DDLFCNCOMPAT
+endif
+
CC=gcc
INSTALL=install
@@ -307,7 +321,7 @@ clean:
rm -f build.h
rm -f ast_expr.c
@if [ -e editline/Makefile ]; then $(MAKE) -C editline distclean ; fi
- @if [ -d mpg123-0.59r ]; then make -C mpg123-0.59r clean; fi
+ @if [ -d mpg123-0.59r ]; then $(MAKE) -C mpg123-0.59r clean; fi
$(MAKE) -C db1-ast clean
$(MAKE) -C stdtime clean
@@ -339,7 +353,7 @@ datafiles: all
exit 1; \
fi; \
done
- for x in sounds/vm-* sounds/transfer* sounds/pbx-* sounds/ss-* sounds/beep* sounds/dir-* sounds/conf-* sounds/agent-* sounds/invalid* sounds/tt-* sounds/auth-* sounds/privacy-* sounds/queue-*; do \
+ for x in sounds/vm-* sounds/transfer* sounds/pbx-* sounds/ss-* sounds/beep* sounds/dir-* sounds/conf-* sounds/agent-* sounds/invalid* sounds/tt-* sounds/auth-* sounds/privacy-* sounds/queue-* sounds/hello-*; do \
if grep -q "^%`basename $$x`%" sounds.txt; then \
install -m 644 $$x $(DESTDIR)$(ASTVARLIBDIR)/sounds ; \
else \
@@ -374,6 +388,7 @@ bininstall: all
mkdir -p $(DESTDIR)$(ASTSPOOLDIR)/tmp
install -m 755 asterisk $(DESTDIR)$(ASTSBINDIR)/
install -m 755 contrib/scripts/astgenkey $(DESTDIR)$(ASTSBINDIR)/
+ install -m 755 contrib/scripts/autosupport $(DESTDIR)$(ASTSBINDIR)/
if [ ! -f $(DESTDIR)$(ASTSBINDIR)/safe_asterisk ]; then \
install -m 755 contrib/scripts/safe_asterisk $(DESTDIR)$(ASTSBINDIR)/ ;\
fi
@@ -398,6 +413,9 @@ bininstall: all
install -m 644 keys/iaxtel.pub $(DESTDIR)$(ASTVARLIBDIR)/keys
install -m 644 keys/freeworlddialup.pub $(DESTDIR)$(ASTVARLIBDIR)/keys
install -m 644 asterisk.8.gz $(DESTDIR)$(ASTMANDIR)/man8
+ install -m 644 contrib/scripts/astgenkey.8 $(DESTDIR)$(ASTMANDIR)/man8
+ install -m 644 contrib/scripts/autosupport.8 $(DESTDIR)$(ASTMANDIR)/man8
+ install -m 644 contrib/scripts/safe_asterisk.8 $(DESTDIR)$(ASTMANDIR)/man8
if [ -d contrib/firmware/iax ]; then \
install -m 644 contrib/firmware/iax/iaxy.bin $(DESTDIR)$(ASTVARLIBDIR)/firmware/iax/iaxy.bin; \
else \
@@ -405,7 +423,7 @@ bininstall: all
fi
( cd $(DESTDIR)$(ASTVARLIBDIR)/sounds ; ln -s $(ASTSPOOLDIR)/vm . )
( cd $(DESTDIR)$(ASTVARLIBDIR)/sounds ; ln -s $(ASTSPOOLDIR)/voicemail . )
- if [ -f mpg123-0.59r/mpg123 ]; then make -C mpg123-0.59r install; fi
+ if [ -f mpg123-0.59r/mpg123 ]; then $(MAKE) -C mpg123-0.59r install; fi
@echo " +---- Asterisk Installation Complete -------+"
@echo " + +"
@echo " + YOU MUST READ THE SECURITY DOCUMENT +"
@@ -427,6 +445,19 @@ bininstall: all
@echo " + **Note** This requires that you have +"
@echo " + doxygen installed on your local system +"
@echo " +-------------------------------------------+"
+ @echo " + +"
+ @echo " + ** NOTE FOR DOWNGRADING FROM CVS HEAD ** +"
+ @echo " + +"
+ @echo " + If you are downgrading from CVS HEAD to +"
+ @echo " + a stable release, remember to delete +"
+ @echo " + everything from your asterisk modules +"
+ @echo " + directory (/usr/lib/asterisk/modules/) +"
+ @echo " + and the asterisk header directory +"
+ @echo " + (/usr/include/asterisk/) +"
+ @echo " + before doing a '$(MAKE) install'. +"
+ @echo " + +"
+ @echo " +-------------------------------------------+"
+
install: all datafiles bininstall
@@ -518,7 +549,7 @@ mpg123:
@wget -V >/dev/null || (echo "You need wget" ; false )
[ -f mpg123-0.59r.tar.gz ] || wget http://www.mpg123.de/mpg123/mpg123-0.59r.tar.gz
[ -d mpg123-0.59r ] || tar xfz mpg123-0.59r.tar.gz
- make -C mpg123-0.59r linux
+ $(MAKE) -C mpg123-0.59r $(MPG123TARG)
config:
if [ -d /etc/rc.d/init.d ]; then \
@@ -537,12 +568,21 @@ depend: .depend
for x in $(SUBDIRS); do $(MAKE) -C $$x depend || exit 1 ; done
.depend:
+ @if ! which mpg123 &>/dev/null ; then \
+ echo "*** You don't have mpg123 installed. You're going to need ***";\
+ echo "*** it if you want MusicOnHold ***";\
+ elif ! mpg123 --longhelp 2>&1 | grep .59r &>/dev/null ; then \
+ echo "*************************************************************";\
+ echo "*** You have the WRONG version of mpg123... you need .59r ***";\
+ echo "*** Use 'make mpg123' to get the right verison ***";\
+ echo "*************************************************************";\
+ fi
./mkdep ${CFLAGS} `ls *.c`
FORCE:
%_env:
- make -C $(shell echo $@ | sed "s/_env//g") env
+ $(MAKE) -C $(shell echo $@ | sed "s/_env//g") env
env:
env
diff --git a/README b/README
index 64bf06a20..2e196c05f 100755
--- a/README
+++ b/README
@@ -136,6 +136,67 @@ parameters. For example, the line "channel => 25-47" creates objects for
the channels 25 through 47 of the tormenta card, obtaining the settings
from the variables specified above.
+* SPECIAL NOTE ON TIME
+
+ Those using SIP phones should be aware the Asterisk is sensitive to
+large jumps in time. Manually changing the system time using date(1)
+(or other similar commands) may cause SIP registrations and other
+internal processes to fail. If your system cannot keep accurate time
+by itself use NTP (http://www.ntp.org/) to keep the system clock
+synchronized to "real time". NTP is designed to keep the system clock
+synchronized by speeding up or slowing down the system clock until it
+is synchronized to "real time" rather than by jumping the time and
+causing discontinuities. Most Linux distributions include precompiled
+versions of NTP. Beware of some time synchronization methods that get
+the correct real time periodically and then manually set the system
+clock.
+
+ Apparent time changes due to daylight savings time are just that,
+apparent. The use of daylight savings time in a Linux system is
+purely a user interface issue and does not affect the operation of the
+Linux kernel or Asterisk. The system clock on Linux kernels operates
+on UTC. UTC does not use daylight savings time.
+
+ Also note that this issue is separate from the clocking of TDM
+channels, and is known to at least affect SIP registrations.
+
+* FILE DESCRIPTORS
+
+ Depending on the size of your system and your configuration,
+Asterisk can consume a large number of file descriptors. In UNIX,
+file descriptors are used for more than just files on disk. File
+descriptors are also used for handling network communication
+(e.g. SIP, IAX2, or H.323 calls) and hardware access (e.g. analog and
+digital trunk hardware). Asterisk accesses many on-disk files for
+everything from configuration information to voicemail storage.
+
+ Most systems limit the number of file descriptors that Asterisk can
+have open at one time. This can limit the number of simultaneous
+calls that your system can handle. For example, if the limit is set
+at 1024 (a common default value) Asterisk can handle approxiately 150
+SIP calls simultaneously. To change the number of file descriptors
+follow the instructions for your system below:
+
+== PAM-based Linux System ==
+
+ If your system uses PAM (Pluggable Authentication Modules) edit
+/etc/security/limits.conf. Add these lines to the bottom of the file:
+
+root soft nofile 4096
+root hard nofile 8196
+asterisk soft nofile 4096
+asterisk hard nofile 8196
+
+(adjust the numbers to taste). You may need to reboot the system for
+these changes to take effect.
+
+== Generic UNIX System ==
+
+ If there are no instructions specifically adapted to your system
+above you can try adding the command "ulimit -n 8192" to the script
+that starts Asterisk.
+
+
* MORE INFORMATION
See the doc directory for more documentation.
diff --git a/acl.c b/acl.c
index 6c460969f..6e4ffc44a 100755
--- a/acl.c
+++ b/acl.c
@@ -242,20 +242,19 @@ int ast_ouraddrfor(struct in_addr *them, struct in_addr *us)
memset(&m_rtmsg, 0, sizeof(m_rtmsg));
m_rtmsg.m_rtm.rtm_type = RTM_GET;
- m_rtmsg.m_rtm.rtm_flags = RTF_UP | RTF_HOST;
m_rtmsg.m_rtm.rtm_version = RTM_VERSION;
ast_mutex_lock(&routeseq_lock);
seq = ++routeseq;
ast_mutex_unlock(&routeseq_lock);
m_rtmsg.m_rtm.rtm_seq = seq;
- m_rtmsg.m_rtm.rtm_addrs = RTA_IFA | RTA_DST;
+ m_rtmsg.m_rtm.rtm_addrs = RTA_DST | RTA_IFA;
m_rtmsg.m_rtm.rtm_msglen = sizeof(struct rt_msghdr) + sizeof(struct sockaddr_in);
sin = (struct sockaddr_in *)m_rtmsg.m_space;
sin->sin_family = AF_INET;
sin->sin_len = sizeof(struct sockaddr_in);
sin->sin_addr = *them;
- if ((s = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) {
+ if ((s = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC)) < 0) {
ast_log(LOG_ERROR, "Error opening routing socket\n");
return -1;
}
@@ -268,7 +267,7 @@ int ast_ouraddrfor(struct in_addr *them, struct in_addr *us)
}
do {
l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
- } while (l > 0 && (m_rtmsg.m_rtm.rtm_seq != 1 || m_rtmsg.m_rtm.rtm_pid != pid));
+ } while (l > 0 && (m_rtmsg.m_rtm.rtm_seq != seq || m_rtmsg.m_rtm.rtm_pid != pid));
if (l < 0) {
if (errno != EAGAIN)
ast_log(LOG_ERROR, "Error reading from routing socket\n");
@@ -379,3 +378,32 @@ int ast_ouraddrfor(struct in_addr *them, struct in_addr *us)
return 0;
#endif
}
+
+int ast_find_ourip(struct in_addr *ourip, struct sockaddr_in bindaddr)
+{
+ char ourhost[MAXHOSTNAMELEN]="";
+ struct ast_hostent ahp;
+ struct hostent *hp;
+ struct in_addr saddr;
+
+ /* just use the bind address if it is nonzero */
+ if (ntohl(bindaddr.sin_addr.s_addr)) {
+ memcpy(ourip, &bindaddr.sin_addr, sizeof(*ourip));
+ return 0;
+ }
+ /* try to use our hostname */
+ if (gethostname(ourhost, sizeof(ourhost)-1)) {
+ ast_log(LOG_WARNING, "Unable to get hostname\n");
+ } else {
+ hp = ast_gethostbyname(ourhost, &ahp);
+ if (hp) {
+ memcpy(ourip, hp->h_addr, sizeof(*ourip));
+ return 0;
+ }
+ }
+ /* A.ROOT-SERVERS.NET. */
+ if (inet_aton("198.41.0.4", &saddr) && !ast_ouraddrfor(&saddr, ourip))
+ return 0;
+ return -1;
+}
+
diff --git a/aesopt.h b/aesopt.h
index 94e3e47f1..d5ae00160 100755
--- a/aesopt.h
+++ b/aesopt.h
@@ -136,6 +136,7 @@
#define _AESOPT_H
#include <asterisk/aes.h>
+#include "asterisk/endian.h"
/* CONFIGURATION - USE OF DEFINES
@@ -146,24 +147,6 @@
#if clauses.
*/
-/* PLATFORM SPECIFIC INCLUDES */
-
-#if defined( __OpenBSD__ )
-# include <machine/types.h>
-# include <sys/endian.h>
-#elif defined( __FreeBSD__ ) || defined( __NetBSD__ )
-# include <sys/types.h>
-# include <sys/endian.h>
-#elif defined( BSD ) && ( BSD >= 199103 ) || defined(__APPLE__)
-# include <machine/endian.h>
-#elif defined( __GNUC__ ) || defined( __GNU_LIBRARY__ )
-# include <endian.h>
-#if !defined(__APPLE__)
-# include <byteswap.h>
-#endif
-#elif defined( linux )
-# include <endian.h>
-#endif
/* BYTE ORDER IN 32-BIT WORDS
diff --git a/app.c b/app.c
index f653aa909..72617fd7e 100755
--- a/app.c
+++ b/app.c
@@ -136,6 +136,13 @@ int ast_app_getvoice(struct ast_channel *c, char *dest, char *dstfmt, char *prom
ast_frfree(f);
break;
}
+ res = ast_writestream(writer, f);
+ if (res < 0) {
+ ast_log(LOG_WARNING, "Failed to write to stream at %s!\n", dest);
+ ast_frfree(f);
+ break;
+ }
+
}
ast_frfree(f);
}
@@ -278,7 +285,7 @@ int ast_dtmf_stream(struct ast_channel *chan,struct ast_channel *peer,char *digi
if (!res) {
res = ast_waitfor(chan,100);
if (res > -1) {
- for (ptr=digits;*ptr;*ptr++) {
+ for (ptr=digits; *ptr; ptr++) {
if (*ptr == 'w') {
res = ast_safe_sleep(chan, 500);
if (res)
@@ -518,9 +525,10 @@ int ast_play_and_wait(struct ast_channel *chan, char *fn)
static int global_silence_threshold = 128;
static int global_maxsilence = 0;
-int ast_play_and_record(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt, int *duration, int silencethreshold, int maxsilence)
+int ast_play_and_record(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt, int *duration, int silencethreshold, int maxsilence, const char *path)
{
- char d, *fmts;
+ int d;
+ char *fmts;
char comment[256];
int x, fmtcnt=1, res=-1,outmsg=0;
struct ast_frame *f;
@@ -528,7 +536,7 @@ int ast_play_and_record(struct ast_channel *chan, char *playfile, char *recordfi
char *sfmt[MAX_OTHER_FORMATS];
char *stringp=NULL;
time_t start, end;
- struct ast_dsp *sildet; /* silence detector dsp */
+ struct ast_dsp *sildet=NULL; /* silence detector dsp */
int totalsilence = 0;
int dspsilence = 0;
int gotsilence = 0; /* did we timeout for silence? */
@@ -585,18 +593,22 @@ int ast_play_and_record(struct ast_channel *chan, char *playfile, char *recordfi
}
}
- sildet = ast_dsp_new(); /* Create the silence detector */
- if (!sildet) {
- ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
- return -1;
- }
- ast_dsp_set_threshold(sildet, silencethreshold);
+ if (path)
+ ast_unlock_path(path);
+
if (maxsilence > 0) {
+ sildet = ast_dsp_new(); /* Create the silence detector */
+ if (!sildet) {
+ ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
+ return -1;
+ }
+ ast_dsp_set_threshold(sildet, silencethreshold);
rfmt = chan->readformat;
res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
if (res < 0) {
ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
+ ast_dsp_free(sildet);
return -1;
}
}
@@ -640,13 +652,13 @@ int ast_play_and_record(struct ast_channel *chan, char *playfile, char *recordfi
totalsilence = 0;
if (totalsilence > maxsilence) {
- /* Ended happily with silence */
- if (option_verbose > 2)
- ast_verbose( VERBOSE_PREFIX_3 "Recording automatically stopped after a silence of %d seconds\n", totalsilence/1000);
- ast_frfree(f);
- gotsilence = 1;
- outmsg=2;
- break;
+ /* Ended happily with silence */
+ if (option_verbose > 2)
+ ast_verbose( VERBOSE_PREFIX_3 "Recording automatically stopped after a silence of %d seconds\n", totalsilence/1000);
+ ast_frfree(f);
+ gotsilence = 1;
+ outmsg=2;
+ break;
}
}
/* Exit on any error */
@@ -706,10 +718,12 @@ int ast_play_and_record(struct ast_channel *chan, char *playfile, char *recordfi
for (x=0;x<fmtcnt;x++) {
if (!others[x])
break;
- if (totalsilence)
- ast_stream_rewind(others[x], totalsilence-200);
- else
- ast_stream_rewind(others[x], 200);
+ if (res > 0) {
+ if (totalsilence)
+ ast_stream_rewind(others[x], totalsilence-200);
+ else
+ ast_stream_rewind(others[x], 200);
+ }
ast_truncstream(others[x]);
ast_closestream(others[x]);
}
@@ -718,20 +732,20 @@ int ast_play_and_record(struct ast_channel *chan, char *playfile, char *recordfi
ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(rfmt), chan->name);
}
}
- if (outmsg) {
- if (outmsg > 1) {
+ if (outmsg > 1) {
/* Let them know recording is stopped */
- ast_streamfile(chan, "auth-thankyou", chan->language);
+ if(!ast_streamfile(chan, "auth-thankyou", chan->language))
ast_waitstream(chan, "");
- }
}
-
+ if (sildet)
+ ast_dsp_free(sildet);
return res;
}
int ast_play_and_prepend(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt, int *duration, int beep, int silencethreshold, int maxsilence)
{
- char d = 0, *fmts;
+ int d = 0;
+ char *fmts;
char comment[256];
int x, fmtcnt=1, res=-1,outmsg=0;
struct ast_frame *f;
@@ -961,3 +975,46 @@ int ast_play_and_prepend(struct ast_channel *chan, char *playfile, char *recordf
return res;
}
+int ast_lock_path(const char *path)
+{
+ char *s;
+ char *fs;
+ int res;
+ int fd;
+ time_t start;
+ s = alloca(strlen(path) + 10);
+ fs = alloca(strlen(path) + 20);
+ if (!fs || !s) {
+ ast_log(LOG_WARNING, "Out of memory!\n");
+ return -1;
+ }
+ snprintf(fs, strlen(path) + 19, "%s/%s-%08x", path, ".lock", rand());
+ fd = open(fs, O_WRONLY | O_CREAT | O_EXCL, 0600);
+ if (fd < 0) {
+ fprintf(stderr, "Unable to create lock file: %s\n", strerror(errno));
+ return -1;
+ }
+ close(fd);
+ snprintf(s, strlen(path) + 9, "%s/%s", path, ".lock");
+ time(&start);
+ while (((res = link(fs, s)) < 0) && (errno == EEXIST) && (time(NULL) - start < 5))
+ usleep(1);
+ if (res < 0) {
+ ast_log(LOG_WARNING, "Failed to lock path '%s': %s\n", path, strerror(errno));
+ }
+ unlink(fs);
+ ast_log(LOG_DEBUG, "Locked path '%s'\n", path);
+ return res;
+}
+
+int ast_unlock_path(const char *path)
+{
+ char *s;
+ s = alloca(strlen(path) + 10);
+ if (!s)
+ return -1;
+ snprintf(s, strlen(path) + 9, "%s/%s", path, ".lock");
+ ast_log(LOG_DEBUG, "Unlocked path '%s'\n", path);
+ return unlink(s);
+}
+
diff --git a/apps/app_alarmreceiver.c b/apps/app_alarmreceiver.c
index 28d28b4c4..552423036 100755
--- a/apps/app_alarmreceiver.c
+++ b/apps/app_alarmreceiver.c
@@ -55,7 +55,7 @@ static char *tdesc = "Alarm Receiver for Asterisk";
static char *app = "AlarmReceiver";
-static char *synopsis = "Provide support for receving alarm reports from a burglar or fire alarm panel\n";
+static char *synopsis = "Provide support for receving alarm reports from a burglar or fire alarm panel";
static char *descrip =
"Alarm receiver application for Asterisk. Only 1 signalling format is supported at this time:\n"
"Ademco Contact ID. This application should be called whenever there is an alarm panel calling in\n"
diff --git a/apps/app_chanisavail.c b/apps/app_chanisavail.c
index 4438663ce..07ea55c79 100755
--- a/apps/app_chanisavail.c
+++ b/apps/app_chanisavail.c
@@ -38,11 +38,12 @@ static char *descrip =
"Checks is any of the requested channels are available. If none\n"
"of the requested channels are available the new priority will be\n"
"n+101 (unless such a priority does not exist or on error, in which\n"
-"case ChanIsAvail will return -1). If any of the requested channels\n"
-"are available, the next priority will be n+1, the channel variable\n"
-"${AVAILCHAN} will be set to the name of the available channel and\n"
-"the ChanIsAvail app will return 0. ${AVAILORIGCHAN} is\n"
-"the canonical channel name that was used to create the channel.\n";
+"case ChanIsAvail will return -1).\n"
+"If any of the requested channels are available, the next priority will be n+1,\n"
+"the channel variable ${AVAILCHAN} will be set to the name of the available channel\n"
+"and the ChanIsAvail app will return 0.\n"
+"${AVAILORIGCHAN} is the canonical channel name that was used to create the channel.\n"
+"${AVAILSTATUS} is the status code for the channel.\n";
STANDARD_LOCAL_USER;
diff --git a/apps/app_controlplayback.c b/apps/app_controlplayback.c
index b44eafba9..aa6dd3435 100755
--- a/apps/app_controlplayback.c
+++ b/apps/app_controlplayback.c
@@ -64,24 +64,19 @@ static int controlplayback_exec(struct ast_channel *chan, void *data)
file = tmp;
if ((skip=strchr(tmp,'|'))) {
- *skip = '\0';
- *skip++;
+ *skip++ = '\0';
fwd=strchr(skip,'|');
if (fwd) {
- *fwd = '\0';
- *fwd++;
+ *fwd++ = '\0';
rev = strchr(fwd,'|');
if (rev) {
- *rev = '\0';
- *rev++;
+ *rev++ = '\0';
stop = strchr(rev,'|');
if (stop) {
- *stop = '\0';
- *stop++;
+ *stop++ = '\0';
pause = strchr(stop,'|');
if (pause) {
- *pause = '\0';
- *pause++;
+ *pause++ = '\0';
}
}
}
diff --git a/apps/app_cut.c b/apps/app_cut.c
index da397f66e..afaaf8473 100755
--- a/apps/app_cut.c
+++ b/apps/app_cut.c
@@ -31,10 +31,10 @@ static char *tdesc = "Cuts up variables";
static char *app_cut = "Cut";
-static char *cut_synopsis = "Cut(newvar=varname|delimiter|fieldspec)";
+static char *cut_synopsis = "Splits a variable's content using the specified delimiter";
static char *cut_descrip =
-"Cut(newvar=varname,delimiter,field)\n"
+"Usage: Cut(newvar=varname,delimiter,fieldspec)\n"
" newvar - new variable created from result string\n"
" varname - variable you want cut\n"
" delimiter - defaults to '-'\n"
diff --git a/apps/app_dial.c b/apps/app_dial.c
index 7f3c3d768..c7b51c19f 100755
--- a/apps/app_dial.c
+++ b/apps/app_dial.c
@@ -113,6 +113,7 @@ struct localuser {
int allowdisconnect_in;
int allowdisconnect_out;
int forcecallerid;
+ int noforwardhtml;
struct localuser *next;
};
@@ -134,7 +135,7 @@ static void hanguptree(struct localuser *outgoing, struct ast_channel *exception
#define AST_MAX_WATCHERS 256
-static struct ast_channel *wait_for_answer(struct ast_channel *in, struct localuser *outgoing, int *to, int *allowredir_in, int *allowredir_out, int *allowdisconnect_in, int *allowdisconnect_out, int *sentringing, char *status, size_t statussize)
+static struct ast_channel *wait_for_answer(struct ast_channel *in, struct localuser *outgoing, int *to, int *allowredir_in, int *allowredir_out, int *allowdisconnect_in, int *allowdisconnect_out, int *noforwardhtml, int *sentringing, char *status, size_t statussize)
{
struct localuser *o;
int found;
@@ -207,6 +208,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, struct localu
*allowredir_out = o->allowredirect_out;
*allowdisconnect_in = o->allowdisconnect_in;
*allowdisconnect_out = o->allowdisconnect_out;
+ *noforwardhtml = o->noforwardhtml;
}
} else if (o->chan && (o->chan == winner)) {
if (!ast_strlen_zero(o->chan->call_forward)) {
@@ -301,6 +303,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, struct localu
*allowredir_out = o->allowredirect_out;
*allowdisconnect_in = o->allowdisconnect_in;
*allowdisconnect_out = o->allowdisconnect_out;
+ *noforwardhtml = o->noforwardhtml;
}
break;
case AST_CONTROL_BUSY:
@@ -336,13 +339,14 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, struct localu
case AST_CONTROL_PROGRESS:
if (option_verbose > 2)
ast_verbose ( VERBOSE_PREFIX_3 "%s is making progress passing it to %s\n", o->chan->name,in->name);
- ast_indicate(in, AST_CONTROL_PROGRESS);
+ if (!outgoing->ringbackonly)
+ ast_indicate(in, AST_CONTROL_PROGRESS);
break;
case AST_CONTROL_OFFHOOK:
/* Ignore going off hook */
break;
case -1:
- if (!outgoing->ringbackonly && !outgoing->musiconhold) {
+ if (!(outgoing->ringbackonly || outgoing->musiconhold)) {
if (option_verbose > 2)
ast_verbose( VERBOSE_PREFIX_3 "%s stopped sounds\n", o->chan->name);
ast_indicate(in, -1);
@@ -360,7 +364,14 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, struct localu
!(outgoing->ringbackonly || outgoing->musiconhold)) {
if (ast_write(in, f))
ast_log(LOG_WARNING, "Unable to forward image\n");
+ } else if (single && (f->frametype == AST_FRAME_TEXT) &&
+ !(outgoing->ringbackonly || outgoing->musiconhold)) {
+ if (ast_write(in, f))
+ ast_log(LOG_WARNING, "Unable to text\n");
+ } else if (single && (f->frametype == AST_FRAME_HTML) && !outgoing->noforwardhtml) {
+ ast_channel_sendhtml(in, f->subclass, f->data, f->datalen);
}
+
ast_frfree(f);
} else {
in->hangupcause = o->chan->hangupcause;
@@ -383,6 +394,8 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, struct localu
/* Got hung up */
*to=-1;
strncpy(status, "CANCEL", statussize - 1);
+ if (f)
+ ast_frfree(f);
return NULL;
}
if (f && (f->frametype == AST_FRAME_DTMF) && *allowdisconnect_out &&
@@ -391,13 +404,18 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, struct localu
ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass);
*to=0;
strcpy(status, "CANCEL");
+ ast_frfree(f);
return NULL;
}
+
+ if (single && f && (f->frametype == AST_FRAME_HTML) && !outgoing->noforwardhtml)
+ ast_channel_sendhtml(outgoing->chan, f->subclass, f->data, f->datalen);
+
if (single && ((f->frametype == AST_FRAME_VOICE) || (f->frametype == AST_FRAME_DTMF))) {
if (ast_write(outgoing->chan, f))
ast_log(LOG_WARNING, "Unable to forward voice\n");
- ast_frfree(f);
}
+ ast_frfree(f);
}
if (!*to && (option_verbose > 2))
ast_verbose( VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", orig);
@@ -421,6 +439,7 @@ static int dial_exec(struct ast_channel *chan, void *data)
int allowredir_out=0;
int allowdisconnect_in=0;
int allowdisconnect_out=0;
+ int noforwardhtml=0;
int hasmacro = 0;
int privacy=0;
int announce=0;
@@ -726,6 +745,9 @@ static int dial_exec(struct ast_channel *chan, void *data)
if (strchr(transfer, 'f'))
tmp->forcecallerid = 1;
else tmp->forcecallerid = 0;
+ if (url)
+ tmp->noforwardhtml = 1;
+ else tmp->noforwardhtml = 0;
}
strncpy(numsubst, number, sizeof(numsubst)-1);
/* If we're dialing by extension, look at the extension to know what to dial */
@@ -746,6 +768,7 @@ static int dial_exec(struct ast_channel *chan, void *data)
cur = rest;
continue;
}
+ pbx_builtin_setvar_helper(tmp->chan, "DIALEDPEERNUMBER", numsubst);
if (!ast_strlen_zero(tmp->chan->call_forward)) {
char tmpchan[256]="";
char *stuff;
@@ -879,7 +902,7 @@ static int dial_exec(struct ast_channel *chan, void *data)
strncpy(status, "CHANUNAVAIL", sizeof(status) - 1);
time(&start_time);
- peer = wait_for_answer(chan, outgoing, &to, &allowredir_in, &allowredir_out, &allowdisconnect_in, &allowdisconnect_out, &sentringing, status, sizeof(status));
+ peer = wait_for_answer(chan, outgoing, &to, &allowredir_in, &allowredir_out, &allowdisconnect_in, &allowdisconnect_out, &sentringing, &noforwardhtml, status, sizeof(status));
if (!peer) {
if (to)
@@ -908,8 +931,11 @@ static int dial_exec(struct ast_channel *chan, void *data)
ast_cdr_setdestchan(chan->cdr, peer->name);
if (peer->name)
pbx_builtin_setvar_helper(chan, "DIALEDPEERNAME", peer->name);
- if (numsubst)
- pbx_builtin_setvar_helper(chan, "DIALEDPEERNUMBER", numsubst);
+
+ number = pbx_builtin_getvar_helper(peer, "DIALEDPEERNUMBER");
+ if (!number)
+ number = numsubst;
+ pbx_builtin_setvar_helper(chan, "DIALEDPEERNUMBER", number);
/* JDG: sendurl */
if( url && !ast_strlen_zero(url) && ast_channel_supports_html(peer) ) {
ast_log(LOG_DEBUG, "app_dial: sendurl=%s.\n", url);
@@ -1029,7 +1055,7 @@ out:
LOCAL_USER_REMOVE(u);
- if((go_on>0) && (!chan->_softhangup))
+ if((go_on>0) && (!chan->_softhangup) && (res != AST_PBX_KEEPALIVE))
res=0;
return res;
diff --git a/apps/app_disa.c b/apps/app_disa.c
index 03f13c67c..b58d5a54e 100755
--- a/apps/app_disa.c
+++ b/apps/app_disa.c
@@ -22,6 +22,7 @@
#include <asterisk/module.h>
#include <asterisk/translate.h>
#include <asterisk/ulaw.h>
+#include <asterisk/utils.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
@@ -161,7 +162,7 @@ static int disa_exec(struct ast_channel *chan, void *data)
if (!strcasecmp(tmp, "no-password"))
{;
- k = 1;
+ k |= 1; /* We have the password */
ast_log(LOG_DEBUG, "DISA no-password login success\n");
}
gettimeofday(&lastdigittime,NULL);
@@ -173,10 +174,10 @@ static int disa_exec(struct ast_channel *chan, void *data)
gettimeofday(&now,NULL);
/* if outa time, give em reorder */
if (ms_diff(&now,&lastdigittime) >
- ((k) ? digittimeout : firstdigittimeout))
+ ((k&2) ? digittimeout : firstdigittimeout))
{
ast_log(LOG_DEBUG,"DISA %s entry timeout on chan %s\n",
- ((k) ? "extension" : "password"),chan->name);
+ ((k&1) ? "extension" : "password"),chan->name);
break;
}
if ((res = ast_waitfor(chan, -1) < 0)) {
@@ -211,13 +212,15 @@ static int disa_exec(struct ast_channel *chan, void *data)
j = f->subclass; /* save digit */
ast_frfree(f);
if (i == 0)
+ {
+ k|=2; /* We have the first digit */
ast_playtones_stop(chan);
-
+ }
gettimeofday(&lastdigittime,NULL);
/* got a DTMF tone */
if (i < AST_MAX_EXTENSION) /* if still valid number of digits */
{
- if (!k) /* if in password state */
+ if (!(k&1)) /* if in password state */
{
if (j == '#') /* end of password */
{
@@ -268,7 +271,7 @@ static int disa_exec(struct ast_channel *chan, void *data)
ast_log(LOG_DEBUG,"DISA on chan %s password is good\n",chan->name);
play_dialtone(chan);
- k = 1;
+ k|=1; /* In number mode */
i = 0; /* re-set buffer pointer */
exten[sizeof(acctcode)] = 0;
strncpy(acctcode,exten, sizeof(acctcode) - 1);
@@ -280,7 +283,7 @@ static int disa_exec(struct ast_channel *chan, void *data)
exten[i++] = j; /* save digit */
exten[i] = 0;
- if (!k) continue; /* if getting password, continue doing it */
+ if (!(k&1)) continue; /* if getting password, continue doing it */
/* if this exists */
if (ast_ignore_pattern(ourcontext, exten)) {
@@ -299,7 +302,7 @@ static int disa_exec(struct ast_channel *chan, void *data)
}
}
- if (k && ast_exists_extension(chan,ourcontext,exten,1, chan->callerid))
+ if ((k==3) && (ast_exists_extension(chan,ourcontext,exten,1, chan->callerid)))
{
ast_playtones_stop(chan);
/* We're authenticated and have a valid extension */
@@ -310,7 +313,8 @@ static int disa_exec(struct ast_channel *chan, void *data)
}
strncpy(chan->exten, exten, sizeof(chan->exten) - 1);
strncpy(chan->context, ourcontext, sizeof(chan->context) - 1);
- strncpy(chan->accountcode, acctcode, sizeof(chan->accountcode) - 1);
+ if (!ast_strlen_zero(acctcode))
+ strncpy(chan->accountcode, acctcode, sizeof(chan->accountcode) - 1);
chan->priority = 0;
ast_cdr_init(chan->cdr,chan);
LOCAL_USER_REMOVE(u);
diff --git a/apps/app_eval.c b/apps/app_eval.c
index dc61df2f6..de80d9cb6 100755
--- a/apps/app_eval.c
+++ b/apps/app_eval.c
@@ -31,10 +31,10 @@ static char *tdesc = "Reevaluates strings";
static char *app_eval = "Eval";
-static char *eval_synopsis = "Eval(newvar=somestring)";
+static char *eval_synopsis = "Evaluates a string";
static char *eval_descrip =
-"Eval(newvar=somestring)\n"
+"Usage: Eval(newvar=somestring)\n"
" Normally Asterisk evaluates variables inline. But what if you want to\n"
"store variable offsets in a database, to be evaluated later? Eval is\n"
"the answer, by allowing a string to be evaluated twice in the dialplan,\n"
diff --git a/apps/app_festival.c b/apps/app_festival.c
index e7e0bd426..6ce8a4f83 100755
--- a/apps/app_festival.c
+++ b/apps/app_festival.c
@@ -131,7 +131,6 @@ static int send_waveform_to_fd(char *waveform, int length, int fd) {
#endif
write(fd,waveform,length);
- write(fd,"a",1);
close(fd);
exit(0);
}
@@ -305,9 +304,9 @@ static int festival_exec(struct ast_channel *chan, void *vdata)
if (!(festivalcommand = ast_variable_retrieve(cfg, "general", "festivalcommand"))) {
festivalcommand = "(tts_textasterisk \"%s\" 'file)(quit)\n";
}
- ast_destroy(cfg);
if (!vdata || ast_strlen_zero(vdata)) {
ast_log(LOG_WARNING, "festival requires an argument (text)\n");
+ ast_destroy(cfg);
return -1;
}
strncpy(data, vdata, sizeof(data) - 1);
@@ -325,6 +324,7 @@ static int festival_exec(struct ast_channel *chan, void *vdata)
if (fd < 0) {
ast_log(LOG_WARNING,"festival_client: can't get socket\n");
+ ast_destroy(cfg);
return -1;
}
memset(&serv_addr, 0, sizeof(serv_addr));
@@ -333,6 +333,7 @@ static int festival_exec(struct ast_channel *chan, void *vdata)
serverhost = ast_gethostbyname(host, &ahp);
if (serverhost == (struct hostent *)0) {
ast_log(LOG_WARNING,"festival_client: gethostbyname failed\n");
+ ast_destroy(cfg);
return -1;
}
memmove(&serv_addr.sin_addr,serverhost->h_addr, serverhost->h_length);
@@ -342,6 +343,7 @@ static int festival_exec(struct ast_channel *chan, void *vdata)
if (connect(fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) != 0) {
ast_log(LOG_WARNING,"festival_client: connect to server failed\n");
+ ast_destroy(cfg);
return -1;
}
@@ -444,6 +446,7 @@ static int festival_exec(struct ast_channel *chan, void *vdata)
}
} while (strcmp(ack,"OK\n") != 0);
close(fd);
+ ast_destroy(cfg);
LOCAL_USER_REMOVE(u);
return res;
diff --git a/apps/app_forkcdr.c b/apps/app_forkcdr.c
index 547bfa45e..460aba0b7 100755
--- a/apps/app_forkcdr.c
+++ b/apps/app_forkcdr.c
@@ -20,10 +20,11 @@
#include <string.h>
#include <pthread.h>
-static char *tdesc = "Fork The CDR into 2 seperate entities.";
+static char *tdesc = "Fork The CDR into 2 separate entities.";
static char *app = "ForkCDR";
static char *synopsis =
-"Forks the Call Data Record\n"
+"Forks the Call Data Record";
+static char *descrip =
" ForkCDR(): Causes the Call Data Record to fork an additional\n"
"cdr record starting from the time of the fork call\n";
@@ -68,7 +69,7 @@ int unload_module(void)
int load_module(void)
{
- return ast_register_application(app, forkcdr_exec, synopsis, tdesc);
+ return ast_register_application(app, forkcdr_exec, synopsis, descrip);
}
char *description(void)
diff --git a/apps/app_getcpeid.c b/apps/app_getcpeid.c
index d0a0be6bc..8ebd568e8 100755
--- a/apps/app_getcpeid.c
+++ b/apps/app_getcpeid.c
@@ -3,9 +3,9 @@
*
* Execute arbitrary system commands
*
- * Copyright (C) 1999, Mark Spencer
+ * Copyright (C) 1999-2005, Digium
*
- * Mark Spencer <markster@linux-support.net>
+ * Mark Spencer <markster@digium.com>
*
* This program is free software, distributed under the terms of
* the GNU General Public License
@@ -31,9 +31,9 @@ static char *app = "GetCPEID";
static char *synopsis = "Get ADSI CPE ID";
static char *descrip =
-" GetCPEID: Obtains and displays CPE ID and other information in order to\n"
-"properly setup zapata.conf for on-hook operations. Returns -1 on hanup\n"
-"only.";
+" GetCPEID: Obtains and displays ADSI CPE ID and other information in order\n"
+"to properly setup zapata.conf for on-hook operations.\n"
+"Returns -1 on hangup only.\n";
STANDARD_LOCAL_USER;
diff --git a/apps/app_hasnewvoicemail.c b/apps/app_hasnewvoicemail.c
index 733a65ec8..e74739653 100755
--- a/apps/app_hasnewvoicemail.c
+++ b/apps/app_hasnewvoicemail.c
@@ -38,6 +38,7 @@
#include <asterisk/pbx.h>
#include <asterisk/module.h>
#include <asterisk/lock.h>
+#include <asterisk/utils.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
@@ -70,7 +71,7 @@ static int hasvoicemail_exec(struct ast_channel *chan, void *data)
{
int res=0;
struct localuser *u;
- char vmpath[256], *input, *varname = NULL, *vmbox, *vmfolder = "INBOX", *context = "default";
+ char vmpath[256], *temps, *input, *varname = NULL, *vmbox, *vmfolder = "INBOX", *context = "default";
DIR *vmdir;
struct dirent *vment;
int vmcount = 0;
@@ -83,21 +84,22 @@ static int hasvoicemail_exec(struct ast_channel *chan, void *data)
input = ast_strdupa((char *)data);
if (input) {
- if ((vmbox = strsep(&input,":")))
- if ((vmfolder = strsep(&input,"|")))
+ temps = input;
+ if ((temps = strsep(&input, "|"))) {
+ if (input && !ast_strlen_zero(input))
varname = input;
- else
+ input = temps;
+ }
+ if ((temps = strsep(&input, ":"))) {
+ if (input && !ast_strlen_zero(input))
vmfolder = input;
- else
- if ((vmbox = strsep(&input,"|")))
- varname = input;
- else
- vmbox = input;
-
- if (index(vmbox,'@')) {
- context = vmbox;
- vmbox = strsep(&context,"@");
+ input = temps;
}
+ if ((vmbox = strsep(&input, "@")))
+ if (input && !ast_strlen_zero(input))
+ context = input;
+ if (!vmbox)
+ vmbox = input;
snprintf(vmpath,sizeof(vmpath), "%s/voicemail/%s/%s/%s", (char *)ast_config_AST_SPOOL_DIR, context, vmbox, vmfolder);
if (!(vmdir = opendir(vmpath))) {
diff --git a/apps/app_macro.c b/apps/app_macro.c
index ea6775c90..03da13ed4 100755
--- a/apps/app_macro.c
+++ b/apps/app_macro.c
@@ -140,7 +140,8 @@ static int macro_exec(struct ast_channel *chan, void *data)
while(ast_exists_extension(chan, chan->context, chan->exten, chan->priority, chan->callerid)) {
if ((res = ast_spawn_extension(chan, chan->context, chan->exten, chan->priority, chan->callerid))) {
/* Something bad happened, or a hangup has been requested. */
- if (((res >= '0') && (res <= '9')) || ((res >= 'A') && (res <= 'F'))) {
+ if (((res >= '0') && (res <= '9')) || ((res >= 'A') && (res <= 'F')) ||
+ (res == '*') || (res == '#')) {
/* Just return result as to the previous application as if it had been dialed */
ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
break;
diff --git a/apps/app_meetme.c b/apps/app_meetme.c
index ef2ff3de9..47d05e5a4 100755
--- a/apps/app_meetme.c
+++ b/apps/app_meetme.c
@@ -482,9 +482,39 @@ static int confnonzero(void *ptr)
return res;
}
+/* Remove the conference from the list and free it.
+ We assume that this was called while holding conflock. */
+static int conf_free(struct ast_conference *conf)
+{
+ struct ast_conference *prev = NULL, *cur = confs;
+
+ while(cur) {
+ if (cur == conf) {
+ if (prev)
+ prev->next = conf->next;
+ else
+ confs = conf->next;
+ break;
+ }
+ prev = cur;
+ cur = cur->next;
+ }
+
+ if (!cur)
+ ast_log(LOG_WARNING, "Conference not found\n");
+
+ if (conf->chan)
+ ast_hangup(conf->chan);
+ else
+ close(conf->fd);
+
+ free(conf);
+
+ return 0;
+}
+
static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int confflags)
{
- struct ast_conference *prev=NULL, *cur;
struct ast_conf_user *user = malloc(sizeof(struct ast_conf_user));
int fd;
struct zt_confinfo ztc;
@@ -524,7 +554,9 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int c
memset(user, 0, sizeof(struct ast_conf_user));
user->user_no = 0; /* User number 0 means starting up user! (dead - not in the list!) */
-
+
+ time(&user->jointime);
+
if (conf->locked) {
/* Sorry, but this confernce is locked! */
if (!ast_streamfile(chan, "conf-locked", chan->language))
@@ -557,7 +589,6 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int c
conf->lastuser = user;
}
}
- strncpy(user->usrvalue, "test", sizeof(user->usrvalue) - 1);
user->chan = chan;
user->userflags = confflags;
user->adminflags = 0;
@@ -990,31 +1021,12 @@ outrun:
"Meetme: %s\r\n"
"Usernum: %i\r\n",
chan->name, chan->uniqueid, conf->confno, user->user_no);
- prev = NULL;
conf->users--;
if (confflags & CONFFLAG_MARKEDUSER)
conf->markedusers--;
- cur = confs;
if (!conf->users) {
/* No more users -- close this one out */
- while(cur) {
- if (cur == conf) {
- if (prev)
- prev->next = conf->next;
- else
- confs = conf->next;
- break;
- }
- prev = cur;
- cur = cur->next;
- }
- if (!cur)
- ast_log(LOG_WARNING, "Conference not found\n");
- if (conf->chan)
- ast_hangup(conf->chan);
- else
- close(conf->fd);
- free(conf);
+ conf_free(conf);
} else {
/* Remove the user struct */
if (user == conf->firstuser) {
@@ -1043,10 +1055,10 @@ outrun:
else
ast_log(LOG_ERROR, "Bad! Bad! Bad! user->prevuser is NULL but we're not the beginning!\n");
}
- /* Return the number of seconds the user was in the conf */
- snprintf(meetmesecs, sizeof(meetmesecs), "%i", (int) (user->jointime - time(NULL)));
- pbx_builtin_setvar_helper(chan, "MEETMESECS", meetmesecs);
}
+ /* Return the number of seconds the user was in the conf */
+ snprintf(meetmesecs, sizeof(meetmesecs), "%i", (int) (time(NULL) - user->jointime));
+ pbx_builtin_setvar_helper(chan, "MEETMESECS", meetmesecs);
}
free(user);
ast_mutex_unlock(&conflock);
@@ -1298,7 +1310,7 @@ static int conf_exec(struct ast_channel *chan, void *data)
if (!found) {
/* At this point, we have a confno_tmp (static conference) that is empty */
if ((empty_no_pin && ((!stringp) || (stringp && (stringp[0] == '\0')))) || (!empty_no_pin)) {
- /* Case 1: empty_no_pin and pin is nonexistant (NULL)
+ /* Case 1: empty_no_pin and pin is nonexistent (NULL)
* Case 2: empty_no_pin and pin is blank (but not NULL)
* Case 3: not empty_no_pin
*/
@@ -1399,8 +1411,15 @@ static int conf_exec(struct ast_channel *chan, void *data)
confno[0] = '\0';
}
} else {
+ /* failed when getting the pin */
res = -1;
allowretry = 0;
+ /* see if we need to get rid of the conference */
+ ast_mutex_lock(&conflock);
+ if (!cnf->users) {
+ conf_free(cnf);
+ }
+ ast_mutex_unlock(&conflock);
break;
}
@@ -1419,8 +1438,9 @@ static int conf_exec(struct ast_channel *chan, void *data)
}
}
} while (allowretry);
- /* Do the conference */
+
LOCAL_USER_REMOVE(u);
+
return res;
}
@@ -1454,14 +1474,17 @@ static int admin_exec(struct ast_channel *chan, void *data) {
command = strsep(&params, "|");
caller = strsep(&params, "|");
- ast_mutex_lock(&conflock);
+ if (!command) {
+ ast_log(LOG_WARNING, "MeetmeAdmin requires a command!\n");
+ ast_mutex_unlock(&conflock);
+ return -1;
+ }
cnf = confs;
while (cnf) {
if (strcmp(cnf->confno, conf) == 0)
break;
cnf = cnf->next;
}
- ast_mutex_unlock(&conflock);
if (caller)
user = find_user(cnf, caller);
diff --git a/apps/app_parkandannounce.c b/apps/app_parkandannounce.c
index c3f949ec3..7492dd4b2 100755
--- a/apps/app_parkandannounce.c
+++ b/apps/app_parkandannounce.c
@@ -41,7 +41,7 @@ static char *synopsis = "Park and Announce";
static char *descrip =
" ParkAndAnnounce(announce:template|timeout|dial|[return_context]):\n"
"Park a call into the parkinglot and announce the call over the console.\n"
-"announce template: colon seperated list of files to announce, the word PARKED\n"
+"announce template: colon separated list of files to announce, the word PARKED\n"
" will be replaced by a say_digits of the ext the call is parked in\n"
"timeout: time in seconds before the call returns into the return context.\n"
"dial: The app_dial style resource to call to make the announcement. Console/dsp calls the console.\n"
@@ -94,7 +94,7 @@ static int parkandannounce_exec(struct ast_channel *chan, void *data)
}
dial=strsep(&s, "|");
if(!dial) {
- ast_log(LOG_WARNING, "PARK: A dial resouce must be specified i.e: Console/dsp or Zap/g1/5551212\n");
+ ast_log(LOG_WARNING, "PARK: A dial resource must be specified i.e: Console/dsp or Zap/g1/5551212\n");
free(orig_s);
return -1;
} else {
diff --git a/apps/app_qcall.c b/apps/app_qcall.c
index f5721e167..659a39dd7 100755
--- a/apps/app_qcall.c
+++ b/apps/app_qcall.c
@@ -317,7 +317,7 @@ static void *qcall_do(void *arg)
extstr,context,channel->name);
if (strlen(ident)) {
strncat(ident,"-ok", sizeof(ident) - strlen(ident) - 1);
- /* if file existant, play it */
+ /* if file existent, play it */
if (!ast_streamfile(channel,ident,0))
{
ast_waitstream(channel,"");
diff --git a/apps/app_queue.c b/apps/app_queue.c
index 542ede246..221a1986d 100755
--- a/apps/app_queue.c
+++ b/apps/app_queue.c
@@ -96,7 +96,7 @@ static char *descrip =
"Queues an incoming call in a particular call queue as defined in queues.conf.\n"
" This application returns -1 if the originating channel hangs up, or if the\n"
"call is bridged and either of the parties in the bridge terminate the call.\n"
-"Returns 0 if the queue is full, nonexistant, or has no members.\n"
+"Returns 0 if the queue is full, nonexistent, or has no members.\n"
"The option string may contain zero or more of the following characters:\n"
" 't' -- allow the called user transfer the calling user\n"
" 'T' -- to allow the calling user to transfer the call.\n"
@@ -226,6 +226,7 @@ struct ast_call_queue {
int wrapped; /* Round Robin - wrapped around? */
int joinempty; /* Do we care if the queue has no members? */
int eventwhencalled; /* Generate an event when the agent is called (before pickup) */
+ int leavewhenempty; /* If all agents leave the queue, remove callers from the queue */
struct member *members; /* Member channels to be tried */
struct queue_ent *head; /* Start of the actual queue */
@@ -544,14 +545,17 @@ static void hanguptree(struct localuser *outgoing, struct ast_channel *exception
}
}
-static int ring_entry(struct queue_ent *qe, struct localuser *tmp)
+static int ring_entry(struct queue_ent *qe, struct localuser *tmp, int *busies)
{
int res;
+ struct ast_var_t *current, *newvar;
+ struct varshead *headp, *newheadp;
if (qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime)) {
ast_log(LOG_DEBUG, "Wrapuptime not yet expired for %s/%s\n", tmp->tech, tmp->numsubst);
if (qe->chan->cdr)
ast_cdr_busy(qe->chan->cdr);
tmp->stillgoing = 0;
+ (*busies)++;
return 0;
}
/* Request the peer */
@@ -563,8 +567,29 @@ static int ring_entry(struct queue_ent *qe, struct localuser *tmp)
if (qe->chan->cdr)
ast_cdr_busy(qe->chan->cdr);
tmp->stillgoing = 0;
+ (*busies)++;
return 0;
}
+ /* If creating a SIP channel, look for a variable called */
+ /* VXML_URL in the calling channel and copy it to the */
+ /* new channel. */
+
+ /* Check for ALERT_INFO in the SetVar list. This is for */
+ /* SIP distinctive ring as per the RFC. For Cisco 7960s, */
+ /* SetVar(ALERT_INFO=<x>) where x is an integer value 1-5. */
+ /* However, the RFC says it should be a URL. -km- */
+ headp=&qe->chan->varshead;
+ AST_LIST_TRAVERSE(headp,current,entries) {
+ if (!strcasecmp(ast_var_name(current),"VXML_URL") ||
+ !strcasecmp(ast_var_name(current), "ALERT_INFO") ||
+ !strcasecmp(ast_var_name(current), "OSPTOKEN") ||
+ !strcasecmp(ast_var_name(current), "OSPHANDLE"))
+ {
+ newvar=ast_var_assign(ast_var_name(current),ast_var_value(current));
+ newheadp=&tmp->chan->varshead;
+ AST_LIST_INSERT_HEAD(newheadp,newvar,entries);
+ }
+ }
tmp->chan->appl = "AppQueue";
tmp->chan->data = "(Outgoing Line)";
tmp->chan->whentohangup = 0;
@@ -593,6 +618,7 @@ static int ring_entry(struct queue_ent *qe, struct localuser *tmp)
ast_hangup(tmp->chan);
tmp->chan = NULL;
tmp->stillgoing = 0;
+ (*busies)++;
return 0;
} else {
if (qe->parent->eventwhencalled) {
@@ -610,10 +636,10 @@ static int ring_entry(struct queue_ent *qe, struct localuser *tmp)
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "Called %s/%s\n", tmp->tech, tmp->numsubst);
}
- return 0;
+ return 1;
}
-static int ring_one(struct queue_ent *qe, struct localuser *outgoing)
+static int ring_one(struct queue_ent *qe, struct localuser *outgoing, int *busies)
{
struct localuser *cur;
struct localuser *best;
@@ -635,9 +661,9 @@ static int ring_one(struct queue_ent *qe, struct localuser *outgoing)
/* Ring everyone who shares this best metric (for ringall) */
cur = outgoing;
while(cur) {
- if (cur->stillgoing && !cur->chan && (cur->metric == bestmetric)) {
+ if (cur->stillgoing && !cur->chan && (cur->metric <= bestmetric)) {
ast_log(LOG_DEBUG, "(Parallel) Trying '%s/%s' with metric %d\n", cur->tech, cur->numsubst, cur->metric);
- ring_entry(qe, cur);
+ ring_entry(qe, cur, busies);
}
cur = cur->next;
}
@@ -646,7 +672,7 @@ static int ring_one(struct queue_ent *qe, struct localuser *outgoing)
if (option_debug)
ast_log(LOG_DEBUG, "Trying '%s/%s' with metric %d\n",
best->tech, best->numsubst, best->metric);
- ring_entry(qe, best);
+ ring_entry(qe, best, busies);
}
}
} while (best && !best->chan);
@@ -710,15 +736,36 @@ static int valid_exit(struct queue_ent *qe, char digit)
#define AST_MAX_WATCHERS 256
-static struct localuser *wait_for_answer(struct queue_ent *qe, struct localuser *outgoing, int *to, int *allowredir_in, int *allowredir_out, int *allowdisconnect_in, int *allowdisconnect_out, char *digit)
+#define BUILD_STATS do { \
+ o = outgoing; \
+ found = -1; \
+ pos = 1; \
+ numlines = 0; \
+ watchers[0] = in; \
+ while(o) { \
+ /* Keep track of important channels */ \
+ if (o->stillgoing) { \
+ stillgoing = 1; \
+ if (o->chan) { \
+ watchers[pos++] = o->chan; \
+ found = 1; \
+ } \
+ } \
+ o = o->next; \
+ numlines++; \
+ } \
+ } while(0)
+
+static struct localuser *wait_for_answer(struct queue_ent *qe, struct localuser *outgoing, int *to, int *allowredir_in, int *allowredir_out, int *allowdisconnect_in, int *allowdisconnect_out, char *digit, int prebusies)
{
char *queue = qe->parent->name;
struct localuser *o;
int found;
int numlines;
int sentringing = 0;
- int numbusies = 0;
+ int numbusies = prebusies;
int orig = *to;
+ int stillgoing = 0;
struct ast_frame *f;
struct localuser *peer = NULL;
struct ast_channel *watchers[AST_MAX_WATCHERS];
@@ -727,25 +774,18 @@ static struct localuser *wait_for_answer(struct queue_ent *qe, struct localuser
struct ast_channel *in = qe->chan;
while(*to && !peer) {
- o = outgoing;
- found = -1;
- pos = 1;
- numlines = 0;
- watchers[0] = in;
- while(o) {
- /* Keep track of important channels */
- if (o->stillgoing && o->chan) {
- watchers[pos++] = o->chan;
- found = 1;
- }
- o = o->next;
- numlines++;
+ BUILD_STATS;
+ if ((found < 0) && stillgoing && !qe->parent->strategy) {
+ /* On "ringall" strategy we only move to the next penalty level
+ when *all* ringing phones are done in the current penalty level */
+ ring_one(qe, outgoing, &numbusies);
+ BUILD_STATS;
}
if (found < 0) {
if (numlines == numbusies) {
ast_log(LOG_DEBUG, "Everyone is busy at this time\n");
} else {
- ast_log(LOG_NOTICE, "No one is answering queue '%s'\n", queue);
+ ast_log(LOG_NOTICE, "No one is answering queue '%s' (%d/%d)\n", queue, numlines, numbusies);
}
*to = 0;
return NULL;
@@ -789,7 +829,7 @@ static struct localuser *wait_for_answer(struct queue_ent *qe, struct localuser
ast_hangup(o->chan);
o->chan = NULL;
if (qe->parent->strategy)
- ring_one(qe, outgoing);
+ ring_one(qe, outgoing, &numbusies);
numbusies++;
break;
case AST_CONTROL_CONGESTION:
@@ -801,7 +841,7 @@ static struct localuser *wait_for_answer(struct queue_ent *qe, struct localuser
ast_hangup(o->chan);
o->chan = NULL;
if (qe->parent->strategy)
- ring_one(qe, outgoing);
+ ring_one(qe, outgoing, &numbusies);
numbusies++;
break;
case AST_CONTROL_RINGING:
@@ -827,7 +867,7 @@ static struct localuser *wait_for_answer(struct queue_ent *qe, struct localuser
ast_hangup(o->chan);
o->chan = NULL;
if (qe->parent->strategy)
- ring_one(qe, outgoing);
+ ring_one(qe, outgoing, &numbusies);
}
}
o = o->next;
@@ -843,21 +883,26 @@ static struct localuser *wait_for_answer(struct queue_ent *qe, struct localuser
if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
/* Got hung up */
*to=-1;
+ if (f)
+ ast_frfree(f);
return NULL;
}
- if (f && (f->frametype == AST_FRAME_DTMF) && allowdisconnect_out && (f->subclass == '*')) {
+ if ((f->frametype == AST_FRAME_DTMF) && allowdisconnect_out && (f->subclass == '*')) {
if (option_verbose > 3)
ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass);
*to=0;
+ ast_frfree(f);
return NULL;
}
- if (f && (f->frametype == AST_FRAME_DTMF) && (f->subclass != '*') && valid_exit(qe, f->subclass)) {
+ if ((f->frametype == AST_FRAME_DTMF) && (f->subclass != '*') && valid_exit(qe, f->subclass)) {
if (option_verbose > 3)
- ast_verbose(VERBOSE_PREFIX_3 "User pressed digit: %c", f->subclass);
+ ast_verbose(VERBOSE_PREFIX_3 "User pressed digit: %c\n", f->subclass);
*to=0;
*digit=f->subclass;
+ ast_frfree(f);
return NULL;
}
+ ast_frfree(f);
}
if (!*to && (option_verbose > 2))
ast_verbose( VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", orig);
@@ -912,6 +957,12 @@ static int wait_our_turn(struct queue_ent *qe, int ringing)
break;
}
+ /* leave the queue if no agents, if enabled */
+ if (!(qe->parent->members) && qe->parent->leavewhenempty) {
+ leave_queue(qe);
+ break;
+ }
+
/* Make a position announcement, if enabled */
if (qe->parent->announcefrequency && !ringing)
say_position(qe);
@@ -1017,6 +1068,7 @@ static int try_calling(struct queue_ent *qe, char *options, char *announceoverri
struct member *member;
int res = 0, bridge = 0;
int zapx = 2;
+ int numbusies = 0;
int x=0;
char *announce = NULL;
char digit = 0;
@@ -1099,9 +1151,9 @@ static int try_calling(struct queue_ent *qe, char *options, char *announceoverri
to = qe->parent->timeout * 1000;
else
to = -1;
- ring_one(qe, outgoing);
+ ring_one(qe, outgoing, &numbusies);
ast_mutex_unlock(&qe->parent->lock);
- lpeer = wait_for_answer(qe, outgoing, &to, &allowredir_in, &allowredir_out, &allowdisconnect_in, &allowdisconnect_out, &digit);
+ lpeer = wait_for_answer(qe, outgoing, &to, &allowredir_in, &allowredir_out, &allowdisconnect_in, &allowdisconnect_out, &digit, numbusies);
ast_mutex_lock(&qe->parent->lock);
if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY) {
store_next(qe, outgoing);
@@ -1626,11 +1678,18 @@ check_turns:
/* This is the wait loop for the head caller*/
/* To exit, they may get their call answered; */
/* they may dial a digit from the queue context; */
- /* or, they may may timeout. */
+ /* or, they may timeout. */
/* Leave if we have exceeded our queuetimeout */
if (qe.queuetimeout && ( (time(NULL) - qe.start) >= qe.queuetimeout) ) {
res = 0;
+ ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
+ break;
+ }
+
+ /* leave the queue if no agents, if enabled */
+ if (!((qe.parent)->members) && (qe.parent)->leavewhenempty) {
+ leave_queue(&qe);
break;
}
@@ -1652,6 +1711,7 @@ check_turns:
/* Leave if we have exceeded our queuetimeout */
if (qe.queuetimeout && ( (time(NULL) - qe.start) >= qe.queuetimeout) ) {
res = 0;
+ ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
break;
}
@@ -1691,7 +1751,7 @@ check_turns:
}
}
/* Don't allow return code > 0 */
- if (res > 0 && res != AST_PBX_KEEPALIVE) {
+ if ((res == 0) || (res > 0 && res != AST_PBX_KEEPALIVE)) {
res = 0;
if (ringing) {
ast_indicate(chan, -1);
@@ -1781,7 +1841,7 @@ static void reload_queues(void)
strncpy(q->sound_minutes, "queue-minutes", sizeof(q->sound_minutes) - 1);
strncpy(q->sound_seconds, "queue-seconds", sizeof(q->sound_seconds) - 1);
strncpy(q->sound_thanks, "queue-thankyou", sizeof(q->sound_thanks) - 1);
- strncpy(q->sound_lessthan, "queue-lessthan", sizeof(q->sound_lessthan) - 1);
+ strncpy(q->sound_lessthan, "queue-less-than", sizeof(q->sound_lessthan) - 1);
prev = q->members;
if (prev) {
/* find the end of any dynamic members */
@@ -1818,7 +1878,7 @@ static void reload_queues(void)
q->members = cur;
prev = cur;
}
- } else if (!strcasecmp(var->name, "music")) {
+ } else if (!strcasecmp(var->name, "music") || !strcasecmp(var->name, "musiconhold")) {
strncpy(q->moh, var->value, sizeof(q->moh) - 1);
} else if (!strcasecmp(var->name, "announce")) {
strncpy(q->announce, var->value, sizeof(q->announce) - 1);
@@ -1872,6 +1932,8 @@ static void reload_queues(void)
}
} else if (!strcasecmp(var->name, "joinempty")) {
q->joinempty = ast_true(var->value);
+ } else if (!strcasecmp(var->name, "leavewhenempty")) {
+ q->leavewhenempty = ast_true(var->value);
} else if (!strcasecmp(var->name, "eventwhencalled")) {
q->eventwhencalled = ast_true(var->value);
} else {
diff --git a/apps/app_random.c b/apps/app_random.c
index c9f8f4788..18af80e4e 100755
--- a/apps/app_random.c
+++ b/apps/app_random.c
@@ -106,7 +106,6 @@ int unload_module(void)
int load_module(void)
{
- srandom((unsigned int)getpid() + (unsigned int)time(NULL));
return ast_register_application(app_random, random_exec, random_synopsis, random_descrip);
}
diff --git a/apps/app_read.c b/apps/app_read.c
index 988ef8009..e91513845 100755
--- a/apps/app_read.c
+++ b/apps/app_read.c
@@ -106,8 +106,9 @@ static int read_exec(struct ast_channel *chan, void *data)
if (res > -1) {
pbx_builtin_setvar_helper(chan, varname, tmp);
ast_verbose(VERBOSE_PREFIX_3 "User entered '%s'\n", tmp);
+ res = 0;
} else {
- ast_verbose(VERBOSE_PREFIX_3 "User entered nothing\n");
+ ast_verbose(VERBOSE_PREFIX_3 "User disconnected\n");
}
}
LOCAL_USER_REMOVE(u);
diff --git a/apps/app_record.c b/apps/app_record.c
index c1f06780a..7de7016c0 100755
--- a/apps/app_record.c
+++ b/apps/app_record.c
@@ -301,7 +301,7 @@ static int record_exec(struct ast_channel *chan, void *data)
ast_log(LOG_WARNING, "Could not answer channel '%s'\n", chan->name);
LOCAL_USER_REMOVE(u);
- if (silence > 0) {
+ if ((silence > 0) && rfmt) {
res = ast_set_read_format(chan, rfmt);
if (res)
ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
diff --git a/apps/app_sms.c b/apps/app_sms.c
index a7b55bd46..31a19e609 100755
--- a/apps/app_sms.c
+++ b/apps/app_sms.c
@@ -24,8 +24,10 @@
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
+#include <sys/stat.h>
#include <dirent.h>
#include <ctype.h>
+#include "../astconf.h"
/* ToDo */
/* When acting as SC and answering, should check for messages and send instead of sending EST as first packet */
@@ -36,6 +38,9 @@
static unsigned char message_ref; /* arbitary message ref */
+static char log_file[255];
+static char spool_dir[255];
+
static char *tdesc = "SMS/PSTN handler";
static char *app = "SMS";
@@ -315,7 +320,7 @@ sms_log (sms_t * h, char status)
{ /* log the output, and remove file */
if (*h->oa || *h->da)
{
- int o = open ("/var/log/asterisk/sms", O_CREAT | O_APPEND | O_WRONLY, 0666);
+ int o = open (log_file, O_CREAT | O_APPEND | O_WRONLY, 0666);
if (o >= 0)
{
char line[1000], *p;
@@ -517,7 +522,7 @@ sms_writefile (sms_t * h)
char fn2[200] = "";
FILE *o;
- strncpy(fn, "/var/spool/asterisk/sms", sizeof(fn) - 1);
+ strncpy(fn, spool_dir, sizeof(fn) - 1);
mkdir (fn, 0777); /* ensure it exists */
snprintf(fn + strlen(fn), sizeof(fn) - strlen(fn), "/%s.%s", h->smsc ? "me-sc" : "sc-me", h->queue);
mkdir (fn, 0777); /* ensure it exists */
@@ -689,7 +694,7 @@ sms_nextoutgoing (sms_t * h)
DIR *d;
char more = 0;
- strncpy(fn, "/var/spool/asterisk/sms", sizeof(fn) - 1);
+ strncpy(fn, spool_dir, sizeof(fn) - 1);
mkdir(fn, 0777); /* ensure it exists */
snprintf(fn + strlen (fn), sizeof(fn) - strlen(fn), "/%s.%s", h->smsc ? "sc-me" : "me-sc", h->queue);
mkdir (fn, 0777); /* ensure it exists */
@@ -769,6 +774,7 @@ sms_nextoutgoing (sms_t * h)
{ /* no message */
h->omsg[0] = 0x94; /* SMS_REL */
h->omsg[1] = 0;
+ h->hangup = 1;
sms_messagetx (h);
}
}
@@ -1204,6 +1210,8 @@ load_module (void)
for (p = 0; p < 128; p++)
sms8to7[sms7to8[p]] = p;
}
+ snprintf(log_file, sizeof(log_file), "%s/sms", ast_config_AST_LOG_DIR);
+ snprintf(spool_dir, sizeof(spool_dir), "%s/sms", ast_config_AST_SPOOL_DIR);
return ast_register_application (app, sms_exec, synopsis, descrip);
}
diff --git a/apps/app_sql_postgres.c b/apps/app_sql_postgres.c
index 1620df635..4d52eb3e4 100755
--- a/apps/app_sql_postgres.c
+++ b/apps/app_sql_postgres.c
@@ -106,8 +106,6 @@ STANDARD_LOCAL_USER;
LOCAL_USER_DECL;
-extern void pbx_builtin_setvar_helper(struct ast_channel *chan, char *name, char *value);
-
#define AST_PGSQL_ID_DUMMY 0
#define AST_PGSQL_ID_CONNID 1
#define AST_PGSQL_ID_RESID 2
diff --git a/apps/app_test.c b/apps/app_test.c
index 3743b6771..702dbdc3f 100755
--- a/apps/app_test.c
+++ b/apps/app_test.c
@@ -1,7 +1,7 @@
/*
* Asterisk -- A telephony toolkit for Linux.
*
- * Applictions connected with CDR engine
+ * Applications to test connection and produce report in text file
*
* Copyright (C) 2004, Digium, Inc.
*
@@ -14,6 +14,7 @@
#include <sys/types.h>
#include <asterisk/channel.h>
+#include <asterisk/options.h>
#include <asterisk/module.h>
#include <asterisk/logger.h>
#include <asterisk/lock.h>
@@ -29,13 +30,15 @@
static char *tdesc = "Interface Test Application";
-static char *tests_descrip = "TestServer(): Perform test server function and write call report"
- "Results stored in /var/log/asterisk/testreports/<testid>.txt";
+static char *tests_descrip =
+ "TestServer(): Perform test server function and write call report.\n"
+ "Results stored in /var/log/asterisk/testreports/<testid>-server.txt";
static char *tests_app = "TestServer";
static char *tests_synopsis = "Execute Interface Test Server";
-static char *testc_descrip = "TestClient(testid): Executes test client with given testid.\n"
- "Results stored in /var/log/asterisk/testreports/<testid>.txt";
+static char *testc_descrip =
+ "TestClient(testid): Executes test client with given testid.\n"
+ "Results stored in /var/log/asterisk/testreports/<testid>-client.txt";
static char *testc_app = "TestClient";
static char *testc_synopsis = "Execute Interface Test Client";
diff --git a/apps/app_userevent.c b/apps/app_userevent.c
index e1a87c2a4..3b3cfc8ca 100755
--- a/apps/app_userevent.c
+++ b/apps/app_userevent.c
@@ -54,22 +54,22 @@ static int userevent_exec(struct ast_channel *chan, void *data)
}
strncpy(info, (char *)data, strlen((char *)data) + AST_MAX_EXTENSION-1);
+ snprintf(eventname, sizeof(eventname), "UserEvent%s", info);
eventbody = strchr(eventname, '|');
if (eventbody) {
*eventbody = '\0';
eventbody++;
}
- snprintf(eventname, sizeof(eventname), "UserEvent%s", info);
LOCAL_USER_ADD(u);
if(eventbody) {
ast_log(LOG_DEBUG, "Sending user event: %s, %s\n", eventname, eventbody);
- manager_event(EVENT_FLAG_CALL, eventname,
+ manager_event(EVENT_FLAG_USER, eventname,
"Channel: %s\r\nUniqueid: %s\r\n%s\r\n",
chan->name, chan->uniqueid, eventbody);
} else {
ast_log(LOG_DEBUG, "Sending user event: %s\n", eventname);
- manager_event(EVENT_FLAG_CALL, eventname,
+ manager_event(EVENT_FLAG_USER, eventname,
"Channel: %s\r\nUniqueid: %s\r\n", chan->name, chan->uniqueid);
}
diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c
index fe13a7fca..e0cb8af0e 100755
--- a/apps/app_voicemail.c
+++ b/apps/app_voicemail.c
@@ -176,8 +176,9 @@ struct vm_state {
};
static int advanced_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msg, int option);
static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context);
-static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt, int outsidecaller, struct ast_vm_user *vmu, int *duration);
+static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt, int outsidecaller, struct ast_vm_user *vmu, int *duration, const char *unlockdir);
static int vm_delete(char *file);
+static int vm_play_folder_name(struct ast_channel *chan, char *mbox);
static char ext_pass_cmd[128];
@@ -215,7 +216,10 @@ static char *descrip_vmain =
"for the checking of voicemail. The mailbox can be passed as the option,\n"
"which will stop the voicemail system from prompting the user for the mailbox.\n"
"If the mailbox is preceded by 's' then the password check will be skipped. If\n"
-"a context is specified, logins are considered in that voicemail context only.\n"
+"the mailbox is preceded by 'p' then the supplied mailbox is prepended to the\n"
+"user's entry and the resulting string is used as the mailbox number. This is\n"
+"useful for virtual hosting of voicemail boxes. If a context is specified,\n"
+"logins are considered in that voicemail context only.\n"
"Returns -1 if the user hangs up or 0 otherwise.\n";
static char *synopsis_vm_box_exists =
@@ -671,7 +675,7 @@ static void vm_change_password(struct ast_vm_user *vmu, char *newpassword)
}
} else {
/* Put it back like it was */
- fprintf(configout, orig);
+ fprintf(configout, "%s", orig);
}
}
}
@@ -692,7 +696,8 @@ static void vm_change_password_shell(struct ast_vm_user *vmu, char *newpassword)
{
char buf[255];
snprintf(buf,255,"%s %s %s %s",ext_pass_cmd,vmu->context,vmu->mailbox,newpassword);
- ast_safe_system(buf);
+ if (!ast_safe_system(buf))
+ strncpy(vmu->password, newpassword, sizeof(vmu->password) - 1);
}
static int make_dir(char *dest, int len, char *context, char *ext, char *mailbox)
@@ -705,6 +710,20 @@ static int make_file(char *dest, int len, char *dir, int num)
return snprintf(dest, len, "%s/msg%04d", dir, num);
}
+static int last_message_index(char *dir)
+{
+ int x;
+ char fn[256];
+ ast_lock_path(dir);
+ for (x=0;x<MAXMSG;x++) {
+ make_file(fn, sizeof(fn), dir, x);
+ if (ast_fileexists(fn, NULL, NULL) < 1)
+ break;
+ }
+ ast_unlock_path(dir);
+ return x-1;
+}
+
static int
inbuf(struct baseio *bio, FILE *fi)
{
@@ -844,7 +863,7 @@ static int sendmail(char *srcemail, struct ast_vm_user *vmu, int msgnum, char *m
FILE *p=NULL;
int pfd;
char date[256];
- char host[256];
+ char host[MAXHOSTNAMELEN] = "";
char who[256];
char bound[256];
char fname[256];
@@ -872,7 +891,7 @@ static int sendmail(char *srcemail, struct ast_vm_user *vmu, int msgnum, char *m
}
}
if (p) {
- gethostname(host, sizeof(host));
+ gethostname(host, sizeof(host)-1);
if (strchr(srcemail, '@'))
strncpy(who, srcemail, sizeof(who)-1);
else {
@@ -989,7 +1008,7 @@ static int sendmail(char *srcemail, struct ast_vm_user *vmu, int msgnum, char *m
fclose(p);
snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
ast_safe_system(tmp2);
- ast_log(LOG_DEBUG, "Sent mail to %s with command '%s'\n", who, mailcmd);
+ ast_log(LOG_DEBUG, "Sent mail to %s with command '%s'\n", vmu->email, mailcmd);
} else {
ast_log(LOG_WARNING, "Unable to launch '%s'\n", mailcmd);
return -1;
@@ -1002,7 +1021,7 @@ static int sendpage(char *srcemail, char *pager, int msgnum, char *mailbox, char
FILE *p=NULL;
int pfd;
char date[256];
- char host[256];
+ char host[MAXHOSTNAMELEN]="";
char who[256];
char dur[256];
char tmp[80] = "/tmp/astmail-XXXXXX";
@@ -1021,7 +1040,7 @@ static int sendpage(char *srcemail, char *pager, int msgnum, char *mailbox, char
}
if (p) {
- gethostname(host, sizeof(host));
+ gethostname(host, sizeof(host)-1);
if (strchr(srcemail, '@'))
strncpy(who, srcemail, sizeof(who)-1);
else {
@@ -1076,7 +1095,7 @@ static int sendpage(char *srcemail, char *pager, int msgnum, char *mailbox, char
fclose(p);
snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
ast_safe_system(tmp2);
- ast_log(LOG_DEBUG, "Sent mail to %s with command '%s'\n", who, mailcmd);
+ ast_log(LOG_DEBUG, "Sent page to %s with command '%s'\n", pager, mailcmd);
} else {
ast_log(LOG_WARNING, "Unable to launch '%s'\n", mailcmd);
return -1;
@@ -1239,6 +1258,7 @@ static void copy_message(struct ast_channel *chan, struct ast_vm_user *vmu, int
make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, frombox);
make_file(frompath, sizeof(frompath), fromdir, msgnum);
+ ast_lock_path(topath);
recipmsgnum = 0;
do {
make_file(topath, sizeof(topath), todir, recipmsgnum);
@@ -1255,7 +1275,7 @@ static void copy_message(struct ast_channel *chan, struct ast_vm_user *vmu, int
} else {
ast_log(LOG_ERROR, "Recipient mailbox %s@%s is full\n", recip->mailbox, recip->context);
}
-
+ ast_unlock_path(topath);
notify_new_message(chan, recip, recipmsgnum, duration, fmt, chan->callerid);
}
@@ -1282,7 +1302,6 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, int silent, int
FILE *txt;
int res = 0;
int msgnum;
- int fd;
int duration = 0;
int ausemacro = 0;
int ousemacro = 0;
@@ -1356,7 +1375,7 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, int silent, int
strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
ausemacro = 1;
}
-
+
/* Play the beginning intro if desired */
if (!ast_strlen_zero(prefile)) {
if (ast_fileexists(prefile, NULL, NULL) > 0) {
@@ -1403,22 +1422,22 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, int silent, int
}
/* Check for a '0' here */
if (res == '0') {
- transfer:
- strncpy(chan->exten, "o", sizeof(chan->exten) - 1);
- if (!ast_strlen_zero(vmu->exit)) {
- strncpy(chan->context, vmu->exit, sizeof(chan->context) - 1);
- } else if (ousemacro && !ast_strlen_zero(chan->macrocontext)) {
- strncpy(chan->context, chan->macrocontext, sizeof(chan->context) - 1);
+ transfer:
+ if (vmu->operator) {
+ strncpy(chan->exten, "o", sizeof(chan->exten) - 1);
+ if (!ast_strlen_zero(vmu->exit)) {
+ strncpy(chan->context, vmu->exit, sizeof(chan->context) - 1);
+ } else if (ousemacro && !ast_strlen_zero(chan->macrocontext)) {
+ strncpy(chan->context, chan->macrocontext, sizeof(chan->context) - 1);
+ }
+ ast_play_and_wait(chan, "transfer");
+ chan->priority = 0;
+ free_user(vmu);
+ return 0;
+ } else {
+ ast_play_and_wait(chan, "vm-sorry");
+ return 0;
}
- chan->priority = 0;
- free_user(vmu);
- return 0;
- }
- if (res >= 0) {
- /* Unless we're *really* silent, try to send the beep */
- res = ast_streamfile(chan, "beep", chan->language);
- if (!res)
- res = ast_waitstream(chan, "");
}
if (res < 0) {
free_user(vmu);
@@ -1428,6 +1447,13 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, int silent, int
strncpy(fmt, vmfmts, sizeof(fmt) - 1);
if (!ast_strlen_zero(fmt)) {
msgnum = 0;
+ if (res >= 0) {
+ /* Unless we're *really* silent, try to send the beep */
+ res = ast_streamfile(chan, "beep", chan->language);
+ if (!res)
+ res = ast_waitstream(chan, "");
+ }
+ ast_lock_path(dir);
do {
make_file(fn, sizeof(fn), dir, msgnum);
if (ast_fileexists(fn, NULL, chan->language) <= 0)
@@ -1462,22 +1488,19 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, int silent, int
chan->name,
chan->callerid ? chan->callerid : "Unknown",
date, (long)time(NULL));
- fclose(txt);
} else
ast_log(LOG_WARNING, "Error opening text file for output\n");
- res = play_record_review(chan, NULL, fn, vmmaxmessage, fmt, 1, vmu, &duration);
- if (res == '0')
+ res = play_record_review(chan, NULL, fn, vmmaxmessage, fmt, 1, vmu, &duration, dir);
+ if (res == '0') {
+ if (txt)
+ fclose(txt);
goto transfer;
+ }
if (res > 0)
res = 0;
- fd = open(txtfile, O_APPEND | O_WRONLY);
- if (fd > -1) {
- txt = fdopen(fd, "a");
- if (txt) {
- fprintf(txt, "duration=%d\n", duration);
- fclose(txt);
- } else
- close(fd);
+ if (txt) {
+ fprintf(txt, "duration=%d\n", duration);
+ fclose(txt);
}
if (duration < vmminmessage) {
if (option_verbose > 2)
@@ -1502,8 +1525,10 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, int silent, int
free_user(recip);
}
}
- notify_new_message(chan, vmu, msgnum, duration, fmt, chan->callerid);
+ if (ast_fileexists(fn, NULL, NULL))
+ notify_new_message(chan, vmu, msgnum, duration, fmt, chan->callerid);
} else {
+ ast_unlock_path(dir);
res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
if (!res)
res = ast_waitstream(chan, "");
@@ -1525,16 +1550,58 @@ leave_vm_out:
static int count_messages(char *dir)
{
- int x;
- char fn[256];
- for (x=0;x<MAXMSG;x++) {
- make_file(fn, sizeof(fn), dir, x);
- if (ast_fileexists(fn, NULL, NULL) < 1)
- break;
+ /* Find all .txt files - even if they are not in sequence from 0000 */
+
+
+ int vmcount = 0;
+ DIR *vmdir = NULL;
+ struct dirent *vment = NULL;
+
+ if ((vmdir = opendir(dir))) {
+ while ((vment = readdir(vmdir)))
+ {
+ if (strlen(vment->d_name) > 7 && !strncmp(vment->d_name + 7,".txt",4))
+ {
+ vmcount++;
+ }
+ }
+ closedir(vmdir);
+ }
+
+ return vmcount;
+}
+
+static void resequence_mailbox(char * dir)
+{
+ /* we know max messages, so stop process when number is hit */
+
+ int x,dest;
+ char sfn[256];
+ char dfn[256];
+ char stxt[256];
+ char dtxt[256];
+
+ ast_lock_path(dir);
+ for (x=0,dest=0;x<MAXMSG;x++) {
+ make_file(sfn, sizeof(sfn), dir, x);
+ if (ast_fileexists(sfn, NULL, NULL) > 0) {
+
+ if(x != dest) {
+ make_file(dfn, sizeof(dfn), dir, dest);
+ ast_filerename(sfn,dfn,NULL);
+
+ snprintf(stxt, sizeof(stxt), "%s.txt", sfn);
+ snprintf(dtxt, sizeof(dtxt), "%s.txt", dfn);
+ rename(stxt, dtxt);
+ }
+
+ dest++;
+ }
}
- return x;
+ ast_unlock_path(dir);
}
+
static int say_and_wait(struct ast_channel *chan, int num, char *language)
{
int d;
@@ -1554,19 +1621,23 @@ static int save_to_folder(char *dir, int msg, char *context, char *username, int
make_file(sfn, sizeof(sfn), dir, msg);
make_dir(ddir, sizeof(ddir), context, username, dbox);
mkdir(ddir, 0700);
+ ast_lock_path(ddir);
for (x=0;x<MAXMSG;x++) {
make_file(dfn, sizeof(dfn), ddir, x);
if (ast_fileexists(dfn, NULL, NULL) < 0)
break;
}
- if (x >= MAXMSG)
+ if (x >= MAXMSG) {
+ ast_unlock_path(ddir);
return -1;
+ }
ast_filecopy(sfn, dfn, NULL);
if (strcmp(sfn, dfn)) {
snprintf(txt, sizeof(txt), "%s.txt", sfn);
snprintf(ntxt, sizeof(ntxt), "%s.txt", dfn);
copy(txt, ntxt);
}
+ ast_unlock_path(ddir);
return 0;
}
@@ -2073,23 +2144,10 @@ static int get_folder(struct ast_channel *chan, int start)
d = ast_play_and_wait(chan, "vm-for"); /* "for" */
if (d)
return d;
- if (!strcasecmp(chan->language, "es") || !strcasecmp(chan->language, "fr") || !strcasecmp(chan->language, "pt")) { /* Spanish, French or Portuguese syntax */
- d = ast_play_and_wait(chan, "vm-messages"); /* "messages */
- if (d)
- return d;
- snprintf(fn, sizeof(fn), "vm-%s", mbox(x)); /* Folder name */
- d = ast_play_and_wait(chan, fn);
- if (d)
- return d;
- } else { /* Default English */
- snprintf(fn, sizeof(fn), "vm-%s", mbox(x)); /* Folder name */
- d = ast_play_and_wait(chan, fn);
- if (d)
- return d;
- d = ast_play_and_wait(chan, "vm-messages"); /* "messages */
- if (d)
- return d;
- }
+ snprintf(fn, sizeof(fn), "vm-%s", mbox(x)); /* Folder name */
+ d = vm_play_folder_name(chan, fn);
+ if (d)
+ return d;
d = ast_waitfordigit(chan, 500);
if (d)
return d;
@@ -2212,7 +2270,7 @@ static int forward_message(struct ast_channel *chan, char *context, char *dir, i
char callerid[512];
char ext_context[256]="";
int res = 0, cmd = 0;
- struct ast_vm_user *receiver, *extensions = NULL, *vmtmp = NULL, *vmfree;
+ struct ast_vm_user *receiver = NULL, *extensions = NULL, *vmtmp = NULL, *vmfree;
char tmp[256];
char *stringp, *s;
int saved_messages = 0, found = 0;
@@ -2272,7 +2330,7 @@ static int forward_message(struct ast_channel *chan, char *context, char *dir, i
snprintf(todir, sizeof(todir), "%s/voicemail/%s/%s/INBOX", (char *)ast_config_AST_SPOOL_DIR, vmtmp->context, vmtmp->mailbox);
snprintf(sys, sizeof(sys), "mkdir -p %s\n", todir);
snprintf(ext_context, sizeof(ext_context), "%s@%s", vmtmp->mailbox, vmtmp->context);
- ast_log(LOG_DEBUG, sys);
+ ast_log(LOG_DEBUG, "%s", sys);
ast_safe_system(sys);
todircount = count_messages(todir);
@@ -2283,11 +2341,11 @@ static int forward_message(struct ast_channel *chan, char *context, char *dir, i
if (!strcasecmp(s, "wav49"))
s = "WAV";
snprintf(sys, sizeof(sys), "cp %s/msg%04d.%s %s/msg%04d.%s\n", dir, curmsg, s, todir, todircount, s);
- ast_log(LOG_DEBUG, sys);
+ ast_log(LOG_DEBUG, "%s", sys);
ast_safe_system(sys);
}
snprintf(sys, sizeof(sys), "cp %s/msg%04d.txt %s/msg%04d.txt\n", dir, curmsg, todir, todircount);
- ast_log(LOG_DEBUG, sys);
+ ast_log(LOG_DEBUG, "%s", sys);
ast_safe_system(sys);
snprintf(fn, sizeof(fn), "%s/msg%04d", todir,todircount);
@@ -2545,6 +2603,20 @@ static void open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu,int box)
strncpy(vms->curbox, mbox(box), sizeof(vms->curbox) - 1);
make_dir(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
vms->lastmsg = count_messages(vms->curdir) - 1;
+
+ /*
+ The following test is needed in case sequencing gets messed up.
+ There appears to be more than one way to mess up sequence, so
+ we will not try to find all of the root causes--just fix it when
+ detected.
+ */
+
+ if(vms->lastmsg != last_message_index(vms->curdir))
+ {
+ ast_log(LOG_NOTICE, "Resequencing Mailbox: %s\n", vms->curdir);
+ resequence_mailbox(vms->curdir);
+ }
+
snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);
}
@@ -2555,6 +2627,7 @@ static void close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
char txt[256] = "";
if (vms->lastmsg > -1) {
/* Get the deleted messages fixed */
+ ast_lock_path(vms->curdir);
vms->curmsg = -1;
for (x=0;x < MAXMSG;x++) {
if (!vms->deleted[x] && (strcasecmp(vms->curbox, "INBOX") || !vms->heard[x])) {
@@ -2581,13 +2654,33 @@ static void close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
break;
vm_delete(vms->fn);
}
- }
- memset(vms->deleted, 0, sizeof(vms->deleted));
- memset(vms->heard, 0, sizeof(vms->heard));
+ ast_unlock_path(vms->curdir);
+ }
+ if (vms->deleted)
+ memset(vms->deleted, 0, sizeof(vms->deleted));
+ if (vms->heard)
+ memset(vms->heard, 0, sizeof(vms->heard));
+}
+
+static int vm_play_folder_name(struct ast_channel *chan, char *mbox)
+{
+ int cmd;
+
+ if (!strcasecmp(chan->language, "es") || !strcasecmp(chan->language, "fr") || !strcasecmp(chan->language, "pt")) { /*Spanish, French or Portuguese syntax */
+ cmd = ast_play_and_wait(chan, "vm-messages"); /* "messages */
+ if (cmd)
+ return cmd;
+ return ast_play_and_wait(chan, mbox);
+ } else { /* Default English */
+ cmd = ast_play_and_wait(chan, mbox);
+ if (cmd)
+ return cmd;
+ return ast_play_and_wait(chan, "vm-messages"); /* "messages */
+ }
}
/* Default English syntax */
-static int vm_intro(struct ast_channel *chan,struct vm_state *vms)
+static int vm_intro_en(struct ast_channel *chan,struct vm_state *vms)
{
/* Introduce messages they have */
int res;
@@ -2949,6 +3042,26 @@ static int vm_intro_cz(struct ast_channel *chan,struct vm_state *vms)
return res;
}
+static int vm_intro(struct ast_channel *chan,struct vm_state *vms)
+{
+ /* Play voicemail intro - syntax is different for different languages */
+ if (!strcasecmp(chan->language, "de")) { /* GERMAN syntax */
+ return vm_intro_de(chan, vms);
+ } else if (!strcasecmp(chan->language, "es")) { /* SPANISH syntax */
+ return vm_intro_es(chan, vms);
+ } else if (!strcasecmp(chan->language, "fr")) { /* FRENCH syntax */
+ return vm_intro_fr(chan, vms);
+ } else if (!strcasecmp(chan->language, "nl")) { /* DUTCH syntax */
+ return vm_intro_nl(chan, vms);
+ } else if (!strcasecmp(chan->language, "pt")) { /* PORTUGUESE syntax */
+ return vm_intro_pt(chan, vms);
+ } else if (!strcasecmp(chan->language, "cz")) { /* CZECH syntax */
+ return vm_intro_cz(chan, vms);
+ } else { /* Default to ENGLISH */
+ return vm_intro_en(chan, vms);
+ }
+}
+
static int vm_instructions(struct ast_channel *chan, struct vm_state *vms, int skipadvanced)
{
int res = 0;
@@ -2957,17 +3070,8 @@ static int vm_instructions(struct ast_channel *chan, struct vm_state *vms, int s
if (vms->starting) {
if (vms->lastmsg > -1) {
res = ast_play_and_wait(chan, "vm-onefor");
- if (!strcasecmp(chan->language, "es") || !strcasecmp(chan->language, "fr") || !strcasecmp(chan->language, "pt")) { /* Spanish, French & Portuguese Syntax */
- if (!res)
- res = ast_play_and_wait(chan, "vm-messages");
- if (!res)
- res = ast_play_and_wait(chan, vms->vmbox);
- } else { /* Default English syntax */
- if (!res)
- res = ast_play_and_wait(chan, vms->vmbox);
- if (!res)
- res = ast_play_and_wait(chan, "vm-messages");
- }
+ if (!res)
+ res = vm_play_folder_name(chan, vms->vmbox);
}
if (!res)
res = ast_play_and_wait(chan, "vm-opts");
@@ -3031,15 +3135,15 @@ static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct
switch (cmd) {
case '1':
snprintf(prefile,sizeof(prefile),"voicemail/%s/%s/unavail",vmu->context, vms->username);
- cmd = play_record_review(chan,"vm-rec-unv",prefile, maxgreet, fmtc, 0, vmu, &duration);
+ cmd = play_record_review(chan,"vm-rec-unv",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL);
break;
case '2':
snprintf(prefile,sizeof(prefile),"voicemail/%s/%s/busy",vmu->context, vms->username);
- cmd = play_record_review(chan,"vm-rec-busy",prefile, maxgreet, fmtc, 0, vmu, &duration);
+ cmd = play_record_review(chan,"vm-rec-busy",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL);
break;
case '3':
snprintf(prefile,sizeof(prefile),"voicemail/%s/%s/greet",vmu->context, vms->username);
- cmd = play_record_review(chan,"vm-rec-name",prefile, maxgreet, fmtc, 0, vmu, &duration);
+ cmd = play_record_review(chan,"vm-rec-name",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL);
break;
case '4':
if (vmu->password[0] == '-') {
@@ -3048,19 +3152,24 @@ static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct
}
newpassword[1] = '\0';
newpassword[0] = cmd = ast_play_and_wait(chan,"vm-newpassword");
- if (cmd < 0)
- break;
- if ((cmd = ast_readstring(chan,newpassword + strlen(newpassword),sizeof(newpassword)-1,2000,10000,"#")) < 0) {
- break;
- }
+ if (cmd == '#')
+ newpassword[0] = '\0';
+ else {
+ if (cmd < 0)
+ break;
+ if ((cmd = ast_readstring(chan,newpassword + strlen(newpassword),sizeof(newpassword)-1,2000,10000,"#")) < 0)
+ break;
+ }
newpassword2[1] = '\0';
newpassword2[0] = cmd = ast_play_and_wait(chan,"vm-reenterpassword");
- if (cmd < 0)
- break;
-
- if ((cmd = ast_readstring(chan,newpassword2 + strlen(newpassword2),sizeof(newpassword2)-1,2000,10000,"#"))) {
- break;
- }
+ if (cmd == '#')
+ newpassword2[0] = '\0';
+ else {
+ if (cmd < 0)
+ break;
+ if ((cmd = ast_readstring(chan,newpassword2 + strlen(newpassword2),sizeof(newpassword2)-1,2000,10000,"#")))
+ break;
+ }
if (strcmp(newpassword, newpassword2)) {
ast_log(LOG_NOTICE,"Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
cmd = ast_play_and_wait(chan, "vm-mismatch");
@@ -3092,7 +3201,7 @@ static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct
}
/* Default English syntax */
-static int vm_browse_messages(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
+static int vm_browse_messages_en(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
{
int cmd=0;
@@ -3150,6 +3259,17 @@ static int vm_browse_messages_pt(struct ast_channel *chan, struct vm_state *vms,
return cmd;
}
+static int vm_browse_messages(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
+{
+ if (!strcasecmp(chan->language, "es")) { /* SPANISH */
+ return vm_browse_messages_es(chan, vms, vmu);
+ } else if (!strcasecmp(chan->language, "pt")) { /* PORTUGUESE */
+ return vm_browse_messages_pt(chan, vms, vmu);
+ } else { /* Default to English syntax */
+ return vm_browse_messages_en(chan, vms, vmu);
+ }
+}
+
static int vm_execmain(struct ast_channel *chan, void *data)
{
/* XXX This is, admittedly, some pretty horrendus code. For some
@@ -3269,7 +3389,7 @@ static int vm_execmain(struct ast_channel *chan, void *data)
goto out;
}
}
- if (prefix) {
+ if (prefix && !ast_strlen_zero(prefixstr)) {
char fullusername[80] = "";
strncpy(fullusername, prefixstr, sizeof(fullusername) - 1);
strncat(fullusername, vms.username, sizeof(fullusername) - 1);
@@ -3290,15 +3410,20 @@ static int vm_execmain(struct ast_channel *chan, void *data)
logretries++;
if (!valid) {
if (skipuser || logretries >= maxlogins) {
- if (ast_streamfile(chan, "vm-incorrect", chan->language))
- break;
+ if (ast_streamfile(chan, "vm-incorrect", chan->language)) {
+ ast_log(LOG_WARNING, "Unable to stream incorrect message\n");
+ return -1;
+ }
} else {
if (useadsi)
adsi_login(chan);
- if (ast_streamfile(chan, "vm-incorrect-mailbox", chan->language))
- break;
+ if (ast_streamfile(chan, "vm-incorrect-mailbox", chan->language)) {
+ ast_log(LOG_WARNING, "Unable to stream incorrect mailbox message\n");
+ return -1;
+ }
}
- ast_waitstream(chan, "");
+ if (ast_waitstream(chan, "")) /* Channel is hung up */
+ return -1;
}
}
if (!valid && (logretries >= maxlogins)) {
@@ -3333,22 +3458,7 @@ static int vm_execmain(struct ast_channel *chan, void *data)
if (useadsi)
adsi_status(chan, &vms);
res = 0;
- /* Play voicemail intro - syntax is different for different languages */
- if (!strcasecmp(chan->language, "de")) { /* GERMAN syntax */
- cmd = vm_intro_de(chan, &vms);
- } else if (!strcasecmp(chan->language, "es")) { /* SPANISH syntax */
- cmd = vm_intro_es(chan, &vms);
- } else if (!strcasecmp(chan->language, "fr")) { /* FRENCH syntax */
- cmd = vm_intro_fr(chan, &vms);
- } else if (!strcasecmp(chan->language, "nl")) { /* DUTCH syntax */
- cmd = vm_intro_nl(chan, &vms);
- } else if (!strcasecmp(chan->language, "pt")) { /* PORTUGUESE syntax */
- cmd = vm_intro_pt(chan, &vms);
- } else if (!strcasecmp(chan->language, "cz")) { /* CZECH syntax */
- cmd = vm_intro_cz(chan, &vms);
- } else { /* Default to ENGLISH */
- cmd = vm_intro(chan, &vms);
- }
+ cmd = vm_intro(chan, &vms);
vms.repeats = 0;
vms.starting = 1;
while((cmd > -1) && (cmd != 't') && (cmd != '#')) {
@@ -3358,13 +3468,7 @@ static int vm_execmain(struct ast_channel *chan, void *data)
vms.curmsg = 0;
/* Fall through */
case '5':
- if (!strcasecmp(chan->language, "es")) { /* SPANISH */
- cmd = vm_browse_messages_es(chan, &vms, vmu);
- } else if (!strcasecmp(chan->language, "pt")) { /* PORTUGUESE */
- cmd = vm_browse_messages_pt(chan, &vms, vmu);
- } else { /* Default to English syntax */
- cmd = vm_browse_messages(chan, &vms, vmu);
- }
+ cmd = vm_browse_messages(chan, &vms, vmu);
break;
case '2': /* Change folders */
if (useadsi)
@@ -3380,17 +3484,8 @@ static int vm_execmain(struct ast_channel *chan, void *data)
}
if (useadsi)
adsi_status2(chan, &vms);
- if (!strcasecmp(chan->language, "es") || !strcasecmp(chan->language, "pt")) { /* SPANISH or PORTUGUESE */
- if (!cmd)
- cmd = ast_play_and_wait(chan, "vm-messages");
- if (!cmd)
- cmd = ast_play_and_wait(chan, vms.vmbox);
- } else { /* Default to English syntax */
- if (!cmd)
- cmd = ast_play_and_wait(chan, vms.vmbox);
- if (!cmd)
- cmd = ast_play_and_wait(chan, "vm-messages");
- }
+ if (!cmd)
+ cmd = vm_play_folder_name(chan, vms.vmbox);
vms.starting = 1;
break;
case '3': /* Advanced options */
@@ -3549,21 +3644,9 @@ static int vm_execmain(struct ast_channel *chan, void *data)
cmd = say_and_wait(chan, vms.curmsg + 1, chan->language);
if (!cmd)
cmd = ast_play_and_wait(chan, "vm-savedto");
- if (!strcasecmp(chan->language, "es") || !strcasecmp(chan->language, "pt")) { /* SPANISH or PORTUGUESE */
- if (!cmd)
- cmd = ast_play_and_wait(chan, "vm-messages");
- if (!cmd) {
- snprintf(vms.fn, sizeof(vms.fn), "vm-%s", mbox(box));
- cmd = ast_play_and_wait(chan, vms.fn);
- }
- } else { /* Default to English */
- if (!cmd) {
- snprintf(vms.fn, sizeof(vms.fn), "vm-%s", mbox(box));
- cmd = ast_play_and_wait(chan, vms.fn);
- }
- if (!cmd)
- cmd = ast_play_and_wait(chan, "vm-messages");
- }
+ snprintf(vms.fn, sizeof(vms.fn), "vm-%s", mbox(box));
+ if (!cmd)
+ cmd = vm_play_folder_name(chan, vms.fn);
if (skipaftercmd) {
if (vms.curmsg < vms.lastmsg) {
vms.curmsg++;
@@ -3577,17 +3660,8 @@ static int vm_execmain(struct ast_channel *chan, void *data)
case '*':
if (!vms.starting) {
cmd = ast_play_and_wait(chan, "vm-onefor");
- if (!strcasecmp(chan->language, "es") || !strcasecmp(chan->language, "pt")) { /* Spanish or Portuguese syntax */
- if (!cmd)
- cmd = ast_play_and_wait(chan, "vm-messages");
- if (!cmd)
- cmd = ast_play_and_wait(chan, vms.vmbox);
- } else {
- if (!cmd)
- cmd = ast_play_and_wait(chan, vms.vmbox);
- if (!cmd)
- cmd = ast_play_and_wait(chan, "vm-messages");
- }
+ if (!cmd)
+ cmd = vm_play_folder_name(chan, vms.vmbox);
if (!cmd)
cmd = ast_play_and_wait(chan, "vm-opts");
if (!cmd)
@@ -3800,7 +3874,7 @@ static int handle_show_voicemail_users(int fd, int argc, char *argv[])
if ((vmdir = opendir(dirname))) {
/* No matter what the format of VM, there will always be a .txt file for each message. */
while ((vment = readdir(vmdir)))
- if (!strncmp(vment->d_name + 7,".txt",4))
+ if (strlen(vment->d_name) > 7 && !strncmp(vment->d_name + 7,".txt",4))
vmcount++;
closedir(vmdir);
}
@@ -3924,7 +3998,7 @@ static int load_config(void)
zonesl = NULL;
users = NULL;
usersl = NULL;
- memset(ext_pass_cmd, 0, sizeof(ext_pass_cmd) - 1);
+ memset(ext_pass_cmd, 0, sizeof(ext_pass_cmd));
if (cfg) {
/* General settings */
@@ -4526,7 +4600,7 @@ static int advanced_options(struct ast_channel *chan, struct ast_vm_user *vmu, s
-static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt, int outsidecaller, struct ast_vm_user *vmu, int *duration)
+static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt, int outsidecaller, struct ast_vm_user *vmu, int *duration, const char *unlockdir)
{
/* Record message & let caller review or re-record it, or set options if applicable */
int res = 0;
@@ -4579,14 +4653,12 @@ static int play_record_review(struct ast_channel *chan, char *playfile, char *re
}
recorded = 1;
/* After an attempt has been made to record message, we have to take care of INTRO and beep for incoming messages, but not for greetings */
- cmd = ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, silencethreshold, maxsilence);
+ cmd = ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, silencethreshold, maxsilence, unlockdir);
if (cmd == -1)
/* User has hung up, no options to give */
- return res;
+ return cmd;
if (cmd == '0') {
- /* Erase the message if 0 pushed during playback */
- ast_play_and_wait(chan, "vm-deleted");
- vm_delete(recordfile);
+ break;
} else if (cmd == '*') {
break;
}
@@ -4639,13 +4711,20 @@ static int play_record_review(struct ast_channel *chan, char *playfile, char *re
return 1;
#endif
case '0':
- if (outsidecaller && vmu->operator) {
- if (message_exists)
- ast_play_and_wait(chan, "vm-msgsaved");
- return cmd;
- } else
- cmd = ast_play_and_wait(chan, "vm-sorry");
- break;
+ if (message_exists || recorded) {
+ cmd = ast_play_and_wait(chan, "vm-saveoper");
+ if (!cmd)
+ cmd = ast_waitfordigit(chan, 3000);
+ if (cmd == '1') {
+ ast_play_and_wait(chan, "vm-msgsaved");
+ cmd = '0';
+ } else {
+ ast_play_and_wait(chan, "vm-deleted");
+ vm_delete(recordfile);
+ cmd = '0';
+ }
+ }
+ return cmd;
default:
/* If the caller is an ouside caller, and the review option is enabled,
allow them to review the message, but let the owner of the box review
@@ -4681,7 +4760,7 @@ static int play_record_review(struct ast_channel *chan, char *playfile, char *re
}
}
if (outsidecaller)
- ast_play_and_wait(chan, "vm-goodbye");
+ ast_play_and_wait(chan, "vm-goodbye");
if (cmd == 't')
cmd = 0;
return cmd;
@@ -4703,6 +4782,7 @@ static int vm_delete(char *file)
return ast_filedelete(file, NULL);
}
+
int usecount(void)
{
int res;
diff --git a/apps/app_zapras.c b/apps/app_zapras.c
index d835e12f8..09c93bdb1 100755
--- a/apps/app_zapras.c
+++ b/apps/app_zapras.c
@@ -125,8 +125,14 @@ static void run_ras(struct ast_channel *chan, char *args)
int status;
int res;
int signalled = 0;
- struct zt_bufferinfo bi;
+ struct zt_bufferinfo savebi;
int x;
+
+ res = ioctl(chan->fds[0], ZT_GET_BUFINFO, &savebi);
+ if(res) {
+ ast_log(LOG_WARNING, "Unable to check buffer policy on channel %s\n", chan->name);
+ return;
+ }
pid = spawn_ras(chan, args);
if (pid < 0) {
@@ -162,20 +168,11 @@ static void run_ras(struct ast_channel *chan, char *args)
x = 1;
ioctl(chan->fds[0], ZT_AUDIOMODE, &x);
- /* Double check buffering too */
- res = ioctl(chan->fds[0], ZT_GET_BUFINFO, &bi);
- if (!res) {
- /* XXX This is ZAP_BLOCKSIZE XXX */
- bi.bufsize = 204;
- bi.txbufpolicy = ZT_POLICY_IMMEDIATE;
- bi.rxbufpolicy = ZT_POLICY_IMMEDIATE;
- bi.numbufs = 4;
- res = ioctl(chan->fds[0], ZT_SET_BUFINFO, &bi);
- if (res < 0) {
- ast_log(LOG_WARNING, "Unable to set buffer policy on channel %s\n", chan->name);
- }
- } else
- ast_log(LOG_WARNING, "Unable to check buffer policy on channel %s\n", chan->name);
+ /* Restore saved values */
+ res = ioctl(chan->fds[0], ZT_SET_BUFINFO, &savebi);
+ if (res < 0) {
+ ast_log(LOG_WARNING, "Unable to set buffer policy on channel %s\n", chan->name);
+ }
break;
}
}
diff --git a/ast_expr.y b/ast_expr.y
index 97b2b021c..df08f6829 100755
--- a/ast_expr.y
+++ b/ast_expr.y
@@ -215,6 +215,7 @@ struct val *vp;
}
if (vp->type == string || vp->type == numeric_string)
free (vp->u.s);
+ free (vp);
}
@@ -650,19 +651,24 @@ struct val *a, *b;
{
struct val *r;
- if (!to_integer (a) || !to_integer (b)) {
+ if (!to_integer (a)) {
ast_log(LOG_WARNING,"non-numeric argument\n");
- free_value(a);
+ if (!to_integer (b)) {
+ free_value(a);
+ free_value(b);
+ return make_integer(0);
+ } else {
+ free_value(a);
+ return (b);
+ }
+ } else if (!to_integer(b)) {
free_value(b);
- return(NULL);
+ return (a);
}
r = make_integer (/*(quad_t)*/(a->u.i + b->u.i));
if (chk_plus (a->u.i, b->u.i, r->u.i)) {
ast_log(LOG_WARNING,"overflow\n");
- free_value(a);
- free_value(b);
- return(NULL);
}
free_value (a);
free_value (b);
@@ -690,19 +696,27 @@ struct val *a, *b;
{
struct val *r;
- if (!to_integer (a) || !to_integer (b)) {
- free_value(a);
- free_value(b);
+ if (!to_integer (a)) {
ast_log(LOG_WARNING, "non-numeric argument\n");
- return(NULL);
+ if (!to_integer (b)) {
+ free_value(a);
+ free_value(b);
+ return make_integer(0);
+ } else {
+ r = make_integer(0 - b->u.i);
+ free_value(a);
+ free_value(b);
+ return (r);
+ }
+ } else if (!to_integer(b)) {
+ ast_log(LOG_WARNING, "non-numeric argument\n");
+ free_value(b);
+ return (a);
}
r = make_integer (/*(quad_t)*/(a->u.i - b->u.i));
if (chk_minus (a->u.i, b->u.i, r->u.i)) {
- free_value(a);
- free_value(b);
- ast_log(LOG_WARNING, "overload\n");
- return(NULL);
+ ast_log(LOG_WARNING, "overflow\n");
}
free_value (a);
free_value (b);
@@ -732,15 +746,12 @@ struct val *a, *b;
free_value(a);
free_value(b);
ast_log(LOG_WARNING, "non-numeric argument\n");
- return(NULL);
+ return(make_integer(0));
}
r = make_integer (/*(quad_t)*/(a->u.i * b->u.i));
if (chk_times (a->u.i, b->u.i, r->u.i)) {
ast_log(LOG_WARNING, "overflow\n");
- free_value(a);
- free_value(b);
- return(NULL);
}
free_value (a);
free_value (b);
@@ -765,26 +776,28 @@ struct val *a, *b;
{
struct val *r;
- if (!to_integer (a) || !to_integer (b)) {
+ if (!to_integer (a)) {
free_value(a);
free_value(b);
ast_log(LOG_WARNING, "non-numeric argument\n");
- return(NULL);
+ return make_integer(0);
+ } else if (!to_integer (b)) {
+ free_value(a);
+ free_value(b);
+ ast_log(LOG_WARNING, "non-numeric argument\n");
+ return make_integer(INT_MAX);
}
if (b->u.i == 0) {
ast_log(LOG_WARNING, "division by zero\n");
free_value(a);
free_value(b);
- return(NULL);
+ return make_integer(INT_MAX);
}
r = make_integer (/*(quad_t)*/(a->u.i / b->u.i));
if (chk_div (a->u.i, b->u.i)) {
ast_log(LOG_WARNING, "overflow\n");
- free_value(a);
- free_value(b);
- return(NULL);
}
free_value (a);
free_value (b);
@@ -801,14 +814,13 @@ struct val *a, *b;
ast_log(LOG_WARNING, "non-numeric argument\n");
free_value(a);
free_value(b);
- return(NULL);
+ return make_integer(0);
}
if (b->u.i == 0) {
ast_log(LOG_WARNING, "div by zero\n");
free_value(a);
- free_value(b);
- return(NULL);
+ return (b);
}
r = make_integer (/*(quad_t)*/(a->u.i % b->u.i));
@@ -838,7 +850,7 @@ struct val *a, *b;
ast_log(LOG_WARNING,"regcomp() error : %s",errbuf);
free_value(a);
free_value(b);
- return(NULL);
+ return make_str("");
}
/* compare string against pattern */
diff --git a/asterisk.c b/asterisk.c
index 3c4d230ee..0364f1b26 100755
--- a/asterisk.c
+++ b/asterisk.c
@@ -247,13 +247,15 @@ static void network_verboser(const char *s, int pos, int replace, int complete)
char *t = alloca(strlen(s) + 2);
if (t) {
sprintf(t, "\r%s", s);
- ast_network_puts(t);
+ if (complete)
+ ast_network_puts(t);
} else {
ast_log(LOG_ERROR, "Out of memory\n");
ast_network_puts(s);
}
} else {
- ast_network_puts(s);
+ if (complete)
+ ast_network_puts(s);
}
}
@@ -262,12 +264,12 @@ static pthread_t lthread;
static void *netconsole(void *vconsole)
{
struct console *con = vconsole;
- char hostname[256];
+ char hostname[MAXHOSTNAMELEN]="";
char tmp[512];
int res;
struct pollfd fds[2];
- if (gethostname(hostname, sizeof(hostname)))
+ if (gethostname(hostname, sizeof(hostname)-1))
strncpy(hostname, "<Unknown>", sizeof(hostname)-1);
snprintf(tmp, sizeof(tmp), "%s/%d/%s\n", hostname, ast_mainpid, ASTERISK_VERSION);
fdprint(con->fd, tmp);
@@ -757,12 +759,12 @@ static char shutdown_when_convenient_help[] =
static char restart_now_help[] =
"Usage: restart now\n"
-" Causes Asterisk to hangup all calls and exec() itself performing a cold.\n"
+" Causes Asterisk to hangup all calls and exec() itself performing a cold\n"
" restart.\n";
static char restart_gracefully_help[] =
"Usage: restart gracefully\n"
-" Causes Asterisk to stop accepting new calls and exec() itself performing a cold.\n"
+" Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n"
" restart when all active calls have ended.\n";
static char restart_when_convenient_help[] =
@@ -925,7 +927,7 @@ static int ast_el_read_char(EditLine *el, char *cp)
usleep(1000000 / reconnects_per_second);
}
}
- if (tries >= 30) {
+ if (tries >= 30 * reconnects_per_second) {
fprintf(stderr, "Failed to reconnect for 30 seconds. Quitting.\n");
quit_handler(0, 0, 0, 0);
}
@@ -962,7 +964,7 @@ static char *cli_prompt(EditLine *el)
memset(prompt, 0, sizeof(prompt));
while (*t != '\0' && *p < sizeof(prompt)) {
if (*t == '%') {
- char hostname[256];
+ char hostname[MAXHOSTNAMELEN]="";
int i;
struct timeval tv;
struct tm tm;
@@ -1471,13 +1473,13 @@ static int show_cli_help(void) {
printf(" -f Do not fork\n");
printf(" -g Dump core in case of a crash\n");
printf(" -h This help screen\n");
- printf(" -i Initializie crypto keys at startup\n");
+ printf(" -i Initialize crypto keys at startup\n");
printf(" -n Disable console colorization\n");
printf(" -p Run as pseudo-realtime thread\n");
- printf(" -q Quiet mode (supress output)\n");
+ printf(" -q Quiet mode (suppress output)\n");
printf(" -r Connect to Asterisk on this machine\n");
printf(" -R Connect to Asterisk, and attempt to reconnect if disconnected\n");
- printf(" -t Record soundfiles in /tmp and move them where they belong after they are done.\n");
+ printf(" -t Record soundfiles in /var/tmp and move them where they belong after they are done.\n");
printf(" -v Increase verbosity (multiple v's = more verbose)\n");
printf(" -x <cmd> Execute command <cmd> (only valid with -r)\n");
printf("\n");
@@ -1570,7 +1572,7 @@ int main(int argc, char *argv[])
{
int c;
char filename[80] = "";
- char hostname[256];
+ char hostname[MAXHOSTNAMELEN]="";
char tmp[80];
char * xarg = NULL;
int x;
@@ -1579,6 +1581,7 @@ int main(int argc, char *argv[])
int num;
char *buf;
char *runuser=NULL, *rungroup=NULL;
+ struct pollfd silly_macos[1];
/* Remember original args for restart */
if (argc > sizeof(_argv) / sizeof(_argv[0]) - 1) {
@@ -1594,7 +1597,7 @@ int main(int argc, char *argv[])
option_remote++;
option_nofork++;
}
- if (gethostname(hostname, sizeof(hostname)))
+ if (gethostname(hostname, sizeof(hostname)-1))
strncpy(hostname, "<Unknown>", sizeof(hostname)-1);
ast_mainpid = getpid();
ast_ulaw_init();
@@ -1691,6 +1694,14 @@ int main(int argc, char *argv[])
}
}
+ if (option_console && !option_verbose)
+ ast_verbose("[ Reading Master Configuration ]");
+ ast_readconfig();
+
+ if (set_priority(option_highpriority)) {
+ exit(1);
+ }
+
if (rungroup) {
struct group *gr;
gr = getgrnam(rungroup);
@@ -1706,9 +1717,6 @@ int main(int argc, char *argv[])
ast_verbose("Running as group '%s'\n", rungroup);
}
- if (set_priority(option_highpriority)) {
- exit(1);
- }
if (runuser) {
struct passwd *pw;
pw = getpwnam(runuser);
@@ -1728,14 +1736,6 @@ int main(int argc, char *argv[])
printf(term_end());
fflush(stdout);
- /* Test recursive mutex locking. */
- if (test_for_thread_safety())
- ast_verbose("Warning! Asterisk is not thread safe.\n");
-
- if (option_console && !option_verbose)
- ast_verbose("[ Reading Master Configuration ]");
- ast_readconfig();
-
if (option_console && !option_verbose)
ast_verbose("[ Initializing Custom Configuration Options]");
/* custom config setup */
@@ -1796,6 +1796,10 @@ int main(int argc, char *argv[])
ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", (char *)ast_config_AST_PID, strerror(errno));
}
+ /* Test recursive mutex locking. */
+ if (test_for_thread_safety())
+ ast_verbose("Warning! Asterisk is not thread safe.\n");
+
ast_makesocket();
sigemptyset(&sigs);
sigaddset(&sigs, SIGHUP);
@@ -1820,6 +1824,12 @@ int main(int argc, char *argv[])
signal(SIGCHLD, child_handler);
signal(SIGPIPE, SIG_IGN);
+ /* ensure that the random number generators are seeded with a different value every time
+ Asterisk is started
+ */
+ srand((unsigned int) getpid() + (unsigned int) time(NULL));
+ srandom((unsigned int) getpid() + (unsigned int) time(NULL));
+
if (init_logger()) {
printf(term_quit());
exit(1);
@@ -1905,15 +1915,24 @@ int main(int argc, char *argv[])
consolehandler((char *)buf);
} else {
- if (option_remote)
- ast_cli(STDOUT_FILENO, "\nUse EXIT or QUIT to exit the asterisk console\n");
+ if (write(STDOUT_FILENO, "\nUse EXIT or QUIT to exit the asterisk console\n",
+ strlen("\nUse EXIT or QUIT to exit the asterisk console\n")) < 0) {
+ /* Whoa, stdout disappeared from under us... Make /dev/null's */
+ int fd;
+ fd = open("/dev/null", O_RDWR);
+ if (fd > -1) {
+ dup2(fd, STDOUT_FILENO);
+ dup2(fd, STDIN_FILENO);
+ } else
+ ast_log(LOG_WARNING, "Failed to open /dev/null to recover from dead console. Bad things will happen!\n");
+ break;
+ }
}
}
- } else {
- /* Do nothing */
- for(;;)
- poll(NULL,0, -1);
}
+ /* Do nothing */
+ for(;;)
+ poll(silly_macos,0, -1);
return 0;
}
diff --git a/astman/astman.c b/astman/astman.c
index ebeeb67f1..c26c24be6 100755
--- a/astman/astman.c
+++ b/astman/astman.c
@@ -28,6 +28,14 @@
#define MAX_HEADERS 80
#define MAX_LEN 256
+/*
+ * 2005.05.27 - different versions of newt define the type of the buffer
+ * for the 5th argument to newtEntry() as char ** or const char ** . To
+ * let the code compile cleanly with -Werror, we cast it to void * through
+ * _NEWT_CAST.
+ */
+#define _NEWT_CAST (void *)
+
static struct ast_mansession {
struct sockaddr_in sin;
int fd;
@@ -436,7 +444,7 @@ static int get_user_input(char *msg, char *buf, int buflen)
newtCenteredWindow(60,7, msg);
- inpfield = newtEntry(5, 2, "", 50, &input, 0);
+ inpfield = newtEntry(5, 2, "", 50, _NEWT_CAST &input, 0);
ok = newtButton(22, 3, "OK");
cancel = newtButton(32, 3, "Cancel");
form = newtForm(NULL, NULL, 0);
@@ -603,8 +611,8 @@ static int login(char *hostname)
ulabel = newtLabel(4,2,"Username:");
plabel = newtLabel(4,3,"Password:");
- username = newtEntry(14, 2, "", 20, &user, 0);
- password = newtEntry(14, 3, "", 20, &pass, NEWT_FLAG_HIDDEN);
+ username = newtEntry(14, 2, "", 20, _NEWT_CAST &user, 0);
+ password = newtEntry(14, 3, "", 20, _NEWT_CAST &pass, NEWT_FLAG_HIDDEN);
form = newtForm(NULL, NULL, 0);
newtFormAddComponents(form, username, password, login, cancel, label, ulabel, plabel,NULL);
diff --git a/callerid.c b/callerid.c
index 348c84404..5481676ec 100755
--- a/callerid.c
+++ b/callerid.c
@@ -334,6 +334,8 @@ int callerid_feed(struct callerid_state *cid, unsigned char *ubuf, int len, int
cid->number[res] = '\0';
}
break;
+ case 6: /* Stentor Call Qualifier (ie. Long Distance call) */
+ break;
case 7: /* Name */
case 8: /* Name */
res = cid->rawdata[x];
diff --git a/cdr.c b/cdr.c
index f4e97efce..5a8102f30 100755
--- a/cdr.c
+++ b/cdr.c
@@ -524,11 +524,16 @@ void ast_cdr_reset(struct ast_cdr *cdr, int flags)
}
-void ast_cdr_append(struct ast_cdr *cdr, struct ast_cdr *newcdr) {
+struct ast_cdr *ast_cdr_append(struct ast_cdr *cdr, struct ast_cdr *newcdr)
+{
+ struct ast_cdr *ret;
if (cdr) {
+ ret = cdr;
while(cdr->next)
cdr = cdr->next;
cdr->next = newcdr;
- } else
- ast_log(LOG_ERROR, "Can't append a CDR to NULL!\n");
+ } else {
+ ret = newcdr;
+ }
+ return ret;
}
diff --git a/cdr/cdr_csv.c b/cdr/cdr_csv.c
index a1d391cfb..bd18a7775 100755
--- a/cdr/cdr_csv.c
+++ b/cdr/cdr_csv.c
@@ -33,6 +33,7 @@
#include <stdio.h>
#include <string.h>
+#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
@@ -184,7 +185,7 @@ static int build_csv_record(char *buf, size_t bufsize, struct ast_cdr *cdr)
static int writefile(char *s, char *acc)
{
- char tmp[256];
+ char tmp[AST_CONFIG_MAX_PATH];
FILE *f;
if (strchr(acc, '/') || (acc[0] == '.')) {
ast_log(LOG_WARNING, "Account code '%s' insecure for writing file\n", acc);
@@ -195,6 +196,7 @@ static int writefile(char *s, char *acc)
if (!f)
return -1;
fputs(s, f);
+ fflush(f);
fclose(f);
return 0;
}
@@ -217,7 +219,7 @@ static int csv_log(struct ast_cdr *cdr)
we open write and close the log file each time */
mf = fopen(csvmaster, "a");
if (!mf) {
- ast_log(LOG_ERROR, "Unable to re-open master file %s\n", csvmaster);
+ ast_log(LOG_ERROR, "Unable to re-open master file %s : %s\n", csvmaster, strerror(errno));
}
if (mf) {
fputs(buf, mf);
@@ -227,7 +229,7 @@ static int csv_log(struct ast_cdr *cdr)
}
if (!ast_strlen_zero(cdr->accountcode)) {
if (writefile(buf, cdr->accountcode))
- ast_log(LOG_WARNING, "Unable to write CSV record to account file '%s'\n", cdr->accountcode);
+ ast_log(LOG_WARNING, "Unable to write CSV record to account file '%s' : %s\n", cdr->accountcode, strerror(errno));
}
}
return 0;
diff --git a/cdr/cdr_odbc.c b/cdr/cdr_odbc.c
index e52730f2e..80bd97334 100755
--- a/cdr/cdr_odbc.c
+++ b/cdr/cdr_odbc.c
@@ -3,13 +3,12 @@
*
* ODBC CDR Backend
*
+ * Copyright (C) 2003-2005, Digium, Inc.
+ *
* Brian K. West <brian@bkw.org>
*
* This program is free software, distributed under the terms of
- * the GNU General Public License.
- *
- * Copyright (c) 2003 Digium, Inc.
- *
+ * the GNU General Public License
*/
#include <sys/types.h>
@@ -37,8 +36,9 @@
static char *desc = "ODBC CDR Backend";
static char *name = "ODBC";
static char *config = "cdr_odbc.conf";
-static char *dsn = NULL, *username = NULL, *password = NULL, *loguniqueid = NULL;
-static int dsn_alloc = 0, username_alloc = 0, password_alloc = 0, loguniqueid_alloc = 0;
+static char *dsn = NULL, *username = NULL, *password = NULL;
+static int dsn_alloc = 0, username_alloc = 0, password_alloc = 0;
+static int loguniqueid = 0;
static int connected = 0;
AST_MUTEX_DEFINE_STATIC(odbc_lock);
@@ -65,38 +65,31 @@ static int odbc_log(struct ast_cdr *cdr)
ast_mutex_lock(&odbc_lock);
strftime(timestr, sizeof(timestr), DATE_FORMAT, &tm);
memset(sqlcmd,0,2048);
- if((loguniqueid != NULL) && ((strcmp(loguniqueid, "1") == 0) || (strcmp(loguniqueid, "yes") == 0)))
- {
+ if (loguniqueid) {
snprintf(sqlcmd,sizeof(sqlcmd),"INSERT INTO cdr "
"(calldate,clid,src,dst,dcontext,channel,dstchannel,lastapp,"
"lastdata,duration,billsec,disposition,amaflags,accountcode,uniqueid,userfield) "
"VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)");
- }
- else
- {
+ } else {
snprintf(sqlcmd,sizeof(sqlcmd),"INSERT INTO cdr "
"(calldate,clid,src,dst,dcontext,channel,dstchannel,lastapp,lastdata,"
"duration,billsec,disposition,amaflags,accountcode) "
"VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)");
}
- if(!connected)
- {
- res = odbc_init();
- if(res < 0)
- {
+ if (!connected) {
+ res = odbc_init();
+ if (res < 0) {
connected = 0;
ast_mutex_unlock(&odbc_lock);
return 0;
}
-
}
ODBC_res = SQLAllocHandle(SQL_HANDLE_STMT, ODBC_con, &ODBC_stmt);
- if((ODBC_res != SQL_SUCCESS) && (ODBC_res != SQL_SUCCESS_WITH_INFO))
- {
- if(option_verbose > 10)
+ if ((ODBC_res != SQL_SUCCESS) && (ODBC_res != SQL_SUCCESS_WITH_INFO)) {
+ if (option_verbose > 10)
ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: Failure in AllocStatement %d\n", ODBC_res);
SQLGetDiagRec(SQL_HANDLE_DBC, ODBC_con, 1, ODBC_stat, &ODBC_err, ODBC_msg, 100, &ODBC_mlen);
SQLFreeHandle(SQL_HANDLE_STMT, ODBC_stmt);
@@ -111,9 +104,8 @@ static int odbc_log(struct ast_cdr *cdr)
ODBC_res = SQLPrepare(ODBC_stmt, sqlcmd, SQL_NTS);
- if((ODBC_res != SQL_SUCCESS) && (ODBC_res != SQL_SUCCESS_WITH_INFO))
- {
- if(option_verbose > 10)
+ if ((ODBC_res != SQL_SUCCESS) && (ODBC_res != SQL_SUCCESS_WITH_INFO)) {
+ if (option_verbose > 10)
ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: Error in PREPARE %d\n", ODBC_res);
SQLGetDiagRec(SQL_HANDLE_DBC, ODBC_con, 1, ODBC_stat, &ODBC_err, ODBC_msg, 100, &ODBC_mlen);
SQLFreeHandle(SQL_HANDLE_STMT, ODBC_stmt);
@@ -137,46 +129,38 @@ static int odbc_log(struct ast_cdr *cdr)
SQLBindParameter(ODBC_stmt, 13, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->amaflags, 0, NULL);
SQLBindParameter(ODBC_stmt, 14, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->accountcode), 0, cdr->accountcode, 0, NULL);
- if((loguniqueid != NULL) && ((strcmp(loguniqueid, "1") == 0) || (strcmp(loguniqueid, "yes") == 0)))
- {
+ if (loguniqueid) {
SQLBindParameter(ODBC_stmt, 15, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->uniqueid), 0, cdr->uniqueid, 0, NULL);
SQLBindParameter(ODBC_stmt, 16, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->userfield), 0, cdr->userfield, 0, NULL);
}
- if(connected)
- {
+ if (connected) {
res = odbc_do_query();
- if(res < 0)
- {
- if(option_verbose > 10)
+ if (res < 0) {
+ if (option_verbose > 10)
ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: Query FAILED Call not logged!\n");
res = odbc_init();
- if(option_verbose > 10)
+ if (option_verbose > 10)
ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: Reconnecting to dsn %s\n", dsn);
- if(res < 0)
- {
- if(option_verbose > 10)
+ if (res < 0) {
+ if (option_verbose > 10)
ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: %s has gone away!\n", dsn);
connected = 0;
- }
- else
- {
- if(option_verbose > 10)
+ } else {
+ if (option_verbose > 10)
ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: Trying Query again!\n");
res = odbc_do_query();
- if(res < 0)
- {
- if(option_verbose > 10)
+ if (res < 0) {
+ if (option_verbose > 10)
ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: Query FAILED Call not logged!\n");
}
}
}
- }
- else
- {
- if(option_verbose > 10)
+ } else {
+ if (option_verbose > 10)
ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: Query FAILED Call not logged!\n");
}
+ SQLFreeHandle(SQL_HANDLE_STMT, ODBC_stmt);
ast_mutex_unlock(&odbc_lock);
return 0;
}
@@ -189,9 +173,8 @@ char *description(void)
static int odbc_unload_module(void)
{
ast_mutex_lock(&odbc_lock);
- if (connected)
- {
- if(option_verbose > 10)
+ if (connected) {
+ if (option_verbose > 10)
ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: Disconnecting from %s\n", dsn);
SQLFreeHandle(SQL_HANDLE_STMT, ODBC_stmt);
SQLDisconnect(ODBC_con);
@@ -199,38 +182,29 @@ static int odbc_unload_module(void)
SQLFreeHandle(SQL_HANDLE_ENV, ODBC_env);
connected = 0;
}
- if (dsn && dsn_alloc)
- {
- if(option_verbose > 10)
+ if (dsn && dsn_alloc) {
+ if (option_verbose > 10)
ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: free dsn\n");
free(dsn);
dsn = NULL;
dsn_alloc = 0;
}
- if (username && username_alloc)
- {
- if(option_verbose > 10)
+ if (username && username_alloc) {
+ if (option_verbose > 10)
ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: free username\n");
free(username);
username = NULL;
username_alloc = 0;
}
- if (password && password_alloc)
- {
- if(option_verbose > 10)
+ if (password && password_alloc) {
+ if (option_verbose > 10)
ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: free password\n");
free(password);
password = NULL;
password_alloc = 0;
}
- if (loguniqueid && loguniqueid_alloc)
- {
- if(option_verbose > 10)
- ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: free loguniqueid\n");
- free(loguniqueid);
- loguniqueid = NULL;
- loguniqueid_alloc = 0;
- }
+ loguniqueid = 0;
+
ast_cdr_unregister(name);
ast_mutex_unlock(&odbc_lock);
return 0;
@@ -246,8 +220,7 @@ static int odbc_load_module(void)
ast_mutex_lock(&odbc_lock);
cfg = ast_load(config);
- if (!cfg)
- {
+ if (!cfg) {
ast_log(LOG_WARNING, "cdr_odbc: Unable to load config for ODBC CDR's: %s\n", config);
goto out;
}
@@ -259,113 +232,85 @@ static int odbc_load_module(void)
}
tmp = ast_variable_retrieve(cfg,"global","dsn");
- if (tmp)
- {
+ if (tmp) {
dsn = malloc(strlen(tmp) + 1);
- if (dsn != NULL)
- {
+ if (dsn != NULL) {
memset(dsn, 0, strlen(tmp) + 1);
dsn_alloc = 1;
strncpy(dsn, tmp, strlen(tmp));
- }
- else
- {
+ } else {
ast_log(LOG_ERROR,"cdr_odbc: Out of memory error.\n");
- return -1;
+ res = -1;
+ goto out;
}
- }
- else
- {
+ } else {
ast_log(LOG_WARNING,"cdr_odbc: dsn not specified. Assuming asteriskdb\n");
dsn = "asteriskdb";
}
tmp = ast_variable_retrieve(cfg,"global","username");
- if (tmp)
- {
+ if (tmp) {
username = malloc(strlen(tmp) + 1);
- if (username != NULL)
- {
+ if (username != NULL) {
memset(username, 0, strlen(tmp) + 1);
username_alloc = 1;
strncpy(username, tmp, strlen(tmp));
- }
- else
- {
+ } else {
ast_log(LOG_ERROR,"cdr_odbc: Out of memory error.\n");
- return -1;
+ res = -1;
+ goto out;
}
- }
- else
- {
+ } else {
ast_log(LOG_WARNING,"cdr_odbc: username not specified. Assuming root\n");
username = "root";
}
tmp = ast_variable_retrieve(cfg,"global","password");
- if (tmp)
- {
+ if (tmp) {
password = malloc(strlen(tmp) + 1);
- if (password != NULL)
- {
+ if (password != NULL) {
memset(password, 0, strlen(tmp) + 1);
password_alloc = 1;
strncpy(password, tmp, strlen(tmp));
- }
- else
- {
+ } else {
ast_log(LOG_ERROR,"cdr_odbc: Out of memory error.\n");
- return -1;
+ res = -1;
+ goto out;
}
- }
- else
- {
+ } else {
ast_log(LOG_WARNING,"cdr_odbc: database password not specified. Assuming blank\n");
password = "";
}
tmp = ast_variable_retrieve(cfg,"global","loguniqueid");
- if (tmp)
- {
- loguniqueid = malloc(strlen(tmp) + 1);
- if (loguniqueid != NULL)
- {
- strcpy(loguniqueid,tmp);
- loguniqueid_alloc = 1;
+ if (tmp) {
+ loguniqueid = ast_true(tmp);
+ if (loguniqueid) {
ast_log(LOG_NOTICE,"cdr_odbc: Logging uniqueid\n");
- }
- else
- {
+ } else {
ast_log(LOG_ERROR,"cdr_odbc: Not logging uniqueid\n");
- loguniqueid_alloc = 1;
- loguniqueid = NULL;
}
- }
- else
- {
+ } else {
ast_log(LOG_WARNING,"cdr_odbc: Not logging uniqueid\n");
- loguniqueid = NULL;
+ loguniqueid = 0;
}
ast_destroy(cfg);
- if(option_verbose > 3)
- {
- ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: dsn is %s\n",dsn);
- ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: username is %s\n",username);
- ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: password is [secret]\n");
-
+ if (option_verbose > 2) {
+ ast_verbose( VERBOSE_PREFIX_3 "cdr_odbc: dsn is %s\n",dsn);
+ ast_verbose( VERBOSE_PREFIX_3 "cdr_odbc: username is %s\n",username);
+ ast_verbose( VERBOSE_PREFIX_3 "cdr_odbc: password is [secret]\n");
}
res = odbc_init();
- if(res < 0)
- {
+ if (res < 0) {
ast_log(LOG_ERROR, "cdr_odbc: Unable to connect to datasource: %s\n", dsn);
- ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: Unable to connect to datasource: %s\n", dsn);
+ if (option_verbose > 2) {
+ ast_verbose( VERBOSE_PREFIX_3 "cdr_odbc: Unable to connect to datasource: %s\n", dsn);
+ }
}
-
res = ast_cdr_register(name, desc, odbc_log);
- if (res)
- {
+ if (res) {
ast_log(LOG_ERROR, "cdr_odbc: Unable to register ODBC CDR handling\n");
}
out:
@@ -375,25 +320,22 @@ out:
static int odbc_do_query(void)
{
- long int ODBC_err;
+ long int ODBC_err;
int ODBC_res;
- short int ODBC_mlen;
- char ODBC_msg[200], ODBC_stat[10];
-
+ short int ODBC_mlen;
+ char ODBC_msg[200], ODBC_stat[10];
+
ODBC_res = SQLExecute(ODBC_stmt);
-
- if((ODBC_res != SQL_SUCCESS) && (ODBC_res != SQL_SUCCESS_WITH_INFO))
- {
- if(option_verbose > 10)
+
+ if ((ODBC_res != SQL_SUCCESS) && (ODBC_res != SQL_SUCCESS_WITH_INFO)) {
+ if (option_verbose > 10)
ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: Error in Query %d\n", ODBC_res);
SQLGetDiagRec(SQL_HANDLE_DBC, ODBC_con, 1, ODBC_stat, &ODBC_err, ODBC_msg, 100, &ODBC_mlen);
SQLFreeHandle(SQL_HANDLE_STMT, ODBC_stmt);
connected = 0;
return -1;
- }
- else
- {
- if(option_verbose > 10)
+ } else {
+ if (option_verbose > 10)
ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: Query Successful!\n");
connected = 1;
}
@@ -407,13 +349,10 @@ static int odbc_init(void)
int ODBC_res;
char ODBC_msg[200], ODBC_stat[10];
- if ( ODBC_env == SQL_NULL_HANDLE || connected == 0 )
- {
+ if (ODBC_env == SQL_NULL_HANDLE || connected == 0) {
ODBC_res = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &ODBC_env);
-
- if((ODBC_res != SQL_SUCCESS) && (ODBC_res != SQL_SUCCESS_WITH_INFO))
- {
- if(option_verbose > 10)
+ if ((ODBC_res != SQL_SUCCESS) && (ODBC_res != SQL_SUCCESS_WITH_INFO)) {
+ if (option_verbose > 10)
ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: Error AllocHandle\n");
connected = 0;
return -1;
@@ -421,9 +360,8 @@ static int odbc_init(void)
ODBC_res = SQLSetEnvAttr(ODBC_env, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);
- if((ODBC_res != SQL_SUCCESS) && (ODBC_res != SQL_SUCCESS_WITH_INFO))
- {
- if(option_verbose > 10)
+ if ((ODBC_res != SQL_SUCCESS) && (ODBC_res != SQL_SUCCESS_WITH_INFO)) {
+ if (option_verbose > 10)
ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: Error SetEnv\n");
SQLFreeHandle(SQL_HANDLE_ENV, ODBC_env);
connected = 0;
@@ -432,32 +370,27 @@ static int odbc_init(void)
ODBC_res = SQLAllocHandle(SQL_HANDLE_DBC, ODBC_env, &ODBC_con);
- if((ODBC_res != SQL_SUCCESS) && (ODBC_res != SQL_SUCCESS_WITH_INFO))
- {
- if(option_verbose > 10)
+ if ((ODBC_res != SQL_SUCCESS) && (ODBC_res != SQL_SUCCESS_WITH_INFO)) {
+ if (option_verbose > 10)
ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: Error AllocHDB %d\n", ODBC_res);
SQLFreeHandle(SQL_HANDLE_ENV, ODBC_env);
connected = 0;
return -1;
}
-
SQLSetConnectAttr(ODBC_con, SQL_LOGIN_TIMEOUT, (SQLPOINTER *)10, 0);
}
ODBC_res = SQLConnect(ODBC_con, (SQLCHAR*)dsn, SQL_NTS, (SQLCHAR*)username, SQL_NTS, (SQLCHAR*)password, SQL_NTS);
- if((ODBC_res != SQL_SUCCESS) && (ODBC_res != SQL_SUCCESS_WITH_INFO))
- {
- if(option_verbose > 10)
+ if ((ODBC_res != SQL_SUCCESS) && (ODBC_res != SQL_SUCCESS_WITH_INFO)) {
+ if (option_verbose > 10)
ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: Error SQLConnect %d\n", ODBC_res);
SQLGetDiagRec(SQL_HANDLE_DBC, ODBC_con, 1, ODBC_stat, &ODBC_err, ODBC_msg, 100, &ODBC_mlen);
SQLFreeHandle(SQL_HANDLE_ENV, ODBC_env);
connected = 0;
return -1;
- }
- else
- {
- if(option_verbose > 10)
+ } else {
+ if (option_verbose > 10)
ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: Connected to %s\n", dsn);
connected = 1;
}
diff --git a/cdr/cdr_pgsql.c b/cdr/cdr_pgsql.c
index ccec5f9e5..90d386fdc 100755
--- a/cdr/cdr_pgsql.c
+++ b/cdr/cdr_pgsql.c
@@ -127,6 +127,19 @@ static int pgsql_log(struct ast_cdr *cdr)
pgerror = PQresultErrorMessage(result);
ast_log(LOG_ERROR,"cdr_pgsql: Failed to insert call detail record into database!\n");
ast_log(LOG_ERROR,"cdr_pgsql: Reason: %s\n", pgerror);
+ ast_log(LOG_ERROR,"cdr_pgsql: Connection may have been lost... attempting to reconnect.\n");
+ PQreset(conn);
+ if (PQstatus(conn) == CONNECTION_OK) {
+ ast_log(LOG_ERROR, "cdr_pgsql: Connection reestablished.\n");
+ connected = 1;
+ result = PQexec(conn, sqlcmd);
+ if ( PQresultStatus(result) != PGRES_COMMAND_OK)
+ {
+ pgerror = PQresultErrorMessage(result);
+ ast_log(LOG_ERROR,"cdr_pgsql: HARD ERROR! Attempted reconnection failed. DROPPING CALL RECORD!\n");
+ ast_log(LOG_ERROR,"cdr_pgsql: Reason: %s\n", pgerror);
+ }
+ }
ast_mutex_unlock(&pgsql_lock);
return -1;
}
@@ -180,20 +193,13 @@ static int my_unload_module(void)
return 0;
}
-static int my_load_module(void)
+static int process_my_load_module(struct ast_config *cfg)
{
int res;
- struct ast_config *cfg;
struct ast_variable *var;
char *pgerror;
char *tmp;
- cfg = ast_load(config);
- if (!cfg) {
- ast_log(LOG_WARNING, "Unable to load config for PostgreSQL CDR's: %s\n", config);
- return 0;
- }
-
var = ast_variable_browse(cfg, "global");
if (!var) {
/* nothing configured */
@@ -280,8 +286,6 @@ static int my_load_module(void)
pgdbport = "5432";
}
- ast_destroy(cfg);
-
ast_log(LOG_DEBUG,"cdr_pgsql: got hostname of %s\n",pghostname);
ast_log(LOG_DEBUG,"cdr_pgsql: got port of %s\n",pgdbport);
if (pgdbsock)
@@ -296,7 +300,7 @@ static int my_load_module(void)
connected = 1;
} else {
pgerror = PQerrorMessage(conn);
- ast_log(LOG_ERROR, "cdr_pgsql: Unable to connect to database server %s. Calls will not be logged!\n", pghostname);
+ ast_log(LOG_ERROR, "cdr_pgsql: Unable to connect to database server %s. CALLS WILL NOT BE LOGGED!!\n", pghostname);
ast_log(LOG_ERROR, "cdr_pgsql: Reason: %s\n", pgerror);
connected = 0;
}
@@ -308,6 +312,20 @@ static int my_load_module(void)
return res;
}
+static int my_load_module(void)
+{
+ struct ast_config *cfg;
+ int res;
+ cfg = ast_load(config);
+ if (!cfg) {
+ ast_log(LOG_WARNING, "Unable to load config for PostgreSQL CDR's: %s\n", config);
+ return 0;
+ }
+ res = process_my_load_module(cfg);
+ ast_destroy(cfg);
+ return res;
+}
+
int load_module(void)
{
return my_load_module();
diff --git a/cdr/cdr_tds.c b/cdr/cdr_tds.c
index 448c02495..5d678067c 100755
--- a/cdr/cdr_tds.c
+++ b/cdr/cdr_tds.c
@@ -65,6 +65,11 @@ static char *desc = "MSSQL CDR Backend";
static char *name = "mssql";
static char *config = "cdr_tds.conf";
+static char *hostname = NULL, *dbname = NULL, *dbuser = NULL, *password = NULL, *charset = NULL, *language = NULL;
+
+static int connected = 0;
+static time_t connect_time = 0;
+
AST_MUTEX_DEFINE_STATIC(tds_lock);
static TDSSOCKET *tds;
@@ -75,11 +80,15 @@ static char *stristr(const char*, const char*);
static char *anti_injection(const char *, int);
static void get_date(char *, struct timeval);
+static int mssql_connect(void);
+static int mssql_disconnect(void);
+
static int tds_log(struct ast_cdr *cdr)
{
char sqlcmd[2048], start[80], answer[80], end[80];
char *accountcode, *src, *dst, *dcontext, *clid, *channel, *dstchannel, *lastapp, *lastdata, *uniqueid;
int res = 0;
+ int retried = 0;
#ifdef TDS_PRE_0_62
TDS_INT result_type;
#endif
@@ -164,16 +173,27 @@ static int tds_log(struct ast_cdr *cdr)
uniqueid
);
+ do {
+ if (!connected) {
+ if (mssql_connect())
+ ast_log(LOG_ERROR, "Failed to reconnect to SQL database.\n");
+ else
+ ast_log(LOG_WARNING, "Reconnected to SQL database.\n");
+
+ retried = 1; /* note that we have now tried */
+ }
+
#ifdef TDS_PRE_0_62
- if ((tds_submit_query(tds, sqlcmd) != TDS_SUCCEED) || (tds_process_simple_query(tds, &result_type) != TDS_SUCCEED || result_type != TDS_CMD_SUCCEED))
+ if (!connected || (tds_submit_query(tds, sqlcmd) != TDS_SUCCEED) || (tds_process_simple_query(tds, &result_type) != TDS_SUCCEED || result_type != TDS_CMD_SUCCEED))
#else
- if ((tds_submit_query(tds, sqlcmd) != TDS_SUCCEED) || (tds_process_simple_query(tds) != TDS_SUCCEED))
+ if (!connected || (tds_submit_query(tds, sqlcmd) != TDS_SUCCEED) || (tds_process_simple_query(tds) != TDS_SUCCEED))
#endif
- {
- ast_log(LOG_ERROR, "Failed to insert record into database.\n");
+ {
+ ast_log(LOG_ERROR, "Failed to insert Call Data Record into SQL database.\n");
- res = -1;
- }
+ mssql_disconnect(); /* this is ok even if we are already disconnected */
+ }
+ } while (!connected && !retried);
free(accountcode);
free(src);
@@ -368,32 +388,129 @@ char *description(void)
return desc;
}
+static int mssql_disconnect(void)
+{
+ if (tds) {
+ tds_free_socket(tds);
+ tds = NULL;
+ }
+
+ if (context) {
+ tds_free_context(context);
+ context = NULL;
+ }
+
+ if (login) {
+ tds_free_login(login);
+ login = NULL;
+ }
+
+ connected = 0;
+
+ return 0;
+}
+
+static int mssql_connect(void)
+{
+ TDSCONNECTINFO *connection = NULL;
+ char query[128];
+
+ /* Connect to M$SQL Server */
+ if (!(login = tds_alloc_login()))
+ {
+ ast_log(LOG_ERROR, "tds_alloc_login() failed.\n");
+ return -1;
+ }
+
+ tds_set_server(login, hostname);
+ tds_set_user(login, dbuser);
+ tds_set_passwd(login, password);
+ tds_set_app(login, "TSQL");
+ tds_set_library(login, "TDS-Library");
+#ifndef TDS_PRE_0_62
+ tds_set_client_charset(login, charset);
+#endif
+ tds_set_language(login, language);
+ tds_set_packet(login, 512);
+ tds_set_version(login, 7, 0);
+
+ if (!(context = tds_alloc_context()))
+ {
+ ast_log(LOG_ERROR, "tds_alloc_context() failed.\n");
+ goto connect_fail;
+ }
+
+ if (!(tds = tds_alloc_socket(context, 512))) {
+ ast_log(LOG_ERROR, "tds_alloc_socket() failed.\n");
+ goto connect_fail;
+ }
+
+ tds_set_parent(tds, NULL);
+ connection = tds_read_config_info(tds, login, context->locale);
+ if (!connection)
+ {
+ ast_log(LOG_ERROR, "tds_read_config() failed.\n");
+ goto connect_fail;
+ }
+
+ if (tds_connect(tds, connection) == TDS_FAIL)
+ {
+ ast_log(LOG_ERROR, "Failed to connect to MSSQL server.\n");
+ tds = NULL; /* freed by tds_connect() on error */
+ tds_free_connect(connection);
+ connection = NULL;
+ goto connect_fail;
+ }
+ tds_free_connect(connection);
+ connection = NULL;
+
+ sprintf(query, "USE %s", dbname);
+#ifdef TDS_PRE_0_62
+ if ((tds_submit_query(tds, query) != TDS_SUCCEED) || (tds_process_simple_query(tds, &result_type) != TDS_SUCCEED || result_type != TDS_CMD_SUCCEED))
+#else
+ if ((tds_submit_query(tds, query) != TDS_SUCCEED) || (tds_process_simple_query(tds) != TDS_SUCCEED))
+#endif
+ {
+ ast_log(LOG_ERROR, "Could not change database (%s)\n", dbname);
+ goto connect_fail;
+ }
+
+ connected = 1;
+ return 0;
+
+connect_fail:
+ mssql_disconnect();
+ return -1;
+}
+
int unload_module(void)
{
- tds_free_socket(tds);
- tds_free_login(login);
- tds_free_context(context);
+ mssql_disconnect();
ast_cdr_unregister(name);
+ if (hostname) free(hostname);
+ if (dbname) free(dbname);
+ if (dbuser) free(dbuser);
+ if (password) free(password);
+ if (charset) free(charset);
+ if (language) free(language);
+
return 0;
}
int load_module(void)
{
- TDSCONNECTINFO *connection;
int res = 0;
struct ast_config *cfg;
struct ast_variable *var;
- char query[1024], *ptr = NULL;
- char *hostname = NULL, *dbname = NULL, *dbuser = NULL, *password = NULL, *charset = NULL, *language = NULL;
+ char *ptr = NULL;
#ifdef TDS_PRE_0_62
TDS_INT result_type;
#endif
cfg = ast_load(config);
- if (!cfg)
- {
+ if (!cfg) {
ast_log(LOG_NOTICE, "Unable to load config for MSSQL CDR's: %s\n", config);
return 0;
}
@@ -404,133 +521,69 @@ int load_module(void)
ptr = ast_variable_retrieve(cfg, "global", "hostname");
if (ptr)
- {
- hostname = strdupa(ptr);
- }
+ hostname = strdup(ptr);
else
- {
ast_log(LOG_ERROR,"Database server hostname not specified.\n");
- }
ptr = ast_variable_retrieve(cfg, "global", "dbname");
if (ptr)
- {
- dbname = strdupa(ptr);
- }
+ dbname = strdup(ptr);
else
- {
ast_log(LOG_ERROR,"Database dbname not specified.\n");
- }
ptr = ast_variable_retrieve(cfg, "global", "user");
if (ptr)
- {
- dbuser = strdupa(ptr);
- }
+ dbuser = strdup(ptr);
else
- {
ast_log(LOG_ERROR,"Database dbuser not specified.\n");
- }
ptr = ast_variable_retrieve(cfg, "global", "password");
if (ptr)
- {
- password = strdupa(ptr);
- }
+ password = strdup(ptr);
else
- {
ast_log(LOG_ERROR,"Database password not specified.\n");
- }
ptr = ast_variable_retrieve(cfg, "global", "charset");
if (ptr)
- {
- charset = strdupa(ptr);
- }
+ charset = strdup(ptr);
else
- {
- charset = strdupa("iso_1");
- }
+ charset = strdup("iso_1");
ptr = ast_variable_retrieve(cfg, "global", "language");
if (ptr)
- {
- language = strdupa(ptr);
- }
+ language = strdup(ptr);
else
- {
- language = strdupa("us_english");
- }
+ language = strdup("us_english");
ast_destroy(cfg);
- /* Connect to M$SQL Server */
- if (!(login = tds_alloc_login()))
+ mssql_connect();
+
+ /* Register MSSQL CDR handler */
+ res = ast_cdr_register(name, desc, tds_log);
+ if (res)
{
- ast_log(LOG_ERROR, "tds_alloc_login() failed.\n");
- res = -1;
+ ast_log(LOG_ERROR, "Unable to register MSSQL CDR handling\n");
}
- else
- {
- tds_set_server(login, hostname);
- tds_set_user(login, dbuser);
- tds_set_passwd(login, password);
- tds_set_app(login, "TSQL");
- tds_set_library(login, "TDS-Library");
-#ifndef TDS_PRE_0_62
- tds_set_client_charset(login, charset);
-#endif
- tds_set_language(login, language);
- tds_set_packet(login, 512);
- tds_set_version(login, 7, 0);
-
- context = tds_alloc_context();
- tds = tds_alloc_socket(context, 512);
-
- tds_set_parent(tds, NULL);
- connection = tds_read_config_info(NULL, login, context->locale);
- if (!connection || tds_connect(tds, connection) == TDS_FAIL)
- {
- ast_log(LOG_ERROR, "Failed to connect to MSSQL server.\n");
- res = -1;
- }
- tds_free_connect(connection);
- if (!res)
- {
- memset(query, 0, sizeof(query));
- sprintf(query, "USE %s", dbname);
-#ifdef TDS_PRE_0_62
- if ((tds_submit_query(tds, query) != TDS_SUCCEED) || (tds_process_simple_query(tds, &result_type) != TDS_SUCCEED || result_type != TDS_CMD_SUCCEED))
-#else
- if ((tds_submit_query(tds, query) != TDS_SUCCEED) || (tds_process_simple_query(tds) != TDS_SUCCEED))
-#endif
- {
- ast_log(LOG_ERROR, "Could not change database (%s)\n", dbname);
- res = -1;
- }
- else
- {
- /* Register MSSQL CDR handler */
- res = ast_cdr_register(name, desc, tds_log);
- if (res)
- {
- ast_log(LOG_ERROR, "Unable to register MSSQL CDR handling\n");
- }
- }
- }
- }
return res;
}
int reload(void)
{
- return 0;
+ unload_module();
+ return load_module();
}
int usecount(void)
{
- return 0;
+ /* Simplistic use count */
+ if (ast_mutex_trylock(&tds_lock)) {
+ return 1;
+ } else {
+ ast_mutex_unlock(&tds_lock);
+ return 0;
+ }
}
char *key()
diff --git a/channel.c b/channel.c
index 2f6f28d7f..cb43057f1 100755
--- a/channel.c
+++ b/channel.c
@@ -1089,11 +1089,11 @@ int ast_waitfor(struct ast_channel *c, int ms)
return ms;
}
-char ast_waitfordigit(struct ast_channel *c, int ms)
+int ast_waitfordigit(struct ast_channel *c, int ms)
{
/* XXX Should I be merged with waitfordigit_full XXX */
struct ast_frame *f;
- char result = 0;
+ int result = 0;
/* Stop if we're a zombie or need a soft hangup */
if (c->zombie || ast_check_hangup(c))
return -1;
@@ -1133,7 +1133,7 @@ int ast_settimeout(struct ast_channel *c, int samples, int (*func)(void *data),
#endif
return res;
}
-char ast_waitfordigit_full(struct ast_channel *c, int ms, int audiofd, int cmdfd)
+int ast_waitfordigit_full(struct ast_channel *c, int ms, int audiofd, int cmdfd)
{
struct ast_frame *f;
struct ast_channel *rchan;
@@ -1144,8 +1144,11 @@ char ast_waitfordigit_full(struct ast_channel *c, int ms, int audiofd, int cmdfd
return -1;
/* Wait for a digit, no more than ms milliseconds total. */
while(ms) {
+ errno = 0;
rchan = ast_waitfor_nandfds(&c, 1, &cmdfd, (cmdfd > -1) ? 1 : 0, NULL, &outfd, &ms);
if ((!rchan) && (outfd < 0) && (ms)) {
+ if (errno == 0 || errno == EINTR)
+ continue;
ast_log(LOG_WARNING, "Wait failed (%s)\n", strerror(errno));
return -1;
} else if (outfd > -1) {
@@ -1394,6 +1397,7 @@ struct ast_frame *ast_read(struct ast_channel *chan)
ast_settimeout(chan, 160, generator_force, chan);
}
}
+ /* High bit prints debugging */
if (chan->fin & 0x80000000)
ast_frame_dump(chan->name, f, "<<");
if ((chan->fin & 0x7fffffff) == 0x7fffffff)
@@ -1598,6 +1602,7 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
return 0;
}
}
+ /* High bit prints debugging */
if (chan->fout & 0x80000000)
ast_frame_dump(chan->name, fr, ">>");
CHECK_BLOCKING(chan);
@@ -1616,6 +1621,14 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
case AST_FRAME_TEXT:
if (chan->pvt->send_text)
res = chan->pvt->send_text(chan, (char *) fr->data);
+ else
+ res = 0;
+ break;
+ case AST_FRAME_HTML:
+ if (chan->pvt->send_html)
+ res = chan->pvt->send_html(chan, fr->subclass, (char *) fr->data, fr->datalen);
+ else
+ res = 0;
break;
case AST_FRAME_VIDEO:
/* XXX Handle translation of video codecs one day XXX */
@@ -1670,7 +1683,6 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
chan->fout &= 0x80000000;
else
chan->fout++;
- chan->fout++;
}
ast_mutex_unlock(&chan->lock);
return res;
@@ -1888,7 +1900,7 @@ struct ast_channel *ast_request(char *type, int format, void *data)
manager_event(EVENT_FLAG_CALL, "Newchannel",
"Channel: %s\r\n"
"State: %s\r\n"
- "Callerid: %s\r\n"
+ "CallerID: %s\r\n"
"Uniqueid: %s\r\n",
c->name, ast_state2str(c->_state), c->callerid ? c->callerid : "<unknown>", c->uniqueid);
}
@@ -2001,7 +2013,7 @@ int ast_readstring(struct ast_channel *c, char *s, int len, int timeout, int fti
{
int pos=0;
int to = ftimeout;
- char d;
+ int d;
/* XXX Merge with full version? XXX */
/* Stop if we're a zombie or need a soft hangup */
if (c->zombie || ast_check_hangup(c))
@@ -2040,7 +2052,7 @@ int ast_readstring_full(struct ast_channel *c, char *s, int len, int timeout, in
{
int pos=0;
int to = ftimeout;
- char d;
+ int d;
/* Stop if we're a zombie or need a soft hangup */
if (c->zombie || ast_check_hangup(c))
return -1;
@@ -2199,13 +2211,14 @@ int ast_do_masquerade(struct ast_channel *original)
struct ast_frame *cur, *prev;
struct ast_channel_pvt *p;
struct ast_channel *clone = original->masq;
+ struct ast_channel_monitor *monitor;
int rformat = original->readformat;
int wformat = original->writeformat;
char newn[100];
char orig[100];
char masqn[100];
char zombn[100];
-
+
#if 1
ast_log(LOG_DEBUG, "Actually Masquerading %s(%d) into the structure of %s(%d)\n",
clone->name, clone->_state, original->name, original->_state);
@@ -2304,9 +2317,17 @@ int ast_do_masquerade(struct ast_channel *original)
strncpy(clone->name, zombn, sizeof(clone->name) - 1);
manager_event(EVENT_FLAG_CALL, "Rename", "Oldname: %s\r\nNewname: %s\r\nUniqueid: %s\r\n", masqn, zombn, clone->uniqueid);
- /* Keep the same language. */
/* Update the type. */
original->type = clone->type;
+
+ /* copy the monitor */
+ monitor = original->monitor;
+ original->monitor = clone->monitor;
+ clone->monitor = monitor;
+
+ /* Keep the same language. */
+ strncpy(original->language, clone->language, sizeof(original->language));
+
/* Copy the FD's */
for (x=0;x<AST_MAX_FDS;x++) {
original->fds[x] = clone->fds[x];
@@ -2362,6 +2383,9 @@ int ast_do_masquerade(struct ast_channel *original)
/* Set the read format */
ast_set_read_format(original, rformat);
+ /* Copy the music class */
+ strncpy(original->musicclass, clone->musicclass, sizeof(original->musicclass) - 1);
+
ast_log(LOG_DEBUG, "Putting channel %s in %d/%d formats\n", original->name, wformat, rformat);
/* Okay. Last thing is to let the channel driver know about all this mess, so he
@@ -2387,8 +2411,10 @@ int ast_do_masquerade(struct ast_channel *original)
ast_channel_free(clone);
manager_event(EVENT_FLAG_CALL, "Hangup", "Channel: %s\r\n", zombn);
} else {
+ struct ast_frame null_frame = { AST_FRAME_NULL, };
ast_log(LOG_DEBUG, "Released clone lock on '%s'\n", clone->name);
clone->zombie=1;
+ ast_queue_frame(clone, &null_frame);
ast_mutex_unlock(&clone->lock);
}
@@ -2419,7 +2445,7 @@ void ast_set_callerid(struct ast_channel *chan, char *callerid, int anitoo)
ast_cdr_setcid(chan->cdr, chan);
manager_event(EVENT_FLAG_CALL, "Newcallerid",
"Channel: %s\r\n"
- "Callerid: %s\r\n"
+ "CallerID: %s\r\n"
"Uniqueid: %s\r\n",
chan->name, chan->callerid ?
chan->callerid : "<Unknown>",
@@ -2436,14 +2462,14 @@ int ast_setstate(struct ast_channel *chan, int state)
manager_event(EVENT_FLAG_CALL, "Newchannel",
"Channel: %s\r\n"
"State: %s\r\n"
- "Callerid: %s\r\n"
+ "CallerID: %s\r\n"
"Uniqueid: %s\r\n",
chan->name, ast_state2str(chan->_state), chan->callerid ? chan->callerid : "<unknown>", chan->uniqueid);
} else {
manager_event(EVENT_FLAG_CALL, "Newstate",
"Channel: %s\r\n"
"State: %s\r\n"
- "Callerid: %s\r\n"
+ "CallerID: %s\r\n"
"Uniqueid: %s\r\n",
chan->name, ast_state2str(chan->_state), chan->callerid ? chan->callerid : "<unknown>", chan->uniqueid);
}
@@ -2667,6 +2693,7 @@ int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, struct as
(f->frametype == AST_FRAME_TEXT) ||
(f->frametype == AST_FRAME_VIDEO) ||
(f->frametype == AST_FRAME_IMAGE) ||
+ (f->frametype == AST_FRAME_HTML) ||
(f->frametype == AST_FRAME_DTMF)) {
if ((f->frametype == AST_FRAME_DTMF) &&
(flags & (AST_BRIDGE_DTMF_CHANNEL_0 | AST_BRIDGE_DTMF_CHANNEL_1))) {
@@ -2899,8 +2926,8 @@ unsigned int ast_get_group(char *s)
/* Just one */
finish = start;
} else {
- ast_log(LOG_ERROR, "Syntax error parsing '%s' at '%s'. Using '0'\n", s,piece);
- return 0;
+ ast_log(LOG_ERROR, "Syntax error parsing '%s' at '%s'.\n", s, piece);
+ continue;
}
for (x=start;x<=finish;x++) {
if ((x > 31) || (x < 0)) {
diff --git a/channels/chan_agent.c b/channels/chan_agent.c
index c5dcc891e..a648b744d 100755
--- a/channels/chan_agent.c
+++ b/channels/chan_agent.c
@@ -193,12 +193,12 @@ static struct agent_pvt *add_agent(char *agent, int pending)
if ((password = strchr(tmp, ','))) {
*password = '\0';
password++;
- while (*password < 33) password++;
+ while (*password && *password < 33) password++;
}
if (password && (name = strchr(password, ','))) {
*name = '\0';
name++;
- while (*name < 33) name++;
+ while (*name && *name < 33) name++;
}
prev=NULL;
p = agents;
@@ -367,6 +367,11 @@ static struct ast_frame *agent_read(struct ast_channel *ast)
ast_frfree(f);
f = NULL;
}
+ if (f && (f->frametype == AST_FRAME_VOICE) && !p->acknowledged) {
+ /* Don't pass along agent audio until call is acknowledged */
+ ast_frfree(f);
+ f = &null_frame;
+ }
CLEANUP(ast,p);
ast_mutex_unlock(&p->lock);
if (recordagentcalls && f == &answer_frame)
@@ -374,6 +379,17 @@ static struct ast_frame *agent_read(struct ast_channel *ast)
return f;
}
+static int agent_sendhtml(struct ast_channel *ast, int subclass, char *data, int datalen)
+{
+ struct agent_pvt *p = ast->pvt->pvt;
+ int res = -1;
+ ast_mutex_lock(&p->lock);
+ if (p->chan)
+ res = ast_channel_sendhtml(p->chan, subclass, data, datalen);
+ ast_mutex_unlock(&p->lock);
+ return res;
+}
+
static int agent_write(struct ast_channel *ast, struct ast_frame *f)
{
struct agent_pvt *p = ast->pvt->pvt;
@@ -519,9 +535,26 @@ static int agent_hangup(struct ast_channel *ast)
ast->pvt->pvt = NULL;
p->app_sleep_cond = 1;
p->acknowledged = 0;
- if (p->start && (ast->_state != AST_STATE_UP))
+
+ /* if they really are hung up then set start to 0 so the test
+ * later if we're called on an already downed channel
+ * doesn't cause an agent to be logged out like when
+ * agent_request() is followed immediately by agent_hangup()
+ * as in apps/app_chanisavail.c:chanavail_exec()
+ */
+
+ ast_mutex_lock(&usecnt_lock);
+ usecnt--;
+ ast_mutex_unlock(&usecnt_lock);
+
+ ast_log(LOG_DEBUG, "Hangup called for state %s\n", ast_state2str(ast->_state));
+ if (p->start && (ast->_state != AST_STATE_UP)) {
howlong = time(NULL) - p->start;
- time(&p->start);
+ p->start = 0;
+ } else if (ast->_state == AST_STATE_RESERVED) {
+ howlong = 0;
+ } else
+ p->start = 0;
if (p->chan) {
/* If they're dead, go ahead and hang up on the agent now */
if (!ast_strlen_zero(p->loginchan)) {
@@ -726,6 +759,7 @@ static struct ast_channel *agent_new(struct agent_pvt *p, int state)
tmp->pvt->answer = agent_answer;
tmp->pvt->read = agent_read;
tmp->pvt->write = agent_write;
+ tmp->pvt->send_html = agent_sendhtml;
tmp->pvt->exception = agent_read;
tmp->pvt->indicate = agent_indicate;
tmp->pvt->fixup = agent_fixup;
diff --git a/channels/chan_alsa.c b/channels/chan_alsa.c
index acf80b857..7d3b89bd7 100755
--- a/channels/chan_alsa.c
+++ b/channels/chan_alsa.c
@@ -27,6 +27,7 @@
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
+#include "asterisk/endian.h"
#define ALSA_PCM_NEW_HW_PARAMS_API
#define ALSA_PCM_NEW_SW_PARAMS_API
@@ -59,8 +60,13 @@
/* Don't switch between read/write modes faster than every 300 ms */
#define MIN_SWITCH_TIME 600
+#if __BYTE_ORDER == __LITTLE_ENDIAN
static snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE;
-//static int block = O_NONBLOCK;
+#else
+static snd_pcm_format_t format = SND_PCM_FORMAT_S16_BE;
+#endif
+
+/* static int block = O_NONBLOCK; */
static char indevname[50] = ALSA_INDEV;
static char outdevname[50] = ALSA_OUTDEV;
@@ -863,10 +869,11 @@ static int console_sendtext(int fd, int argc, char *argv[])
struct ast_frame f = { AST_FRAME_TEXT, 0 };
char text2send[256] = "";
text2send[0] = '\0';
- while(tmparg <= argc) {
+ while(tmparg < argc) {
strncat(text2send, argv[tmparg++], sizeof(text2send) - strlen(text2send) - 1);
strncat(text2send, " ", sizeof(text2send) - strlen(text2send) - 1);
}
+ text2send[strlen(text2send) - 1] = '\n';
f.data = text2send;
f.datalen = strlen(text2send) + 1;
grab_owner();
@@ -1047,10 +1054,12 @@ int load_module()
int unload_module()
{
int x;
+
+ ast_channel_unregister(type);
for (x=0;x<sizeof(myclis)/sizeof(struct ast_cli_entry); x++)
ast_cli_unregister(myclis + x);
- close(readdev);
- close(writedev);
+ snd_pcm_close(alsa.icard);
+ snd_pcm_close(alsa.ocard);
if (sndcmd[0] > 0) {
close(sndcmd[0]);
close(sndcmd[1]);
diff --git a/channels/chan_h323.c b/channels/chan_h323.c
index c64a6e254..a7437b91d 100755
--- a/channels/chan_h323.c
+++ b/channels/chan_h323.c
@@ -82,7 +82,7 @@ con_established_cb on_connection_established;
clear_con_cb on_connection_cleared;
answer_call_cb on_answer_call;
-int h323debug;
+int h323debug = 0;
/** String variables required by ASTERISK */
static char *type = "H323";
@@ -348,7 +348,9 @@ static struct oh323_peer *build_peer(char *name, struct ast_variable *v)
} else {
ast_mutex_unlock(&peerl.lock);
peer = (struct oh323_peer*)malloc(sizeof(struct oh323_peer));
- memset(peer, 0, sizeof(struct oh323_peer));
+ if (peer) {
+ memset(peer, 0, sizeof(struct oh323_peer));
+ }
}
if (peer) {
if (!found) {
@@ -403,7 +405,7 @@ static int oh323_digit(struct ast_channel *c, char digit)
ast_rtp_senddigit(p->rtp, digit);
}
/* If in-band DTMF is desired, send that */
- if (p->dtmfmode & H323_DTMF_INBAND)
+ if (!(p->dtmfmode & H323_DTMF_RFC2833))
h323_send_tone(p->cd.call_token, digit);
return 0;
}
@@ -442,14 +444,14 @@ static int oh323_call(struct ast_channel *c, char *dest, int timeout)
/* Clear the call token */
if ((p->cd).call_token == NULL)
(p->cd).call_token = (char *)malloc(128);
-
- memset((char *)(p->cd).call_token, 0, 128);
- if (p->cd.call_token == NULL) {
+ if ((p->cd).call_token == NULL) {
ast_log(LOG_ERROR, "Not enough memory.\n");
return -1;
}
+ memset((char *)(p->cd).call_token, 0, 128);
+
/* Build the address to call */
memset(called_addr, 0, sizeof(called_addr));
memcpy(called_addr, dest, strlen(dest));
@@ -601,7 +603,7 @@ static struct ast_frame *oh323_rtp_read(struct oh323_pvt *p)
}
/* Do in-band DTMF detection */
- if (p->dtmfmode & H323_DTMF_INBAND) {
+ if ((p->dtmfmode & H323_DTMF_INBAND) && p->vad) {
f = ast_dsp_process(p->owner,p->vad,f);
if (f->frametype == AST_FRAME_DTMF)
ast_log(LOG_DEBUG, "Got in-band digit %c.\n", f->subclass);
@@ -1032,8 +1034,6 @@ struct rtp_info *create_connection(unsigned call_reference, const char * token)
the oh323_pvt structure XXX */
static char iabuf[INET_ADDRSTRLEN];
- info = (struct rtp_info *) malloc(sizeof(struct rtp_info));
-
p = find_call(call_reference, token);
if (!p) {
@@ -1041,6 +1041,12 @@ struct rtp_info *create_connection(unsigned call_reference, const char * token)
return NULL;
}
+ info = (struct rtp_info *) malloc(sizeof(struct rtp_info));
+ if (!info) {
+ ast_log(LOG_ERROR, "Unable to allocate rtp_info, this is very bad.\n");
+ return NULL;
+ }
+
/* figure out our local RTP port and tell the H.323 stack about it*/
ast_rtp_get_us(p->rtp, &us);
ast_rtp_get_peer(p->rtp, &them);
@@ -1594,9 +1600,9 @@ static struct ast_cli_entry cli_show_codecs =
static struct ast_cli_entry cli_gk_cycle =
{ { "h.323", "gk", "cycle", NULL }, h323_gk_cycle, "Manually re-register with the Gatekeper", show_cycle_usage };
static struct ast_cli_entry cli_hangup_call =
- { { "h.323", "hangup", NULL }, h323_ep_hangup, "Show all active call tokens", show_hangup_usage };
+ { { "h.323", "hangup", NULL }, h323_ep_hangup, "Manually try to hang up a call", show_hangup_usage };
static struct ast_cli_entry cli_show_tokens =
- { { "h.323", "show", "tokens", NULL }, h323_tokens_show, "Manually try to hang up a call", show_tokens_usage };
+ { { "h.323", "show", "tokens", NULL }, h323_tokens_show, "Show all active call tokens", show_tokens_usage };
diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c
index e8b56282d..b1756efb3 100755
--- a/channels/chan_iax2.c
+++ b/channels/chan_iax2.c
@@ -361,6 +361,8 @@ struct chan_iax2_pvt {
unsigned int lastsent;
/* Next outgoing timestamp if everything is good */
unsigned int nextpred;
+ /* True if the last voice we transmitted was not silence/CNG */
+ int notsilenttx;
/* Ping time */
unsigned int pingtime;
/* Max time for initial response */
@@ -504,8 +506,8 @@ static struct ast_firmware_list {
/* Extension exists */
#define CACHE_FLAG_EXISTS (1 << 0)
-/* Extension is non-existant */
-#define CACHE_FLAG_NONEXISTANT (1 << 1)
+/* Extension is nonexistent */
+#define CACHE_FLAG_NONEXISTENT (1 << 1)
/* Extension can exist */
#define CACHE_FLAG_CANEXIST (1 << 2)
/* Waiting to hear back response */
@@ -536,12 +538,12 @@ AST_MUTEX_DEFINE_STATIC(dpcache_lock);
static void iax_debug_output(const char *data)
{
if (iaxdebug)
- ast_verbose(data);
+ ast_verbose("%s", data);
}
static void iax_error_output(const char *data)
{
- ast_log(LOG_WARNING, data);
+ ast_log(LOG_WARNING, "%s", data);
}
/* XXX We probably should use a mutex when working with this XXX */
@@ -641,10 +643,9 @@ static int iax2_getpeername(struct sockaddr_in sin, char *host, int len, int loc
return res;
}
-static struct chan_iax2_pvt *new_iax(struct sockaddr_in *sin, int lockpeer)
+static struct chan_iax2_pvt *new_iax(struct sockaddr_in *sin, int lockpeer, const char *host)
{
struct chan_iax2_pvt *tmp;
- char iabuf[INET_ADDRSTRLEN];
tmp = malloc(sizeof(struct chan_iax2_pvt));
if (tmp) {
memset(tmp, 0, sizeof(struct chan_iax2_pvt));
@@ -659,8 +660,7 @@ static struct chan_iax2_pvt *new_iax(struct sockaddr_in *sin, int lockpeer)
tmp->initid = -1;
/* strncpy(tmp->context, context, sizeof(tmp->context)-1); */
strncpy(tmp->exten, "s", sizeof(tmp->exten)-1);
- if (!iax2_getpeername(*sin, tmp->host, sizeof(tmp->host), lockpeer))
- snprintf(tmp->host, sizeof(tmp->host), "%s:%d", ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr), ntohs(sin->sin_port));
+ strncpy(tmp->host, host, sizeof(tmp->host)-1);
}
return tmp;
}
@@ -826,6 +826,8 @@ static int find_callno(unsigned short callno, unsigned short dcallno, struct soc
int res = 0;
int x;
struct timeval now;
+ char iabuf[INET_ADDRSTRLEN];
+ char host[80];
if (new <= NEW_ALLOW) {
/* Look for an existing connection first */
for (x=1;(res < 1) && (x<maxnontrunkcall);x++) {
@@ -850,6 +852,8 @@ static int find_callno(unsigned short callno, unsigned short dcallno, struct soc
}
}
if ((res < 1) && (new >= NEW_ALLOW)) {
+ if (!iax2_getpeername(*sin, host, sizeof(host), lockpeer))
+ snprintf(host, sizeof(host), "%s:%d", ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr), ntohs(sin->sin_port));
gettimeofday(&now, NULL);
for (x=1;x<TRUNK_CALL_START;x++) {
/* Find first unused call number that hasn't been used in a while */
@@ -860,9 +864,9 @@ static int find_callno(unsigned short callno, unsigned short dcallno, struct soc
/* We've still got lock held if we found a spot */
if (x >= TRUNK_CALL_START) {
ast_log(LOG_WARNING, "No more space\n");
- return -1;
+ return 0;
}
- iaxs[x] = new_iax(sin, lockpeer);
+ iaxs[x] = new_iax(sin, lockpeer, host);
update_max_nontrunk();
if (iaxs[x]) {
if (option_debug)
@@ -1600,8 +1604,8 @@ static int iax2_show_cache(int fd, int argc, char *argv[])
tmp[0] = '\0';
if (dp->flags & CACHE_FLAG_EXISTS)
strncat(tmp, "EXISTS|", sizeof(tmp) - strlen(tmp) - 1);
- if (dp->flags & CACHE_FLAG_NONEXISTANT)
- strncat(tmp, "NONEXISTANT|", sizeof(tmp) - strlen(tmp) - 1);
+ if (dp->flags & CACHE_FLAG_NONEXISTENT)
+ strncat(tmp, "NONEXISTENT|", sizeof(tmp) - strlen(tmp) - 1);
if (dp->flags & CACHE_FLAG_CANEXIST)
strncat(tmp, "CANEXIST|", sizeof(tmp) - strlen(tmp) - 1);
if (dp->flags & CACHE_FLAG_PENDING)
@@ -1731,7 +1735,7 @@ static void unwrap_timestamp(struct iax_frame *fr)
}
}
-static int schedule_delivery(struct iax_frame *fr, int reallydeliver, int updatehistory)
+static int schedule_delivery(struct iax_frame *fr, int reallydeliver, int updatehistory, int fromtrunk)
{
int ms,x;
int delay;
@@ -1794,7 +1798,7 @@ static int schedule_delivery(struct iax_frame *fr, int reallydeliver, int update
ms = 0;
/* delivery time is sender's sent timestamp converted back into absolute time according to our clock */
- if (iaxs[fr->callno]->rxcore.tv_sec || iaxs[fr->callno]->rxcore.tv_usec) {
+ if ( (!fromtrunk) && (iaxs[fr->callno]->rxcore.tv_sec || iaxs[fr->callno]->rxcore.tv_usec) ) {
fr->af.delivery.tv_sec = iaxs[fr->callno]->rxcore.tv_sec;
fr->af.delivery.tv_usec = iaxs[fr->callno]->rxcore.tv_usec;
fr->af.delivery.tv_sec += fr->ts / 1000;
@@ -1807,7 +1811,7 @@ static int schedule_delivery(struct iax_frame *fr, int reallydeliver, int update
else {
#if 0
if (reallydeliver)
- ast_log(LOG_DEBUG, "schedule_delivery: set delivery to 0 as we don't have an rxcore yet.\n");
+ ast_log(LOG_DEBUG, "schedule_delivery: set delivery to 0 as we don't have an rxcore yet, or frame is from trunk.\n");
#endif
fr->af.delivery.tv_sec = 0;
fr->af.delivery.tv_usec = 0;
@@ -1888,7 +1892,8 @@ static int schedule_delivery(struct iax_frame *fr, int reallydeliver, int update
delay = maxjitterbuffer;
/* If jitter buffer is disabled then just pretend the frame is "right on time" */
- if (!iaxs[fr->callno]->usejitterbuf)
+ /* If frame came from trunk, also don't do any delay */
+ if ( (!iaxs[fr->callno]->usejitterbuf) || fromtrunk )
delay = 0;
if (option_debug) {
@@ -2364,7 +2369,7 @@ static int iax2_call(struct ast_channel *c, char *dest, int timeout)
if (secret) {
if (secret[0] == '[') {
/* This is an RSA key, not a normal secret */
- strncpy(iaxs[callno]->outkey, secret + 1, sizeof(iaxs[callno]->secret)-1);
+ strncpy(iaxs[callno]->outkey, secret + 1, sizeof(iaxs[callno]->outkey)-1);
if (!ast_strlen_zero(iaxs[callno]->outkey)) {
iaxs[callno]->outkey[strlen(iaxs[callno]->outkey) - 1] = '\0';
}
@@ -2628,8 +2633,10 @@ tackygoto:
cs[1] = cs[2];
}
lock_both(callno0, callno1);
- iaxs[callno0]->bridgecallno = 0;
- iaxs[callno1]->bridgecallno = 0;
+ if(iaxs[callno0])
+ iaxs[callno0]->bridgecallno = 0;
+ if(iaxs[callno1])
+ iaxs[callno1]->bridgecallno = 0;
unlock_both(callno0, callno1);
return res;
}
@@ -2708,8 +2715,8 @@ static struct ast_channel *ast_iax2_new(int callno, int state, int capability)
tmp->type = type;
/* We can support any format by default, until we get restricted */
tmp->nativeformats = capability;
- tmp->readformat = 0;
- tmp->writeformat = 0;
+ tmp->readformat = ast_best_codec(capability);
+ tmp->writeformat = ast_best_codec(capability);
tmp->pvt->pvt = CALLNO_TO_PTR(i->callno);
tmp->pvt->send_digit = iax2_digit;
tmp->pvt->send_text = iax2_sendtext;
@@ -2808,6 +2815,18 @@ static unsigned int fix_peerts(struct timeval *tv, int callno, unsigned int ts)
return ms + ts;
}
+static void add_ms(struct timeval *tv, int ms) {
+ tv->tv_usec += ms * 1000;
+ if(tv->tv_usec > 1000000) {
+ tv->tv_usec -= 1000000;
+ tv->tv_sec++;
+ }
+ if(tv->tv_usec < 0) {
+ tv->tv_usec += 1000000;
+ tv->tv_sec--;
+ }
+}
+
static unsigned int calc_timestamp(struct chan_iax2_pvt *p, unsigned int ts, struct ast_frame *f)
{
struct timeval tv;
@@ -2828,6 +2847,8 @@ static unsigned int calc_timestamp(struct chan_iax2_pvt *p, unsigned int ts, str
delivery = &f->delivery;
} else if (f->frametype == AST_FRAME_IAX) {
genuine = 1;
+ } else if (f->frametype == AST_FRAME_CNG) {
+ p->notsilenttx = 0;
}
}
if (!p->offset.tv_sec && !p->offset.tv_usec) {
@@ -2852,15 +2873,36 @@ static unsigned int calc_timestamp(struct chan_iax2_pvt *p, unsigned int ts, str
ms = 0;
if (voice) {
/* On a voice frame, use predicted values if appropriate */
- if (abs(ms - p->nextpred) <= MAX_TIMESTAMP_SKEW) {
+ if (p->notsilenttx && abs(ms - p->nextpred) <= MAX_TIMESTAMP_SKEW) {
+ /* Adjust our txcore, keeping voice and
+ non-voice synchronized */
+ add_ms(&p->offset, (int)(ms - p->nextpred)/10);
+
if (!p->nextpred) {
p->nextpred = ms; /*f->samples / 8;*/
if (p->nextpred <= p->lastsent)
p->nextpred = p->lastsent + 3;
}
ms = p->nextpred;
- } else
+ } else {
+ /* in this case, just use the actual
+ * time, since we're either way off
+ * (shouldn't happen), or we're ending a
+ * silent period -- and seed the next
+ * predicted time. Also, round ms to the
+ * next multiple of frame size (so our
+ * silent periods are multiples of
+ * frame size too) */
+ int adj = f->samples / 8;
+ if (adj) {
+ int diff = ms % adj;
+ if(diff)
+ ms += adj - diff;
+ }
+
p->nextpred = ms;
+ p->notsilenttx = 1;
+ }
} else {
/* On a dataframe, use last value + 3 (to accomodate jitter buffer shrinking) if appropriate unless
it's a genuine frame */
@@ -2905,9 +2947,6 @@ static unsigned int calc_fakestamp(struct chan_iax2_pvt *p1, struct chan_iax2_pv
(1000000 + p1->rxcore.tv_usec - p2->offset.tv_usec) / 1000 - 1000;
fakets += ms;
- /* FIXME? SLD would rather remove this and leave it to the end system to deal with */
- if (fakets <= p2->lastsent)
- fakets = p2->lastsent + 1;
p2->lastsent = fakets;
return fakets;
}
@@ -3849,12 +3888,15 @@ static int register_verify(int callno, struct sockaddr_in *sin, struct iax_ies *
ast_log(LOG_NOTICE, "Empty registration from %s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr));
return -1;
}
-
+ /* We release the lock for the call to prevent a deadlock, but it's okay because
+ only the current thread could possibly make it go away or make changes */
+ ast_mutex_unlock(&iaxsl[callno]);
ast_mutex_lock(&peerl.lock);
for (p = peerl.peers; p ; p = p->next)
if (!strcasecmp(p->name, peer))
break;
ast_mutex_unlock(&peerl.lock);
+ ast_mutex_lock(&iaxsl[callno]);
#ifdef MYSQL_FRIENDS
if (!p)
p = mysql_peer(peer);
@@ -4110,8 +4152,8 @@ static int complete_dpreply(struct chan_iax2_pvt *pvt, struct iax_ies *ies)
status = CACHE_FLAG_EXISTS;
else if (ies->dpstatus & IAX_DPSTATUS_CANEXIST)
status = CACHE_FLAG_CANEXIST;
- else if (ies->dpstatus & IAX_DPSTATUS_NONEXISTANT)
- status = CACHE_FLAG_NONEXISTANT;
+ else if (ies->dpstatus & IAX_DPSTATUS_NONEXISTENT)
+ status = CACHE_FLAG_NONEXISTENT;
if (ies->dpstatus & IAX_DPSTATUS_IGNOREPAT) {
/* Don't really do anything with this */
@@ -4340,7 +4382,8 @@ static int expire_registry(void *data)
p->expire = -1;
/* Reset expirey value */
p->expirey = expirey;
- ast_db_del("IAX/Registry", p->name);
+ if (p->temponly !=1)
+ ast_db_del("IAX/Registry", p->name);
register_peer_exten(p, 0);
if (iax2_regfunk)
iax2_regfunk(p->name, 0);
@@ -4356,7 +4399,7 @@ static void reg_source_db(struct iax2_peer *p)
struct in_addr in;
char iabuf[INET_ADDRSTRLEN];
char *c, *d;
- if (!ast_db_get("IAX/Registry", p->name, data, sizeof(data))) {
+ if ((p->temponly != 1) && (!ast_db_get("IAX/Registry", p->name, data, sizeof(data)))) {
c = strchr(data, ':');
if (c) {
*c = '\0';
@@ -4416,7 +4459,7 @@ static int update_registry(char *name, struct sockaddr_in *sin, int callno, char
if (iax2_regfunk)
iax2_regfunk(p->name, 1);
snprintf(data, sizeof(data), "%s:%d:%d", ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr), ntohs(sin->sin_port), p->expirey);
- if (sin->sin_addr.s_addr) {
+ if ((p->temponly != 1) && (sin->sin_addr.s_addr)) {
ast_db_put("IAX/Registry", p->name, data);
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "Registered '%s' (%s) at %s:%d\n", p->name,
@@ -4818,7 +4861,7 @@ static void dp_lookup(int callno, char *context, char *callednum, char *callerid
} else if (ast_canmatch_extension(NULL, context, callednum, 1, callerid)) {
dpstatus = IAX_DPSTATUS_CANEXIST;
} else {
- dpstatus = IAX_DPSTATUS_NONEXISTANT;
+ dpstatus = IAX_DPSTATUS_NONEXISTENT;
}
if (ast_ignore_pattern(context, callednum))
dpstatus |= IAX_DPSTATUS_IGNOREPAT;
@@ -5017,6 +5060,10 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
/* This is a meta header */
switch(meta->metacmd) {
case IAX_META_TRUNK:
+ if (meta->cmddata != 0) {
+ ast_log(LOG_WARNING, "meta trunk cmd %d received, I only understand 0 (perhaps the remote side is sending trunk timestamps?)\n", meta->cmddata);
+ return 1;
+ }
if (res < sizeof(struct ast_iax2_meta_hdr) + sizeof(struct ast_iax2_meta_trunk_hdr)) {
ast_log(LOG_WARNING, "midget meta trunk packet received (%d of %d min)\n", res, (int)sizeof(struct ast_iax2_mini_hdr));
return 1;
@@ -5079,10 +5126,10 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
if (iaxs[fr.callno]->bridgecallno) {
forward_delivery(&fr);
} else {
- schedule_delivery(iaxfrdup2(&fr), 1, updatehistory);
+ schedule_delivery(iaxfrdup2(&fr), 1, updatehistory, 1);
}
#else
- schedule_delivery(iaxfrdup2(&fr), 1, updatehistory);
+ schedule_delivery(iaxfrdup2(&fr), 1, updatehistory, 1);
#endif
}
} else {
@@ -5132,7 +5179,7 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
ast_mutex_lock(&iaxsl[fr.callno]);
if (!fr.callno || !iaxs[fr.callno]) {
- /* A call arrived for a non-existant destination. Unless it's an "inval"
+ /* A call arrived for a nonexistent destination. Unless it's an "inval"
frame, reply with an inval */
if (ntohs(mh->callno) & IAX_FLAG_FULL) {
/* We can only raw hangup control frames */
@@ -5148,7 +5195,9 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
ast_mutex_unlock(&iaxsl[fr.callno]);
return 1;
}
- if (!inaddrcmp(&sin, &iaxs[fr.callno]->addr) && !minivid)
+ if (!inaddrcmp(&sin, &iaxs[fr.callno]->addr) && !minivid &&
+ f.subclass != IAX_COMMAND_TXCNT && /* for attended transfer */
+ f.subclass != IAX_COMMAND_TXACC) /* for attended transfer */
iaxs[fr.callno]->peercallno = (unsigned short)(ntohs(mh->callno) & ~IAX_FLAG_FULL);
if (ntohs(mh->callno) & IAX_FLAG_FULL) {
if (option_debug)
@@ -5170,12 +5219,18 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
if ((iaxs[fr.callno]->iseqno != fr.oseqno) &&
(iaxs[fr.callno]->iseqno ||
((f.subclass != IAX_COMMAND_TXCNT) &&
+ (f.subclass != IAX_COMMAND_TXREADY) && /* for attended transfer */
+ (f.subclass != IAX_COMMAND_TXREL) && /* for attended transfer */
+ (f.subclass != IAX_COMMAND_UNQUELCH ) && /* for attended transfer */
(f.subclass != IAX_COMMAND_TXACC)) ||
- (f.subclass != AST_FRAME_IAX))) {
+ (f.frametype != AST_FRAME_IAX))) {
if (
((f.subclass != IAX_COMMAND_ACK) &&
(f.subclass != IAX_COMMAND_INVAL) &&
(f.subclass != IAX_COMMAND_TXCNT) &&
+ (f.subclass != IAX_COMMAND_TXREADY) && /* for attended transfer */
+ (f.subclass != IAX_COMMAND_TXREL) && /* for attended transfer */
+ (f.subclass != IAX_COMMAND_UNQUELCH ) && /* for attended transfer */
(f.subclass != IAX_COMMAND_TXACC) &&
(f.subclass != IAX_COMMAND_VNAK)) ||
(f.frametype != AST_FRAME_IAX)) {
@@ -5335,7 +5390,7 @@ retryowner:
if (option_debug)
ast_log(LOG_DEBUG, "IAX subclass %d received\n", f.subclass);
/* Go through the motions of delivering the packet without actually doing so */
- schedule_delivery(&fr, 0, updatehistory);
+ schedule_delivery(&fr, 0, updatehistory, 0);
switch(f.subclass) {
case IAX_COMMAND_ACK:
/* Do nothing */
@@ -5613,13 +5668,15 @@ retryowner2:
if (iaxs[fr.callno]->peerpoke) {
peer = iaxs[fr.callno]->peerpoke;
if ((peer->lastms < 0) || (peer->lastms > peer->maxms)) {
- if (iaxs[fr.callno]->pingtime <= peer->maxms)
+ if (iaxs[fr.callno]->pingtime <= peer->maxms) {
ast_log(LOG_NOTICE, "Peer '%s' is now REACHABLE!\n", peer->name);
manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "Peer: IAX2/%s\r\nPeerStatus: Reachable\r\nTime: %d\r\n", peer->name,iaxs[fr.callno]->pingtime);
+ }
} else if ((peer->lastms > 0) && (peer->lastms <= peer->maxms)) {
- if (iaxs[fr.callno]->pingtime > peer->maxms)
+ if (iaxs[fr.callno]->pingtime > peer->maxms) {
ast_log(LOG_NOTICE, "Peer '%s' is now TOO LAGGED (%d ms)!\n", peer->name, iaxs[fr.callno]->pingtime);
manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "Peer: IAX2/%s\r\nPeerStatus: Lagged\r\nTime: %d\r\n", peer->name,iaxs[fr.callno]->pingtime);
+ }
}
peer->lastms = iaxs[fr.callno]->pingtime;
if (peer->pokeexpire > -1)
@@ -5885,6 +5942,7 @@ retryowner2:
/* Send ack immediately, rather than waiting until we've changed addresses */
send_command_immediate(iaxs[fr.callno], AST_FRAME_IAX, IAX_COMMAND_ACK, fr.ts, NULL, 0,fr.iseqno);
complete_transfer(fr.callno, &ies);
+ stop_stuff(fr.callno); /* for attended transfer to work with libiax */
break;
case IAX_COMMAND_DPREP:
complete_dpreply(iaxs[fr.callno], &ies);
@@ -5929,7 +5987,7 @@ retryowner2:
if (iaxs[fr.callno]->videoformat > 0)
f.subclass = iaxs[fr.callno]->videoformat | (ntohs(vh->ts) & 0x8000 ? 1 : 0);
else {
- ast_log(LOG_WARNING, "Received mini frame before first full voice frame\n ");
+ ast_log(LOG_WARNING, "Received mini frame before first full video frame\n ");
iax2_vnak(fr.callno);
ast_mutex_unlock(&iaxsl[fr.callno]);
return 1;
@@ -5973,9 +6031,12 @@ retryowner2:
f.src = "IAX2";
f.mallocd = 0;
f.offset = 0;
- if (f.datalen && (f.frametype == AST_FRAME_VOICE))
+ if (f.datalen && (f.frametype == AST_FRAME_VOICE)) {
f.samples = get_samples(&f);
- else
+ /* We need to byteswap incoming slinear samples from network byte order */
+ if (f.subclass == AST_FORMAT_SLINEAR)
+ ast_frame_byteswap_be(&f);
+ } else
f.samples = 0;
iax_frame_wrap(&fr, &f);
@@ -5993,12 +6054,12 @@ retryowner2:
forward_delivery(&fr);
} else {
duped_fr = iaxfrdup2(&fr);
- schedule_delivery(duped_fr, 1, updatehistory);
+ schedule_delivery(duped_fr, 1, updatehistory, 0);
fr.ts = duped_fr->ts;
}
#else
duped_fr = iaxfrdup2(&fr);
- schedule_delivery(duped_fr, 1, updatehistory);
+ schedule_delivery(duped_fr, 1, updatehistory, 0);
fr.ts = duped_fr->ts;
#endif
@@ -6252,7 +6313,7 @@ static struct ast_channel *iax2_request(char *type, int format, void *data)
ast_mutex_unlock(&iaxsl[callno]);
if (c) {
/* Choose a format we can live with */
- if (c->nativeformats & format)
+ if (c->nativeformats & format)
c->nativeformats &= format;
else {
native = c->nativeformats;
@@ -6265,6 +6326,8 @@ static struct ast_channel *iax2_request(char *type, int format, void *data)
}
c->nativeformats = native;
}
+ c->readformat = ast_best_codec(c->nativeformats);
+ c->writeformat = c->readformat;
}
return c;
}
@@ -6386,9 +6449,11 @@ static struct iax2_peer *build_peer(char *name, struct ast_variable *v)
} else {
ast_mutex_unlock(&peerl.lock);
peer = malloc(sizeof(struct iax2_peer));
- memset(peer, 0, sizeof(struct iax2_peer));
- peer->expire = -1;
- peer->pokeexpire = -1;
+ if (peer) {
+ memset(peer, 0, sizeof(struct iax2_peer));
+ peer->expire = -1;
+ peer->pokeexpire = -1;
+ }
}
if (peer) {
peer->messagedetail = globalmessagedetail;
@@ -6525,7 +6590,6 @@ static struct iax2_user *build_user(char *name, struct ast_variable *v)
struct ast_ha *oldha = NULL;
struct iax2_context *oldcon = NULL;
int format;
- int found;
prev = NULL;
ast_mutex_lock(&userl.lock);
@@ -6538,7 +6602,6 @@ static struct iax2_user *build_user(char *name, struct ast_variable *v)
user = user->next;
}
if (user) {
- found++;
oldha = user->ha;
oldcon = user->contexts;
user->ha = NULL;
@@ -6553,7 +6616,8 @@ static struct iax2_user *build_user(char *name, struct ast_variable *v)
} else {
ast_mutex_unlock(&userl.lock);
user = malloc(sizeof(struct iax2_user));
- memset(user, 0, sizeof(struct iax2_user));
+ if (user)
+ memset(user, 0, sizeof(struct iax2_user));
}
if (user) {
@@ -6951,7 +7015,6 @@ static int reload_config(void)
delayreject = 0;
globalnotransfer = 0;
globalusejitterbuf = 0;
- srand(time(NULL));
delete_users();
set_config(config,&dead_sin);
prune_peers();
@@ -7310,7 +7373,7 @@ static int iax2_exec(struct ast_channel *chan, char *context, char *exten, int p
ast_verbose(VERBOSE_PREFIX_3 "Executing Dial('%s')\n", req);
} else {
ast_mutex_unlock(&dpcache_lock);
- ast_log(LOG_WARNING, "Can't execute non-existant extension '%s[@%s]' in data '%s'\n", exten, context, data);
+ ast_log(LOG_WARNING, "Can't execute nonexistent extension '%s[@%s]' in data '%s'\n", exten, context, data);
return -1;
}
}
@@ -7409,6 +7472,8 @@ int load_module(void)
ast_log(LOG_WARNING, "Unable to open IAX timing interface: %s\n", strerror(errno));
#endif
+ memset(iaxs, 0, sizeof(iaxs));
+
for (x=0;x<IAX_MAX_CALLS;x++)
ast_mutex_init(&iaxsl[x]);
@@ -7471,9 +7536,9 @@ int load_module(void)
if (setsockopt(netsocket, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)))
ast_log(LOG_WARNING, "Unable to set TOS to %d\n", tos);
-
+
+ res = start_network_thread();
if (!res) {
- res = start_network_thread();
if (option_verbose > 1)
ast_verbose(VERBOSE_PREFIX_2 "IAX Ready and Listening on %s port %d\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), ntohs(sin.sin_port));
} else {
diff --git a/channels/chan_local.c b/channels/chan_local.c
index fc8fd8820..bdf8101ec 100755
--- a/channels/chan_local.c
+++ b/channels/chan_local.c
@@ -139,7 +139,7 @@ static void check_bridge(struct local_pvt *p, int isoutbound)
{
if (p->alreadymasqed || p->nooptimization)
return;
- if (isoutbound && p->chan && p->chan->bridge && p->owner) {
+ if (isoutbound && p->chan && p->chan->bridge && p->owner && !p->owner->pvt->readq) {
/* Masquerade bridged channel into owner */
/* Lock everything we need, one by one, and give up if
we can't get everything. Remember, we'll get another
@@ -152,7 +152,7 @@ static void check_bridge(struct local_pvt *p, int isoutbound)
}
ast_mutex_unlock(&p->chan->bridge->lock);
}
- } else if (!isoutbound && p->owner && p->owner->bridge && p->chan) {
+ } else if (!isoutbound && p->owner && p->owner->bridge && p->chan && !p->chan->pvt->readq) {
/* Masquerade bridged channel into chan */
if (!ast_mutex_trylock(&p->owner->bridge->lock)) {
if (!ast_mutex_trylock(&p->chan->lock)) {
@@ -177,12 +177,17 @@ static int local_write(struct ast_channel *ast, struct ast_frame *f)
int res = -1;
int isoutbound;
-
/* Just queue for delivery to the other side */
ast_mutex_lock(&p->lock);
isoutbound = IS_OUTBOUND(ast, p);
- res = local_queue_frame(p, isoutbound, f, ast);
- check_bridge(p, isoutbound);
+ if (f && (f->frametype == AST_FRAME_VOICE))
+ check_bridge(p, isoutbound);
+ if (!p->alreadymasqed)
+ res = local_queue_frame(p, isoutbound, f, ast);
+ else {
+ ast_log(LOG_DEBUG, "Not posting to queue since already masked on '%s'\n", ast->name);
+ res = 0;
+ }
ast_mutex_unlock(&p->lock);
return res;
}
@@ -233,6 +238,22 @@ static int local_digit(struct ast_channel *ast, char digit)
return res;
}
+static int local_sendhtml(struct ast_channel *ast, int subclass, char *data, int datalen)
+{
+ struct local_pvt *p = ast->pvt->pvt;
+ int res = -1;
+ struct ast_frame f = { AST_FRAME_HTML, };
+ int isoutbound;
+ ast_mutex_lock(&p->lock);
+ isoutbound = IS_OUTBOUND(ast, p);
+ f.subclass = subclass;
+ f.data = data;
+ f.datalen = datalen;
+ res = local_queue_frame(p, isoutbound, &f, ast);
+ ast_mutex_unlock(&p->lock);
+ return res;
+}
+
static int local_call(struct ast_channel *ast, char *dest, int timeout)
{
struct local_pvt *p = ast->pvt->pvt;
@@ -304,6 +325,10 @@ static int local_hangup(struct ast_channel *ast)
p->owner = NULL;
ast->pvt->pvt = NULL;
+ ast_mutex_lock(&usecnt_lock);
+ usecnt--;
+ ast_mutex_unlock(&usecnt_lock);
+
if (!p->owner && !p->chan) {
/* Okay, done with the private part now, too. */
glaredetect = p->glaredetect;
@@ -371,7 +396,7 @@ static struct local_pvt *local_alloc(char *data, int format)
strncpy(tmp->context, "default", sizeof(tmp->context) - 1);
tmp->reqformat = format;
if (!ast_exists_extension(NULL, tmp->context, tmp->exten, 1, NULL)) {
- ast_log(LOG_NOTICE, "No such extension/context %s@%s creating local channel\n", tmp->context, tmp->exten);
+ ast_log(LOG_NOTICE, "No such extension/context %s@%s creating local channel\n", tmp->exten, tmp->context);
ast_mutex_destroy(&tmp->lock);
free(tmp);
tmp = NULL;
@@ -421,6 +446,8 @@ static struct ast_channel *local_new(struct local_pvt *p, int state)
tmp2->pvt->pvt = p;
tmp->pvt->send_digit = local_digit;
tmp2->pvt->send_digit = local_digit;
+ tmp->pvt->send_html = local_sendhtml;
+ tmp2->pvt->send_html = local_sendhtml;
tmp->pvt->call = local_call;
tmp2->pvt->call = local_call;
tmp->pvt->hangup = local_hangup;
@@ -441,6 +468,7 @@ static struct ast_channel *local_new(struct local_pvt *p, int state)
p->chan = tmp2;
ast_mutex_lock(&usecnt_lock);
usecnt++;
+ usecnt++;
ast_mutex_unlock(&usecnt_lock);
ast_update_use_count();
strncpy(tmp->context, p->context, sizeof(tmp->context)-1);
diff --git a/channels/chan_mgcp.c b/channels/chan_mgcp.c
index 22058c775..44b62dfc2 100755
--- a/channels/chan_mgcp.c
+++ b/channels/chan_mgcp.c
@@ -239,7 +239,7 @@ static int restart_monitor(void);
static int capability = AST_FORMAT_ULAW;
static int nonCodecCapability = AST_RTP_DTMF;
-static char ourhost[256];
+static char ourhost[MAXHOSTNAMELEN];
static struct in_addr __ourip;
static int ourport;
@@ -365,6 +365,7 @@ struct mgcp_endpoint {
unsigned int callgroup;
unsigned int pickupgroup;
int callwaiting;
+ int hascallwaiting;
int transfer;
int threewaycalling;
int singlepath;
@@ -471,7 +472,7 @@ static int unalloc_sub(struct mgcp_subchannel *sub)
ast_log(LOG_DEBUG, "Released sub %d of channel %s@%s\n", sub->id, p->name, p->parent->name);
sub->owner = NULL;
- if (strlen(sub->cxident)) {
+ if (!ast_strlen_zero(sub->cxident)) {
transmit_connection_del(sub);
}
sub->cxident[0] = '\0';
@@ -686,8 +687,7 @@ static int mgcp_postrequest(struct mgcp_endpoint *p, struct mgcp_subchannel *sub
if (gettimeofday(&tv, NULL) < 0) {
/* This shouldn't ever happen, but let's be sure */
ast_log(LOG_NOTICE, "gettimeofday() failed!\n");
- }
- else {
+ } else {
msg->expire = tv.tv_sec * 1000 + tv.tv_usec / 1000 + DEFAULT_RETRANS;
if (gw->retransid == -1)
@@ -834,7 +834,7 @@ static int mgcp_call(struct ast_channel *ast, char *dest, int timeout)
transmit_modify_request(sub);
}
- if (sub->next->owner && strlen(sub->next->cxident) && strlen(sub->next->callid)) {
+ if (sub->next->owner && !ast_strlen_zero(sub->next->cxident) && !ast_strlen_zero(sub->next->callid)) {
/* try to prevent a callwait from disturbing the other connection */
sub->next->cxmode = MGCP_CX_RECVONLY;
transmit_modify_request(sub->next);
@@ -844,7 +844,7 @@ static int mgcp_call(struct ast_channel *ast, char *dest, int timeout)
ast_setstate(ast, AST_STATE_RINGING);
ast_queue_control(ast, AST_CONTROL_RINGING);
- if (sub->next->owner && strlen(sub->next->cxident) && strlen(sub->next->callid)) {
+ if (sub->next->owner && !ast_strlen_zero(sub->next->cxident) && !ast_strlen_zero(sub->next->callid)) {
/* Put the connection back in sendrecv */
sub->next->cxmode = MGCP_CX_SENDRECV;
transmit_modify_request(sub->next);
@@ -862,8 +862,9 @@ static int mgcp_hangup(struct ast_channel *ast)
struct mgcp_subchannel *sub = ast->pvt->pvt;
struct mgcp_endpoint *p = sub->parent;
- if (option_debug)
+ if (option_debug) {
ast_log(LOG_DEBUG, "mgcp_hangup(%s)\n", ast->name);
+ }
if (!ast->pvt->pvt) {
ast_log(LOG_DEBUG, "Asked to hangup channel not connected\n");
return 0;
@@ -872,14 +873,14 @@ static int mgcp_hangup(struct ast_channel *ast)
ast_log(LOG_DEBUG, "Invalid magic. MGCP subchannel freed up already.\n");
return 0;
}
+ ast_mutex_lock(&sub->lock);
if (mgcpdebug) {
ast_verbose(VERBOSE_PREFIX_3 "MGCP mgcp_hangup(%s) on %s@%s\n", ast->name, p->name, p->parent->name);
}
- if ((p->dtmfmode & MGCP_DTMF_INBAND) && (p->dsp != NULL)){
+ if ((p->dtmfmode & MGCP_DTMF_INBAND) && p->dsp) {
/* SC: check whether other channel is active. */
- if (!sub->next->owner)
- {
+ if (!sub->next->owner) {
if (mgcpdebug) {
ast_verbose(VERBOSE_PREFIX_2 "MGCP free dsp on %s@%s\n", p->name, p->parent->name);
}
@@ -887,10 +888,9 @@ static int mgcp_hangup(struct ast_channel *ast)
p->dsp = NULL;
}
}
- ast_mutex_lock(&sub->lock);
sub->owner = NULL;
- if (strlen(sub->cxident)) {
+ if (!ast_strlen_zero(sub->cxident)) {
transmit_connection_del(sub);
}
sub->cxident[0] = '\0';
@@ -937,7 +937,14 @@ static int mgcp_hangup(struct ast_channel *ast)
/* SC: Decrement use count */
if ((p->hookstate == MGCP_ONHOOK) && (!sub->next->rtp)) {
- if (has_voicemail(p)) {
+ p->hidecallerid = 0;
+ if (p->hascallwaiting && !p->callwaiting) {
+ if (option_verbose > 2) {
+ ast_verbose(VERBOSE_PREFIX_3 "Enabling call waiting on %s\n", ast->name);
+ }
+ p->callwaiting = -1;
+ }
+ if (has_voicemail(p)) {
if (mgcpdebug) {
ast_verbose(VERBOSE_PREFIX_3 "MGCP mgcp_hangup(%s) on %s@%s set vmwi(+)\n", ast->name, p->name, p->parent->name);
}
@@ -967,7 +974,7 @@ static int mgcp_show_endpoints(int fd, int argc, char *argv[])
e = g->endpoints;
ast_cli(fd, "Gateway '%s' at %s (%s)\n", g->name, g->addr.sin_addr.s_addr ? ast_inet_ntoa(iabuf, sizeof(iabuf), g->addr.sin_addr) : ast_inet_ntoa(iabuf, sizeof(iabuf), g->defaddr.sin_addr), g->dynamic ? "Dynamic" : "Static");
while(e) {
- // JS: Don't show wilcard endpoint
+ /* JS: Don't show wilcard endpoint */
if (strcmp(e->name, g->wcardep) !=0)
ast_cli(fd, " -- '%s@%s in '%s' is %s\n", e->name, g->name, e->context, e->sub->owner ? "active" : "idle");
hasendpoints = 1;
@@ -1078,7 +1085,11 @@ static struct ast_frame *mgcp_rtp_read(struct mgcp_subchannel *sub)
{
/* Retrieve audio/etc from channel. Assumes sub->lock is already held. */
struct ast_frame *f;
+ static struct ast_frame null_frame = { AST_FRAME_NULL, };
f = ast_rtp_read(sub->rtp);
+ /* Don't send RFC2833 if we're not supposed to */
+ if (f && (f->frametype == AST_FRAME_DTMF) && !(sub->parent->dtmfmode & MGCP_DTMF_RFC2833))
+ return &null_frame;
if (sub->owner) {
/* We already hold the channel lock */
if (f->frametype == AST_FRAME_VOICE) {
@@ -1089,7 +1100,7 @@ static struct ast_frame *mgcp_rtp_read(struct mgcp_subchannel *sub)
ast_set_write_format(sub->owner, sub->owner->writeformat);
}
/* Courtesy fearnor aka alex@pilosoft.com */
- if (sub->parent->dtmfmode & MGCP_DTMF_INBAND) {
+ if ((sub->parent->dtmfmode & MGCP_DTMF_INBAND) && (sub->parent->dsp)) {
#if 0
ast_log(LOG_NOTICE, "MGCP ast_dsp_process\n");
#endif
@@ -1103,18 +1114,12 @@ static struct ast_frame *mgcp_rtp_read(struct mgcp_subchannel *sub)
static struct ast_frame *mgcp_read(struct ast_channel *ast)
{
- struct ast_frame *fr;
+ struct ast_frame *f;
struct mgcp_subchannel *sub = ast->pvt->pvt;
- static struct ast_frame null_frame = { AST_FRAME_NULL, };
ast_mutex_lock(&sub->lock);
- fr = mgcp_rtp_read(sub);
- if (!(sub->parent->dtmfmode & MGCP_DTMF_RFC2833)) {
- if (fr && (fr->frametype == AST_FRAME_DTMF)) {
- fr = &null_frame;
- }
- }
+ f = mgcp_rtp_read(sub);
ast_mutex_unlock(&sub->lock);
- return fr;
+ return f;
}
static int mgcp_write(struct ast_channel *ast, struct ast_frame *frame)
@@ -1237,9 +1242,9 @@ static int mgcp_indicate(struct ast_channel *ast, int ind)
static struct ast_channel *mgcp_new(struct mgcp_subchannel *sub, int state)
{
struct ast_channel *tmp;
- struct mgcp_endpoint *i = sub->parent;
+ struct mgcp_endpoint *i = sub->parent;
int fmt;
- i = sub->parent;
+
tmp = ast_channel_alloc(1);
if (tmp) {
tmp->nativeformats = i->capability;
@@ -1275,9 +1280,9 @@ static struct ast_channel *mgcp_new(struct mgcp_subchannel *sub, int state)
tmp->pvt->fixup = mgcp_fixup;
tmp->pvt->send_digit = mgcp_senddigit;
tmp->pvt->bridge = ast_rtp_bridge;
- if (strlen(i->language))
+ if (!ast_strlen_zero(i->language))
strncpy(tmp->language, i->language, sizeof(tmp->language)-1);
- if (strlen(i->accountcode))
+ if (!ast_strlen_zero(i->accountcode))
strncpy(tmp->accountcode, i->accountcode, sizeof(tmp->accountcode)-1);
if (i->amaflags)
tmp->amaflags = i->amaflags;
@@ -1313,7 +1318,8 @@ static struct ast_channel *mgcp_new(struct mgcp_subchannel *sub, int state)
return tmp;
}
-static char* get_sdp_by_line(char* line, char *name, int nameLen) {
+static char* get_sdp_by_line(char* line, char *name, int nameLen)
+{
if (strncasecmp(line, name, nameLen) == 0 && line[nameLen] == '=') {
char* r = line + nameLen + 1;
while (*r && (*r < 33)) ++r;
@@ -1323,7 +1329,8 @@ static char* get_sdp_by_line(char* line, char *name, int nameLen) {
return "";
}
-static char *get_sdp(struct mgcp_request *req, char *name) {
+static char *get_sdp(struct mgcp_request *req, char *name)
+{
int x;
int len = strlen(name);
char *r;
@@ -1335,12 +1342,13 @@ static char *get_sdp(struct mgcp_request *req, char *name) {
return "";
}
-static void sdpLineNum_iterator_init(int* iterator) {
+static void sdpLineNum_iterator_init(int* iterator)
+{
*iterator = 0;
}
-static char* get_sdp_iterate(int* iterator,
- struct mgcp_request *req, char *name) {
+static char* get_sdp_iterate(int* iterator, struct mgcp_request *req, char *name)
+{
int len = strlen(name);
char *r;
while (*iterator < req->lines) {
@@ -1529,7 +1537,7 @@ static void parse(struct mgcp_request *req)
#if 0
printf("Header: %s (%d)\n", req->header[f], strlen(req->header[f]));
#endif
- if (!strlen(req->header[f])) {
+ if (ast_strlen_zero(req->header[f])) {
/* Line by itself means we're now in content */
c++;
break;
@@ -1546,7 +1554,7 @@ static void parse(struct mgcp_request *req)
c++;
}
/* Check for last header */
- if (strlen(req->header[f]))
+ if (!ast_strlen_zero(req->header[f]))
f++;
req->headers = f;
/* Now we process any mime content */
@@ -1571,7 +1579,7 @@ static void parse(struct mgcp_request *req)
c++;
}
/* Check for last line */
- if (strlen(req->line[f]))
+ if (!ast_strlen_zero(req->line[f]))
f++;
req->lines = f;
/* Parse up the initial header */
@@ -1626,14 +1634,14 @@ static int process_sdp(struct mgcp_subchannel *sub, struct mgcp_request *req)
struct sockaddr_in sin;
char *codecs;
struct ast_hostent ahp; struct hostent *hp;
- int codec;
+ int codec, codec_count = 0;
int iterator;
- struct mgcp_endpoint *p = sub->parent;
+ struct mgcp_endpoint *p = sub->parent;
/* Get codec and RTP info from SDP */
m = get_sdp(req, "m");
c = get_sdp(req, "c");
- if (!strlen(m) || !strlen(c)) {
+ if (ast_strlen_zero(m) || ast_strlen_zero(c)) {
ast_log(LOG_WARNING, "Insufficient information for SDP (m = '%s', c = '%s')\n", m, c);
return -1;
}
@@ -1658,30 +1666,31 @@ static int process_sdp(struct mgcp_subchannel *sub, struct mgcp_request *req)
#if 0
printf("Peer RTP is at port %s:%d\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), ntohs(sin.sin_port));
#endif
- // Scan through the RTP payload types specified in a "m=" line:
- ast_rtp_pt_clear(sub->rtp);
- codecs = m + len;
- while(strlen(codecs)) {
- if (sscanf(codecs, "%d %n", &codec, &len) != 1) {
- ast_log(LOG_WARNING, "Error in codec string '%s'\n", codecs);
+ /* Scan through the RTP payload types specified in a "m=" line: */
+ ast_rtp_pt_clear(sub->rtp);
+ codecs = ast_strdupa(m + len);
+ while (codecs && !ast_strlen_zero(codecs)) {
+ if (sscanf(codecs, "%d%n", &codec, &len) != 1) {
+ if (codec_count)
+ break;
return -1;
}
ast_rtp_set_m_type(sub->rtp, codec);
+ codec_count++;
codecs += len;
}
- // Next, scan through each "a=rtpmap:" line, noting each
- // specified RTP payload type (with corresponding MIME subtype):
- sdpLineNum_iterator_init(&iterator);
- while ((a = get_sdp_iterate(&iterator, req, "a"))[0] != '\0') {
- char* mimeSubtype = strdup(a); // ensures we have enough space
- if (sscanf(a, "rtpmap: %u %[^/]/", &codec, mimeSubtype) != 2) continue;
- // Note: should really look at the 'freq' and '#chans' params too
- ast_rtp_set_rtpmap_type(sub->rtp, codec, "audio", mimeSubtype);
- free(mimeSubtype);
- }
+ /* Next, scan through each "a=rtpmap:" line, noting each
+ specified RTP payload type (with corresponding MIME subtype): */
+ sdpLineNum_iterator_init(&iterator);
+ while ((a = get_sdp_iterate(&iterator, req, "a"))[0] != '\0') {
+ char* mimeSubtype = ast_strdupa(a); /* ensures we have enough space */
+ if (sscanf(a, "rtpmap: %u %[^/]/", &codec, mimeSubtype) != 2) continue;
+ /* Note: should really look at the 'freq' and '#chans' params too */
+ ast_rtp_set_rtpmap_type(sub->rtp, codec, "audio", mimeSubtype);
+ }
- // Now gather all of the codecs that were asked for:
+ /* Now gather all of the codecs that were asked for: */
ast_rtp_get_current_formats(sub->rtp,
&peercapability, &peerNonCodecCapability);
p->capability = capability & peercapability;
@@ -1696,7 +1705,6 @@ static int process_sdp(struct mgcp_subchannel *sub, struct mgcp_request *req)
return -1;
}
return 0;
-
}
static int add_header(struct mgcp_request *req, char *var, char *value)
@@ -1712,9 +1720,9 @@ static int add_header(struct mgcp_request *req, char *var, char *value)
req->header[req->headers] = req->data + req->len;
snprintf(req->header[req->headers], sizeof(req->data) - req->len, "%s: %s\r\n", var, value);
req->len += strlen(req->header[req->headers]);
- if (req->headers < MGCP_MAX_HEADERS)
+ if (req->headers < MGCP_MAX_HEADERS) {
req->headers++;
- else {
+ } else {
ast_log(LOG_WARNING, "Out of header space\n");
return -1;
}
@@ -1735,9 +1743,9 @@ static int add_line(struct mgcp_request *req, char *line)
req->line[req->lines] = req->data + req->len;
snprintf(req->line[req->lines], sizeof(req->data) - req->len, "%s", line);
req->len += strlen(req->line[req->lines]);
- if (req->lines < MGCP_MAX_LINES)
+ if (req->lines < MGCP_MAX_LINES) {
req->lines++;
- else {
+ } else {
ast_log(LOG_WARNING, "Out of line space\n");
return -1;
}
@@ -1785,7 +1793,7 @@ static int init_req(struct mgcp_endpoint *p, struct mgcp_request *req, char *ver
static int respprep(struct mgcp_request *resp, struct mgcp_endpoint *p, char *msg, struct mgcp_request *req, char *msgrest)
{
- memset(resp, 0, sizeof(*resp));
+ memset(resp, 0, sizeof(struct mgcp_request));
init_resp(resp, msg, req, msgrest);
return 0;
}
@@ -1926,7 +1934,7 @@ static int transmit_modify_with_sdp(struct mgcp_subchannel *sub, struct ast_rtp
capability = p->capability;
if (codecs)
capability = codecs;
- if (!strlen(sub->cxident) && rtp) {
+ if (ast_strlen_zero(sub->cxident) && rtp) {
/* We don't have a CXident yet, store the destination and
wait a bit */
ast_rtp_get_peer(rtp, &sub->tmpdest);
@@ -1947,7 +1955,7 @@ static int transmit_modify_with_sdp(struct mgcp_subchannel *sub, struct ast_rtp
add_header(&resp, "X", sub->txident);
add_header(&resp, "I", sub->cxident);
/*add_header(&resp, "S", "");*/
- ast_rtp_offered_from_local(rtp, 0);
+ ast_rtp_offered_from_local(sub->rtp, 0);
add_sdp(&resp, sub, rtp);
/* SC: fill in new fields */
resp.cmd = MGCP_CMD_MDCX;
@@ -1981,7 +1989,7 @@ static int transmit_connect_with_sdp(struct mgcp_subchannel *sub, struct ast_rtp
/* SC: X header should not be sent. kept for compatibility */
add_header(&resp, "X", sub->txident);
/*add_header(&resp, "S", "");*/
- ast_rtp_offered_from_local(rtp, 1);
+ ast_rtp_offered_from_local(sub->rtp, 1);
add_sdp(&resp, sub, rtp);
/* SC: fill in new fields */
resp.cmd = MGCP_CMD_CRCX;
@@ -2009,7 +2017,7 @@ static int transmit_notify_request(struct mgcp_subchannel *sub, char *tone)
add_header(&resp, "R", (sub->rtp && (p->dtmfmode & MGCP_DTMF_INBAND)) ? "L/hu(N),L/hf(N)" : "L/hu(N),L/hf(N),D/[0-9#*](N)");
break;
}
- if (strlen(tone)) {
+ if (!ast_strlen_zero(tone)) {
add_header(&resp, "S", tone);
}
/* SC: fill in new fields */
@@ -2063,7 +2071,7 @@ static int transmit_notify_request_with_callerid(struct mgcp_subchannel *sub, ch
add_header(&resp, "R", (sub->rtp && (p->dtmfmode & MGCP_DTMF_INBAND)) ? "L/hu(N),L/hf(N)" : "L/hu(N),L/hf(N),D/[0-9#*](N)");
break;
}
- if (strlen(tone2)) {
+ if (!ast_strlen_zero(tone2)) {
add_header(&resp, "S", tone2);
}
if (mgcpdebug) {
@@ -2079,8 +2087,8 @@ static int transmit_notify_request_with_callerid(struct mgcp_subchannel *sub, ch
static int transmit_modify_request(struct mgcp_subchannel *sub)
{
struct mgcp_request resp;
- struct mgcp_endpoint *p = sub->parent;
- if (!strlen(sub->cxident)) {
+ struct mgcp_endpoint *p = sub->parent;
+ if (ast_strlen_zero(sub->cxident)) {
/* We don't have a CXident yet, store the destination and
wait a bit */
return 0;
@@ -2115,7 +2123,7 @@ static int transmit_audit_endpoint(struct mgcp_endpoint *p)
struct mgcp_request resp;
reqprep(&resp, p, "AUEP");
/* SC: removed unknown param VS */
- //add_header(&resp, "F", "A,R,D,S,X,N,I,T,O,ES,E,MD,M");
+ /*add_header(&resp, "F", "A,R,D,S,X,N,I,T,O,ES,E,MD,M");*/
add_header(&resp, "F", "A");
/* SC: fill in new fields */
resp.cmd = MGCP_CMD_AUEP;
@@ -2304,10 +2312,10 @@ static void handle_response(struct mgcp_endpoint *p, struct mgcp_subchannel *sub
if (resp) {
if (req->cmd == MGCP_CMD_CRCX) {
if ((c = get_header(resp, "I"))) {
- if (strlen(c) && sub) {
+ if (!ast_strlen_zero(c) && sub) {
/* SC: if we are hanging up do not process this conn. */
if (sub->owner) {
- if (strlen(sub->cxident)) {
+ if (!ast_strlen_zero(sub->cxident)) {
if (strcasecmp(c, sub->cxident)) {
ast_log(LOG_WARNING, "Subchannel already has a cxident. sub->cxident: %s requested %s\n", sub->cxident, c);
}
@@ -2354,7 +2362,7 @@ static void handle_response(struct mgcp_endpoint *p, struct mgcp_subchannel *sub
/* Try to determine the hookstate returned from an audit endpoint command */
if ((c = get_header(resp, "ES"))) {
- if (strlen(c)) {
+ if (!ast_strlen_zero(c)) {
if (strstr(c, "hu")) {
if (p->hookstate != MGCP_ONHOOK) {
/* SC: XXX cleanup if we think we are offhook XXX */
@@ -2411,7 +2419,7 @@ static void start_rtp(struct mgcp_subchannel *sub)
sub->rtp = NULL;
}
/* Allocate the RTP now */
- sub->rtp = ast_rtp_new(sched, io, 1, 0);
+ sub->rtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0, bindaddr.sin_addr);
if (sub->rtp && sub->owner)
sub->owner->fds[0] = ast_rtp_fd(sub->rtp);
if (sub->rtp)
@@ -2518,7 +2526,7 @@ static void *mgcp_ss(void *data)
/*zt_wait_event(p->subs[index].zfd);*/
ast_hangup(chan);
return NULL;
- } else if (p->callwaiting && !strcmp(exten, "*70")) {
+ } else if (p->hascallwaiting && p->callwaiting && !strcmp(exten, "*70")) {
if (option_verbose > 2) {
ast_verbose(VERBOSE_PREFIX_3 "Disabling call waiting on %s\n", chan->name);
}
@@ -2559,7 +2567,7 @@ static void *mgcp_ss(void *data)
timeout = firstdigittimeout;
} else if (p->callreturn && !strcmp(exten, "*69")) {
res = 0;
- if (strlen(p->lastcallerid)) {
+ if (!ast_strlen_zero(p->lastcallerid)) {
res = ast_say_digit_str(chan, p->lastcallerid, "", chan->language);
}
if (!res)
@@ -2614,7 +2622,7 @@ static void *mgcp_ss(void *data)
ast_verbose(VERBOSE_PREFIX_3 "Parking call to '%s'\n", chan->name);
}
break;
- } else if (strlen(p->lastcallerid) && !strcmp(exten, "*60")) {
+ } else if (!ast_strlen_zero(p->lastcallerid) && !strcmp(exten, "*60")) {
if (option_verbose > 2) {
ast_verbose(VERBOSE_PREFIX_3 "Blacklisting number %s\n", p->lastcallerid);
}
@@ -2860,7 +2868,7 @@ static int handle_request(struct mgcp_subchannel *sub, struct mgcp_request *req,
if (option_verbose > 2 && (strcmp(p->name, p->parent->wcardep) != 0)) {
ast_verbose(VERBOSE_PREFIX_3 "Resetting interface %s@%s\n", p->name, p->parent->name);
}
- // JS: For RSIP on wildcard we reset all endpoints
+ /* JS: For RSIP on wildcard we reset all endpoints */
if (!strcmp(p->name, p->parent->wcardep)) {
/* Reset all endpoints */
struct mgcp_endpoint *tmp_ep;
@@ -2868,7 +2876,7 @@ static int handle_request(struct mgcp_subchannel *sub, struct mgcp_request *req,
g = p->parent;
tmp_ep = g->endpoints;
while (tmp_ep) {
- //if ((strcmp(tmp_ep->name, "*") != 0) && (strcmp(tmp_ep->name, "aaln/*") != 0)) {
+ /*if ((strcmp(tmp_ep->name, "*") != 0) && (strcmp(tmp_ep->name, "aaln/" "*") != 0)) {*/
if (strcmp(tmp_ep->name, g->wcardep) != 0) {
struct mgcp_subchannel *tmp_sub, *first_sub;
if (option_verbose > 2) {
@@ -2879,7 +2887,7 @@ static int handle_request(struct mgcp_subchannel *sub, struct mgcp_request *req,
tmp_sub = tmp_ep->sub;
while (tmp_sub) {
if (tmp_sub->owner)
- ast_softhangup(sub->owner, AST_SOFTHANGUP_DEV);
+ ast_softhangup(tmp_sub->owner, AST_SOFTHANGUP_DEV);
tmp_sub = tmp_sub->next;
if (tmp_sub == first_sub)
break;
@@ -2928,7 +2936,9 @@ static int handle_request(struct mgcp_subchannel *sub, struct mgcp_request *req,
return -1;
}
/* do not let * confrnce two down channels */
- if( sub->owner && sub->owner->_state == AST_STATE_DOWN && !sub->next->owner) return -1;
+ if( sub->owner && sub->owner->_state == AST_STATE_DOWN && !sub->next->owner) {
+ return -1;
+ }
if (p->callwaiting || p->transfer || p->threewaycalling) {
if (option_verbose > 2) {
@@ -3046,12 +3056,23 @@ static int handle_request(struct mgcp_subchannel *sub, struct mgcp_request *req,
} else {
/* SC: verbose level check */
if (option_verbose > 2) {
- ast_verbose(VERBOSE_PREFIX_3 "MGCP handle_request(%s@%s-%d) ast_channel already destroyed\n",
- p->name, p->parent->name, sub->id);
+ ast_verbose(VERBOSE_PREFIX_3 "MGCP handle_request(%s@%s-%d) ast_channel already destroyed, resending DLCX.\n",
+ p->name, p->parent->name, sub->id);
}
+ /* Instruct the other side to remove the connection since it apparently *
+ * still thinks the channel is active. *
+ * For Cisco IAD2421 /BAK/ */
+ transmit_connection_del(sub);
}
}
if ((p->hookstate == MGCP_ONHOOK) && (!sub->rtp) && (!sub->next->rtp)) {
+ p->hidecallerid = 0;
+ if (p->hascallwaiting && !p->callwaiting) {
+ if (option_verbose > 2) {
+ ast_verbose(VERBOSE_PREFIX_3 "Enabling call waiting on MGCP/%s@%s-%d\n", p->name, p->parent->name, sub->id);
+ }
+ p->callwaiting = -1;
+ }
if (has_voicemail(p)) {
if (option_verbose > 2) {
ast_verbose(VERBOSE_PREFIX_3 "MGCP handle_request(%s@%s) set vmwi(+)\n", p->name, p->parent->name);
@@ -3081,11 +3102,9 @@ static int handle_request(struct mgcp_subchannel *sub, struct mgcp_request *req,
if (strstr(p->curtone, "wt") && (ev[0] == 'A')) {
memset(p->curtone, 0, sizeof(p->curtone));
}
- }
- else if (!strcasecmp(ev, "T")) {
+ } else if (!strcasecmp(ev, "T")) {
/* Digit timeout -- unimportant */
- }
- else if (!strcasecmp(ev, "ping")) {
+ } else if (!strcasecmp(ev, "ping")) {
/* ping -- unimportant */
} else {
ast_log(LOG_NOTICE, "Received unknown event '%s' from %s@%s\n", ev, p->name, p->parent->name);
@@ -3140,7 +3159,7 @@ static int mgcpsock_read(int *id, int fd, short events, void *ignore)
int ident;
char iabuf[INET_ADDRSTRLEN];
len = sizeof(sin);
- memset(&req, 0, sizeof(req));
+ memset(&req, 0, sizeof(struct mgcp_request));
res = recvfrom(mgcpsock, req.data, sizeof(req.data) - 1, 0, (struct sockaddr *)&sin, &len);
if (res < 0) {
if (errno != ECONNREFUSED)
@@ -3150,14 +3169,14 @@ static int mgcpsock_read(int *id, int fd, short events, void *ignore)
req.data[res] = '\0';
req.len = res;
if (mgcpdebug) {
- ast_verbose("MGCP read: \n%s\nfrom %s:%d", req.data, ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), ntohs(sin.sin_port));
- }
+ ast_verbose("MGCP read: \n%s\nfrom %s:%d\n", req.data, ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), ntohs(sin.sin_port));
+ }
parse(&req);
if (req.headers < 1) {
/* Must have at least one header */
return 1;
}
- if (!req.identifier || !strlen(req.identifier)) {
+ if (!req.identifier || ast_strlen_zero(req.identifier)) {
ast_log(LOG_NOTICE, "Message from %s missing identifier\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr));
return 1;
}
@@ -3200,9 +3219,9 @@ static int mgcpsock_read(int *id, int fd, short events, void *ignore)
gw->name, ident);
}
} else {
- if (!req.endpoint || !strlen(req.endpoint) ||
- !req.version || !strlen(req.version) ||
- !req.verb || !strlen(req.verb)) {
+ if (!req.endpoint || ast_strlen_zero(req.endpoint) ||
+ !req.version || ast_strlen_zero(req.version) ||
+ !req.verb || ast_strlen_zero(req.verb)) {
ast_log(LOG_NOTICE, "Message must have a verb, an idenitifier, version, and endpoint\n");
return 1;
}
@@ -3257,10 +3276,10 @@ static void *do_monitor(void *data)
/* Lock the network interface */
ast_mutex_lock(&netlock);
+#if 0
/* XXX THIS IS COMPLETELY HOSED */
/* The gateway goes into a state of panic */
/* If the vmwi indicator is sent while it is reseting interfaces */
-#if 0
lastpass = thispass;
thispass = time(NULL);
g = gateways;
@@ -3356,7 +3375,7 @@ static struct ast_channel *mgcp_request(char *type, int format, void *data)
return NULL;
}
strncpy(tmp, dest, sizeof(tmp) - 1);
- if (!strlen(tmp)) {
+ if (ast_strlen_zero(tmp)) {
ast_log(LOG_NOTICE, "MGCP Channels require an endpoint\n");
return NULL;
}
@@ -3374,7 +3393,7 @@ static struct ast_channel *mgcp_request(char *type, int format, void *data)
/* Must be busy */
if (((sub->parent->callwaiting) && ((sub->owner) && (sub->next->owner))) ||
((!sub->parent->callwaiting) && (sub->owner)) ||
- (sub->parent->dnd && (!strlen(sub->parent->call_forward)))) {
+ (sub->parent->dnd && (ast_strlen_zero(sub->parent->call_forward)))) {
if (sub->parent->hookstate == MGCP_ONHOOK) {
if (has_voicemail(sub->parent)) {
transmit_notify_request(sub,"L/vmwi(+)");
@@ -3385,8 +3404,9 @@ static struct ast_channel *mgcp_request(char *type, int format, void *data)
return NULL;
}
tmpc = mgcp_new(sub->owner ? sub->next : sub, AST_STATE_DOWN);
- if (!tmpc)
+ if (!tmpc) {
ast_log(LOG_WARNING, "Unable to make channel for '%s'\n", tmp);
+ }
restart_monitor();
return tmpc;
}
@@ -3516,8 +3536,6 @@ static struct mgcp_gateway *build_gateway(char *cat, struct ast_variable *v)
adsi = ast_true(v->value);
} else if (!strcasecmp(v->name, "callreturn")) {
callreturn = ast_true(v->value);
- } else if (!strcasecmp(v->name, "immediate")) {
- immediate = ast_true(v->value);
} else if (!strcasecmp(v->name, "callwaiting")) {
callwaiting = ast_true(v->value);
} else if (!strcasecmp(v->name, "slowsequence")) {
@@ -3555,8 +3573,9 @@ static struct mgcp_gateway *build_gateway(char *cat, struct ast_variable *v)
e->needaudit = 1;
}
strncpy(gw->wcardep, v->value, sizeof(gw->wcardep)-1);
- //strncpy(e->name, "aaln/*", sizeof(e->name) - 1);
+ /*strncpy(e->name, "aaln/" "*", sizeof(e->name) - 1);*/
/* XXX Should we really check for uniqueness?? XXX */
+ strncpy(e->accountcode, accountcode, sizeof(e->accountcode) - 1);
strncpy(e->context, context, sizeof(e->context) - 1);
strncpy(e->callerid, callerid, sizeof(e->callerid) - 1);
strncpy(e->language, language, sizeof(e->language) - 1);
@@ -3564,6 +3583,7 @@ static struct mgcp_gateway *build_gateway(char *cat, struct ast_variable *v)
strncpy(e->mailbox, mailbox, sizeof(e->mailbox)-1);
snprintf(e->rqnt_ident, sizeof(e->rqnt_ident), "%08x", rand());
e->msgstate = -1;
+ e->amaflags = amaflags;
e->capability = capability;
e->parent = gw;
e->dtmfmode = dtmfmode;
@@ -3577,6 +3597,7 @@ static struct mgcp_gateway *build_gateway(char *cat, struct ast_variable *v)
e->singlepath = singlepath;
e->canreinvite = canreinvite;
e->callwaiting = callwaiting;
+ e->hascallwaiting = callwaiting;
e->slowsequence = slowsequence;
e->transfer = transfer;
e->threewaycalling = threewaycalling;
@@ -3649,12 +3670,13 @@ static struct mgcp_gateway *build_gateway(char *cat, struct ast_variable *v)
e->needaudit = 1;
}
/* XXX Should we really check for uniqueness?? XXX */
+ strncpy(e->accountcode, accountcode, sizeof(e->accountcode) - 1);
strncpy(e->context, context, sizeof(e->context) - 1);
strncpy(e->callerid, callerid, sizeof(e->callerid) - 1);
strncpy(e->language, language, sizeof(e->language) - 1);
strncpy(e->musicclass, musicclass, sizeof(e->musicclass)-1);
strncpy(e->mailbox, mailbox, sizeof(e->mailbox)-1);
- if (strlen(mailbox)) {
+ if (!ast_strlen_zero(mailbox)) {
ast_verbose(VERBOSE_PREFIX_3 "Setting mailbox '%s' on %s@%s\n", mailbox, gw->name, e->name);
}
if (!ep_reload) {
@@ -3662,6 +3684,7 @@ static struct mgcp_gateway *build_gateway(char *cat, struct ast_variable *v)
e->msgstate = -1;
e->parent = gw;
}
+ e->amaflags = amaflags;
e->capability = capability;
e->dtmfmode = dtmfmode;
e->adsi = adsi;
@@ -3678,6 +3701,7 @@ static struct mgcp_gateway *build_gateway(char *cat, struct ast_variable *v)
e->canreinvite = canreinvite;
e->singlepath = singlepath;
e->callwaiting = callwaiting;
+ e->hascallwaiting = callwaiting;
e->slowsequence = slowsequence;
e->transfer = transfer;
e->threewaycalling = threewaycalling;
@@ -3748,6 +3772,8 @@ static struct mgcp_gateway *build_gateway(char *cat, struct ast_variable *v)
}
return NULL;
}
+ gw->defaddr.sin_family = AF_INET;
+ gw->addr.sin_family = AF_INET;
if (gw->defaddr.sin_addr.s_addr && !ntohs(gw->defaddr.sin_port))
gw->defaddr.sin_port = htons(DEFAULT_MGCP_GW_PORT);
if (gw->addr.sin_addr.s_addr && !ntohs(gw->addr.sin_port))
@@ -3830,7 +3856,7 @@ static void destroy_endpoint(struct mgcp_endpoint *e)
for (i = 0; i < MAX_SUBS; i++) {
ast_mutex_lock(&sub->lock);
- if (strlen(sub->cxident)) {
+ if (!ast_strlen_zero(sub->cxident)) {
transmit_connection_del(sub);
}
if (sub->rtp) {
@@ -3933,7 +3959,7 @@ static int reload_config(void)
struct ast_hostent ahp; struct hostent *hp;
int format;
- if (gethostname(ourhost, sizeof(ourhost))) {
+ if (gethostname(ourhost, sizeof(ourhost)-1)) {
ast_log(LOG_WARNING, "Unable to get hostname, MGCP disabled\n");
return 0;
}
@@ -4226,4 +4252,3 @@ char *description()
{
return desc;
}
-
diff --git a/channels/chan_modem.c b/channels/chan_modem.c
index c2f3bf0f9..50a63bb75 100755
--- a/channels/chan_modem.c
+++ b/channels/chan_modem.c
@@ -509,6 +509,18 @@ static int modem_write(struct ast_channel *ast, struct ast_frame *frame)
return res;
}
+static int modem_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
+{
+ struct ast_modem_pvt *p = newchan->pvt->pvt;
+ast_log(LOG_WARNING, "fixup called\n");
+ if (p->owner!=oldchan) {
+ ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n",oldchan,p->owner);
+ return -1;
+ }
+ p->owner = newchan;
+ return 0;
+}
+
struct ast_channel *ast_modem_new(struct ast_modem_pvt *i, int state)
{
struct ast_channel *tmp;
@@ -528,6 +540,7 @@ struct ast_channel *ast_modem_new(struct ast_modem_pvt *i, int state)
tmp->pvt->answer = modem_answer;
tmp->pvt->read = modem_read;
tmp->pvt->write = modem_write;
+ tmp->pvt->fixup = modem_fixup;
strncpy(tmp->context, i->context, sizeof(tmp->context)-1);
if (strlen(i->cid))
tmp->callerid = strdup(i->cid);
@@ -707,8 +720,8 @@ static struct ast_modem_pvt *mkif(char *iface)
#endif
tmp = malloc(sizeof(struct ast_modem_pvt));
- memset(tmp, 0, sizeof(struct ast_modem_pvt));
if (tmp) {
+ memset(tmp, 0, sizeof(struct ast_modem_pvt));
tmp->fd = open(iface, O_RDWR | O_NONBLOCK);
if (tmp->fd < 0) {
ast_log(LOG_WARNING, "Unable to open '%s'\n", iface);
diff --git a/channels/chan_modem_bestdata.c b/channels/chan_modem_bestdata.c
index ddcb72018..94e49ddd1 100755
--- a/channels/chan_modem_bestdata.c
+++ b/channels/chan_modem_bestdata.c
@@ -47,10 +47,10 @@ static char *bestdata_idents[] = {
NULL
};
-static int bestdata_startrec(struct ast_modem_pvt *p)
-{
static int bestdata_break(struct ast_modem_pvt *p);
+static int bestdata_startrec(struct ast_modem_pvt *p)
+{
if (p->ministate != STATE_COMMAND) bestdata_break(p);
if (ast_modem_send(p, "AT+VRX", 0) ||
ast_modem_expect(p, "CONNECT", 5)) {
@@ -63,8 +63,6 @@ static int bestdata_break(struct ast_modem_pvt *p);
static int bestdata_startplay(struct ast_modem_pvt *p)
{
-static int bestdata_break(struct ast_modem_pvt *p);
-
if (p->ministate != STATE_COMMAND) bestdata_break(p);
if (ast_modem_send(p, "AT+VTX", 0) ||
ast_modem_expect(p, "CONNECT", 5)) {
diff --git a/channels/chan_oss.c b/channels/chan_oss.c
index a74a9d847..10e435969 100755
--- a/channels/chan_oss.c
+++ b/channels/chan_oss.c
@@ -34,6 +34,9 @@
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
+
+#include "asterisk/endian.h"
+
#ifdef __linux
#include <linux/soundcard.h>
#elif defined(__FreeBSD__)
@@ -322,7 +325,13 @@ static int setformat(void)
int fmt, desired, res, fd = sounddev;
static int warnedalready = 0;
static int warnedalready2 = 0;
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
fmt = AFMT_S16_LE;
+#else
+ fmt = AFMT_S16_BE;
+#endif
+
res = ioctl(fd, SNDCTL_DSP_SETFMT, &fmt);
if (res < 0) {
ast_log(LOG_WARNING, "Unable to set format to 16-bit signed\n");
@@ -846,6 +855,7 @@ static int console_sendtext(int fd, int argc, char *argv[])
strncat(text2send, " ", sizeof(text2send) - strlen(text2send) - 1);
}
if (strlen(text2send)) {
+ text2send[strlen(text2send) - 1] = '\n';
f.frametype = AST_FRAME_TEXT;
f.subclass = 0;
f.data = text2send;
diff --git a/channels/chan_phone.c b/channels/chan_phone.c
index bacfaa3c4..2204dd299 100755
--- a/channels/chan_phone.c
+++ b/channels/chan_phone.c
@@ -33,6 +33,10 @@
#include <sys/ioctl.h>
#include <linux/telephony.h>
/* Still use some IXJ specific stuff */
+#include <linux/version.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+# include <linux/compiler.h>
+#endif
#include <linux/ixjuser.h>
#include "DialTone.h"
@@ -468,10 +472,13 @@ static struct ast_frame *phone_read(struct ast_channel *ast)
p->fr.frametype = AST_FRAME_VOICE;
p->fr.subclass = p->lastinput;
p->fr.offset = AST_FRIENDLY_OFFSET;
+ /* Byteswap from little-endian to native-endian */
+ if (p->fr.subclass == AST_FORMAT_SLINEAR)
+ ast_frame_byteswap_le(&p->fr);
return &p->fr;
}
-static int phone_write_buf(struct phone_pvt *p, char *buf, int len, int frlen)
+static int phone_write_buf(struct phone_pvt *p, char *buf, int len, int frlen, int swap)
{
int res;
/* Store as much of the buffer as we can, then write fixed frames */
@@ -479,7 +486,10 @@ static int phone_write_buf(struct phone_pvt *p, char *buf, int len, int frlen)
/* Make sure we have enough buffer space to store the frame */
if (space < len)
len = space;
- memcpy(p->obuf + p->obuflen, buf, len);
+ if (swap)
+ ast_memcpy_byteswap(p->obuf+p->obuflen, buf, len/2);
+ else
+ memcpy(p->obuf + p->obuflen, buf, len);
p->obuflen += len;
while(p->obuflen > frlen) {
res = write(p->fd, p->obuf, frlen);
@@ -624,12 +634,17 @@ static int phone_write(struct ast_channel *ast, struct ast_frame *frame)
memset(tmpbuf + 4, 0, sizeof(tmpbuf) - 4);
memcpy(tmpbuf, frame->data, 4);
expected = 24;
- res = phone_write_buf(p, tmpbuf, expected, maxfr);
+ res = phone_write_buf(p, tmpbuf, expected, maxfr, 0);
}
res = 4;
expected=4;
} else {
- res = phone_write_buf(p, pos, expected, maxfr);
+ int swap = 0;
+#if __BYTE_ORDER == __BIG_ENDIAN
+ if (frame->subclass == AST_FORMAT_SLINEAR)
+ swap = 1; /* Swap big-endian samples to little-endian as we copy */
+#endif
+ res = phone_write_buf(p, pos, expected, maxfr, swap);
}
if (res != expected) {
if ((errno != EAGAIN) && (errno != EINTR)) {
@@ -653,6 +668,14 @@ static int phone_write(struct ast_channel *ast, struct ast_frame *frame)
return 0;
}
+static int phone_fixup(struct ast_channel *old, struct ast_channel *new)
+{
+ struct phone_pvt *pvt = old->pvt->pvt;
+ if (pvt && pvt->owner == old)
+ pvt->owner = new;
+ return 0;
+}
+
static struct ast_channel *phone_new(struct phone_pvt *i, int state, char *context)
{
struct ast_channel *tmp;
@@ -676,6 +699,7 @@ static struct ast_channel *phone_new(struct phone_pvt *i, int state, char *conte
tmp->pvt->read = phone_read;
tmp->pvt->write = phone_write;
tmp->pvt->exception = phone_exception;
+ tmp->pvt->fixup = phone_fixup;
strncpy(tmp->context, context, sizeof(tmp->context)-1);
if (strlen(i->ext))
strncpy(tmp->exten, i->ext, sizeof(tmp->exten)-1);
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index be81665c8..03512a725 100755
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -98,6 +98,12 @@
#define SIP_DTMF_INBAND (1 << 1)
#define SIP_DTMF_INFO (1 << 2)
+/* --- SIP Insecure modes */
+#define SIP_SECURE (0 << 0)
+#define SIP_INSECURE_PORT (1 << 0)
+#define SIP_INSECURE_INVITE (1 << 1)
+#define SIP_INSECURE_BOTH (3 << 0)
+
static int max_expiry = DEFAULT_MAX_EXPIRY;
static int default_expiry = DEFAULT_DEFAULT_EXPIRY;
@@ -129,7 +135,9 @@ static char *tdesc = "Session Initiation Protocol (SIP)";
static char *config = "sip.conf";
#define DEFAULT_SIP_PORT 5060 /* From RFC 2543 */
-#define SIP_MAX_PACKET 1500 /* Also from RFC 2543, should sub headers tho */
+/* From RFC2543, this should be 1500, so it's up to the ability of
+ remote devices as to whether it will be accepted when more than that*/
+#define SIP_MAX_PACKET 4096
#define ALLOWED_METHODS "INVITE, ACK, CANCEL, OPTIONS, BYE, REFER"
@@ -168,6 +176,7 @@ static int global_ospauth = 0;
static int usecnt =0;
AST_MUTEX_DEFINE_STATIC(usecnt_lock);
+
/* Protect the interface list (of sip_pvt's) */
AST_MUTEX_DEFINE_STATIC(iflock);
@@ -187,7 +196,6 @@ static int restart_monitor(void);
static int global_capability = AST_FORMAT_ULAW | AST_FORMAT_ALAW | AST_FORMAT_GSM | AST_FORMAT_H263;
static int noncodeccapability = AST_RTP_DTMF;
-static char ourhost[256];
static struct in_addr __ourip;
static int ourport;
@@ -203,7 +211,7 @@ static int recordhistory = 0;
static int global_promiscredir;
static char global_musicclass[MAX_LANGUAGE] = ""; /* Global music on hold class */
-static char global_realm[AST_MAX_EXTENSION] = "asterisk"; /* Default realm */
+static char global_realm[MAXHOSTNAMELEN] = "asterisk"; /* Default realm */
static char regcontext[AST_MAX_EXTENSION] = "";
/* Expire slowly */
@@ -222,10 +230,8 @@ static struct io_context *io;
#define DEC_OUT_USE 2
#define INC_OUT_USE 3
-static struct sip_codec_pref {
- int codec;
- struct sip_codec_pref *next;
-} *prefs;
+static struct ast_codec_pref prefs;
+
/* sip_request: The data grabbed from the UDP socket */
struct sip_request {
@@ -256,6 +262,7 @@ static struct sip_pvt {
ast_mutex_t lock; /* Channel private lock */
char callid[80]; /* Global CallID */
char randdata[80]; /* Random data */
+ struct ast_codec_pref prefs; /* codec prefs */
unsigned int ocseq; /* Current outgoing seqno */
unsigned int icseq; /* Current incoming seqno */
unsigned int callgroup; /* Call group */
@@ -298,9 +305,10 @@ static struct sip_pvt {
char from[256]; /* The From: header */
char useragent[256]; /* User agent in SIP request */
char context[AST_MAX_EXTENSION]; /* Context for this call */
- char fromdomain[AST_MAX_EXTENSION]; /* Domain to show in the from field */
- char fromuser[AST_MAX_EXTENSION]; /* Domain to show in the user field */
- char tohost[AST_MAX_EXTENSION]; /* Host we should put in the "to" field */
+ char fromdomain[MAXHOSTNAMELEN]; /* Domain to show in the from field */
+ char fromuser[AST_MAX_EXTENSION]; /* User to show in the user field */
+ char fromname[AST_MAX_EXTENSION]; /* Name to show in the user field */
+ char tohost[MAXHOSTNAMELEN]; /* Host we should put in the "to" field */
char language[MAX_LANGUAGE]; /* Default language for this call */
char musicclass[MAX_LANGUAGE]; /* Music on Hold class */
char rdnis[256]; /* Referring DNIS */
@@ -314,14 +322,14 @@ static struct sip_pvt {
char callerid[256]; /* Caller*ID */
int restrictcid; /* hide presentation from remote user */
char via[256];
- char fullcontact[128]; /* Extra parameters to go in the "To" header */
+ char fullcontact[128]; /* Extra parameters to go in the "To" header */
char accountcode[20]; /* Account code */
char our_contact[256]; /* Our contact header */
- char realm[256]; /* Authorization realm */
+ char realm[MAXHOSTNAMELEN]; /* Authorization realm */
char nonce[256]; /* Authorization nonce */
char opaque[256]; /* Opaque nonsense */
char qop[80]; /* Quality of Protection, since SIP wasn't complicated enough yet. */
- char domain[256]; /* Authorization nonce */
+ char domain[MAXHOSTNAMELEN]; /* Authorization domain */
char lastmsg[256]; /* Last Message sent/received */
int amaflags; /* AMA Flags */
int pendinginvite; /* Any pending invite */
@@ -383,7 +391,7 @@ struct sip_user {
char name[80];
char secret[80];
char md5secret[80];
- char context[80];
+ char context[AST_MAX_EXTENSION];
char callerid[80];
char accountcode[20];
char language[MAX_LANGUAGE];
@@ -391,6 +399,7 @@ struct sip_user {
char useragent[256]; /* User agent in SIP request */
unsigned int callgroup;
unsigned int pickupgroup;
+ struct ast_codec_pref prefs; /* codec prefs */
int nat;
int hascallerid;
int amaflags;
@@ -421,17 +430,18 @@ struct sip_peer {
char name[80];
char secret[80];
char md5secret[80];
- char context[80]; /* JK02: peers need context too to allow parking etc */
+ char context[AST_MAX_EXTENSION]; /* JK02: peers need context too to allow parking etc */
char username[80];
- char tohost[80];
+ char tohost[MAXHOSTNAMELEN];
char regexten[AST_MAX_EXTENSION]; /* Extension to register (if regcontext is used) */
char fromuser[80];
- char fromdomain[80];
- char fullcontact[128];
+ char fromdomain[MAXHOSTNAMELEN];
+ char fullcontact[256];
char mailbox[AST_MAX_EXTENSION];
char language[MAX_LANGUAGE];
char musicclass[MAX_LANGUAGE]; /* Music on Hold class */
char useragent[256]; /* User agent in SIP request */
+ struct ast_codec_pref prefs; /* codec prefs */
int lastmsgssent;
time_t lastmsgcheck;
int dynamic;
@@ -492,10 +502,10 @@ struct sip_registry {
int portno; /* Optional port override */
char username[80]; /* Who we are registering as */
char authuser[80]; /* Who we *authenticate* as */
- char hostname[80];
+ char hostname[MAXHOSTNAMELEN];
char secret[80]; /* Password or key name in []'s */
char md5secret[80];
- char contact[80]; /* Contact extension */
+ char contact[256]; /* Contact extension */
char random[80];
int expire; /* Sched ID of expiration */
int timeout; /* sched id of sip_reg_timeout */
@@ -506,6 +516,15 @@ struct sip_registry {
char callid[80]; /* Global CallID for this registry */
unsigned int ocseq; /* Sequence number we got to for REGISTERs for this registry */
struct sockaddr_in us; /* Who the server thinks we are */
+
+ /* Saved headers */
+ char realm[MAXHOSTNAMELEN]; /* Authorization realm */
+ char nonce[256]; /* Authorization nonce */
+ char domain[MAXHOSTNAMELEN]; /* Authorization domain */
+ char opaque[256]; /* Opaque nonsense */
+ char qop[80]; /* Quality of Protection. */
+
+ char lastmsg[256]; /* Last Message sent/received */
struct sip_registry *next;
};
@@ -590,6 +609,7 @@ static int __sip_xmit(struct sip_pvt *p, char *data, int len)
{
int res;
char iabuf[INET_ADDRSTRLEN];
+// ast_log(LOG_WARNING, "__sip_xmit from '%s' to '%s'\n", "", ast_inet_ntoa(iabuf, sizeof(iabuf), p->recv.sin_addr));
if (p->nat & SIP_NAT_ROUTE)
res=sendto(sipsock, data, len, 0, (struct sockaddr *)&p->recv, sizeof(struct sockaddr_in));
else
@@ -688,6 +708,7 @@ static int retrans_pkt(void *data)
ast_mutex_lock(&pkt->owner->lock);
}
if (pkt->owner->owner) {
+ pkt->owner->alreadygone=1;
ast_queue_hangup(pkt->owner->owner);
ast_mutex_unlock(&pkt->owner->owner->lock);
} else {
@@ -827,6 +848,15 @@ static int __sip_ack(struct sip_pvt *p, int seqno, int resp, const char *msg)
return res;
}
+/* Pretend to ack all packets */
+static int __sip_pretend_ack(struct sip_pvt *p)
+{
+ while(p->packets) {
+ __sip_ack(p, p->packets->seqno, (p->packets->flags & FLAG_RESPONSE), p->packets->data);
+ }
+ return 0;
+}
+
/*--- __sip_semi_ack: Acks receipt of packet, keep it around (used for provisional responses) ---*/
static int __sip_semi_ack(struct sip_pvt *p, int seqno, int resp, const char *msg)
{
@@ -1049,7 +1079,7 @@ static struct sip_user *mysql_user(char *user)
if (sscanf(rowval[x], "%li", &regseconds) != 1)
regseconds = 0;
} else if (!strcasecmp(fields[x].name, "restrictcid")) {
- u->restrictcid = 1;
+ u->restrictcid = *(rowval[x])-'0';
} else if (!strcasecmp(fields[x].name, "callerid")) {
strncpy(u->callerid, rowval[x], sizeof(u->callerid) - 1);
u->hascallerid=1;
@@ -1216,7 +1246,7 @@ static struct sip_peer *find_peer(char *peer, struct sockaddr_in *sin)
/* Find by sin */
while(p) {
if (!inaddrcmp(&p->addr, sin) ||
- (p->insecure &&
+ ((p->insecure & SIP_INSECURE_PORT) &&
(p->addr.sin_addr.s_addr == sin->sin_addr.s_addr))) {
break;
}
@@ -1265,7 +1295,7 @@ static int create_addr(struct sip_pvt *r, char *opeer)
char *port;
char *callhost;
int portno;
- char host[256], *hostn;
+ char host[MAXHOSTNAMELEN], *hostn;
char peer[256]="";
strncpy(peer, opeer, sizeof(peer) - 1);
@@ -1326,8 +1356,10 @@ static int create_addr(struct sip_pvt *r, char *opeer)
}
r->promiscredir = p->promiscredir;
strncpy(r->context, p->context,sizeof(r->context)-1);
+ r->rtptimeout = p->rtptimeout;
+ r->rtpholdtimeout = p->rtpholdtimeout;
if ((p->addr.sin_addr.s_addr || p->defaddr.sin_addr.s_addr) &&
- (!p->maxms || ((p->lastms > 0) && (p->lastms <= p->maxms)))) {
+ (!p->maxms || ((p->lastms >= 0) && (p->lastms <= p->maxms)))) {
if (p->addr.sin_addr.s_addr) {
r->sa.sin_addr = p->addr.sin_addr;
r->sa.sin_port = p->addr.sin_port;
@@ -1354,7 +1386,7 @@ static int create_addr(struct sip_pvt *r, char *opeer)
else
portno = DEFAULT_SIP_PORT;
if (srvlookup) {
- char service[256];
+ char service[MAXHOSTNAMELEN];
int tportno;
int ret;
snprintf(service, sizeof(service), "_sip._udp.%s", peer);
@@ -1405,71 +1437,8 @@ static int auto_congest(void *nothing)
return 0;
}
-/*--- sip_prefs_free: Free codec list in preference structure ---*/
-static void sip_prefs_free(void)
-{
- struct sip_codec_pref *cur, *next;
- cur = prefs;
- while(cur) {
- next = cur->next;
- free(cur);
- cur = next;
- }
- prefs = NULL;
-}
-
-/*--- sip_pref_remove: Remove codec from pref list ---*/
-static void sip_pref_remove(int format)
-{
- struct sip_codec_pref *cur, *prev=NULL;
- cur = prefs;
- while(cur) {
- if (cur->codec == format) {
- if (prev)
- prev->next = cur->next;
- else
- prefs = cur->next;
- free(cur);
- return;
- }
- prev = cur;
- cur = cur->next;
- }
-}
-/*--- sip_pref_append: Append codec to list ---*/
-static int sip_pref_append(int format)
-{
- struct sip_codec_pref *cur, *tmp;
- sip_pref_remove(format);
- tmp = (struct sip_codec_pref *)malloc(sizeof(struct sip_codec_pref));
- if (!tmp)
- return -1;
- memset(tmp, 0, sizeof(struct sip_codec_pref));
- tmp->codec = format;
- if (prefs) {
- cur = prefs;
- while(cur->next)
- cur = cur->next;
- cur->next = tmp;
- } else
- prefs = tmp;
- return 0;
-}
-/*--- sip_codec_choose: Pick a codec ---*/
-static int sip_codec_choose(int formats)
-{
- struct sip_codec_pref *cur;
- formats &= ((AST_FORMAT_MAX_AUDIO << 1) - 1);
- cur = prefs;
- while(cur) {
- if (formats & cur->codec)
- return cur->codec;
- cur = cur->next;
- }
- return ast_best_codec(formats);
-}
/*--- sip_call: Initiate SIP call from PBX ---*/
/* used from the dial() application */
@@ -1682,6 +1651,10 @@ static int update_user_counter(struct sip_pvt *fup, int event)
ast_log(LOG_ERROR, "update_user_counter(%s,%d) called with no event!\n",u->name,event);
}
ast_mutex_unlock(&userl.lock);
+#ifdef MYSQL_USERS
+ if (u && u->temponly)
+ free(u);
+#endif
return 0;
}
@@ -1842,7 +1815,11 @@ static int sip_answer(struct ast_channel *ast)
fmt=ast_getformatbyname(codec);
if (fmt) {
ast_log(LOG_NOTICE, "Changing codec to '%s' for this call because of ${SIP_CODEC) variable\n",codec);
- p->jointcapability=fmt;
+ if (p->jointcapability & fmt) {
+ p->jointcapability &= fmt;
+ p->capability &= fmt;
+ } else
+ ast_log(LOG_NOTICE, "Ignoring ${SIP_CODEC} variable because it is not shared by both ends.\n");
} else ast_log(LOG_NOTICE, "Ignoring ${SIP_CODEC} variable because of unrecognized/not configured codec (check allow/disallow in sip.conf): %s\n",codec);
}
@@ -2002,6 +1979,7 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, char *title)
{
struct ast_channel *tmp;
int fmt;
+
ast_mutex_unlock(&i->lock);
/* Don't hold a sip pvt lock while we allocate a channel */
tmp = ast_channel_alloc(1);
@@ -2009,12 +1987,14 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, char *title)
if (tmp) {
/* Select our native format based on codec preference until we receive
something from another device to the contrary. */
+ ast_mutex_lock(&i->lock);
if (i->jointcapability)
- tmp->nativeformats = sip_codec_choose(i->jointcapability);
+ tmp->nativeformats = ast_codec_choose(&i->prefs, i->jointcapability, 1);
else if (i->capability)
- tmp->nativeformats = sip_codec_choose(i->capability);
+ tmp->nativeformats = ast_codec_choose(&i->prefs, i->capability, 1);
else
- tmp->nativeformats = sip_codec_choose(global_capability);
+ tmp->nativeformats = ast_codec_choose(&i->prefs, global_capability, 1);
+ ast_mutex_unlock(&i->lock);
fmt = ast_best_codec(tmp->nativeformats);
if (title)
snprintf(tmp->name, sizeof(tmp->name), "SIP/%s-%04x", title, rand() & 0xffff);
@@ -2122,9 +2102,14 @@ static struct cfalias {
{ "To", "t" },
{ "Supported", "k" },
{ "Refer-To", "r" },
+ { "Referred-By", "b" },
{ "Allow-Events", "u" },
{ "Event", "o" },
{ "Via", "v" },
+ { "Accept-Contact", "a" },
+ { "Reject-Contact", "j" },
+ { "Request-Disposition", "d" },
+ { "Session-Expires", "x" },
};
/*--- get_sdp_by_line: Reads one line of SIP message body */
@@ -2259,7 +2244,7 @@ static struct ast_frame *sip_rtp_read(struct ast_channel *ast, struct sip_pvt *p
}
if ((p->dtmfmode & SIP_DTMF_INBAND) && p->vad) {
f = ast_dsp_process(p->owner,p->vad,f);
- if (f && (f->frametype == AST_FRAME_DTMF))
+ if (f && (f->frametype == AST_FRAME_DTMF))
ast_log(LOG_DEBUG, "Detected DTMF '%c'\n", f->subclass);
}
}
@@ -2311,9 +2296,11 @@ static struct sip_pvt *sip_alloc(char *callid, struct sockaddr_in *sin, int useg
/* Keep track of stuff */
memset(p, 0, sizeof(struct sip_pvt));
ast_mutex_init(&p->lock);
+
p->initid = -1;
p->autokillid = -1;
p->stateid = -1;
+ p->prefs = prefs;
#ifdef OSP_SUPPORT
p->osphandle = -1;
#endif
@@ -2418,7 +2405,7 @@ static struct sip_pvt *find_call(struct sip_request *req, struct sockaddr_in *si
strncpy(tmp, get_header(req, "To"), sizeof(tmp) - 1);
else
strncpy(tmp, get_header(req, "From"), sizeof(tmp) - 1);
- tag = strstr(tmp, "tag=");
+ tag = ast_strcasestr(tmp, "tag=");
if (tag) {
tag += 4;
c = strchr(tag, ';');
@@ -2540,33 +2527,32 @@ static int lws2sws(char *msgbuf, int len)
}
/* Check for end-of-line */
if (msgbuf[h] == '\n') {
- /* Check for end-of-message */
+ /* Check for end-of-message */
if (h + 1 == len)
- break;
- /* Check for a continuation line */
- if (msgbuf[h + 1] == ' ') {
- /* Merge continuation line */
- h++;
+ break;
+ /* Check for a continuation line */
+ if (msgbuf[h + 1] == ' ' || msgbuf[h + 1] == '\t') {
+ /* Merge continuation line */
+ h++;
+ continue;
+ }
+ /* Propagate LF and start new line */
+ msgbuf[t++] = msgbuf[h++];
+ lws = 0;
continue;
}
- /* Propagate LF and start new line */
- msgbuf[t++] = msgbuf[h++];
- lws = 0;
- continue;
- }
-
- if (msgbuf[h] == ' ' || msgbuf[h] == '\t') {
- if (lws) {
- h++;
+ if (msgbuf[h] == ' ' || msgbuf[h] == '\t') {
+ if (lws) {
+ h++;
+ continue;
+ }
+ msgbuf[t++] = msgbuf[h++];
+ lws = 1;
continue;
}
msgbuf[t++] = msgbuf[h++];
- lws = 1;
- continue;
- }
- msgbuf[t++] = msgbuf[h++];
- if (lws)
- lws = 0;
+ if (lws)
+ lws = 0;
}
msgbuf[t] = '\0';
return t;
@@ -2648,8 +2634,8 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
char host[258];
char iabuf[INET_ADDRSTRLEN];
int len = -1;
- int portno=0;
- int vportno=0;
+ int portno = -1;
+ int vportno = -1;
int peercapability, peernoncodeccapability;
int vpeercapability=0, vpeernoncodeccapability=0;
struct sockaddr_in sin;
@@ -2660,6 +2646,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
int iterator;
int sendonly = 0;
int x;
+ int found;
int debug=sip_debug_test_pvt(p);
/* Update our last rtprx when we receive an SDP, too */
@@ -2689,7 +2676,9 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
sdpLineNum_iterator_init(&iterator);
p->novideo = 1;
while ((m = get_sdp_iterate(&iterator, req, "m"))[0] != '\0') {
+ found = 0;
if ((sscanf(m, "audio %d RTP/AVP %n", &x, &len) == 1)) {
+ found = 1;
portno = x;
/* Scan through the RTP payload types specified in a "m=" line: */
ast_rtp_pt_clear(p->rtp);
@@ -2711,6 +2700,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
ast_rtp_pt_clear(p->vrtp); /* Must be cleared in case no m=video line exists */
if (p->vrtp && (sscanf(m, "video %d RTP/AVP %n", &x, &len) == 1)) {
+ found = 1;
p->novideo = 0;
vportno = x;
/* Scan through the RTP payload types specified in a "m=" line: */
@@ -2728,6 +2718,12 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
while(*codecs && (*codecs < 33)) codecs++;
}
}
+ if (!found)
+ ast_log(LOG_WARNING, "Unknown SDP media type in offer %s\n", m);
+ }
+ if (portno == -1 && vportno == -1) {
+ /* No acceptable offer found in SDP */
+ return -2;
}
/* RTP addresses and ports for audio and video */
@@ -2758,21 +2754,22 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
*/
sdpLineNum_iterator_init(&iterator);
while ((a = get_sdp_iterate(&iterator, req, "a"))[0] != '\0') {
- char* mimeSubtype = ast_strdupa(a); /* ensures we have enough space */
- if (!strcasecmp(a, "sendonly")) {
- sendonly=1;
- continue;
- }
- if (!strcasecmp(a, "sendrecv")) {
- sendonly=0;
- }
- if (sscanf(a, "rtpmap: %u %[^/]/", &codec, mimeSubtype) != 2) continue;
- if (debug)
- ast_verbose("Found description format %s\n", mimeSubtype);
- /* Note: should really look at the 'freq' and '#chans' params too */
- ast_rtp_set_rtpmap_type(p->rtp, codec, "audio", mimeSubtype);
- if (p->vrtp)
- ast_rtp_set_rtpmap_type(p->vrtp, codec, "video", mimeSubtype);
+ char* mimeSubtype = ast_strdupa(a); /* ensures we have enough space */
+ if (!strcasecmp(a, "sendonly")) {
+ sendonly=1;
+ continue;
+ }
+ if (!strcasecmp(a, "sendrecv")) {
+ sendonly=0;
+ }
+ if (sscanf(a, "rtpmap: %u %[^/]/", &codec, mimeSubtype) != 2)
+ continue;
+ if (debug)
+ ast_verbose("Found description format %s\n", mimeSubtype);
+ /* Note: should really look at the 'freq' and '#chans' params too */
+ ast_rtp_set_rtpmap_type(p->rtp, codec, "audio", mimeSubtype);
+ if (p->vrtp)
+ ast_rtp_set_rtpmap_type(p->vrtp, codec, "video", mimeSubtype);
}
/* Now gather all of the codecs that were asked for: */
@@ -2786,7 +2783,8 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
p->noncodeccapability = noncodeccapability & peernoncodeccapability;
if (debug) {
- const unsigned slen=80;
+ /* shame on whoever coded this.... */
+ const unsigned slen=512;
char s1[slen], s2[slen], s3[slen], s4[slen];
ast_verbose("Capabilities: us - %s, peer - audio=%s/video=%s, combined - %s\n",
@@ -2796,22 +2794,22 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
ast_getformatname_multiple(s4, slen, p->jointcapability));
ast_verbose("Non-codec capabilities: us - %s, peer - %s, combined - %s\n",
- ast_getformatname_multiple(s1, slen, noncodeccapability),
- ast_getformatname_multiple(s2, slen, peernoncodeccapability),
- ast_getformatname_multiple(s3, slen, p->noncodeccapability));
+ ast_rtp_lookup_mime_multiple(s1, slen, noncodeccapability, 0),
+ ast_rtp_lookup_mime_multiple(s2, slen, peernoncodeccapability, 0),
+ ast_rtp_lookup_mime_multiple(s3, slen, p->noncodeccapability, 0));
}
if (!p->jointcapability) {
- ast_log(LOG_WARNING, "No compatible codecs!\n");
+ ast_log(LOG_NOTICE, "No compatible codecs!\n");
return -1;
}
if (p->owner) {
if (!(p->owner->nativeformats & p->jointcapability)) {
- const unsigned slen=80;
+ const unsigned slen=512;
char s1[slen], s2[slen];
ast_log(LOG_DEBUG, "Oooh, we need to change our formats since our peer supports only %s and not %s\n",
ast_getformatname_multiple(s1, slen, p->jointcapability),
ast_getformatname_multiple(s2, slen, p->owner->nativeformats));
- p->owner->nativeformats = sip_codec_choose(p->jointcapability);
+ p->owner->nativeformats = ast_codec_choose(&p->prefs, p->jointcapability, 1);
ast_set_read_format(p->owner, p->owner->readformat);
ast_set_write_format(p->owner, p->owner->writeformat);
}
@@ -2821,6 +2819,8 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
ast_moh_stop(p->owner->bridge);
} else {
ast_moh_start(p->owner->bridge, NULL);
+ if (sendonly)
+ ast_rtp_stop(p->rtp);
}
}
}
@@ -2831,54 +2831,52 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
/*--- add_header: Add header to SIP message */
static int add_header(struct sip_request *req, char *var, char *value)
{
- if (req->len >= sizeof(req->data) - 4) {
- ast_log(LOG_WARNING, "Out of space, can't add anymore (%s:%s)\n", var, value);
+ if (req->headers == SIP_MAX_HEADERS) {
+ ast_log(LOG_WARNING, "Out of SIP header space\n");
return -1;
}
if (req->lines) {
ast_log(LOG_WARNING, "Can't add more headers when lines have been added\n");
return -1;
}
+ if (req->len >= sizeof(req->data) - 4) {
+ ast_log(LOG_WARNING, "Out of space, can't add anymore (%s:%s)\n", var, value);
+ return -1;
+ }
req->header[req->headers] = req->data + req->len;
snprintf(req->header[req->headers], sizeof(req->data) - req->len - 4, "%s: %s\r\n", var, value);
req->len += strlen(req->header[req->headers]);
- if (req->headers < SIP_MAX_HEADERS)
- req->headers++;
- else {
- ast_log(LOG_WARNING, "Out of header space\n");
- return -1;
- }
+ req->headers++;
return 0;
}
/*--- add_blank_header: Add blank header to SIP message */
static int add_blank_header(struct sip_request *req)
{
- if (req->len >= sizeof(req->data) - 4) {
- ast_log(LOG_WARNING, "Out of space, can't add anymore\n");
+ if (req->headers == SIP_MAX_HEADERS) {
+ ast_log(LOG_WARNING, "Out of SIP header space\n");
return -1;
}
if (req->lines) {
ast_log(LOG_WARNING, "Can't add more headers when lines have been added\n");
return -1;
}
+ if (req->len >= sizeof(req->data) - 4) {
+ ast_log(LOG_WARNING, "Out of space, can't add anymore\n");
+ return -1;
+ }
req->header[req->headers] = req->data + req->len;
snprintf(req->header[req->headers], sizeof(req->data) - req->len, "\r\n");
req->len += strlen(req->header[req->headers]);
- if (req->headers < SIP_MAX_HEADERS)
- req->headers++;
- else {
- ast_log(LOG_WARNING, "Out of header space\n");
- return -1;
- }
+ req->headers++;
return 0;
}
/*--- add_line: Add content (not header) to SIP message */
static int add_line(struct sip_request *req, char *line)
{
- if (req->len >= sizeof(req->data) - 4) {
- ast_log(LOG_WARNING, "Out of space, can't add anymore\n");
+ if (req->lines == SIP_MAX_LINES) {
+ ast_log(LOG_WARNING, "Out of line space\n");
return -1;
}
if (!req->lines) {
@@ -2886,15 +2884,14 @@ static int add_line(struct sip_request *req, char *line)
snprintf(req->data + req->len, sizeof(req->data) - req->len, "\r\n");
req->len += strlen(req->data + req->len);
}
+ if (req->len >= sizeof(req->data) - 4) {
+ ast_log(LOG_WARNING, "Out of space, can't add anymore\n");
+ return -1;
+ }
req->line[req->lines] = req->data + req->len;
snprintf(req->line[req->lines], sizeof(req->data) - req->len, "%s", line);
req->len += strlen(req->line[req->lines]);
- if (req->lines < SIP_MAX_LINES)
- req->lines++;
- else {
- ast_log(LOG_WARNING, "Out of line space\n");
- return -1;
- }
+ req->lines++;
return 0;
}
@@ -3070,10 +3067,7 @@ static int init_resp(struct sip_request *req, char *resp, struct sip_request *or
req->header[req->headers] = req->data + req->len;
snprintf(req->header[req->headers], sizeof(req->data) - req->len, "SIP/2.0 %s\r\n", resp);
req->len += strlen(req->header[req->headers]);
- if (req->headers < SIP_MAX_HEADERS)
- req->headers++;
- else
- ast_log(LOG_WARNING, "Out of header space\n");
+ req->headers++;
return 0;
}
@@ -3088,10 +3082,7 @@ static int init_req(struct sip_request *req, char *resp, char *recip)
req->header[req->headers] = req->data + req->len;
snprintf(req->header[req->headers], sizeof(req->data) - req->len, "%s %s SIP/2.0\r\n", resp, recip);
req->len += strlen(req->header[req->headers]);
- if (req->headers < SIP_MAX_HEADERS)
- req->headers++;
- else
- ast_log(LOG_WARNING, "Out of header space\n");
+ req->headers++;
return 0;
}
@@ -3106,7 +3097,7 @@ static int respprep(struct sip_request *resp, struct sip_pvt *p, char *msg, stru
if (msg[0] == '2') copy_all_header(resp, req, "Record-Route");
copy_header(resp, req, "From");
ot = get_header(req, "To");
- if (!strstr(ot, "tag=")) {
+ if (!ast_strcasestr(ot, "tag=") && strncmp(msg, "100", 3)) {
/* Add the proper tag if we don't have it already. If they have specified
their tag, use it. Otherwise, use our own tag */
if (!ast_strlen_zero(p->theirtag) && p->outgoing)
@@ -3139,6 +3130,7 @@ static int respprep(struct sip_request *resp, struct sip_pvt *p, char *msg, stru
return 0;
}
+/*--- reqprep: Initialize a SIP request packet ---*/
static int reqprep(struct sip_request *req, struct sip_pvt *p, char *msg, int seqno, int newbranch)
{
struct sip_request *orig = &p->initreq;
@@ -3165,12 +3157,14 @@ static int reqprep(struct sip_request *req, struct sip_pvt *p, char *msg, int se
else /* Some implementations (e.g. Uniden UIP200) can't handle rport being in the message!! */
snprintf(p->via, sizeof(p->via), "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport, p->branch);
}
- if (!strcasecmp(msg, "CANCEL") || !strcasecmp(msg, "ACK")) {
- /* MUST use original URI */
+ if (!strcasecmp(msg, "CANCEL")) {
+ c = p->initreq.rlPart2; /* Use original URI */
+ } else if (!strcasecmp(msg, "ACK")) {
c = p->initreq.rlPart2;
} else if (!ast_strlen_zero(p->uri)) {
c = p->uri;
} else {
+ /* We have no URI, use To: or From: header as URI (depending on direction) */
if (p->outgoing)
strncpy(stripped, get_header(orig, "To"), sizeof(stripped) - 1);
else
@@ -3203,7 +3197,7 @@ static int reqprep(struct sip_request *req, struct sip_pvt *p, char *msg, int se
/* Add tag *unless* this is a CANCEL, in which case we need to send it exactly
as our original request, including tag (or presumably lack thereof) */
- if (!strstr(ot, "tag=") && strcasecmp(msg, "CANCEL")) {
+ if (!ast_strcasestr(ot, "tag=") && strcasecmp(msg, "CANCEL")) {
/* Add the proper tag if we don't have it already. If they have specified
their tag, use it. Otherwise, use our own tag */
if (p->outgoing && !ast_strlen_zero(p->theirtag))
@@ -3340,13 +3334,13 @@ static int add_digit(struct sip_request *req, char digit)
/*--- add_sdp: Add Session Description Protocol message ---*/
static int add_sdp(struct sip_request *resp, struct sip_pvt *p)
{
- int len;
- int codec;
+ int len = 0;
+ int codec = 0;
+ int pref_codec = 0;
int alreadysent = 0;
char costr[80];
struct sockaddr_in sin;
struct sockaddr_in vsin;
- struct sip_codec_pref *cur;
char v[256] = "";
char s[256] = "";
char o[256] = "";
@@ -3357,11 +3351,13 @@ static int add_sdp(struct sip_request *resp, struct sip_pvt *p)
char a[1024] = "";
char a2[1024] = "";
char iabuf[INET_ADDRSTRLEN];
- int x;
- int capability;
+ int x = 0;
+ int capability = 0 ;
struct sockaddr_in dest;
struct sockaddr_in vdest = { 0, };
- int debug=sip_debug_test_pvt(p);
+ int debug=0;
+
+ debug = sip_debug_test_pvt(p);
/* XXX We break with the "recommendation" and send our IP, in order that our
peer doesn't have to ast_gethostbyname() us XXX */
@@ -3413,9 +3409,10 @@ static int add_sdp(struct sip_request *resp, struct sip_pvt *p)
snprintf(t, sizeof(t), "t=0 0\r\n");
snprintf(m, sizeof(m), "m=audio %d RTP/AVP", ntohs(dest.sin_port));
snprintf(m2, sizeof(m2), "m=video %d RTP/AVP", ntohs(vdest.sin_port));
+ /* Prefer the codec we were requested to use, first, no matter what */
if (capability & p->prefcodec) {
if (debug)
- ast_verbose("Answering/Requesting with root capability %d\n", p->prefcodec);
+ ast_verbose("Answering/Requesting with root capability 0x%x (%s)\n", p->prefcodec, ast_getformatname(p->prefcodec));
codec = ast_rtp_lookup_code(p->rtp, 1, p->prefcodec);
if (codec > -1) {
snprintf(costr, sizeof(costr), " %d", codec);
@@ -3432,33 +3429,34 @@ static int add_sdp(struct sip_request *resp, struct sip_pvt *p)
alreadysent |= p->prefcodec;
}
/* Start by sending our preferred codecs */
- cur = prefs;
- while(cur) {
- if ((capability & cur->codec) && !(alreadysent & cur->codec)) {
+ for (x = 0 ; x < 32 ; x++) {
+ if(!(pref_codec = ast_codec_pref_index(&p->prefs,x)))
+ break;
+ if ((capability & pref_codec) && !(alreadysent & pref_codec)) {
if (debug)
- ast_verbose("Answering with preferred capability 0x%x(%s)\n", cur->codec, ast_getformatname(cur->codec));
- codec = ast_rtp_lookup_code(p->rtp, 1, cur->codec);
+ ast_verbose("Answering with preferred capability 0x%x (%s)\n", pref_codec, ast_getformatname(pref_codec));
+ codec = ast_rtp_lookup_code(p->rtp, 1, pref_codec);
if (codec > -1) {
snprintf(costr, sizeof(costr), " %d", codec);
- if (cur->codec <= AST_FORMAT_MAX_AUDIO) {
+ if (pref_codec <= AST_FORMAT_MAX_AUDIO) {
strncat(m, costr, sizeof(m) - strlen(m) - 1);
- snprintf(costr, sizeof(costr), "a=rtpmap:%d %s/8000\r\n", codec, ast_rtp_lookup_mime_subtype(1, cur->codec));
+ snprintf(costr, sizeof(costr), "a=rtpmap:%d %s/8000\r\n", codec, ast_rtp_lookup_mime_subtype(1, pref_codec));
strncat(a, costr, sizeof(a) - strlen(a) - 1);
} else {
strncat(m2, costr, sizeof(m2) - strlen(m2) - 1);
- snprintf(costr, sizeof(costr), "a=rtpmap:%d %s/90000\r\n", codec, ast_rtp_lookup_mime_subtype(1, cur->codec));
+ snprintf(costr, sizeof(costr), "a=rtpmap:%d %s/90000\r\n", codec, ast_rtp_lookup_mime_subtype(1, pref_codec));
strncat(a2, costr, sizeof(a2) - strlen(a) - 1);
}
}
}
- alreadysent |= cur->codec;
- cur = cur->next;
+ alreadysent |= pref_codec;
}
+
/* Now send any other common codecs, and non-codec formats: */
for (x = 1; x <= ((videosupport && p->vrtp) ? AST_FORMAT_MAX_VIDEO : AST_FORMAT_MAX_AUDIO); x <<= 1) {
if ((capability & x) && !(alreadysent & x)) {
if (debug)
- ast_verbose("Answering with capability 0x%x(%s)\n", x, ast_getformatname(x));
+ ast_verbose("Answering with capability 0x%x (%s)\n", x, ast_getformatname(x));
codec = ast_rtp_lookup_code(p->rtp, 1, x);
if (codec > -1) {
snprintf(costr, sizeof(costr), " %d", codec);
@@ -3477,7 +3475,7 @@ static int add_sdp(struct sip_request *resp, struct sip_pvt *p)
for (x = 1; x <= AST_RTP_MAX; x <<= 1) {
if (p->noncodeccapability & x) {
if (debug)
- ast_verbose("Answering with non-codec capability 0x%x(%s)\n", x, ast_getformatname(x));
+ ast_verbose("Answering with non-codec capability 0x%x (%s)\n", x, ast_rtp_lookup_mime_subtype(0, x));
codec = ast_rtp_lookup_code(p->rtp, 0, x);
if (codec > -1) {
snprintf(costr, sizeof(costr), " %d", codec);
@@ -3485,7 +3483,7 @@ static int add_sdp(struct sip_request *resp, struct sip_pvt *p)
snprintf(costr, sizeof(costr), "a=rtpmap:%d %s/8000\r\n", codec, ast_rtp_lookup_mime_subtype(0, x));
strncat(a, costr, sizeof(a) - strlen(a) - 1);
if (x == AST_RTP_DTMF) {
- /* Indicate we support DTMF... Not sure about 16, but MSN supports it so dang it, we will too... */
+ /* Indicate we support DTMF and FLASH... */
snprintf(costr, sizeof costr, "a=fmtp:%d 0-16\r\n",
codec);
strncat(a, costr, sizeof(a) - strlen(a) - 1);
@@ -3598,7 +3596,7 @@ static int determine_firstline_parts( struct sip_request *req ) {
e++;
if( !*e ) { return -1; }
}
- req->rlPart2= e;
+ req->rlPart2= e; /* URI */
if( ( e= strrchr( req->rlPart2, 'S' ) ) == NULL ) {
return -1;
}
@@ -3612,9 +3610,12 @@ static int determine_firstline_parts( struct sip_request *req ) {
return 1;
}
-/* transmit_reinvite_with_sdp: Transmit reinvite with SDP :-) ---*/
-/* A re-invite is basically a new INVITE with the same CALL-ID and TAG as the
- INVITE that opened the SIP dialogue */
+/*--- transmit_reinvite_with_sdp: Transmit reinvite with SDP :-) ---*/
+/* A re-invite is basically a new INVITE with the same CALL-ID and TAG as the
+ INVITE that opened the SIP dialogue
+ We reinvite so that the audio stream (RTP) go directly between
+ the SIP UAs. SIP Signalling stays with * in the path.
+*/
static int transmit_reinvite_with_sdp(struct sip_pvt *p)
{
struct sip_request req;
@@ -3688,7 +3689,7 @@ static void initreqprep(struct sip_request *req, struct sip_pvt *p, char *cmd, c
ast_callerid_parse(cid, &n, &l);
if (l)
ast_shrink_phone_number(l);
- if (!l || !ast_isphonenumber(l))
+ if (!l || (!ast_isphonenumber(l) && default_callerid[0]))
l = default_callerid;
}
/* if user want's his callerid restricted */
@@ -3701,15 +3702,25 @@ static void initreqprep(struct sip_request *req, struct sip_pvt *p, char *cmd, c
/* Allow user to be overridden */
if (!ast_strlen_zero(p->fromuser))
l = p->fromuser;
+ else /* Save for any further attempts */
+ strncpy(p->fromuser, l, sizeof(p->fromuser) - 1);
+
+ /* Allow user to be overridden */
+ if (!ast_strlen_zero(p->fromname))
+ n = p->fromname;
+ else /* Save for any further attempts */
+ strncpy(p->fromname, n, sizeof(p->fromname) - 1);
if ((ourport != 5060) && ast_strlen_zero(p->fromdomain))
snprintf(from, sizeof(from), "\"%s\" <sip:%s@%s:%d>;tag=as%08x", n, l, ast_strlen_zero(p->fromdomain) ? ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip) : p->fromdomain, ourport, p->tag);
else
snprintf(from, sizeof(from), "\"%s\" <sip:%s@%s>;tag=as%08x", n, l, ast_strlen_zero(p->fromdomain) ? ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip) : p->fromdomain, p->tag);
+ /* If we're calling a registred SIP peer, use the fullcontact to dial to the peer */
if (!ast_strlen_zero(p->fullcontact)) {
/* If we have full contact, trust it */
strncpy(invite, p->fullcontact, sizeof(invite) - 1);
+ /* Otherwise, use the username while waiting for registration */
} else if (!ast_strlen_zero(p->username)) {
if (ntohs(p->sa.sin_port) != DEFAULT_SIP_PORT) {
snprintf(invite, sizeof(invite), "sip:%s@%s:%d",p->username, p->tohost, ntohs(p->sa.sin_port));
@@ -3782,7 +3793,7 @@ static int transmit_invite(struct sip_pvt *p, char *cmd, int sdp, char *auth, ch
#endif
if (distinctive_ring && !ast_strlen_zero(distinctive_ring))
{
- add_header(&req, "Alert-info",distinctive_ring);
+ add_header(&req, "Alert-Info",distinctive_ring);
}
add_header(&req, "Allow", ALLOWED_METHODS);
if (sdp) {
@@ -3846,6 +3857,8 @@ static int transmit_state_notify(struct sip_pvt *p, int state, int full)
}
mto = c;
+ add_header(&req, "Event", "presence");
+ add_header(&req, "Subscription-State", "active");
add_header(&req, "Content-Type", "application/xpidf+xml");
if ((state==AST_EXTENSION_UNAVAILABLE) || (state==AST_EXTENSION_BUSY))
@@ -3872,7 +3885,7 @@ static int transmit_state_notify(struct sip_pvt *p, int state, int full)
bytes = snprintf(t, maxbytes, "<atom id=\"%s\">\n", p->exten);
t += bytes;
maxbytes -= bytes;
- bytes = snprintf(t, maxbytes, "<address uri=\"%s;user=ip\" priority=\"0,800000\">\n", mto);
+ bytes = snprintf(t, maxbytes, "<address uri=\"%s;user=ip\" priority=\"0.800000\">\n", mto);
t += bytes;
maxbytes -= bytes;
bytes = snprintf(t, maxbytes, "<status status=\"%s\" />\n", !state ? "open" : (state==1) ? "inuse" : "closed");
@@ -3928,8 +3941,8 @@ static int transmit_notify_with_mwi(struct sip_pvt *p, int newmsgs, int oldmsgs)
add_header(&req, "Event", "message-summary");
add_header(&req, "Content-Type", notifymime);
- snprintf(tmp, sizeof(tmp), "Messages-Waiting: %s\n", newmsgs ? "yes" : "no");
- snprintf(tmp2, sizeof(tmp2), "Voicemail: %d/%d\n", newmsgs, oldmsgs);
+ snprintf(tmp, sizeof(tmp), "Messages-Waiting: %s\r\n", newmsgs ? "yes" : "no");
+ snprintf(tmp2, sizeof(tmp2), "Voice-Message: %d/%d\r\n", newmsgs, oldmsgs);
snprintf(clen, sizeof(clen), "%d", (int)(strlen(tmp) + strlen(tmp2)));
add_header(&req, "Content-Length", clen);
add_line(&req, tmp);
@@ -3957,7 +3970,7 @@ static int transmit_notify_with_sipfrag(struct sip_pvt *p, int cseq)
struct sip_request req;
char tmp[256];
char clen[20];
- initreqprep(&req, p, "NOTIFY", NULL);
+ reqprep(&req, p, "NOTIFY", 0, 1);
snprintf(tmp, sizeof(tmp), "refer;id=%d", cseq);
add_header(&req, "Event", tmp);
add_header(&req, "Subscription-state", "terminated;reason=noresource");
@@ -4009,6 +4022,10 @@ static int sip_reregister(void *data)
{
/* if we are here, we know that we need to reregister. */
struct sip_registry *r=(struct sip_registry *)data;
+
+ if (sipdebug)
+ ast_log(LOG_NOTICE, " -- Re-registration for %s@%s\n", r->username, r->hostname);
+
ast_mutex_lock(&regl.lock);
r->expire = -1;
__sip_do_register(r);
@@ -4027,12 +4044,15 @@ static int __sip_do_register(struct sip_registry *r)
/*--- sip_reg_timeout: Registration timeout, register again */
static int sip_reg_timeout(void *data)
{
+
/* if we are here, our registration timed out, so we'll just do it over */
struct sip_registry *r=data;
struct sip_pvt *p;
int res;
+
ast_mutex_lock(&regl.lock);
- ast_log(LOG_NOTICE, "Registration for '%s@%s' timed out, trying again\n", r->username, r->hostname);
+
+ ast_log(LOG_NOTICE, " -- Registration for '%s@%s' timed out, trying again\n", r->username, r->hostname);
if (r->call) {
/* Unlink us, destroy old call. Locking is not relevent here because all this happens
in the single SIP manager thread. */
@@ -4040,16 +4060,18 @@ static int sip_reg_timeout(void *data)
p->registry = NULL;
r->call = NULL;
p->needdestroy = 1;
+ /* Pretend to ACK anything just in case */
+ __sip_pretend_ack(p);
}
r->regstate=REG_STATE_UNREGISTERED;
- manager_event(EVENT_FLAG_SYSTEM, "Registry", "Channel: SIP\r\nDomain: %s\r\nStatus: %s\r\n", r->hostname, regstate2str(r->regstate));
+ manager_event(EVENT_FLAG_SYSTEM, "Registry", "Channel: SIP\r\nUser: %s\r\nDomain: %s\r\nStatus: %s\r\n", r->username, r->hostname, regstate2str(r->regstate));
r->timeout = -1;
res=transmit_register(r, "REGISTER", NULL, NULL);
ast_mutex_unlock(&regl.lock);
return 0;
}
-/*--- transmit_register: Transmit register to SIP proxy ---*/
+/*--- transmit_register: Transmit register to SIP proxy or UA ---*/
static int transmit_register(struct sip_registry *r, char *cmd, char *auth, char *authheader)
{
struct sip_request req;
@@ -4074,41 +4096,57 @@ static int transmit_register(struct sip_registry *r, char *cmd, char *auth, char
} else
p = r->call;
} else {
+ /* Build callid for registration if we haven't registred before */
if (!r->callid_valid) {
build_callid(r->callid, sizeof(r->callid), __ourip, default_fromdomain);
r->callid_valid = 1;
}
+ /* Allocate SIP packet for registration */
p=sip_alloc( r->callid, NULL, 0);
if (!p) {
ast_log(LOG_WARNING, "Unable to allocate registration call\n");
return 0;
}
+ /* Find address to hostname */
if (create_addr(p,r->hostname)) {
- sip_destroy(p);
+ /* we have what we hope is a temporary network error,
+ * probably DNS. We need to reschedule a registration try */
+ sip_destroy(p);
+ if (r->timeout > -1) {
+ ast_log(LOG_WARNING, "Still have a registration timeout (create_addr() error), %d\n", r->timeout);
+ ast_sched_del(sched, r->timeout);
+ }
+ r->timeout = ast_sched_add(sched, 20*1000, sip_reg_timeout, r);
+
return 0;
}
+
/* Copy back Call-ID in case create_addr changed it */
strncpy(r->callid, p->callid, sizeof(r->callid) - 1);
if (r->portno)
p->sa.sin_port = htons(r->portno);
- p->outgoing = 1;
- r->call=p;
- p->registry=r;
- if (!ast_strlen_zero(r->secret))
+ p->outgoing = 1; /* Registration is outgoing call */
+ r->call=p; /* Save pointer to SIP packet */
+ p->registry=r; /* Add pointer to registry in packet */
+ if (!ast_strlen_zero(r->secret)) /* Secret (password) */
strncpy(p->peersecret, r->secret, sizeof(p->peersecret)-1);
if (!ast_strlen_zero(r->md5secret))
strncpy(p->peermd5secret, r->md5secret, sizeof(p->peermd5secret)-1);
- if (!ast_strlen_zero(r->authuser)) {
+ /* User name in this realm
+ - if authuser is set, use that, otherwise use username */
+ if (!ast_strlen_zero(r->authuser)) {
strncpy(p->peername, r->authuser, sizeof(p->peername)-1);
strncpy(p->authname, r->authuser, sizeof(p->authname)-1);
} else {
if (!ast_strlen_zero(r->username)) {
strncpy(p->peername, r->username, sizeof(p->peername)-1);
strncpy(p->authname, r->username, sizeof(p->authname)-1);
+ strncpy(p->fromuser, r->username, sizeof(p->fromuser)-1);
}
}
if (!ast_strlen_zero(r->username))
strncpy(p->username, r->username, sizeof(p->username)-1);
+ /* Save extension in packet */
strncpy(p->exten, r->contact, sizeof(p->exten) - 1);
/*
@@ -4124,11 +4162,11 @@ static int transmit_register(struct sip_registry *r, char *cmd, char *auth, char
/* set up a timeout */
if (auth==NULL) {
if (r->timeout > -1) {
- ast_log(LOG_WARNING, "Still have a timeout, %d\n", r->timeout);
+ ast_log(LOG_WARNING, "Still have a registration timeout, %d\n", r->timeout);
ast_sched_del(sched, r->timeout);
}
r->timeout = ast_sched_add(sched, 20*1000, sip_reg_timeout, r);
- ast_log(LOG_DEBUG, "Scheduled a timeout # %d\n", r->timeout);
+ ast_log(LOG_DEBUG, "Scheduled a registration timeout # %d\n", r->timeout);
}
if (strchr(r->username, '@')) {
@@ -4153,6 +4191,7 @@ static int transmit_register(struct sip_registry *r, char *cmd, char *auth, char
memset(&req, 0, sizeof(req));
init_req(&req, cmd, addr);
+ /* Add to CSEQ */
snprintf(tmp, sizeof(tmp), "%u %s", ++r->ocseq, cmd);
p->ocseq = r->ocseq;
@@ -4167,8 +4206,27 @@ static int transmit_register(struct sip_registry *r, char *cmd, char *auth, char
add_header(&req, "Call-ID", p->callid);
add_header(&req, "CSeq", tmp);
add_header(&req, "User-Agent", default_useragent);
- if (auth)
+
+
+ if (auth) /* Add auth header */
add_header(&req, authheader, auth);
+ else if ( !ast_strlen_zero(r->nonce) ) {
+ char digest[1024];
+
+ /* We have auth data to reuse, build a digest header! */
+ if (sipdebug)
+ ast_log(LOG_DEBUG, " >>> Re-using Auth data for %s@%s\n", r->username, r->hostname);
+ strncpy(p->realm, r->realm, sizeof(p->realm)-1);
+ strncpy(p->nonce, r->nonce, sizeof(p->nonce)-1);
+ strncpy(p->domain, r->domain, sizeof(p->domain)-1);
+ strncpy(p->opaque, r->opaque, sizeof(p->opaque)-1);
+ strncpy(p->qop, r->qop, sizeof(p->qop)-1);
+
+ memset(digest,0,sizeof(digest));
+ build_reply_digest(p, "REGISTER", digest, sizeof(digest));
+ add_header(&req, "Authorization", digest);
+
+ }
snprintf(tmp, sizeof(tmp), "%d", default_expiry);
add_header(&req, "Expires", tmp);
@@ -4263,6 +4321,7 @@ static int transmit_request_with_auth(struct sip_pvt *p, char *msg, int seqno, i
if (*p->realm)
{
char digest[1024];
+
memset(digest,0,sizeof(digest));
build_reply_digest(p, msg, digest, sizeof(digest));
add_header(&resp, "Proxy-Authorization", digest);
@@ -4347,8 +4406,9 @@ static void reg_source_db(struct sip_peer *p)
strncpy(p->username, u, sizeof(p->username) - 1);
}
- ast_verbose(VERBOSE_PREFIX_3 "SIP Seeding '%s' at %s@%s:%d for %d\n", p->name,
- p->username, ast_inet_ntoa(iabuf, sizeof(iabuf), in), atoi(c), atoi(d));
+ if (option_verbose > 2)
+ ast_verbose(VERBOSE_PREFIX_3 "SIP Seeding '%s' at %s@%s:%d for %d\n", p->name,
+ p->username, ast_inet_ntoa(iabuf, sizeof(iabuf), in), atoi(c), atoi(d));
expiry = atoi(d);
memset(&p->addr, 0, sizeof(p->addr));
p->addr.sin_family = AF_INET;
@@ -4372,6 +4432,7 @@ static void reg_source_db(struct sip_peer *p)
}
}
+
/*--- parse_contact: Parse contact header and save registration ---*/
static int parse_contact(struct sip_pvt *pvt, struct sip_peer *p, struct sip_request *req)
{
@@ -4524,7 +4585,7 @@ static void list_route(struct sip_route *route)
}
}
-/*--- build_route: Build route headers ---*/
+/*--- build_route: Build route list from Record-Route header ---*/
static void build_route(struct sip_pvt *p, struct sip_request *req, int backwards)
{
struct sip_route *thishop, *head, *tail;
@@ -4716,8 +4777,9 @@ static int check_auth(struct sip_pvt *p, struct sip_request *req, char *randdata
char tmp[256] = "";
char *c;
char *z;
- char *response ="";
+ char *ua_hash ="";
char *resp_uri ="";
+ char *nonce = "";
/* Find their response among the mess that we'r sent for comparison */
strncpy(tmp, authtoken, sizeof(tmp) - 1);
@@ -4730,12 +4792,12 @@ static int check_auth(struct sip_pvt *p, struct sip_request *req, char *randdata
if (!strncasecmp(c, "response=", strlen("response="))) {
c+= strlen("response=");
if ((*c == '\"')) {
- response=++c;
+ ua_hash=++c;
if((c = strchr(c,'\"')))
*c = '\0';
} else {
- response=c;
+ ua_hash=c;
if((c = strchr(c,',')))
*c = '\0';
}
@@ -4752,31 +4814,52 @@ static int check_auth(struct sip_pvt *p, struct sip_request *req, char *randdata
*c = '\0';
}
+ } else if (!strncasecmp(c, "nonce=", strlen("nonce=")))
+{
+ c+= strlen("nonce=");
+ if ((*c == '\"')) {
+ nonce=++c;
+ if ((c = strchr(c,'\"')))
+ *c = '\0';
+ } else {
+ nonce=c;
+ if ((c = strchr(c,',')))
+ *c = '\0';
+ }
} else
if ((z = strchr(c,' ')) || (z = strchr(c,','))) c=z;
if (c)
c++;
}
- snprintf(a1, sizeof(a1), "%s:%s:%s", username, global_realm, secret);
- if(!ast_strlen_zero(resp_uri))
- snprintf(a2, sizeof(a2), "%s:%s", method, resp_uri);
- else
- snprintf(a2, sizeof(a2), "%s:%s", method, uri);
- if (!ast_strlen_zero(md5secret))
- snprintf(a1_hash, sizeof(a1_hash), "%s", md5secret);
- else
- md5_hash(a1_hash, a1);
- md5_hash(a2_hash, a2);
- snprintf(resp, sizeof(resp), "%s:%s:%s", a1_hash, randdata, a2_hash);
- md5_hash(resp_hash, resp);
-
- /* resp_hash now has the expected response, compare the two */
+ /* Check if the nonce the client sends is the same as we are testing authentication with */
+ if (strncasecmp(randdata, nonce, randlen)) {
+ ast_log(LOG_WARNING, "Stale nonce received from '%s'\n", get_header(req, "To"));
+ snprintf(randdata, randlen, "%08x", rand());
+ transmit_response_with_auth(p, response, req, randdata, reliable, respheader);
+ /* Schedule auto destroy in 15 seconds */
+ sip_scheddestroy(p, 15000);
+ return 1;
+ } else {
+ snprintf(a1, sizeof(a1), "%s:%s:%s", username, global_realm, secret);
+ if(!ast_strlen_zero(resp_uri))
+ snprintf(a2, sizeof(a2), "%s:%s", method, resp_uri);
+ else
+ snprintf(a2, sizeof(a2), "%s:%s", method, uri);
+ if (!ast_strlen_zero(md5secret))
+ snprintf(a1_hash, sizeof(a1_hash), "%s", md5secret);
+ else
+ md5_hash(a1_hash, a1);
+ md5_hash(a2_hash, a2);
+ snprintf(resp, sizeof(resp), "%s:%s:%s", a1_hash, randdata, a2_hash);
+ md5_hash(resp_hash, resp);
+
+ /* resp_hash now has the expected response, compare the two */
- if (response && !strncasecmp(response, resp_hash, strlen(resp_hash))) {
- /* Auth is OK */
- res = 0;
+ if (ua_hash && !strncasecmp(ua_hash, resp_hash, strlen(resp_hash))) {
+ /* Auth is OK */
+ return 0;
+ }
}
- /* Assume success ;-) */
}
return res;
}
@@ -5110,9 +5193,13 @@ static int get_refer_info(struct sip_pvt *p, struct sip_request *oreq)
p2 = p2->next;
}
ast_mutex_unlock(&iflock);
- if (p->refer_call)
- return 0;
- else
+ if (p->refer_call) {
+ if (p->refer_call == p) {
+ ast_log(LOG_NOTICE, "Supervised transfer attempted to transfer into same call id (%s == %s)!\n", tmp5, p->callid);
+ p->refer_call = NULL;
+ } else
+ return 0;
+ } else
ast_log(LOG_NOTICE, "Supervised transfer requested, but unable to find callid '%s'\n", tmp5);
} else if (ast_exists_extension(NULL, p->context, c, 1, NULL) || !strcmp(c, ast_parking_ext())) {
/* This is an unsupervised transfer */
@@ -5193,7 +5280,7 @@ static int check_via(struct sip_pvt *p, struct sip_request *req)
c++;
while(*c && (*c < 33))
c++;
- if (strcmp(via, "SIP/2.0/UDP")) {
+ if (strcasecmp(via, "SIP/2.0/UDP")) {
ast_log(LOG_WARNING, "Don't know how to respond via '%s'\n", via);
return -1;
}
@@ -5292,7 +5379,8 @@ static int get_rpid_num(char *input,char *output, int maxlen)
end = strchr(output,'@');
if (end)
*end = '\0';
-
+ else
+ output[0] = '\0';
if(strstr(input,"privacy=full") || strstr(input,"privacy=uri"))
return 1;
@@ -5358,7 +5446,8 @@ static int check_user_full(struct sip_pvt *p, struct sip_request *req, char *cmd
ast_mutex_lock(&userl.lock);
user = find_user(of);
/* Find user based on user name in the from header */
- if (user && ast_apply_ha(user->ha, sin)) {
+ if (!mailbox && user && ast_apply_ha(user->ha, sin)) {
+ p->prefs = user->prefs;
p->nat = user->nat;
#ifdef OSP_SUPPORT
p->ospauth = user->ospauth;
@@ -5414,7 +5503,7 @@ static int check_user_full(struct sip_pvt *p, struct sip_request *req, char *cmd
if (user && debug)
ast_verbose("Found user '%s'\n", user->name);
} else {
- if (user && debug)
+ if (!mailbox && user && debug)
ast_verbose("Found user '%s', but fails host access\n", user->name);
user = NULL;
}
@@ -5460,7 +5549,7 @@ static int check_user_full(struct sip_pvt *p, struct sip_request *req, char *cmd
p->peersecret[sizeof(p->peersecret)-1] = '\0';
strncpy(p->peermd5secret, peer->md5secret, sizeof(p->peermd5secret)-1);
p->peermd5secret[sizeof(p->peermd5secret)-1] = '\0';
- if (peer->insecure > 1) {
+ if (peer->insecure & SIP_INSECURE_INVITE) {
/* Pretend there is no required authentication if insecure is "very" */
p->peersecret[0] = '\0';
p->peermd5secret[0] = '\0';
@@ -5480,6 +5569,7 @@ static int check_user_full(struct sip_pvt *p, struct sip_request *req, char *cmd
strncpy(p->context, peer->context, sizeof(p->context) - 1);
strncpy(p->peersecret, peer->secret, sizeof(p->peersecret) - 1);
strncpy(p->peermd5secret, peer->md5secret, sizeof(p->peermd5secret) - 1);
+ strncpy(p->language, peer->language, sizeof(p->language) -1);
p->callgroup = peer->callgroup;
p->pickupgroup = peer->pickupgroup;
p->capability = peer->capability;
@@ -5608,7 +5698,23 @@ static char *nat2str(int nat)
return "Unknown";
}
}
-
+
+static char *insecure2str(int insecure)
+{
+ switch (insecure) {
+ case SIP_SECURE:
+ return "No";
+ case SIP_INSECURE_PORT:
+ return "port";
+ case SIP_INSECURE_INVITE:
+ return "invite";
+ case SIP_INSECURE_BOTH:
+ return "port,invite";
+ default:
+ return "Unknown";
+ }
+}
+
/*--- sip_show_users: CLI Command 'SIP Show Users' ---*/
static int sip_show_users(int fd, int argc, char *argv[])
{
@@ -5726,6 +5832,9 @@ static int sip_show_peer(int fd, int argc, char *argv[])
char status[30] = "";
char iabuf[INET_ADDRSTRLEN];
struct sip_peer *peer;
+ char codec_buf[512];
+ struct ast_codec_pref *pref;
+ int x = 0, codec = 0;
if (argc != 4)
return RESULT_SHOWUSAGE;
@@ -5747,9 +5856,9 @@ static int sip_show_peer(int fd, int argc, char *argv[])
ast_cli(fd, " Mailbox : %s\n", peer->mailbox);
ast_cli(fd, " LastMsgsSent : %d\n", peer->lastmsgssent);
ast_cli(fd, " Dynamic : %s\n", (peer->dynamic?"Yes":"No"));
- ast_cli(fd, " Expire : %d\n", peer->expire);
+ ast_cli(fd, " Expire : %ld seconds\n", ast_sched_when(sched,peer->expire));
ast_cli(fd, " Expiry : %d\n", peer->expiry);
- ast_cli(fd, " Insecure : %s\n", (peer->insecure?((peer->insecure == 2)?"Very":"Yes"):"No") );
+ ast_cli(fd, " Insecure : %s\n", insecure2str(peer->insecure));
ast_cli(fd, " Nat : %s\n", nat2str(peer->nat));
ast_cli(fd, " ACL : %s\n", (peer->ha?"Yes":"No"));
ast_cli(fd, " CanReinvite : %s\n", (peer->canreinvite?"Yes":"No"));
@@ -5770,38 +5879,23 @@ static int sip_show_peer(int fd, int argc, char *argv[])
ast_cli(fd, " Defaddr->IP : %s Port %d\n", ast_inet_ntoa(iabuf, sizeof(iabuf), peer->defaddr.sin_addr), ntohs(peer->defaddr.sin_port));
ast_cli(fd, " Username : %s\n", peer->username);
ast_cli(fd, " Codecs : ");
- /* This should really be a function in frame.c */
- if (peer->capability & AST_FORMAT_G723_1)
- ast_cli(fd, "G723 ");
- if (peer->capability & AST_FORMAT_GSM)
- ast_cli(fd, "GSM ");
- if (peer->capability & AST_FORMAT_ULAW)
- ast_cli(fd, "ULAW ");
- if (peer->capability & AST_FORMAT_ALAW)
- ast_cli(fd, "ALAW ");
- if (peer->capability & AST_FORMAT_G726)
- ast_cli(fd, "G.726 ");
- if (peer->capability & AST_FORMAT_SLINEAR)
- ast_cli(fd, "SLINR ");
- if (peer->capability & AST_FORMAT_LPC10)
- ast_cli(fd, "LPC10 ");
- if (peer->capability & AST_FORMAT_ADPCM)
- ast_cli(fd, "ADPCM ");
- if (peer->capability & AST_FORMAT_G729A)
- ast_cli(fd, "G.729A ");
- if (peer->capability & AST_FORMAT_SPEEX)
- ast_cli(fd, "SPEEX ");
- if (peer->capability & AST_FORMAT_ILBC)
- ast_cli(fd, "ILBC ");
- if (peer->capability & AST_FORMAT_JPEG)
- ast_cli(fd, "JPEG ");
- if (peer->capability & AST_FORMAT_PNG)
- ast_cli(fd, "PNG ");
- if (peer->capability & AST_FORMAT_H261)
- ast_cli(fd, "H.261 ");
- if (peer->capability & AST_FORMAT_H263)
- ast_cli(fd, "H.263 ");
- ast_cli(fd, "\n");
+ ast_getformatname_multiple(codec_buf, sizeof(codec_buf) -1, peer->capability);
+ ast_cli(fd, "%s\n", codec_buf);
+ ast_cli(fd, " Codec Order : (");
+ pref = &peer->prefs;
+ for(x = 0; x < 32 ; x++) {
+ codec = ast_codec_pref_index(pref,x);
+ if(!codec)
+ break;
+ ast_cli(fd, "%s", ast_getformatname(codec));
+ if(x < 31 && ast_codec_pref_index(pref,x+1))
+ ast_cli(fd, "|");
+ }
+
+ if (!x)
+ ast_cli(fd, "none");
+ ast_cli(fd, ")\n");
+
ast_cli(fd, " Status : ");
if (peer->lastms < 0)
strncpy(status, "UNREACHABLE", sizeof(status) - 1);
@@ -6042,7 +6136,8 @@ static void receive_info(struct sip_pvt *p, struct sip_request *req)
char *c;
/* Need to check the media/type */
- if (!strcasecmp(get_header(req, "Content-Type"), "application/dtmf-relay")) {
+ if ( (!strcasecmp(get_header(req, "Content-Type"), "application/vnd.nortelnetworks.digits")) ||
+ (!strcasecmp(get_header(req, "Content-Type"), "application/dtmf-relay")) ) {
/* Try getting the "signal=" part */
if (ast_strlen_zero(c = get_sdp(req, "Signal")) && ast_strlen_zero(c = get_sdp(req, "d"))) {
@@ -6061,6 +6156,8 @@ static void receive_info(struct sip_pvt *p, struct sip_request *req)
event = 10;
else if (buf[0] == '#')
event = 11;
+ else if ((buf[0] >= 'A') && (buf[0] <= 'D'))
+ event = 12 + buf[0] - 'A';
else
event = atoi(buf);
if (event < 10) {
@@ -6210,27 +6307,34 @@ static int sip_no_debug(int fd, int argc, char *argv[])
static int reply_digest(struct sip_pvt *p, struct sip_request *req, char *header, char *respheader, char *digest, int digest_len);
-/*--- do_register_auth: Challenge for registration ---*/
+/*--- do_register_auth: Authenticate for outbound registration ---*/
static int do_register_auth(struct sip_pvt *p, struct sip_request *req, char *header, char *respheader) {
char digest[1024];
p->authtries++;
memset(digest,0,sizeof(digest));
- if (reply_digest(p,req, header, "REGISTER", digest, sizeof(digest))) {
+ if (reply_digest(p, req, header, "REGISTER", digest, sizeof(digest))) {
/* There's nothing to use for authentication */
+ /* No digest challenge in request */
+ if (sip_debug_test_pvt(p))
+ ast_verbose("No authentication challenge, sending blank registration to domain/host name %s\n", p->registry->hostname);
+ /* No old challenge */
return -1;
}
+ if (sip_debug_test_pvt(p))
+ ast_verbose("Responding to challenge, registration to domain/host name %s\n", p->registry->hostname);
return transmit_register(p->registry,"REGISTER",digest, respheader);
}
-/*--- do_proxy_auth: Challenge user ---*/
+/*--- do_proxy_auth: Add authentication on outbound SIP packet ---*/
static int do_proxy_auth(struct sip_pvt *p, struct sip_request *req, char *header, char *respheader, char *msg, int init) {
char digest[1024];
p->authtries++;
memset(digest,0,sizeof(digest));
- if (reply_digest(p,req, header, msg, digest, sizeof(digest) )) {
+ if (reply_digest(p, req, header, msg, digest, sizeof(digest) )) {
/* No way to authenticate */
return -1;
}
+ /* Now we have a reply digest */
return transmit_invite(p,msg,!strcasecmp(msg, "INVITE"),digest, respheader, NULL,NULL,NULL, init);
}
@@ -6326,6 +6430,17 @@ static int reply_digest(struct sip_pvt *p, struct sip_request *req, char *header
strncpy(p->domain, domain, sizeof(p->domain)-1);
strncpy(p->opaque, opaque, sizeof(p->opaque)-1);
strncpy(p->qop, qop, sizeof(p->qop)-1);
+
+ /* Save auth data for following registrations */
+ if (p->registry) {
+ struct sip_registry *r = p->registry;
+
+ strncpy(r->realm, p->realm, sizeof(r->realm)-1);
+ strncpy(r->nonce, p->nonce, sizeof(r->nonce)-1);
+ strncpy(r->domain, p->domain, sizeof(r->domain)-1);
+ strncpy(r->opaque, p->opaque, sizeof(r->opaque)-1);
+ strncpy(r->qop, p->qop, sizeof(r->qop)-1);
+ }
build_reply_digest(p, orig_header, digest, digest_len);
return 0;
}
@@ -6370,7 +6485,7 @@ static int build_reply_digest(struct sip_pvt *p, char* orig_header, char* digest
md5_hash(resp_hash,resp);
/* XXX We hard code our qop to "auth" for now. XXX */
if (!ast_strlen_zero(p->qop))
- snprintf(digest,digest_len,"Digest username=\"%s\", realm=\"%s\", algorithm=MD5, uri=\"%s\", nonce=\"%s\", response=\"%s\", opaque=\"%s\", qop=\"%s\", cnonce=\"%s\", nc=%s",p->authname,p->realm,uri,p->nonce,resp_hash, p->opaque, "auth", cnonce, "00000001");
+ snprintf(digest,digest_len,"Digest username=\"%s\", realm=\"%s\", algorithm=MD5, uri=\"%s\", nonce=\"%s\", response=\"%s\", opaque=\"%s\", qop=auth, cnonce=\"%s\", nc=00000001",p->authname,p->realm,uri,p->nonce,resp_hash, p->opaque, cnonce);
else
snprintf(digest,digest_len,"Digest username=\"%s\", realm=\"%s\", algorithm=MD5, uri=\"%s\", nonce=\"%s\", response=\"%s\", opaque=\"%s\"",p->authname,p->realm,uri,p->nonce,resp_hash, p->opaque);
@@ -6432,7 +6547,7 @@ static char no_history_usage[] =
static char history_usage[] =
"Usage: sip history\n"
" Enables recording of SIP dialog history for debugging purposes.\n"
-"Use 'sip show hitory' to view the history of a call number.\n";
+"Use 'sip show history' to view the history of a call number.\n";
static char sip_reload_usage[] =
"Usage: sip reload\n"
@@ -6487,6 +6602,9 @@ static void parse_moved_contact(struct sip_pvt *p, struct sip_request *req)
char *s, *e;
strncpy(tmp, get_header(req, "Contact"), sizeof(tmp) - 1);
s = ditch_braces(tmp);
+ e = strchr(s, ';');
+ if (e)
+ *e = '\0';
if (p->promiscredir) {
if (!strncasecmp(s, "sip:", 4))
s += 4;
@@ -6511,6 +6629,7 @@ static void parse_moved_contact(struct sip_pvt *p, struct sip_request *req)
}
}
+/*--- check_pendings: Check pending actions on SIP call ---*/
static void check_pendings(struct sip_pvt *p)
{
/* Go ahead and send bye at this point */
@@ -6553,7 +6672,7 @@ static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_
__sip_ack(p, seqno, 0, msg);
/* Get their tag if we haven't already */
to = get_header(req, "To");
- to = strstr(to, "tag=");
+ to = ast_strcasestr(to, "tag=");
if (to) {
to += 4;
strncpy(p->theirtag, to, sizeof(p->theirtag) - 1);
@@ -6660,6 +6779,7 @@ static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_
sip_cancel_destroy(p);
if (!ast_strlen_zero(get_header(req, "Content-Type")))
process_sdp(p, req);
+
/* Save Record-Route for any later requests we make on this dialogue */
build_route(p, req, 1);
if (p->owner) {
@@ -6727,24 +6847,30 @@ static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_
if (!expires) expires=atoi(get_header(req, "expires"));
if (!expires) expires=default_expiry;
+
expires_ms = expires * 1000;
if (expires <= EXPIRY_GUARD_LIMIT)
expires_ms -= MAX((expires_ms * EXPIRY_GUARD_PCT),EXPIRY_GUARD_MIN);
else
expires_ms -= EXPIRY_GUARD_SECS * 1000;
+ if (sipdebug)
+ ast_log(LOG_NOTICE, "Outbound Registration: Expiry for %s is %d sec (Scheduling reregistration in %d ms)\n", r->hostname, expires, expires_ms);
r->refresh= (int) expires_ms / 1000;
+
+ /* Schedule re-registration before we expire */
r->expire=ast_sched_add(sched, expires_ms, sip_reregister, r);
} else
ast_log(LOG_WARNING, "Got 200 OK on REGISTER that isn't a register\n");
}
break;
- case 401: /* Not authorized on REGISTER */
+ case 401: /* Not www-authorized on REGISTER */
if (!strcasecmp(msg, "INVITE")) {
/* First we ACK */
transmit_request(p, "ACK", seqno, 0, 0);
/* Then we AUTH */
+ p->theirtag[0]='\0'; /* forget their old tag, so we don't match tags when getting response */
if ((p->authtries > 1) || do_proxy_auth(p, req, "WWW-Authenticate", "Authorization", "INVITE", 1)) {
ast_log(LOG_NOTICE, "Failed to authenticate on INVITE to '%s'\n", get_header(&p->initreq, "From"));
p->needdestroy = 1;
@@ -6757,6 +6883,21 @@ static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_
} else
p->needdestroy = 1;
break;
+ case 403: /* Forbidden - we failed authentication */
+ if (!strcasecmp(msg, "INVITE")) {
+ /* First we ACK */
+ transmit_request(p, "ACK", seqno, 0, 0);
+ ast_log(LOG_WARNING, "Forbidden - wrong password on authentication for INVITE to '%s'\n", get_header(&p->initreq, "From"));
+ if (owner)
+ ast_queue_control(p->owner, AST_CONTROL_CONGESTION);
+ p->needdestroy = 1;
+ } else if (p->registry && !strcasecmp(msg, "REGISTER")) {
+ ast_log(LOG_WARNING, "Forbidden - wrong password on authentication for REGISTER for '%s' to '%s'\n", p->registry->username, p->registry->hostname);
+ p->needdestroy = 1;
+ } else {
+ ast_log(LOG_WARNING, "Forbidden - wrong password on authentication for %s\n", msg);
+ }
+ break;
case 407:
if (!strcasecmp(msg, "INVITE")) {
/* First we ACK */
@@ -6764,6 +6905,7 @@ static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_
/* Then we AUTH */
/* But only if the packet wasn't marked as ignore in handle_request */
if(!ignore){
+ p->theirtag[0]='\0'; /* forget their old tag, so we don't match tags when getting response */
if ((p->authtries > 1) || do_proxy_auth(p, req, "Proxy-Authenticate", "Proxy-Authorization", "INVITE", 1)) {
ast_log(LOG_NOTICE, "Failed to authenticate on INVITE to '%s'\n", get_header(&p->initreq, "From"));
p->needdestroy = 1;
@@ -6860,8 +7002,18 @@ static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_
p->alreadygone = 1;
if (!p->owner)
p->needdestroy = 1;
+ } else if ((resp >= 100) && (resp < 200)) {
+ if (!strcasecmp(msg, "INVITE")) {
+ sip_cancel_destroy(p);
+ if (!ast_strlen_zero(get_header(req, "Content-Type")))
+ process_sdp(p, req);
+ if (p->owner) {
+ /* Queue a progress frame */
+ ast_queue_control(p->owner, AST_CONTROL_PROGRESS);
+ }
+ }
} else
- ast_log(LOG_NOTICE, "Dunno anything about a %d %s response from %s\n", resp, rest, p->owner ? p->owner->name : ast_inet_ntoa(iabuf, sizeof(iabuf), p->sa.sin_addr));
+ ast_log(LOG_NOTICE, "Don't know anything about a %d %s response from %s\n", resp, rest, p->owner ? p->owner->name : ast_inet_ntoa(iabuf, sizeof(iabuf), p->sa.sin_addr));
}
} else {
if (sip_debug_test_pvt(p))
@@ -6973,38 +7125,73 @@ static int sip_park(struct ast_channel *chan1, struct ast_channel *chan2, struct
return -1;
}
+static void ast_quiet_chan(struct ast_channel *chan) {
+ if(chan && chan->_state == AST_STATE_UP) {
+ if(chan->generatordata)
+ ast_deactivate_generator(chan);
+ }
+}
/*--- attempt_transfer: Attempt transfer of SIP call ---*/
static int attempt_transfer(struct sip_pvt *p1, struct sip_pvt *p2)
{
+ int res = 0;
+ struct ast_channel
+ *chana = NULL,
+ *chanb = NULL,
+ *bridgea = NULL,
+ *bridgeb = NULL,
+ *peera = NULL,
+ *peerb = NULL,
+ *peerc = NULL,
+ *peerd = NULL;
+
if (!p1->owner || !p2->owner) {
ast_log(LOG_WARNING, "Transfer attempted without dual ownership?\n");
return -1;
}
- if (p1->owner->bridge) {
- if (p2->owner->bridge)
- ast_moh_stop(p2->owner->bridge);
- ast_moh_stop(p1->owner->bridge);
- ast_moh_stop(p1->owner);
- ast_moh_stop(p2->owner);
- if (ast_channel_masquerade(p2->owner, p1->owner->bridge)) {
- ast_log(LOG_WARNING, "Failed to masquerade %s into %s\n", p2->owner->name, p1->owner->bridge->name);
- return -1;
- }
- } else if (p2->owner->bridge) {
- ast_moh_stop(p2->owner->bridge);
- ast_moh_stop(p2->owner);
- ast_moh_stop(p1->owner);
- if (ast_channel_masquerade(p1->owner, p2->owner->bridge)) {
- ast_log(LOG_WARNING, "Failed to masquerade %s into %s\n", p1->owner->name, p2->owner->bridge->name);
- return -1;
- }
+ chana = p1->owner;
+ chanb = p2->owner;
+ bridgea = p1->owner->bridge;
+ bridgeb = p2->owner->bridge;
+
+ if (bridgea) {
+ peera = chana;
+ peerb = chanb;
+ peerc = bridgea;
+ peerd = bridgeb;
+ } else if(bridgeb) {
+ peera = chanb;
+ peerb = chana;
+ peerc = bridgeb;
+ peerd = bridgea;
+ }
+
+ if(peera && peerb && peerc && (peerb != peerc)) {
+ ast_quiet_chan(peera);
+ ast_quiet_chan(peerb);
+ ast_quiet_chan(peerc);
+ ast_quiet_chan(peerd);
+
+ if (peera->cdr && peerb->cdr) {
+ peerb->cdr = ast_cdr_append(peerb->cdr, peera->cdr);
+ } else if(peera->cdr) {
+ peerb->cdr = peera->cdr;
+ }
+ peera->cdr = NULL;
+
+ if (peerb->cdr && peerc->cdr) {
+ peerb->cdr = ast_cdr_append(peerb->cdr, peerc->cdr);
+ } else if(peerc->cdr) {
+ peerb->cdr = peerc->cdr;
+ }
+ peerc->cdr = NULL;
+ if (ast_channel_masquerade(peerb, peerc)) {
+ ast_log(LOG_WARNING, "Failed to masquerade %s into %s\n", peerb->name, peerc->name);
+ res = -1;
+ }
+ return res;
} else {
- ast_log(LOG_NOTICE, "Transfer attempted with no bridged calls to transfer\n");
- if (p1->owner)
- ast_softhangup_nolock(p1->owner, AST_SOFTHANGUP_DEV);
- if (p2->owner)
- ast_softhangup_nolock(p2->owner, AST_SOFTHANGUP_DEV);
return -1;
}
return 0;
@@ -7066,7 +7253,7 @@ static int handle_request(struct sip_pvt *p, struct sip_request *req, struct soc
if (p->icseq && (p->icseq > seqno)) {
ast_log(LOG_DEBUG, "Ignoring too old packet packet %d (expecting >= %d)\n", seqno, p->icseq);
return -1;
- } else if (p->icseq && (p->icseq == seqno)) {
+ } else if (p->icseq && (p->icseq == seqno) && (strcasecmp(cmd, "CANCEL") || p->alreadygone)) {
/* ignore means "don't do anything with it" but still have to
respond appropriately. We do this if we receive a repeat of
the last sequence number */
@@ -7074,7 +7261,7 @@ static int handle_request(struct sip_pvt *p, struct sip_request *req, struct soc
}
if (ast_strlen_zero(p->theirtag)) {
from = get_header(req, "From");
- from = strstr(from, "tag=");
+ from = ast_strcasestr(from, "tag=");
if (from) {
from += 4;
strncpy(p->theirtag, from, sizeof(p->theirtag) - 1);
@@ -7132,7 +7319,6 @@ static int handle_request(struct sip_pvt *p, struct sip_request *req, struct soc
/* We do NOT destroy p here, so that our response will be accepted */
return 0;
}
- /* Process the SDP portion */
if (!ignore) {
/* Use this as the basis */
if (debug)
@@ -7144,19 +7330,22 @@ static int handle_request(struct sip_pvt *p, struct sip_request *req, struct soc
p->pendinginvite = seqno;
copy_request(&p->initreq, req);
check_via(p, req);
- if (!ast_strlen_zero(get_header(req, "Content-Type"))) {
- if (process_sdp(p, req))
- return -1;
- } else {
- p->jointcapability = p->capability;
- ast_log(LOG_DEBUG, "Hm.... No sdp for the moment\n");
+ if (p->owner) {
+ /* Handle SDP here if we already have an owner */
+ if (!ast_strlen_zero(get_header(req, "Content-Type"))) {
+ if (process_sdp(p, req)) {
+ transmit_response(p, "488 Not acceptable here", req);
+ p->needdestroy = 1;
+ return -1;
+ }
+ } else {
+ p->jointcapability = p->capability;
+ ast_log(LOG_DEBUG, "Hm.... No sdp for the moment\n");
+ }
}
- /* Queue NULL frame to prod ast_rtp_bridge if appropriate */
- if (p->owner)
- ast_queue_frame(p->owner, &af);
} else if (debug)
ast_verbose("Ignoring this request\n");
- if (!p->lastinvite) {
+ if (!p->lastinvite && !ignore && !p->owner) {
/* Handle authentication if this is our first invite */
res = check_user(p, req, cmd, e, 1, sin, ignore);
if (res) {
@@ -7170,6 +7359,20 @@ static int handle_request(struct sip_pvt *p, struct sip_request *req, struct soc
}
return 0;
}
+ /* Process the SDP portion */
+ if (!ast_strlen_zero(get_header(req, "Content-Type"))) {
+ if (process_sdp(p, req)) {
+ transmit_response(p, "488 Not acceptable here", req);
+ p->needdestroy = 1;
+ return -1;
+ }
+ } else {
+ p->jointcapability = p->capability;
+ ast_log(LOG_DEBUG, "Hm.... No sdp for the moment\n");
+ }
+ /* Queue NULL frame to prod ast_rtp_bridge if appropriate */
+ if (p->owner)
+ ast_queue_frame(p->owner, &af);
/* Initialize the context if it hasn't been already */
if (ast_strlen_zero(p->context))
strncpy(p->context, default_context, sizeof(p->context) - 1);
@@ -7282,12 +7485,20 @@ static int handle_request(struct sip_pvt *p, struct sip_request *req, struct soc
}
} else {
if (p && !p->needdestroy) {
- ast_log(LOG_NOTICE, "Unable to create/find channel\n");
- if (ignore)
- transmit_response(p, "503 Unavailable", req);
- else
- transmit_response_reliable(p, "503 Unavailable", req, 1);
- p->needdestroy = 1;
+ if (!p->jointcapability) {
+ if (ignore)
+ transmit_response(p, "488 Not Acceptable Here", req);
+ else
+ transmit_response_reliable(p, "488 Not Acceptable Here", req, 1);
+ p->needdestroy = 1;
+ } else {
+ ast_log(LOG_NOTICE, "Unable to create/find channel\n");
+ if (ignore)
+ transmit_response(p, "503 Unavailable", req);
+ else
+ transmit_response_reliable(p, "503 Unavailable", req, 1);
+ p->needdestroy = 1;
+ }
}
}
} else if (!strcasecmp(cmd, "REFER")) {
@@ -7407,12 +7618,17 @@ static int handle_request(struct sip_pvt *p, struct sip_request *req, struct soc
p->needdestroy = 1;
transmit_response(p, "200 OK", req);
} else if (!strcasecmp(cmd, "MESSAGE")) {
- if (!ignore) {
- if (debug)
- ast_verbose("Receiving message!\n");
- receive_message(p, req);
+ if (p->lastinvite) {
+ if (!ignore) {
+ if (debug)
+ ast_verbose("Receiving message!\n");
+ receive_message(p, req);
+ }
+ transmit_response(p, "200 OK", req);
+ } else {
+ transmit_response(p, "405 Method Not Allowed", req);
+ p->needdestroy = 1;
}
- transmit_response(p, "200 OK", req);
} else if (!strcasecmp(cmd, "SUBSCRIBE")) {
if (!ignore) {
/* Use this as the basis */
@@ -7427,8 +7643,8 @@ static int handle_request(struct sip_pvt *p, struct sip_request *req, struct soc
if (!p->lastinvite) {
char mailbox[256]="";
- char rbox[256];
int found = 0;
+
/* Handle authentication if this is our first subscribe */
res = check_user_full(p, req, cmd, e, 0, sin, ignore, mailbox, sizeof(mailbox));
if (res) {
@@ -7457,21 +7673,33 @@ static int handle_request(struct sip_pvt *p, struct sip_request *req, struct soc
p->subscribed = 2;
else if (!strcmp(get_header(req, "Accept"), "application/simple-message-summary")) {
/* Looks like they actually want a mailbox */
- snprintf(rbox, sizeof(rbox), ",%s@%s,", p->exten, p->context);
- if (strstr(mailbox, rbox))
+
+ /* At this point, we should check if they subscribe to a mailbox that
+ has the same extension as the peer or the mailbox id. If we configure
+ the context to be the same as a SIP domain, we could check mailbox
+ context as well. To be able to securely accept subscribes on mailbox
+ IDs, not extensions, we need to check the digest auth user to make
+ sure that the user has access to the mailbox.
+
+ Since we do not act on this subscribe anyway, we might as well
+ accept any authenticated peer with a mailbox definition in their
+ config section.
+
+ */
+ if (!ast_strlen_zero(mailbox)) {
found++;
- if (!found) {
- snprintf(rbox, sizeof(rbox), ",%s,", p->exten);
- if (strstr(mailbox, rbox))
- found++;
}
- if (found)
+
+ if (found) {
transmit_response(p, "200 OK", req);
- else {
+ p->needdestroy = 1;
+ } else {
transmit_response(p, "403 Forbidden", req);
p->needdestroy = 1;
}
-
+
+ return 0;
+
} else
p->subscribed = 1;
if (p->subscribed)
@@ -7484,19 +7712,29 @@ static int handle_request(struct sip_pvt *p, struct sip_request *req, struct soc
if (!ignore && p)
p->lastinvite = seqno;
if (p && !p->needdestroy) {
- if (!(p->expiry = atoi(get_header(req, "Expires")))) {
+ if (!(p->expiry = atoi(get_header(req, "Expires")))) {
+ transmit_response(p, "200 OK", req);
+ p->needdestroy = 1;
+ return 0;
+ }
+ /* The next line can be removed if the SNOM200 Expires bug is fixed */
+ if (p->subscribed == 1) {
+ if (p->expiry>max_expiry) {
+ p->expiry = max_expiry;
+ }
+ }
+ /* Go ahead and free RTP port */
+ if (p->rtp) {
+ ast_rtp_destroy(p->rtp);
+ p->rtp = NULL;
+ }
+ if (p->vrtp) {
+ ast_rtp_destroy(p->vrtp);
+ p->vrtp = NULL;
+ }
transmit_response(p, "200 OK", req);
- p->needdestroy = 1;
- return 0;
- }
- /* The next line can be removed if the SNOM200 Expires bug is fixed */
- if (p->subscribed == 1) {
- if (p->expiry>max_expiry)
- p->expiry = max_expiry;
- }
- transmit_response(p, "200 OK", req);
- sip_scheddestroy(p, (p->expiry+10)*1000);
- transmit_state_notify(p, ast_extension_state(NULL, p->context, p->exten),1);
+ sip_scheddestroy(p, (p->expiry+10)*1000);
+ transmit_state_notify(p, ast_extension_state(NULL, p->context, p->exten),1);
}
} else if (!strcasecmp(cmd, "INFO")) {
if (!ignore) {
@@ -7520,6 +7758,15 @@ static int handle_request(struct sip_pvt *p, struct sip_request *req, struct soc
if ((res = register_verify(p, sin, req, e, ignore)) < 0)
ast_log(LOG_NOTICE, "Registration from '%s' failed for '%s'\n", get_header(req, "To"), ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr));
if (res < 1) {
+ /* Go ahead and free RTP port */
+ if (p->rtp) {
+ ast_rtp_destroy(p->rtp);
+ p->rtp = NULL;
+ }
+ if (p->vrtp) {
+ ast_rtp_destroy(p->vrtp);
+ p->vrtp = NULL;
+ }
/* Destroy the session, but keep us around for just a bit in case they don't
get our 200 OK */
sip_scheddestroy(p, 15*1000);
@@ -7584,8 +7831,7 @@ static int sipsock_read(int *id, int fd, short events, void *ignore)
debug = sip_debug_test_addr(&sin);
if (debug)
ast_verbose("\n\nSip read: \n%s\n", req.data);
- if (pedanticsipchecking)
- req.len = lws2sws(req.data, req.len);
+ req.len = lws2sws(req.data, req.len);
parse(&req);
if (debug)
ast_verbose("%d headers, %d lines\n", req.headers, req.lines);
@@ -7850,6 +8096,8 @@ static int sip_poke_noanswer(void *data)
}
/*--- sip_poke_peer: Check availability of peer, also keep NAT open ---*/
+/* This is done with the interval in qualify= option in sip.conf */
+/* Default is 2 seconds */
static int sip_poke_peer(struct sip_peer *peer)
{
struct sip_pvt *p;
@@ -7875,6 +8123,12 @@ static int sip_poke_peer(struct sip_peer *peer)
}
memcpy(&p->sa, &peer->addr, sizeof(p->sa));
memcpy(&p->recv, &peer->addr, sizeof(p->sa));
+
+ /* Send options to peer's fullcontact */
+ if (!ast_strlen_zero(peer->fullcontact)) {
+ strncpy (p->fullcontact, peer->fullcontact, sizeof(p->fullcontact));
+ }
+
if (!ast_strlen_zero(p->tohost))
strncpy(p->tohost, peer->tohost, sizeof(p->tohost) - 1);
else
@@ -8011,8 +8265,15 @@ static struct ast_channel *sip_request(char *type, int format, void *data)
else /* UNIDEN bug */
snprintf(p->via, sizeof(p->via), "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport, p->branch);
build_callid(p->callid, sizeof(p->callid), p->ourip, p->fromdomain);
- if (ext)
+
+ /* We have an extension to call, don't use the full contact here */
+ /* This to enable dialling registred peers with extension dialling,
+ like SIP/peername/extension
+ SIP/peername will still use the full contact */
+ if (ext) {
strncpy(p->username, ext, sizeof(p->username) - 1);
+ p->fullcontact[0] = 0;
+ }
#if 0
printf("Setting up to call extension '%s' at '%s'\n", ext ? ext : "<none>", host);
#endif
@@ -8027,6 +8288,33 @@ static struct ast_channel *sip_request(char *type, int format, void *data)
return tmpc;
}
+static int parse_insecure(char *varval)
+{
+ int insecure = 0;
+
+ if (!strcasecmp(varval, "very"))
+ insecure = SIP_INSECURE_BOTH;
+ else if (ast_true(varval))
+ insecure = SIP_INSECURE_PORT;
+ else if (!ast_false(varval)) {
+ char buf[64];
+ char *word, *next;
+
+ strncpy(buf, varval, sizeof(buf)-1);
+ next = buf;
+ while ((word = strsep(&next, ","))) {
+ if (!strcasecmp(word, "port"))
+ insecure |= SIP_INSECURE_PORT;
+ else if (!strcasecmp(word, "invite"))
+ insecure |= SIP_INSECURE_INVITE;
+ else
+ ast_log(LOG_WARNING, "Unknown insecure mode '%s'\n", varval);
+ }
+ }
+
+ return insecure;
+}
+
/*--- build_user: Initiate a SIP user structure from sip.conf ---*/
static struct sip_user *build_user(char *name, struct ast_variable *v)
{
@@ -8047,6 +8335,8 @@ static struct sip_user *build_user(char *name, struct ast_variable *v)
user->trustrpid = global_trustrpid;
user->dtmfmode = global_dtmfmode;
user->progressinband = global_progressinband;
+ user->nat = global_nat;
+ user->prefs = prefs;
#ifdef OSP_SUPPORT
user->ospauth = global_ospauth;
#endif
@@ -8120,19 +8410,11 @@ static struct sip_user *build_user(char *name, struct ast_variable *v)
user->amaflags = format;
}
} else if (!strcasecmp(v->name, "allow")) {
- format = ast_getformatbyname(v->value);
- if (format < 1)
- ast_log(LOG_WARNING, "Cannot allow unknown format '%s'\n", v->value);
- else
- user->capability |= format;
+ ast_parse_allow_disallow(&user->prefs, &user->capability, v->value, 1);
} else if (!strcasecmp(v->name, "disallow")) {
- format = ast_getformatbyname(v->value);
- if (format < 1)
- ast_log(LOG_WARNING, "Cannot disallow unknown format '%s'\n", v->value);
- else
- user->capability &= ~format;
+ ast_parse_allow_disallow(&user->prefs, &user->capability, v->value, 0);
} else if (!strcasecmp(v->name, "insecure")) {
- user->insecure = ast_true(v->value);
+ user->insecure = parse_insecure(v->value);
} else if (!strcasecmp(v->name, "restrictcid")) {
user->restrictcid = ast_true(v->value);
} else if (!strcasecmp(v->name, "trustrpid")) {
@@ -8165,6 +8447,9 @@ static struct sip_peer *temp_peer(char *name)
{
struct sip_peer *peer;
peer = malloc(sizeof(struct sip_peer));
+ if (!peer)
+ return NULL;
+
memset(peer, 0, sizeof(struct sip_peer));
peer->expire = -1;
peer->pokeexpire = -1;
@@ -8187,6 +8472,7 @@ static struct sip_peer *temp_peer(char *name)
peer->dynamic = 1;
peer->trustrpid = global_trustrpid;
peer->progressinband = global_progressinband;
+ peer->prefs = prefs;
#ifdef OSP_SUPPORT
peer->ospauth = global_ospauth;
#endif
@@ -8201,7 +8487,6 @@ static struct sip_peer *build_peer(char *name, struct ast_variable *v)
struct sip_peer *prev;
struct ast_ha *oldha = NULL;
int maskfound=0;
- int format;
int found=0;
prev = NULL;
ast_mutex_lock(&peerl.lock);
@@ -8225,22 +8510,34 @@ static struct sip_peer *build_peer(char *name, struct ast_variable *v)
} else {
ast_mutex_unlock(&peerl.lock);
peer = malloc(sizeof(struct sip_peer));
- memset(peer, 0, sizeof(struct sip_peer));
- peer->expire = -1;
- peer->pokeexpire = -1;
+ if (peer) {
+ memset(peer, 0, sizeof(struct sip_peer));
+ peer->expire = -1;
+ peer->pokeexpire = -1;
+ }
}
- peer->lastmsgssent = -1;
if (peer) {
+ peer->lastmsgssent = -1;
if (!found) {
strncpy(peer->name, name, sizeof(peer->name)-1);
- strncpy(peer->context, default_context, sizeof(peer->context)-1);
- strncpy(peer->language, default_language, sizeof(peer->language)-1);
- strncpy(peer->musicclass, global_musicclass, sizeof(peer->musicclass)-1);
- peer->addr.sin_port = htons(DEFAULT_SIP_PORT);
+ peer->addr.sin_port = htons(DEFAULT_SIP_PORT);
peer->addr.sin_family = AF_INET;
peer->defaddr.sin_family = AF_INET;
peer->expiry = expiry;
}
+ strncpy(peer->context, default_context, sizeof(peer->context)-1);
+ strncpy(peer->language, default_language, sizeof(peer->language)-1);
+ strncpy(peer->musicclass, global_musicclass, sizeof(peer->musicclass)-1);
+ peer->secret[0] = '\0';
+ peer->md5secret[0] = '\0';
+ peer->fromdomain[0] = '\0';
+ peer->fromuser[0] = '\0';
+ peer->regexten[0] = '\0';
+ peer->mailbox[0] = '\0';
+ peer->callgroup = 0;
+ peer->pickupgroup = 0;
+ peer->maxms = 0;
+ peer->prefs = prefs;
oldha = peer->ha;
peer->ha = NULL;
peer->addr.sin_family = AF_INET;
@@ -8353,24 +8650,11 @@ static struct sip_peer *build_peer(char *name, struct ast_variable *v)
} else if (!strcasecmp(v->name, "pickupgroup")) {
peer->pickupgroup = ast_get_group(v->value);
} else if (!strcasecmp(v->name, "allow")) {
- format = ast_getformatbyname(v->value);
- if (format < 1)
- ast_log(LOG_WARNING, "Cannot allow unknown format '%s'\n", v->value);
- else
- peer->capability |= format;
+ ast_parse_allow_disallow(&peer->prefs, &peer->capability, v->value, 1);
} else if (!strcasecmp(v->name, "disallow")) {
- format = ast_getformatbyname(v->value);
- if (format < 1)
- ast_log(LOG_WARNING, "Cannot disallow unknown format '%s'\n", v->value);
- else
- peer->capability &= ~format;
+ ast_parse_allow_disallow(&peer->prefs, &peer->capability, v->value, 0);
} else if (!strcasecmp(v->name, "insecure")) {
- if (!strcasecmp(v->value, "very")) {
- peer->insecure = 2;
- } else if (ast_true(v->value))
- peer->insecure = 1;
- else
- peer->insecure = 0;
+ peer->insecure = parse_insecure(v->value);
} else if (!strcasecmp(v->name, "rtptimeout")) {
if ((sscanf(v->value, "%d", &peer->rtptimeout) != 1) || (peer->rtptimeout < 0)) {
ast_log(LOG_WARNING, "'%s' is not a valid RTP hold time at line %d. Using default.\n", v->value, v->lineno);
@@ -8427,7 +8711,7 @@ static int reload_config(void)
struct sip_user *user;
struct ast_hostent ahp;
char *cat;
- char *utype;
+ char *utype;
struct hostent *hp;
int format;
int oldport = ntohs(bindaddr.sin_port);
@@ -8436,10 +8720,6 @@ static int reload_config(void)
global_dtmfmode = SIP_DTMF_RFC2833;
global_promiscredir = 0;
- if (gethostname(ourhost, sizeof(ourhost))) {
- ast_log(LOG_WARNING, "Unable to get hostname, SIP disabled\n");
- return 0;
- }
cfg = ast_load(config);
/* We *must* have a config file otherwise stop immediately */
@@ -8450,11 +8730,10 @@ static int reload_config(void)
global_nat = SIP_NAT_RFC3581;
- sip_prefs_free();
-
memset(&bindaddr, 0, sizeof(bindaddr));
memset(&localaddr, 0, sizeof(localaddr));
memset(&externip, 0, sizeof(externip));
+ memset(&prefs, 0 , sizeof(struct ast_codec_pref));
/* Initialize some reasonable defaults */
strncpy(default_context, "default", sizeof(default_context) - 1);
@@ -8585,21 +8864,9 @@ static int reload_config(void)
else
memcpy(&externip.sin_addr, hp->h_addr, sizeof(externip.sin_addr));
} else if (!strcasecmp(v->name, "allow")) {
- format = ast_getformatbyname(v->value);
- if (format < 1)
- ast_log(LOG_WARNING, "Cannot allow unknown format '%s'\n", v->value);
- else {
- global_capability |= format;
- sip_pref_append(format);
- }
+ ast_parse_allow_disallow(&prefs, &global_capability, v->value, 1);
} else if (!strcasecmp(v->name, "disallow")) {
- format = ast_getformatbyname(v->value);
- if (format < 1)
- ast_log(LOG_WARNING, "Cannot disallow unknown format '%s'\n", v->value);
- else {
- global_capability &= ~format;
- sip_pref_remove(format);
- }
+ ast_parse_allow_disallow(&prefs, &global_capability, v->value, 0);
} else if (!strcasecmp(v->name, "register")) {
sip_register(v->value, v->lineno);
} else if (!strcasecmp(v->name, "recordhistory")) {
@@ -8673,19 +8940,11 @@ static int reload_config(void)
cat = ast_category_browse(cfg, cat);
}
- if (ntohl(bindaddr.sin_addr.s_addr)) {
- memcpy(&__ourip, &bindaddr.sin_addr, sizeof(__ourip));
- } else {
- hp = ast_gethostbyname(ourhost, &ahp);
- if (!hp) {
- ast_log(LOG_WARNING, "Unable to get IP address for %s, SIP disabled\n", ourhost);
- if (!__ourip.s_addr) {
- ast_destroy(cfg);
- return 0;
- }
- } else
- memcpy(&__ourip, hp->h_addr, sizeof(__ourip));
- }
+ if (ast_find_ourip(&__ourip, bindaddr)) {
+ ast_log(LOG_WARNING, "Unable to get own IP address, SIP disabled\n");
+ return 0;
+ }
+
if (!ntohs(bindaddr.sin_port))
bindaddr.sin_port = ntohs(DEFAULT_SIP_PORT);
bindaddr.sin_family = AF_INET;
@@ -8771,6 +9030,7 @@ static struct ast_rtp *sip_get_vrtp_peer(struct ast_channel *chan)
return rtp;
}
+/*--- sip_set_rtp_peer: Set the RTP peer for this call ---*/
static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, int codecs)
{
struct sip_pvt *p;
@@ -8942,20 +9202,31 @@ static void prune_peers(void)
ast_mutex_unlock(&peerl.lock);
}
+/* Send all of our registrations, spaced out to avoid suicide*/
+static void sip_send_all_registers(void)
+{
+ struct sip_registry *reg;
+ int ms;
+ ast_mutex_lock(&regl.lock);
+ for (reg = regl.registrations; reg; reg = reg->next) {
+ if (reg->expire > -1)
+ ast_sched_del(sched, reg->expire);
+ ms = (rand() >> 12) & 0x1fff;
+ reg->expire = ast_sched_add(sched, ms, sip_reregister, reg);
+ }
+ ast_mutex_unlock(&regl.lock);
+}
+
/*--- sip_do_reload: Reload module */
static int sip_do_reload(void)
{
- struct sip_registry *reg;
struct sip_peer *peer;
delete_users();
reload_config();
-
prune_peers();
- /* And start the monitor for the first time */
- ast_mutex_lock(&regl.lock);
- for (reg = regl.registrations; reg; reg = reg->next)
- __sip_do_register(reg);
- ast_mutex_unlock(&regl.lock);
+
+ sip_send_all_registers();
+
ast_mutex_lock(&peerl.lock);
for (peer = peerl.peers; peer; peer = peer->next)
sip_poke_peer(peer);
@@ -8991,11 +9262,10 @@ int load_module()
{
int res;
struct sip_peer *peer;
- struct sip_registry *reg;
- ast_mutex_init(&userl.lock);
- ast_mutex_init(&peerl.lock);
- ast_mutex_init(&regl.lock);
+ ast_mutex_init(&userl.lock);
+ ast_mutex_init(&peerl.lock);
+ ast_mutex_init(&regl.lock);
sched = sched_context_create();
if (!sched) {
ast_log(LOG_WARNING, "Unable to create schedule context\n");
@@ -9004,7 +9274,8 @@ int load_module()
if (!io) {
ast_log(LOG_WARNING, "Unable to create I/O context\n");
}
-
+
+
res = reload_config();
if (!res) {
/* Make sure we can register our sip channel type */
@@ -9039,11 +9310,8 @@ int load_module()
sip_poke_peer(peer);
ast_mutex_unlock(&peerl.lock);
- ast_mutex_lock(&regl.lock);
- for (reg = regl.registrations; reg; reg = reg->next)
- __sip_do_register(reg);
- ast_mutex_unlock(&regl.lock);
-
+ sip_send_all_registers();
+
/* And start the monitor for the first time */
restart_monitor();
}
@@ -9127,7 +9395,9 @@ int unload_module()
ast_mutex_destroy(&userl.lock);
ast_mutex_destroy(&peerl.lock);
ast_mutex_destroy(&regl.lock);
-
+
+ close(sipsock);
+
return 0;
}
diff --git a/channels/chan_skinny.c b/channels/chan_skinny.c
index c58315b4d..98d9d86d8 100755
--- a/channels/chan_skinny.c
+++ b/channels/chan_skinny.c
@@ -1576,19 +1576,22 @@ static int skinny_answer(struct ast_channel *ast)
static struct ast_frame *skinny_rtp_read(struct skinny_subchannel *sub)
{
/* Retrieve audio/etc from channel. Assumes sub->lock is already held. */
- struct ast_frame *f;
- f = ast_rtp_read(sub->rtp);
- if (sub->owner) {
- /* We already hold the channel lock */
- if (f->frametype == AST_FRAME_VOICE) {
- if (f->subclass != sub->owner->nativeformats) {
- ast_log(LOG_DEBUG, "Oooh, format changed to %d\n", f->subclass);
- sub->owner->nativeformats = f->subclass;
- ast_set_read_format(sub->owner, sub->owner->readformat);
- ast_set_write_format(sub->owner, sub->owner->writeformat);
+ struct ast_frame *f = NULL;
+ if (sub->rtp) {
+ f = ast_rtp_read(sub->rtp);
+ if (sub->owner) {
+ /* We already hold the channel lock */
+ if (f->frametype == AST_FRAME_VOICE) {
+ if (f->subclass != sub->owner->nativeformats) {
+ ast_log(LOG_DEBUG, "Oooh, format changed to %d\n", f->subclass);
+ sub->owner->nativeformats = f->subclass;
+ ast_set_read_format(sub->owner, sub->owner->readformat);
+ ast_set_write_format(sub->owner, sub->owner->writeformat);
+ }
}
}
- }
+ } else
+ ast_log(LOG_WARNING, "sub->rtp is NULL - calling read on a channel that has been hungup?\n");
return f;
}
@@ -1700,7 +1703,7 @@ static int skinny_indicate(struct ast_channel *ast, int ind)
}
switch(ind) {
case AST_CONTROL_RINGING:
- if (ast->_state == AST_STATE_RINGING) {
+ if (ast->_state != AST_STATE_UP) {
if (!sub->progress) {
transmit_tone(s, SKINNY_ALERT);
transmit_callstate(s, l->instance, SKINNY_RINGOUT, sub->callid);
@@ -2278,7 +2281,7 @@ static void destroy_session(struct skinnysession *s)
ast_mutex_destroy(&s->lock);
free(s);
} else
- ast_log(LOG_WARNING, "Trying to delete non-existant session %p?\n", s);
+ ast_log(LOG_WARNING, "Trying to delete nonexistent session %p?\n", s);
ast_mutex_unlock(&sessionlock);
}
diff --git a/channels/chan_zap.c b/channels/chan_zap.c
index b4149cfc9..f09553a1f 100755
--- a/channels/chan_zap.c
+++ b/channels/chan_zap.c
@@ -69,6 +69,12 @@
#error "Your zaptel is too old. please cvs update"
#endif
+#ifndef ZT_TONEDETECT
+/* Work around older code with no tone detect */
+#define ZT_EVENT_DTMFDOWN 0
+#define ZT_EVENT_DTMFUP 0
+#endif
+
/*
* Define ZHONE_HACK to cause us to go off hook and then back on hook when
* the user hangs up to reset the state machine so ring works properly.
@@ -153,6 +159,8 @@ static char *config = "zapata.conf";
#define DCHAN_AVAILABLE (DCHAN_PROVISIONED | DCHAN_NOTINALARM | DCHAN_UP)
+#define zt_close(fd) if(fd > 0) close(fd);
+
static char context[AST_MAX_EXTENSION] = "default";
static char callerid[256] = "";
@@ -262,6 +270,9 @@ AST_MUTEX_DEFINE_STATIC(iflock);
static int ifcount = 0;
+/* When to send the CallerID signals (rings) */
+static int sendcalleridafter = DEFAULT_CIDRINGS;
+
/* Protect the monitoring thread, so only one process can kill or start it, and not
when it's doing something critical. */
AST_MUTEX_DEFINE_STATIC(monlock);
@@ -541,6 +552,7 @@ static struct zt_pvt {
int dtmfrelax; /* whether to run in relaxed DTMF mode */
int fake_event;
int zaptrcallerid; /* should we use the callerid from incoming call on zap transfer or not */
+ int sendcalleridafter;
#ifdef ZAPATA_PRI
struct zt_pri *pri;
struct zt_pvt *bearer;
@@ -552,6 +564,7 @@ static struct zt_pvt {
int logicalspan;
int alreadyhungup;
int proceeding;
+ int alerting;
int setup_ack; /* wheter we received SETUP_ACKNOWLEDGE or not */
#endif
#ifdef ZAPATA_R2
@@ -700,6 +713,8 @@ static void zap_queue_frame(struct zt_pvt *p, struct ast_frame *f, void *pri)
#endif
}
+static int restore_gains(struct zt_pvt *p);
+
static void swap_subs(struct zt_pvt *p, int a, int b)
{
int tchan;
@@ -758,7 +773,7 @@ static int zt_open(char *fn)
if (chan) {
if (ioctl(fd, ZT_SPECIFY, &chan)) {
x = errno;
- close(fd);
+ zt_close(fd);
errno = x;
ast_log(LOG_WARNING, "Unable to specify channel %d: %s\n", chan, strerror(errno));
return -1;
@@ -769,11 +784,6 @@ static int zt_open(char *fn)
return fd;
}
-static void zt_close(int fd)
-{
- close(fd);
-}
-
int zt_setlinear(int zfd, int linear)
{
int res;
@@ -1535,7 +1545,7 @@ static int zt_call(struct ast_channel *ast, char *rdest, int timeout)
} else {
if (ioctl(p->subs[SUB_REAL].zfd, ZT_SETCADENCE, NULL))
ast_log(LOG_WARNING, "Unable to reset default ring on '%s'\n", ast->name);
- p->cidrings = DEFAULT_CIDRINGS;
+ p->cidrings = p->sendcalleridafter;
}
@@ -1925,7 +1935,7 @@ int pri_find_dchan(struct zt_pri *pri)
}
if (newslot < 0) {
newslot = 0;
- ast_log(LOG_WARNING, "No D-channels available! Using Primary on channel anyway %d!\n",
+ ast_log(LOG_WARNING, "No D-channels available! Using Primary channel %d as D-channel anyway!\n",
pri->dchannels[newslot]);
}
if (old && (oldslot != newslot))
@@ -1940,7 +1950,6 @@ static int zt_hangup(struct ast_channel *ast)
{
int res;
int index,x, law;
- static int restore_gains(struct zt_pvt *p);
struct zt_pvt *p = ast->pvt->pvt;
struct zt_pvt *tmp = NULL;
struct zt_pvt *prev = NULL;
@@ -2085,6 +2094,7 @@ static int zt_hangup(struct ast_channel *ast)
p->onhooktime = time(NULL);
#ifdef ZAPATA_PRI
p->proceeding = 0;
+ p->alerting = 0;
p->setup_ack = 0;
#endif
if (p->dsp) {
@@ -2886,6 +2896,18 @@ static int attempt_transfer(struct zt_pvt *p)
if (p->subs[SUB_THREEWAY].owner->_state == AST_STATE_RINGING) {
ast_indicate(p->subs[SUB_REAL].owner->bridge, AST_CONTROL_RINGING);
}
+ if (p->subs[SUB_REAL].owner->cdr) {
+ /* Move CDR from second channel to current one */
+ p->subs[SUB_THREEWAY].owner->cdr =
+ ast_cdr_append(p->subs[SUB_THREEWAY].owner->cdr, p->subs[SUB_REAL].owner->cdr);
+ p->subs[SUB_REAL].owner->cdr = NULL;
+ }
+ if (p->subs[SUB_REAL].owner->bridge->cdr) {
+ /* Move CDR from second channel's bridge to current one */
+ p->subs[SUB_THREEWAY].owner->cdr =
+ ast_cdr_append(p->subs[SUB_THREEWAY].owner->cdr, p->subs[SUB_REAL].owner->bridge->cdr);
+ p->subs[SUB_REAL].owner->bridge->cdr = NULL;
+ }
if (ast_channel_masquerade(p->subs[SUB_THREEWAY].owner, p->subs[SUB_REAL].owner->bridge)) {
ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n",
p->subs[SUB_REAL].owner->bridge->name, p->subs[SUB_THREEWAY].owner->name);
@@ -2899,6 +2921,18 @@ static int attempt_transfer(struct zt_pvt *p)
ast_indicate(p->subs[SUB_THREEWAY].owner->bridge, AST_CONTROL_RINGING);
}
ast_moh_stop(p->subs[SUB_THREEWAY].owner->bridge);
+ if (p->subs[SUB_THREEWAY].owner->cdr) {
+ /* Move CDR from second channel to current one */
+ p->subs[SUB_REAL].owner->cdr =
+ ast_cdr_append(p->subs[SUB_REAL].owner->cdr, p->subs[SUB_THREEWAY].owner->cdr);
+ p->subs[SUB_THREEWAY].owner->cdr = NULL;
+ }
+ if (p->subs[SUB_THREEWAY].owner->bridge->cdr) {
+ /* Move CDR from second channel's bridge to current one */
+ p->subs[SUB_REAL].owner->cdr =
+ ast_cdr_append(p->subs[SUB_REAL].owner->cdr, p->subs[SUB_THREEWAY].owner->bridge->cdr);
+ p->subs[SUB_THREEWAY].owner->bridge->cdr = NULL;
+ }
if (ast_channel_masquerade(p->subs[SUB_REAL].owner, p->subs[SUB_THREEWAY].owner->bridge)) {
ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n",
p->subs[SUB_THREEWAY].owner->bridge->name, p->subs[SUB_REAL].owner->name);
@@ -3053,15 +3087,30 @@ static struct ast_frame *zt_handle_event(struct ast_channel *ast)
} else
res = zt_get_event(p->subs[index].zfd);
ast_log(LOG_DEBUG, "Got event %s(%d) on channel %d (index %d)\n", event2str(res), res, p->channel, index);
- if (res & (ZT_EVENT_PULSEDIGIT | ZT_EVENT_DTMFDIGIT)) {
+ if (res & (ZT_EVENT_PULSEDIGIT | ZT_EVENT_DTMFUP)) {
if (res & ZT_EVENT_PULSEDIGIT)
p->pulsedial = 1;
else
p->pulsedial = 0;
- ast_log(LOG_DEBUG, "Pulse dial '%c'\n", res & 0xff);
+ ast_log(LOG_DEBUG, "Detected %sdigit '%c'\n", p->pulsedial ? "pulse " : "", res & 0xff);
+#ifdef ZAPATA_PRI
+ if ((p->proceeding < 2) && p->sig==SIG_PRI && p->pri && p->pri->overlapdial) {
+ p->subs[index].f.frametype = AST_FRAME_NULL;
+ p->subs[index].f.subclass = 0;
+ }
+#endif
p->subs[index].f.frametype = AST_FRAME_DTMF;
p->subs[index].f.subclass = res & 0xff;
- /* Return the captured digit */
+ /* Unmute conference, return the captured digit */
+ zt_confmute(p, 0);
+ return &p->subs[index].f;
+ }
+ if (res & ZT_EVENT_DTMFDOWN) {
+ ast_log(LOG_DEBUG, "DTMF Down '%c'\n", res & 0xff);
+ p->subs[index].f.frametype = AST_FRAME_NULL;
+ p->subs[index].f.subclass = 0;
+ zt_confmute(p, 1);
+ /* Mute conference, return null frame */
return &p->subs[index].f;
}
switch(res) {
@@ -3425,7 +3474,7 @@ static struct ast_frame *zt_handle_event(struct ast_channel *ast)
#ifdef ZAPATA_PRI
/* Extremely unlikely but just in case */
if (p->bearer)
- p->bearer->inalarm = 1;
+ p->bearer->inalarm = 0;
#endif
ast_log(LOG_NOTICE, "Alarm cleared on channel %d\n", p->channel);
manager_event(EVENT_FLAG_SYSTEM, "AlarmClear",
@@ -4016,6 +4065,8 @@ struct ast_frame *zt_read(struct ast_channel *ast)
p->subs[index].f.subclass = AST_CONTROL_ANSWER;
ast_setstate(ast, AST_STATE_UP);
f = &p->subs[index].f;
+ /* Reset confirmanswer so DTMF's will behave properly for the duration of the call */
+ p->confirmanswer = 0;
} else if (p->callwaitcas) {
if ((f->subclass == 'A') || (f->subclass == 'D')) {
ast_log(LOG_DEBUG, "Got some DTMF, but it's for the CAS\n");
@@ -4033,13 +4084,15 @@ struct ast_frame *zt_read(struct ast_channel *ast)
if (!p->faxhandled) {
p->faxhandled++;
if (strcmp(ast->exten, "fax")) {
- if (ast_exists_extension(ast, ast->context, "fax", 1, ast->callerid)) {
+ char *target_context = ast_strlen_zero(ast->macrocontext) ? ast->context : ast->macrocontext;
+
+ if (ast_exists_extension(ast, target_context, "fax", 1, ast->callerid)) {
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "Redirecting %s to fax extension\n", ast->name);
/* Save the DID/DNIS when we transfer the fax call to a "fax" extension */
- pbx_builtin_setvar_helper(ast,"FAXEXTEN",ast->exten);
- if (ast_async_goto(ast, ast->context, "fax", 1))
- ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast->name, ast->context);
+ pbx_builtin_setvar_helper(ast, "FAXEXTEN", ast->exten);
+ if (ast_async_goto(ast, target_context, "fax", 1))
+ ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast->name, target_context);
} else
ast_log(LOG_NOTICE, "Fax detected, but no fax extension\n");
} else
@@ -4140,6 +4193,11 @@ static int zt_write(struct ast_channel *ast, struct ast_frame *frame)
ast_log(LOG_DEBUG, "Dropping frame since I'm still dialing on %s...\n",ast->name);
return 0;
}
+ if (!p->owner) {
+ if (option_debug)
+ ast_log(LOG_DEBUG, "Dropping frame since there is no active owner on %s...\n",ast->name);
+ return 0;
+ }
if (p->cidspill) {
if (option_debug)
ast_log(LOG_DEBUG, "Dropping frame since I've still got a callerid spill\n");
@@ -4199,7 +4257,7 @@ static int zt_indicate(struct ast_channel *chan, int condition)
break;
case AST_CONTROL_RINGING:
#ifdef ZAPATA_PRI
- if ((p->proceeding < 2) && p->sig==SIG_PRI && p->pri && !p->outgoing) {
+ if ((!p->alerting) && p->sig==SIG_PRI && p->pri && !p->outgoing && (chan->_state != AST_STATE_UP)) {
if (p->pri->pri) {
if (!pri_grab(p, p->pri)) {
pri_acknowledge(p->pri->pri,p->call, PVT_TO_CHANNEL(p), 1);
@@ -4208,7 +4266,7 @@ static int zt_indicate(struct ast_channel *chan, int condition)
else
ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
}
- p->proceeding=2;
+ p->alerting=1;
}
#endif
res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_RINGTONE);
@@ -4380,7 +4438,11 @@ static struct ast_channel *zt_new(struct zt_pvt *i, int state, int startpbx, int
(i->outgoing && (i->callprogress & 2))) {
features |= DSP_FEATURE_FAX_DETECT;
}
- features |= DSP_FEATURE_DTMF_DETECT;
+#ifdef ZT_TONEDETECT
+ x = ZT_TONEDETECT_ON | ZT_TONEDETECT_MUTE;
+ if (ioctl(i->subs[index].zfd, ZT_TONEDETECT, &x))
+#endif
+ features |= DSP_FEATURE_DTMF_DETECT;
if (features) {
if (i->dsp) {
ast_log(LOG_DEBUG, "Already have a dsp on %s?\n", tmp->name);
@@ -4603,6 +4665,13 @@ static void *ss_thread(void *data)
} else
break;
}
+ /* if no extension was received ('unspecified') on overlap call, use the 's' extension */
+ if (ast_strlen_zero(exten)) {
+ if (option_verbose > 2)
+ ast_verbose(VERBOSE_PREFIX_3 "Going to extension s|1 because of empty extension received on overlap call\n");
+ exten[0] = 's';
+ exten[1] = '\0';
+ }
tone_zone_play_tone(p->subs[index].zfd, -1);
if (ast_exists_extension(chan, chan->context, exten, 1, p->callerid)) {
/* Start the real PBX */
@@ -4617,6 +4686,9 @@ static void *ss_thread(void *data)
ast_log(LOG_DEBUG, "No such possible extension '%s' in context '%s'\n", exten, chan->context);
chan->hangupcause = AST_CAUSE_UNALLOCATED;
ast_hangup(chan);
+ p->exten[0] = '\0';
+ /* Since we send release complete here, we won't get one */
+ p->call = NULL;
}
return NULL;
break;
@@ -5018,9 +5090,11 @@ static void *ss_thread(void *data)
p->subs[SUB_THREEWAY].owner;
struct zt_pvt *pbridge = NULL;
/* set up the private struct of the bridged one, if any */
- if (nbridge && nbridge->bridge) pbridge = nbridge->bridge->pvt->pvt;
- if (nbridge &&
- (!strcmp(nbridge->type,"Zap")) &&
+ if (nbridge && nbridge->bridge)
+ pbridge = nbridge->bridge->pvt->pvt;
+ if (nbridge && pbridge &&
+ (!strcmp(nbridge->type,"Zap")) &&
+ (!strcmp(nbridge->bridge->type, "Zap")) &&
ISTRUNK(pbridge)) {
int func = ZT_FLASH;
/* Clear out the dial buffer */
@@ -6006,7 +6080,7 @@ static int pri_resolve_span(int *span, int channel, int offset, struct zt_spanin
return 0;
}
}
- ast_log(LOG_WARNING, "Channel %d on span %d configured to use non-existant trunk group %d\n", channel, *span, trunkgroup);
+ ast_log(LOG_WARNING, "Channel %d on span %d configured to use nonexistent trunk group %d\n", channel, *span, trunkgroup);
*span = -1;
} else {
if (pris[*span].trunkgroup) {
@@ -6056,7 +6130,7 @@ static int pri_create_trunkgroup(int trunkgroup, int *channels)
x = channels[y];
if (ioctl(fd, ZT_SPECIFY, &x)) {
ast_log(LOG_WARNING, "Failed to specify channel %d: %s\n", channels[y], strerror(errno));
- close(fd);
+ zt_close(fd);
return -1;
}
if (ioctl(fd, ZT_GET_PARAMS, &p)) {
@@ -6065,18 +6139,18 @@ static int pri_create_trunkgroup(int trunkgroup, int *channels)
}
if (ioctl(fd, ZT_SPANSTAT, &si)) {
ast_log(LOG_WARNING, "Failed go get span information on channel %d (span %d)\n", channels[y], p.spanno);
- close(fd);
+ zt_close(fd);
return -1;
}
span = p.spanno - 1;
if (pris[span].trunkgroup) {
ast_log(LOG_WARNING, "Span %d is already provisioned for trunk group %d\n", span + 1, pris[span].trunkgroup);
- close(fd);
+ zt_close(fd);
return -1;
}
if (pris[span].pvts[0]) {
ast_log(LOG_WARNING, "Span %d is already provisioned with channels (implicit PRI maybe?)\n", span + 1);
- close(fd);
+ zt_close(fd);
return -1;
}
if (!y) {
@@ -6087,7 +6161,7 @@ static int pri_create_trunkgroup(int trunkgroup, int *channels)
pris[ospan].dchannels[y] = channels[y];
pris[ospan].dchanavail[y] |= DCHAN_PROVISIONED;
pris[span].span = span + 1;
- close(fd);
+ zt_close(fd);
}
return 0;
}
@@ -6495,6 +6569,8 @@ static struct zt_pvt *mkintf(int channel, int signalling, int radio, struct zt_p
if (si.alarms) tmp->inalarm = 1;
}
+ tmp->sendcalleridafter = sendcalleridafter;
+
}
if (tmp && !here) {
/* nothing on the iflist */
@@ -6511,6 +6587,7 @@ static struct zt_pvt *mkintf(int channel, int signalling, int radio, struct zt_p
if (working->channel > tmp->channel) {
tmp->next = *wlist;
tmp->prev = NULL;
+ (*wlist)->prev = tmp;
*wlist = tmp;
} else {
/* go through all the members and put the member in the right place */
@@ -6636,7 +6713,7 @@ static inline int available(struct zt_pvt *p, int channelmatch, int groupmatch,
}
if ((p->owner->_state != AST_STATE_UP) &&
- (p->owner->_state != AST_STATE_RINGING)) {
+ ((p->owner->_state != AST_STATE_RINGING) || p->outgoing)) {
/* If the current call is not up, then don't allow the call */
return 0;
}
@@ -6898,6 +6975,8 @@ static struct ast_channel *zt_request(char *type, int format, void *data)
} else if (opt == 'd') {
/* If this is an ISDN call, make it digital */
p->digital = 1;
+ if (tmp)
+ ast_set_flag(tmp, AST_FLAG_DIGITAL);
} else {
ast_log(LOG_WARNING, "Unknown option '%c' in '%s'\n", opt, (char *)data);
}
@@ -7012,6 +7091,7 @@ static int pri_fixup_principle(struct zt_pri *pri, int principle, q931_call *c)
ast_log(LOG_WARNING, "Whoa, there's no owner, and we're having to fix up channel %d to channel %d\n", pri->pvts[x]->channel, pri->pvts[principle]->channel);
pri->pvts[principle]->call = pri->pvts[x]->call;
/* Free up the old channel, now not in use */
+ pri->pvts[x]->subs[SUB_REAL].owner = NULL;
pri->pvts[x]->owner = NULL;
pri->pvts[x]->call = NULL;
}
@@ -7030,7 +7110,7 @@ static int pri_fixup_principle(struct zt_pri *pri, int principle, q931_call *c)
else {
/* Looks good. Drop the pseudo channel now, clear up the assignment, and
wakeup the potential sleeper */
- close(crv->subs[SUB_REAL].zfd);
+ zt_close(crv->subs[SUB_REAL].zfd);
pri->pvts[principle]->call = crv->call;
pri_assign_bearer(crv, pri, pri->pvts[principle]);
ast_log(LOG_DEBUG, "Assigning bearer %d/%d to CRV %d:%d\n",
@@ -7103,8 +7183,7 @@ static void *do_idle_thread(void *vchan)
static void zt_pri_message(char *s)
{
- if (option_verbose)
- ast_verbose(s);
+ ast_verbose("%s", s);
}
static void zt_pri_error(char *s)
@@ -7355,7 +7434,7 @@ static void *pri_dchannel(void *vpri)
x = 0;
res = ioctl(pri->fds[which], ZT_GETEVENT, &x);
if (x)
- ast_log(LOG_NOTICE, "PRI got event: %d on %s D-channel of span %d\n", x, pri_order(which), pri->span);
+ ast_log(LOG_NOTICE, "PRI got event: %s (%d) on %s D-channel of span %d\n", event2str(x), x, pri_order(which), pri->span);
/* Keep track of alarm state */
if (x == ZT_EVENT_ALARM) {
pri->dchanavail[which] &= ~(DCHAN_NOTINALARM | DCHAN_UP);
@@ -7572,6 +7651,9 @@ static void *pri_dchannel(void *vpri)
strncpy(pri->pvts[chanpos]->dnid, e->ring.callednum, sizeof(pri->pvts[chanpos]->dnid) - 1);
} else
pri->pvts[chanpos]->exten[0] = '\0';
+ /* Set DNID on all incoming calls -- even immediate */
+ if (!ast_strlen_zero(e->ring.callednum))
+ strncpy(pri->pvts[chanpos]->dnid, e->ring.callednum, sizeof(pri->pvts[chanpos]->dnid) - 1);
/* No number yet, but received "sending complete"? */
if (e->ring.complete && (ast_strlen_zero(e->ring.callednum))) {
if (option_verbose > 2)
@@ -8033,13 +8115,13 @@ static int start_pri(struct zt_pri *pri)
}
res = ioctl(pri->fds[i], ZT_GET_PARAMS, &p);
if (res) {
- close(pri->fds[i]);
+ zt_close(pri->fds[i]);
pri->fds[i] = -1;
ast_log(LOG_ERROR, "Unable to get parameters for D-channel %d (%s)\n", x, strerror(errno));
return -1;
}
if (p.sigtype != ZT_SIG_HDLCFCS) {
- close(pri->fds[i]);
+ zt_close(pri->fds[i]);
pri->fds[i] = -1;
ast_log(LOG_ERROR, "D-channel %d is not in HDLC/FCS mode. See /etc/zaptel.conf\n", x);
return -1;
@@ -8047,7 +8129,7 @@ static int start_pri(struct zt_pri *pri)
memset(&si, 0, sizeof(si));
res = ioctl(pri->fds[i], ZT_SPANSTAT, &si);
if (res) {
- close(pri->fds[i]);
+ zt_close(pri->fds[i]);
pri->fds[i] = -1;
ast_log(LOG_ERROR, "Unable to get span state for D-channel %d (%s)\n", x, strerror(errno));
}
@@ -8061,7 +8143,7 @@ static int start_pri(struct zt_pri *pri)
bi.bufsize = 1024;
if (ioctl(pri->fds[i], ZT_SET_BUFINFO, &bi)) {
ast_log(LOG_ERROR, "Unable to set appropriate buffering on channel %d\n", x);
- close(pri->fds[i]);
+ zt_close(pri->fds[i]);
pri->fds[i] = -1;
return -1;
}
@@ -8074,7 +8156,7 @@ static int start_pri(struct zt_pri *pri)
if (i)
pri_enslave(pri->dchans[0], pri->dchans[i]);
if (!pri->dchans[i]) {
- close(pri->fds[i]);
+ zt_close(pri->fds[i]);
pri->fds[i] = -1;
ast_log(LOG_ERROR, "Unable to create PRI structure\n");
return -1;
@@ -8089,7 +8171,7 @@ static int start_pri(struct zt_pri *pri)
for (i=0;i<NUM_DCHANS;i++) {
if (!pri->dchannels[i])
break;
- close(pri->fds[i]);
+ zt_close(pri->fds[i]);
pri->fds[i] = -1;
}
ast_log(LOG_ERROR, "Unable to spawn D-channel: %s\n", strerror(errno));
@@ -8237,10 +8319,19 @@ static int handle_pri_show_span(int fd, int argc, char *argv[])
}
for(x=0;x<NUM_DCHANS;x++) {
if (pris[span-1].dchannels[x]) {
+ char *info_str = NULL;
ast_cli(fd, "%s D-channel: %d\n", pri_order(x), pris[span-1].dchannels[x]);
build_status(status, sizeof(status), pris[span-1].dchanavail[x], pris[span-1].dchans[x] == pris[span-1].pri);
ast_cli(fd, "Status: %s\n", status);
+#ifdef PRI_DUMP_INFO_STR
+ info_str = pri_dump_info_str(pris[span-1].pri);
+ if (info_str) {
+ ast_cli(fd, "%s", info_str);
+ free(info_str);
+ }
+#else
pri_dump_info(pris[span-1].pri);
+#endif
ast_cli(fd, "\n");
}
}
@@ -9563,6 +9654,8 @@ static int setup_zap(void)
cur_rxflash = atoi(v->value);
} else if (!strcasecmp(v->name, "debounce")) {
cur_debounce = atoi(v->value);
+ } else if (!strcasecmp(v->name, "sendcalleridafter")) {
+ sendcalleridafter = atoi(v->value);
} else
ast_log(LOG_WARNING, "Ignoring %s\n", v->name);
v = v->next;
diff --git a/channels/h323/.cvsignore b/channels/h323/.cvsignore
new file mode 100755
index 000000000..4671378ae
--- /dev/null
+++ b/channels/h323/.cvsignore
@@ -0,0 +1 @@
+.depend
diff --git a/channels/h323/Makefile b/channels/h323/Makefile
index 52004c1fd..1ccc8a657 100755
--- a/channels/h323/Makefile
+++ b/channels/h323/Makefile
@@ -64,7 +64,7 @@ CFLAGS += -I$(OPENH323DIR)/include
CFLAGS += -Wno-missing-prototypes -Wno-missing-declarations
LIBS+= -lcrypto -lssl -lexpat
-all: libchanh323.a
+all: depend libchanh323.a
samples:
if [ -f $(ASTETCDIR)/h323.conf ]; then \
@@ -73,11 +73,15 @@ samples:
install h323.conf.sample $(ASTETCDIR)/h323.conf
+libchanh323.a: ast_h323.o
+ ar cr libchanh323.a ast_h323.o
+
ast_h323.o: ast_h323.cpp
$(CXX) -g -c -fno-rtti -o $@ $(CFLAGS) $<
-libchanh323.a: ast_h323.o
- ar cr libchanh323.a ast_h323.o
+ifneq ($(wildcard .depend),)
+include .depend
+endif
chan_h323.so:
$(CXX) -g -shared -Xlinker -x -o chan_h323.so chan_h323.o ast_h323.o -L$(PWLIBDIR)/lib -lpt_linux_x86_r -L$(OPENH323DIR)/lib -lh323_linux_x86_r -L/usr/lib $(CHANH323LIB)
@@ -88,6 +92,11 @@ chan_h323_d.so: chan_h323.o ast_h323.o
chan_h323_s.so: chan_h323.o ast_h323.o
$(CXX) -shared -Xlinker -x -o chan_h323.so chan_h323.o ast_h323.o -L$(PWLIBDIR)/lib -lpt_linux_x86_r_s -L$(OPENH323DIR)/lib -lh323_linux_x86_r_s -L/usr/lib $(CHANH323LIB)
clean:
- rm -f *.o *.so core.* libchanh323.a
+ rm -f *.o *.so core.* libchanh323.a .depend
+
+depend: .depend
+
+.depend:
+ ../../mkdep $(CFLAGS) `ls *.cpp`
diff --git a/channels/h323/ast_h323.cpp b/channels/h323/ast_h323.cpp
index afeee365e..4c01d9575 100755
--- a/channels/h323/ast_h323.cpp
+++ b/channels/h323/ast_h323.cpp
@@ -722,7 +722,7 @@ void MyH323Connection::SendUserInputTone(char tone, unsigned duration)
if (h323debug) {
cout << " -- Sending user input tone (" << tone << ") to remote" << endl;
}
- on_send_digit(GetCallReference(), tone);
+ on_send_digit(GetCallReference(), tone, (const char *)GetCallToken());
H323Connection::SendUserInputTone(tone, duration);
}
@@ -732,7 +732,7 @@ void MyH323Connection::OnUserInputTone(char tone, unsigned duration, unsigned lo
if (h323debug) {
cout << " -- Received user input tone (" << tone << ") from remote" << endl;
}
- on_send_digit(GetCallReference(), tone);
+ on_send_digit(GetCallReference(), tone, (const char *)GetCallToken());
}
H323Connection::OnUserInputTone(tone, duration, logicalChannel, rtpTimestamp);
}
@@ -743,7 +743,7 @@ void MyH323Connection::OnUserInputString(const PString &value)
if (h323debug) {
cout << " -- Received user input string (" << value << ") from remote." << endl;
}
- on_send_digit(GetCallReference(), value[0]);
+ on_send_digit(GetCallReference(), value[0], (const char *)GetCallToken());
}
}
diff --git a/channels/h323/chan_h323.h b/channels/h323/chan_h323.h
index 1b277c499..e948a1a02 100755
--- a/channels/h323/chan_h323.h
+++ b/channels/h323/chan_h323.h
@@ -114,7 +114,7 @@ typedef struct rtp_info {
/* This is a callback prototype function, called pass
DTMF down the RTP. */
-typedef int (*send_digit_cb)(unsigned, char);
+typedef int (*send_digit_cb)(unsigned, char, const char *);
extern send_digit_cb on_send_digit;
/* This is a callback prototype function, called to collect
diff --git a/channels/iax2-parser.c b/channels/iax2-parser.c
index c54af66a5..1e7d021c9 100755
--- a/channels/iax2-parser.c
+++ b/channels/iax2-parser.c
@@ -32,7 +32,7 @@ static int oframes = 0;
static void internaloutput(const char *str)
{
- printf(str);
+ fputs(str, stdout);
}
static void internalerror(const char *str)
@@ -299,7 +299,9 @@ void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, s
"NULL ",
"IAX ",
"TEXT ",
- "IMAGE " };
+ "IMAGE ",
+ "HTML ",
+ "CNG " };
char *iaxs[] = {
"(0?)",
"NEW ",
@@ -355,7 +357,7 @@ void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, s
char subclass2[20];
char *class;
char *subclass;
- char tmp[256];
+ char tmp[512];
char iabuf[INET_ADDRSTRLEN];
if (f) {
fh = f->data;
@@ -371,7 +373,7 @@ void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, s
/* Don't mess with mini-frames */
return;
}
- if (fh->type > (int)sizeof(frames)/(int)sizeof(char *)) {
+ if (fh->type >= (int)sizeof(frames)/(int)sizeof(frames[0])) {
snprintf(class2, (int)sizeof(class2), "(%d?)", fh->type);
class = class2;
} else {
@@ -688,8 +690,15 @@ void iax_frame_wrap(struct iax_frame *fr, struct ast_frame *f)
fr->af.delivery.tv_sec = 0;
fr->af.delivery.tv_usec = 0;
fr->af.data = fr->afdata;
- if (fr->af.datalen)
+ if (fr->af.datalen) {
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ /* We need to byte-swap slinear samples from network byte order */
+ if (fr->af.subclass == AST_FORMAT_SLINEAR) {
+ ast_memcpy_byteswap(fr->af.data, f->data, fr->af.samples);
+ } else
+#endif
memcpy(fr->af.data, f->data, fr->af.datalen);
+ }
}
struct iax_frame *iax_frame_new(int direction, int datalen)
diff --git a/channels/iax2.h b/channels/iax2.h
index afc4424e8..f837c4609 100755
--- a/channels/iax2.h
+++ b/channels/iax2.h
@@ -122,7 +122,7 @@
#define IAX_DPSTATUS_EXISTS (1 << 0)
#define IAX_DPSTATUS_CANEXIST (1 << 1)
-#define IAX_DPSTATUS_NONEXISTANT (1 << 2)
+#define IAX_DPSTATUS_NONEXISTENT (1 << 2)
#define IAX_DPSTATUS_IGNOREPAT (1 << 14)
#define IAX_DPSTATUS_MATCHMORE (1 << 15)
diff --git a/cli.c b/cli.c
index 613e3a22f..34fb016d6 100755
--- a/cli.c
+++ b/cli.c
@@ -26,6 +26,7 @@
#include <stdio.h>
#include <signal.h>
#include <string.h>
+#include <ctype.h>
/* For rl_filename_completion */
#include "editline/readline/readline.h"
/* For module directory */
@@ -147,8 +148,8 @@ static int handle_set_verbose(int fd, int argc, char *argv[])
if (oldval != option_verbose && option_verbose > 0)
ast_cli(fd, "Verbosity was %d and is now %d\n", oldval, option_verbose);
else if (oldval > 0 && option_verbose > 0)
- ast_cli(fd, "Verbosity is atleast %d\n", option_verbose);
- else if (oldval > 0 && option_debug == 0)
+ ast_cli(fd, "Verbosity is at least %d\n", option_verbose);
+ else if (oldval > 0 && option_verbose == 0)
ast_cli(fd, "Verbosity is now OFF\n");
return RESULT_SUCCESS;
}
@@ -157,6 +158,7 @@ static int handle_set_debug(int fd, int argc, char *argv[])
{
int val = 0;
int oldval = 0;
+
/* Has a hidden 'at least' argument */
if ((argc != 3) && (argc != 4))
return RESULT_SHOWUSAGE;
@@ -173,7 +175,7 @@ static int handle_set_debug(int fd, int argc, char *argv[])
if (oldval != option_debug && option_debug > 0)
ast_cli(fd, "Core debug was %d and is now %d\n", oldval, option_debug);
else if (oldval > 0 && option_debug > 0)
- ast_cli(fd, "Core debug is atleast %d\n", option_debug);
+ ast_cli(fd, "Core debug is at least %d\n", option_debug);
else if (oldval > 0 && option_debug == 0)
ast_cli(fd, "Core debug is now OFF\n");
return RESULT_SUCCESS;
@@ -437,11 +439,11 @@ static char *__ast_cli_generator(char *text, char *word, int state, int lock);
static int handle_commandmatchesarray(int fd, int argc, char *argv[])
{
- char *buf;
+ char *buf, *obuf;
int buflen = 2048;
int len = 0;
char **matches;
- int x;
+ int x, matchlen;
if (argc != 4)
return RESULT_SHOWUSAGE;
@@ -455,11 +457,17 @@ static int handle_commandmatchesarray(int fd, int argc, char *argv[])
#if 0
printf("command matchesarray for '%s' %s got '%s'\n", argv[2], argv[3], matches[x]);
#endif
- if (len + strlen(matches[x]) >= buflen) {
- buflen += strlen(matches[x]) * 3;
- buf = realloc(buf, buflen);
+ matchlen = strlen(matches[x]) + 1;
+ if (len + matchlen >= buflen) {
+ buflen += matchlen * 3;
+ obuf = buf;
+ buf = realloc(obuf, buflen);
+ if (!buf)
+ /* Out of memory... Just free old buffer and be done */
+ free(obuf);
}
- len += sprintf( buf + len, "%s ", matches[x]);
+ if (buf)
+ len += sprintf( buf + len, "%s ", matches[x]);
free(matches[x]);
matches[x] = NULL;
}
@@ -748,7 +756,7 @@ static struct ast_cli_entry *find_cli(char *cmds[], int exact)
return e;
}
-static void join(char *dest, size_t destsize, char *w[])
+static void join(char *dest, size_t destsize, char *w[], int tws)
{
int x;
/* Join words into a string */
@@ -761,6 +769,8 @@ static void join(char *dest, size_t destsize, char *w[])
strncat(dest, " ", destsize - strlen(dest) - 1);
strncat(dest, w[x], destsize - strlen(dest) - 1);
}
+ if (tws)
+ strncat(dest, " ", destsize - strlen(dest) - 1);
}
static void join2(char *dest, size_t destsize, char *w[])
@@ -789,7 +799,7 @@ static char *find_best(char *argv[])
if (!find_cli(myargv, -1))
break;
}
- join(cmdline, sizeof(cmdline), myargv);
+ join(cmdline, sizeof(cmdline), myargv, 0);
return cmdline;
}
@@ -863,20 +873,20 @@ int ast_cli_register(struct ast_cli_entry *e)
static int help_workhorse(int fd, char *match[])
{
- char fullcmd1[80];
- char fullcmd2[80];
+ char fullcmd1[80] = "";
+ char fullcmd2[80] = "";
char matchstr[80];
- char *fullcmd;
+ char *fullcmd = NULL;
struct ast_cli_entry *e, *e1, *e2;
e1 = builtins;
e2 = helpers;
if (match)
- join(matchstr, sizeof(matchstr), match);
+ join(matchstr, sizeof(matchstr), match, 0);
while(e1->cmda[0] || e2) {
if (e2)
- join(fullcmd2, sizeof(fullcmd2), e2->cmda);
+ join(fullcmd2, sizeof(fullcmd2), e2->cmda, 0);
if (e1->cmda[0])
- join(fullcmd1, sizeof(fullcmd1), e1->cmda);
+ join(fullcmd1, sizeof(fullcmd1), e1->cmda, 0);
if (!e1->cmda[0] ||
(e2 && (strcmp(fullcmd2, fullcmd1) < 0))) {
/* Use e2 */
@@ -910,13 +920,18 @@ static int handle_help(int fd, int argc, char *argv[]) {
return RESULT_SHOWUSAGE;
if (argc > 1) {
e = find_cli(argv + 1, 1);
- if (e)
- ast_cli(fd, e->usage);
- else {
+ if (e) {
+ if (e->usage)
+ ast_cli(fd, "%s", e->usage);
+ else {
+ join(fullcmd, sizeof(fullcmd), argv+1, 0);
+ ast_cli(fd, "No help text available for '%s'.\n", fullcmd);
+ }
+ } else {
if (find_cli(argv + 1, -1)) {
return help_workhorse(fd, argv + 1);
} else {
- join(fullcmd, sizeof(fullcmd), argv+1);
+ join(fullcmd, sizeof(fullcmd), argv+1, 0);
ast_cli(fd, "No such command '%s'.\n", fullcmd);
}
}
@@ -926,72 +941,63 @@ static int handle_help(int fd, int argc, char *argv[]) {
return RESULT_SUCCESS;
}
-static char *parse_args(char *s, int *max, char *argv[])
+static char *parse_args(char *s, int *argc, char *argv[], int max, int *trailingwhitespace)
{
char *dup, *cur;
- int x=0;
- int quoted=0;
- int escaped=0;
- int whitespace=1;
-
- dup = strdup(s);
- if (dup) {
- cur = dup;
- while(*s) {
- switch(*s) {
- case '"':
- /* If it's escaped, put a literal quote */
- if (escaped)
- goto normal;
- else
- quoted = !quoted;
- if (quoted && whitespace) {
- /* If we're starting a quote, coming off white space start a new word, too */
- argv[x++] = cur;
- whitespace=0;
- }
- escaped = 0;
- break;
- case ' ':
- case '\t':
- if (!quoted && !escaped) {
- /* If we're not quoted, mark this as whitespace, and
- end the previous argument */
- whitespace = 1;
- *(cur++) = '\0';
- } else
- /* Otherwise, just treat it as anything else */
- goto normal;
- break;
- case '\\':
- /* If we're escaped, print a literal, otherwise enable escaping */
- if (escaped) {
- goto normal;
- } else {
- escaped=1;
+ int x = 0;
+ int quoted = 0;
+ int escaped = 0;
+ int whitespace = 1;
+
+ *trailingwhitespace = 0;
+ if (!(dup = strdup(s)))
+ return NULL;
+
+ cur = dup;
+ while (*s) {
+ if ((*s == '"') && !escaped) {
+ quoted = !quoted;
+ if (quoted & whitespace) {
+ /* If we're starting a quoted string, coming off white space, start a new argument */
+ if (x >= (max - 1)) {
+ ast_log(LOG_WARNING, "Too many arguments, truncating\n");
+ break;
}
- break;
- default:
-normal:
- if (whitespace) {
- if (x >= AST_MAX_ARGS -1) {
- ast_log(LOG_WARNING, "Too many arguments, truncating\n");
- break;
- }
- /* Coming off of whitespace, start the next argument */
- argv[x++] = cur;
- whitespace=0;
+ argv[x++] = cur;
+ whitespace = 0;
+ }
+ escaped = 0;
+ } else if (((*s == ' ') || (*s == '\t')) && !(quoted || escaped)) {
+ /* If we are not already in whitespace, and not in a quoted string or
+ processing an escape sequence, and just entered whitespace, then
+ finalize the previous argument and remember that we are in whitespace
+ */
+ if (!whitespace) {
+ *(cur++) = '\0';
+ whitespace = 1;
+ }
+ } else if ((*s == '\\') && !escaped) {
+ escaped = 1;
+ } else {
+ if (whitespace) {
+ /* If we are coming out of whitespace, start a new argument */
+ if (x >= (max - 1)) {
+ ast_log(LOG_WARNING, "Too many arguments, truncating\n");
+ break;
}
- *(cur++) = *s;
- escaped=0;
+ argv[x++] = cur;
+ whitespace = 0;
}
- s++;
+ *(cur++) = *s;
+ escaped = 0;
}
- /* Null terminate */
- *(cur++) = '\0';
- argv[x] = NULL;
- *max = x;
+ s++;
}
+ /* Null terminate */
+ *(cur++) = '\0';
+ argv[x] = NULL;
+ *argc = x;
+ *trailingwhitespace = whitespace;
return dup;
}
@@ -999,17 +1005,17 @@ normal:
int ast_cli_generatornummatches(char *text, char *word)
{
int matches = 0, i = 0;
- char *buf, *oldbuf = NULL;
-
+ char *buf = NULL, *oldbuf = NULL;
- while ( (buf = ast_cli_generator(text, word, i)) ) {
- if (++i > 1 && strcmp(buf,oldbuf) == 0) {
- continue;
- }
+ while ( (buf = ast_cli_generator(text, word, i++)) ) {
+ if (!oldbuf || strcmp(buf,oldbuf))
+ matches++;
+ if (oldbuf)
+ free(oldbuf);
oldbuf = buf;
- matches++;
}
-
+ if (oldbuf)
+ free(oldbuf);
return matches;
}
@@ -1035,7 +1041,7 @@ char **ast_cli_completion_matches(char *text, char *word)
prevstr = match_list[1];
max_equal = strlen(prevstr);
for (; which <= matches; which++) {
- for (i = 0; i < max_equal && prevstr[i] == match_list[which][i]; i++)
+ for (i = 0; i < max_equal && toupper(prevstr[i]) == toupper(match_list[which][i]); i++)
continue;
max_equal = i;
}
@@ -1059,22 +1065,23 @@ static char *__ast_cli_generator(char *text, char *word, int state, int lock)
int x;
int matchnum=0;
char *dup, *res;
- char fullcmd1[80];
- char fullcmd2[80];
+ char fullcmd1[80] = "";
+ char fullcmd2[80] = "";
char matchstr[80];
- char *fullcmd;
+ char *fullcmd = NULL;
+ int tws;
- if ((dup = parse_args(text, &x, argv))) {
- join(matchstr, sizeof(matchstr), argv);
+ if ((dup = parse_args(text, &x, argv, sizeof(argv) / sizeof(argv[0]), &tws))) {
+ join(matchstr, sizeof(matchstr), argv, tws);
if (lock)
ast_mutex_lock(&clilock);
e1 = builtins;
e2 = helpers;
while(e1->cmda[0] || e2) {
if (e2)
- join(fullcmd2, sizeof(fullcmd2), e2->cmda);
+ join(fullcmd2, sizeof(fullcmd2), e2->cmda, tws);
if (e1->cmda[0])
- join(fullcmd1, sizeof(fullcmd1), e1->cmda);
+ join(fullcmd1, sizeof(fullcmd1), e1->cmda, tws);
if (!e1->cmda[0] ||
(e2 && (strcmp(fullcmd2, fullcmd1) < 0))) {
/* Use e2 */
@@ -1135,8 +1142,9 @@ int ast_cli_command(int fd, char *s)
struct ast_cli_entry *e;
int x;
char *dup;
- x = AST_MAX_ARGS;
- if ((dup = parse_args(s, &x, argv))) {
+ int tws;
+
+ if ((dup = parse_args(s, &x, argv, sizeof(argv) / sizeof(argv[0]), &tws))) {
/* We need at least one entry, or ignore */
if (x > 0) {
ast_mutex_lock(&clilock);
@@ -1147,7 +1155,7 @@ int ast_cli_command(int fd, char *s)
if (e) {
switch(e->handler(fd, x, argv)) {
case RESULT_SHOWUSAGE:
- ast_cli(fd, e->usage);
+ ast_cli(fd, "%s", e->usage);
break;
}
} else
diff --git a/codecs/Makefile b/codecs/Makefile
index 82d8f458e..e7aa6b91a 100755
--- a/codecs/Makefile
+++ b/codecs/Makefile
@@ -19,10 +19,12 @@
#MODG723=codec_g723_1.so codec_g723_1b.so
MODG723=$(shell [ -f g723.1/coder.c ] && echo "codec_g723_1.so")
MODG723+=$(shell [ -f g723.1b/coder2.c ] && echo "codec_g723_1b.so")
-MODSPEEX=$(shell [ -f /usr/include/speex.h ] || [ -f /usr/local/include/speex.h ] && echo "codec_speex.so")
+MODSPEEX=$(shell [ -f /usr/include/speex.h ] || [ -f /usr/include/speex/speex.h ] || [ -f /usr/local/include/speex.h ] || [ -f /usr/local/include/speex/speex.h ] && echo "codec_speex.so")
MODILBC=$(shell [ -f ilbc/iLBC_decode.h ] && echo "codec_ilbc.so")
CFLAGS+=-fPIC
CFLAGS+=$(shell [ -f /usr/local/include/speex.h ] && echo "-I/usr/local/include")
+CFLAGS+=$(shell [ -f /usr/local/include/speex/speex.h ] && echo "-I/usr/local/include/speex")
+CFLAGS+=$(shell [ -f /usr/include/speex/speex.h ] && echo "-I/usr/include/speex")
LIBG723=g723.1/libg723.a
LIBG723B=g723.1b/libg723b.a
diff --git a/codecs/gsm/Makefile b/codecs/gsm/Makefile
index a21bd7e52..895df113e 100755
--- a/codecs/gsm/Makefile
+++ b/codecs/gsm/Makefile
@@ -42,12 +42,20 @@ ifneq (${PROC},x86_64)
ifneq (${PROC},ultrasparc)
ifneq ($(shell uname -m),ppc)
ifneq ($(shell uname -m),alpha)
+ifneq ($(shell uname -m),armv4l)
+ifneq (${PROC},sparc64)
+ifneq (${PROC},ppc)
+ifneq (${PROC},ppc64)
OPTIMIZE+=-march=$(PROC)
endif
endif
endif
endif
endif
+endif
+endif
+endif
+endif
#The problem with sparc is the best stuff is in newer versions of gcc (post 3.0) only.
#This works for even old (2.96) versions of gcc and provides a small boost either way.
@@ -214,6 +222,7 @@ ifeq (${OSARCH},Linux)
ifneq ($(shell uname -m),x86_64)
ifneq ($(shell uname -m),ppc)
ifneq ($(shell uname -m),alpha)
+ifneq ($(shell uname -m),armv4l)
ifneq ($(shell uname -m),sparc64)
GSM_SOURCES+= $(SRC)/k6opt.s
endif
@@ -221,6 +230,7 @@ endif
endif
endif
endif
+endif
TOAST_SOURCES = $(SRC)/toast.c \
$(SRC)/toast_lin.c \
@@ -270,6 +280,7 @@ ifeq (${OSARCH},Linux)
ifneq ($(shell uname -m), x86_64)
ifneq ($(shell uname -m), ppc)
ifneq ($(shell uname -m), alpha)
+ifneq ($(shell uname -m), armv4l)
ifneq ($(shell uname -m), sparc64)
GSM_OBJECTS+= $(SRC)/k6opt.o
endif
@@ -277,6 +288,7 @@ endif
endif
endif
endif
+endif
TOAST_OBJECTS = $(SRC)/toast.o \
$(SRC)/toast_lin.o \
@@ -489,7 +501,7 @@ clean: semi-clean
-rm $(RMFLAGS) $(LIBGSM) $(ADDTST)/add \
$(TOAST) $(TCAT) $(UNTOAST) \
$(ROOT)/gsm-1.0.tar.Z
-
+ rm -rf lib
# Two tools that helped me generate gsm_encode.c and gsm_decode.c,
# but aren't generally needed to port this.
diff --git a/config.c b/config.c
index 41c53b6b6..4e435881a 100755
--- a/config.c
+++ b/config.c
@@ -662,7 +662,7 @@ int ast_save(char *configfile, struct ast_config *cfg, char *generator)
if (configfile[0] == '/') {
strncpy(fn, configfile, sizeof(fn)-1);
} else {
- snprintf(fn, sizeof(fn), "%s/%s", AST_CONFIG_DIR, configfile);
+ snprintf(fn, sizeof(fn), "%s/%s", ast_config_AST_CONFIG_DIR, configfile);
}
time(&t);
strncpy(date, ctime(&t), sizeof(date) - 1);
diff --git a/configs/agents.conf.sample b/configs/agents.conf.sample
index bde308134..d8641e60b 100755
--- a/configs/agents.conf.sample
+++ b/configs/agents.conf.sample
@@ -11,7 +11,7 @@
;autologoff=15
;
; Define ackcall to require an acknowledgement by '#' when
-; an agent logs in over agentcallpark. Default is "yes".
+; an agent logs in using agentcallbacklogin. Default is "yes".
;
;ackcall=yes
;
@@ -32,7 +32,7 @@
;
;updatecdr=no
;
-; Group memberships for agents (may change in mid-file just)
+; Group memberships for agents (may change in mid-file)
;
;group=3
;group=1,2
diff --git a/configs/enum.conf.sample b/configs/enum.conf.sample
index 905f10fe1..1e0c1e1be 100755
--- a/configs/enum.conf.sample
+++ b/configs/enum.conf.sample
@@ -2,6 +2,7 @@
; ENUM Configuration for resolving phone numbers over DNS
;
; Sample config for Asterisk
+; This file is reloaded at "reload" in the CLI
;
[general]
;
diff --git a/configs/extensions.conf.sample b/configs/extensions.conf.sample
index 624aff8aa..ed8785a7b 100755
--- a/configs/extensions.conf.sample
+++ b/configs/extensions.conf.sample
@@ -3,6 +3,9 @@
; the pbx_config module. This is where you configure all your
; inbound and outbound calls in Asterisk.
;
+; This configuration file is reloaded
+; - With the "extensions reload" command in the CLI
+; - With the "reload" command (that reloads everything) in the CLI
;
; The "General" category is for certain variables.
@@ -38,6 +41,16 @@ CONSOLE=Console/dsp ; Console interface for demo
IAXINFO=guest ; IAXtel username/password
;IAXINFO=myuser:mypass
TRUNK=Zap/g2 ; Trunk interface
+;
+; Note the 'g2' in the TRUNK variable above. It specifies which group (defined
+; in zapata.conf) to dial, i.e. group 2, and how to choose a channel to use in
+; the specified group. The four possible options are:
+;
+; g: select the lowest-numbered non-busy Zap channel (aka. ascending sequential hunt group).
+; G: select the highest-numbered non-busy Zap channel (aka. descending sequential hunt group).
+; r: use a round-robin search, starting at the next highest channel than last time (aka. ascending rotary hunt group).
+; R: use a round-robin search, starting at the next lowest channel than last time (aka. descending rotary hunt group).
+;
TRUNKMSD=1 ; MSD digits to strip (usually 1 or 0)
;TRUNK=IAX2/user:pass@provider
diff --git a/configs/iax.conf.sample b/configs/iax.conf.sample
index 98ffd3d9c..d34d9bc87 100755
--- a/configs/iax.conf.sample
+++ b/configs/iax.conf.sample
@@ -1,6 +1,9 @@
; Inter-Asterisk eXchange driver definition
;
+; This configuration is re-read at reload
+; or with the CLI command
+; reload chan_iax2.so
;
; General settings, like port number to bind to, and
; an option address (the default is to bind to all
diff --git a/configs/indications.conf.sample b/configs/indications.conf.sample
index df05da4ce..7298a3612 100755
--- a/configs/indications.conf.sample
+++ b/configs/indications.conf.sample
@@ -1,14 +1,14 @@
+; indications.conf
+; Configuration file for location specific tone indications
+; used by the pbx_indications module.
;
-; Static indications configuration files, used by
-; the pbx_indications module.
+; The [general] category is for certain global variables.
+; All other categories are interpreted as location specific indications
;
-; The "general" category is for certain variables. All other categories
-; are interpreted as indication countries
-;
-; Please note that there are NOT spaces allowed in lists!
;
[general]
-country=us
+country=us ; default location
+
; [example]
; description = string
@@ -23,28 +23,36 @@ country=us
; busy = tonelist
; Set of tones played when the receiving end is busy.
; congestion = tonelist
-; Set of tones played when the is some congestion (on the network?)
+; Set of tones played when there is some congestion (on the network?)
; callwaiting = tonelist
-; Set of tones played when there is a callwaiting in the background.
+; Set of tones played when there is a call waiting in the background.
; dialrecall = tonelist
-; Set of tones played when there is somebody ???
+; Not well defined, many phone systems play a recall dial tone after hook flash
; record = tonelist
-; Set of tones played whenver we feel like it ???
+; Set of tones played when call recording is in progress
; info = tonelist
-; Set of tones played when information is to be tranfered?
-; every other variable will be available as a shortcut for the "PlayList" command
-; but will not automaticly be used by Asterisk.
+; Set of tones played with special information messages (e.g., "number is out of service")
+; 'name' = tonelist
+; Every other variable will be available as a shortcut for the "PlayList" command
+; but will not automaticly be used by Asterisk.
+;
;
-; The tonelist itself is defined by a sequence of elements, seperated by ,'s.
-; Each element consist of a frequency (f) with a possible frequency attached
-; (f1+f2) to it. Behind the frequency there is an optional duration, in
-; milliseconds. If the element starts with a !, that element is NOT repeat,
-; so only if all elements start with !, the tonelist is time-limited, all
-; others will repeat indefinitly.
+; The tonelist itself is defined by a comma-separated sequence of elements.
+; Each element consist of a frequency (f) with an optional duration (in ms)
+; attached to it (f/duration). The frequency component may be a mixture of two
+; frequencies (f1+f2) or a frequency modulated by another frequency (f1*f2).
+; The implicit modulation depth is fixed at 90%, though.
+; If the list element starts with a !, that element is NOT repeated,
+; therefore, only if all elements start with !, the tonelist is time-limited,
+; all others will repeat indefinitely.
;
-; In tech-talk:
+; concisely:
+; element = [!]freq[+|*freq2][/duration]
; tonelist = element[,element]*
-; element = [!]freq[+freq2][/duration]
+;
+; Please note that SPACES ARE NOT ALLOWED in tone lists!
+;
+
; Tone definitions for Chile
; According to specs from Telefonica CTC Chile
@@ -61,7 +69,6 @@ record = 1400/500,0/15000
info = 950/333,1400/333,1800/333,0/1000
[tw]
-; °Ñ¦Ò¸ê®Æ :
; http://nemesis.lonestar.org/reference/telecom/signaling/dialtone.html
; http://nemesis.lonestar.org/reference/telecom/signaling/busy.html
; http://www.iproducts.com.tw/ee/kylink/06ky-1000a.htm
@@ -69,14 +76,11 @@ info = 950/333,1400/333,1800/333,0/1000
; http://www.nettwerked.net/tones.txt
; http://www.cisco.com/univercd/cc/td/doc/product/tel_pswt/vco_prod/taiw_sup/taiw2.htm
;
-; ¸ß°Ý¤¤µØ¹q«H«á±o¨ìªº¦^ÂÐ :
-; dial tone 350+440Hz continuous
; busy tone 480+620Hz 0.5 sec. on ,0.5 sec. off
; reorder tone 480+620Hz 0.25 sec. on,0.25 sec. off
; ringing tone 440+480Hz 1 sec. on ,2 sec. off
;
description = Taiwan
-alias = tw
ringcadance = 1000,4000
dial = 350+440
busy = 480+620/500,0/500
@@ -181,15 +185,36 @@ info = 950/330,1400/330,1800/330,0/1000
[uk]
description = United Kingdom
ringcadance = 400,200,400,2000
+; These are the official tones taken from BT SIN350. The actual tones
+; used by BT include some volume differences so sound slightly different
+; from Asterisk-generated ones.
dial = 350+440
+; Special dial is the intermittent dial tone heard when, for example,
+; you have a divert active on the line
+specialdial = 350+440/750,440/750
+; Busy is also called "Engaged"
busy = 400/375,0/375
-ring = 400+450/400,0/200,400+450/400,0/2000
+; "Congestion" is the Beep-bip engaged tone
congestion = 400/400,0/350,400/225,0/525
-callwaiting = 440/100,0/4000
-dialrecall = 350+440
-; XXX Not sure about the RECORDTONE
-record = 1400/500,0/10000
-info = 950/330,1400/330,1800/330
+; "Special Congestion" is not used by BT very often if at all
+specialcongestion = 400/200,1004/300
+unobtainable = 400
+ring = 400+450/400,0/200,400+450/400,0/2000
+callwaiting = 400/100,0/4000
+; BT seem to use "Special Call Waiting" rather than just "Call Waiting" tones
+specialcallwaiting = 400/250,0/250,400/250,0/250,400/250,0/5000
+; "Pips" used by BT on payphones. (Souds wrong, but this is what BT claim it
+; is and I've not used a payphone for years)
+creditexpired = 400/125,0/125
+; These two are used to confirm/reject service requests on exchanges that
+; don't do voice announcements.
+confirm = 1400
+switching = 400/200,0/400,400/2000,0/400
+; This is the three rising tones Doo-dah-dee "Special Information Tone",
+; usually followed by the BT woman saying an appropriate message.
+info = 950/330,0/15,1400/330,0/15,1800/330,0/1000
+; Not listed in SIN350
+record = 1400/500,0/60000
[fi]
description = Finland
@@ -317,3 +342,120 @@ callwaiting = !400/200,!0/3000,!400/200,!0/3000,!400/200,!0/3000,!400/200
dialrecall = !400/100!0/100,!400/100,!0/100,!400/100,!0/100,400
record = 1400/425,0/15000
info = 400/750,0/100,400/750,0/100,400/750,0/100,400/750,0/400
+
+; Singapore
+; Reference: http://www.ida.gov.sg/idaweb/doc/download/I397/ida_ts_pstn1_i4r2.pdf
+; Frequency specs are: 425 Hz +/- 20Hz; 24 Hz +/- 2Hz; modulation depth 100%; SIT +/- 50Hz
+[sg]
+description = Singapore
+ringcadence = 400,200,400,2000
+dial = 425
+ring = 425*24/400,0/200,425*24/400,0/2000 ; modulation should be 100%, not 90%
+busy = 425/750,0/750
+congestion = 425/250,0/250
+callwaiting= 425*24/300,0/200,425*24/300,0/3200
+stutter = !425/200,!0/200,!425/600,!0/200,!425/200,!0/200,!425/600,!0/200,!425/200,!0/200,!425/600,!0/200,!425/200,!0/200,!425/600,!0/200,425
+info = 950/330,1400/330,1800/330,0/1000 ; not currently in use acc. to reference
+dialrecall = 425*24/500,0/500,425/500,0/2500 ; unspecified in IDA reference, use repeating Holding Tone A,B
+record = 1400/500,0/15000 ; unspecified in IDA reference, use 0.5s tone every 15s
+; additionally defined in reference
+nutone = 425/2500,0/500
+intrusion = 425/250,0/2000
+warning = 425/624,0/4376 ; end of period tone, warning
+acceptance = 425/125,0/125
+holdinga = !425*24/500,!0/500 ; followed by holdingb
+holdingb = !425/500,!0/2500
+
+[hu]
+description = Hungary
+ringcadance = 1000,4000
+dial = 425
+busy = 425/300,0/300
+ring = 425/1250,0/3750
+congestion = 425/300,0/300
+callwaiting = 425/40,0/1960
+; Dialrecall not used in Hungary, use standard (using UK standard)
+dialrecall = 350+440
+; Record tone is not used in Hungary, use busy tone
+record = 425/250,0/250
+info = !950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,!0/1000,0
+
+[lt]
+description = Lithuania
+ringcadence = 1000,4000
+dial = 425
+busy = 425/350,0/350
+ring = 425/1000,0/4000
+congestion = 425/200,0/200
+callwaiting = 425/150,0/150,425/150,0/4000
+; XXX I'm making up the dialrecall tone XXX
+dialrecall = 425/500,0/50
+; XXX I'm making up the record tone XXX
+record = 1400/500,0/15000
+info = !950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,!0/1000,0
+
+[pl]
+description = Poland
+ringcadence = 1000,4000
+dial = 425
+busy = 425/500,0/500
+ring = 425/1000,0/4000
+congestion = 425/500,0/500
+callwaiting = 425/150,0/150,425/150,0/4000
+; DIALRECALL - not specified
+dialrecall = 425/500,0/50
+; RECORDTONE - not specified
+record = 1400/500,0/15000
+; 950/1400/1800 3x0.33 on 1.0 off repeated 3 times
+info = !950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,!0/1000
+
+
+[pt]
+description = Portugal
+ringcadance = 1000,5000
+dial = 425
+busy = 425/500,0/500
+ring = 425/1000,0/5000
+congestion = 425/200,0/200
+callwaiting = 440/300,0/10000
+dialrecall = 425/1000,0/200
+record = 1400/500,0/15000
+info = 950/330,1400/330,1800/330,0/1000
+
+[ee]
+description = Estonia
+ringcadance = 1000,4000
+dial = 425
+busy = 425/300,0/300
+ring = 425/1000,0/4000
+congestion = 425/200,0/200
+callwaiting = 950/650,0/325,950/325,0/30,1400/1300,0/2600
+dialrecall = 425/650,0/25
+record = 1400/500,0/15000
+info = 950/650,0/325,950/325,0/30,1400/1300,0/2600
+
+[mx]
+description = Mexico
+ringcadance = 2000,4000
+dial = 425
+busy = 425/250,0/250
+ring = 425/1000,0/4000
+congestion = 425/250,0/250
+callwaiting = 425/200,0/600,425/200,0/10000
+dialrecall = !350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440
+record = 1400/500,0/15000
+info = 950/330,0/30,1400/330,0/30,1800/330,0/1000
+
+[se]
+description = Sweden
+ringcadance = 1000,5000
+dial = 425
+busy = 425/250,0/250
+ring = 425/1000,0/5000
+congestion = 425/250,0/750
+callwaiting = 425/200,0/500,425/200,0/9100
+dialrecall = !425/100,!0/100,!425/100,!0/100,!425/100,!0/100,425
+record = 1400/500,0/15000
+info = !950/332,!0/24,!1400/332,!0/24,!1800/332,!0/2024,!950/332,!0/24,!1400/332,!0/24,!1800/332,!0/2024,!950/332,!0/24,!1400/332,!0/24,!1800/332,!0/2024,!950/332,!0/24,!1400/332,!0/24,!1800/332,!0/2024,!950/332,!0/24,!1400/332,!0/24,!1800/332,0
+stutter = !425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,425
+; stutter = 425/320,0/20 ; Real swedish standard, not used for now
diff --git a/configs/logger.conf.sample b/configs/logger.conf.sample
index bf28f2f40..338f2bb1f 100755
--- a/configs/logger.conf.sample
+++ b/configs/logger.conf.sample
@@ -3,6 +3,9 @@
;
; In this file, you configure logging to files or to
; the syslog system.
+;
+; "logger reload" at the CLI will reload configuration
+; of the logging system.
[general]
; Customize the display of debug message time stamps
@@ -40,10 +43,6 @@ console => notice,warning,error
messages => notice,warning,error
;full => notice,warning,error,debug,verbose
;
-; Uncomment the following line (with *no* events) if you want the
-; queue log to automatically rotate.
-;
-;queue_log =>
;syslog keyword : This special keyword logs to syslog facility
;
diff --git a/configs/manager.conf.sample b/configs/manager.conf.sample
index 4560904e2..479c91938 100755
--- a/configs/manager.conf.sample
+++ b/configs/manager.conf.sample
@@ -1,5 +1,23 @@
;
-; Asterisk Call Management support
+; AMI - The Asterisk Manager Interface
+;
+; Third party application call management support
+; and PBX event supervision
+;
+; This configuration file is read every time someone
+; logs in
+;
+; Use the "show manager commands" at the CLI to list
+; availabale manager commands and their authorization
+; levels.
+;
+; "show manager command <command>" will show a help text.
+;
+; ------------------- SECURITY NOTE -----------------
+; Note that you should not enable the AMI on a public
+; IP address. If needed, block this TCP port with
+; iptables (or another FW software) and reach it
+; with IPsec, SSH or SSL vpn tunnel
;
[general]
enabled = no
@@ -10,5 +28,7 @@ bindaddr = 0.0.0.0
;secret = mysecret
;deny=0.0.0.0/0.0.0.0
;permit=209.16.236.73/255.255.255.0
+;
+; Authorization for various classes
;read = system,call,log,verbose,command,agent,user
;write = system,call,log,verbose,command,agent,user
diff --git a/configs/meetme.conf.sample b/configs/meetme.conf.sample
index c78cc21ac..417ce862e 100755
--- a/configs/meetme.conf.sample
+++ b/configs/meetme.conf.sample
@@ -2,6 +2,8 @@
; Configuration file for MeetMe simple conference rooms
; for Asterisk of course.
;
+; This configuration file is read every time you call app meetme()
+;
[rooms]
;
; Usage is conf => confno[,pin]
diff --git a/configs/modem.conf.sample b/configs/modem.conf.sample
index 3af4530b0..bca405d96 100755
--- a/configs/modem.conf.sample
+++ b/configs/modem.conf.sample
@@ -84,7 +84,7 @@ mode=immediate
; two other devices, which are in group '1' and are used when an
; outgoing dial used: exten => s,1,Dial,Modem/g1:1234|60|r
; (we do not need more outgoing devices, since ISDN2 has only 2 channels.)
-; Lines can be in more than one group (1-31); comma seperated list.
+; Lines can be in more than one group (1-31); comma separated list.
;
group=1 ; group=1,2,3,9-12
;msn=50780023
diff --git a/configs/queues.conf.sample b/configs/queues.conf.sample
index 7ba488ad3..a0e73e04d 100755
--- a/configs/queues.conf.sample
+++ b/configs/queues.conf.sample
@@ -17,10 +17,10 @@
;
; A sample call queue
;
-; Music sets which musiconhold applies for this particular
-; call queue
+; Musiconhold sets which music applies for this particular
+; call queue (configure classes in musiconhold.conf)
;
-;music = default
+;musiconhold = default
;
; An announcement may be specified which is played for the member as
; soon as they answer a call, typically to indicate to them which queue
@@ -92,6 +92,7 @@
;queue-minutes = queue-minutes ; ("minutes.")
;queue-seconds = queue-seconds ; ("seconds.")
;queue-thankyou = queue-thankyou ; ("Thank you for your patience.")
+;queue-lessthan = queue-less-than ; ("less than")
;
; Calls may be recorded using Asterisk's monitor resource
; This can be enabled from within the Queue application, starting recording
@@ -109,10 +110,16 @@
;
; monitor-join = yes
;
-; If you wish to allow queues that have no members currently to be joined, set this to yes
+; If you wish to allow queues that have no members currently to be joined, then set this
+; to yes. Note that this is for use with dynamic queue members!
;
; joinempty = yes
;
+; If you wish to remove callers from the queue if there are no agents present, then set
+; this to yes. Note that this is for use with dynamic queue members!
+;
+; leavewhenempty = yes
+;
; Asterisk can generate AgentCalled events when an agent is rung, if this is turned on
; (may generate a LOT of extra manager events)
;
@@ -128,6 +135,12 @@
;member => Agent/1001
;member => Agent/1002
+;
+; Note that using agent groups is probably not what you want. Strategies do
+; not propagate down to the Agent system so if you want round robin, least
+; recent, etc, you should list all the agents in this file individually and not
+; use agent groups.
+;
;member => Agent/@1 ; Any agent in group 1
;member => Agent/:1,1 ; Any agent in group 1, wait for first
; available, but consider with penalty
diff --git a/configs/rtp.conf.sample b/configs/rtp.conf.sample
index 76327cd95..a9a455c92 100755
--- a/configs/rtp.conf.sample
+++ b/configs/rtp.conf.sample
@@ -5,6 +5,8 @@
;
; RTP start and RTP end configure start and end addresses
;
+; Defaults are rtpstart=5000 and rtpend=31000
+;
rtpstart=10000
rtpend=20000
;
diff --git a/configs/sip.conf.sample b/configs/sip.conf.sample
index de46d9439..2a5659b0c 100755
--- a/configs/sip.conf.sample
+++ b/configs/sip.conf.sample
@@ -19,6 +19,9 @@
;
; sip debug Show all SIP messages
;
+; reload chan_sip.so Reload configuration file
+; Active SIP peers will not be reconfigured
+;
[general]
context=default ; Default context for incoming calls
@@ -131,7 +134,6 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls
; context context
; permit permit
; deny deny
-; auth auth
; secret secret
; md5secret md5secret
; dtmfmode dtmfmode
@@ -229,13 +231,26 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls
;mailbox=1234@context,2345 ; Mailbox(-es) for message waiting indicator
+;[polycom]
+;type=friend ; Friends place calls and receive calls
+;context=from-sip ; Context for incoming calls from this user
+;secret=blahpoly
+;host=dynamic ; This peer register with us
+;dtmfmode=rfc2833 ; Choices are inband, rfc2833, or info
+;username=polly ; Username to use in INVITE until peer registers
+;disallow=all
+;allow=ulaw ; dtmfmode=inband only works with ulaw or alaw!
+;progressinband=no ; Polycom phones don't work properly with "never"
+
+
;[pingtel]
;type=friend
;username=pingtel
;secret=blah
;host=dynamic
-;insecure=yes ; To match a peer based by IP address only and not peer
-;insecure=very ; To allow registered hosts to call without re-authenticating
+;insecure=port ; Allow matching of peer by IP address without matching port number
+;insecure=invite ; Do not require authentication of incoming INVITEs
+;insecure=port,invite ; (both)
;qualify=1000 ; Consider it down if it's 1 second to reply
; Helps with NAT session
; qualify=yes uses default value
diff --git a/configs/voicemail.conf.sample b/configs/voicemail.conf.sample
index 315611a76..5b55eed09 100755
--- a/configs/voicemail.conf.sample
+++ b/configs/voicemail.conf.sample
@@ -55,8 +55,10 @@ maxlogins=3
;
; Note: The emailbody config row can be up to 512 characters due to a limitation in
; asterisk config files.
-;emailsubject=New VM (${VM_MSGNUM}) - ${VM_DUR} long in mailbox ${VM_MAILBOX} from ${VM_CALLERID}
-;emailbody=Dear ${VM_NAME}:\n\n\tjust wanted to let you know you were just left a ${VM_DUR} long message (number ${VM_MSGNUM})\nin mailbox ${VM_MAILBOX} from ${VM_CALLERID}, on ${VM_DATE} so you might\nwant to check it when you get a chance. Thanks!\n\n\t\t\t\t--Asterisk\n
+;emailsubject=[PBX]: New message ${VM_MSGNUM} in mailbox ${VM_MAILBOX}
+; The following definition is very close to the default, but the default shows just
+; the CIDNAME, if it is not null, else just the CIDNUM, or "an unknown caller" if they are both null.
+;emailbody=Dear ${VM_NAME}:\n\n\tjust wanted to let you know you were just left a ${VM_DUR} long message (number ${VM_MSGNUM})\nin mailbox ${VM_MAILBOX} from ${VM_CALLERID}, on ${VM_DATE}, so you might\nwant to check it when you get a chance. Thanks!\n\n\t\t\t\t--Asterisk\n
;
; You can override the default program to send e-mail if you wish, too
diff --git a/configs/zapata.conf.sample b/configs/zapata.conf.sample
index c692a27b8..b7b660318 100755
--- a/configs/zapata.conf.sample
+++ b/configs/zapata.conf.sample
@@ -177,6 +177,13 @@ callwaiting=yes
;
usecallingpres=yes
;
+; Some countries (UK) have ring tones with different ring tones (ring-ring),
+; which means the callerid needs to be set later on, and not just after
+; the first ring, as per the default.
+;
+;sendcalleridafter=1
+;
+;
; Support Caller*ID on Call Waiting
;
callwaitingcallerid=yes
diff --git a/contrib/README.festival b/contrib/README.festival
index a6a7c067c..24912827c 100755
--- a/contrib/README.festival
+++ b/contrib/README.festival
@@ -11,6 +11,23 @@ You need :
1.4.2 RELEASE are included. The patch adds a new command to festival
(asterisk_tts).
+It is possible to run Festival without patches in the source-code. Just
+add this to your /etc/festival.scm or /usr/share/festival/festival/scm:
+
+ (define (tts_textasterisk string mode)
+ "(tts_textasterisk STRING MODE)
+ Apply tts to STRING. This function is specifically designed for
+ use in server mode so a single function call may synthesize the string.
+ This function name may be added to the server safe functions."
+ (let ((wholeutt (utt.synth (eval (list 'Utterance 'Text string)))))
+ (utt.wave.resample wholeutt 8000)
+ (utt.wave.rescale wholeutt 5)
+ (utt.send.wave.client wholeutt)))
+
+[See the comment with subject "Using Debian
+ festival >= 1.4.3-15 (no recompiling needed!)" on
+ http://www.voip-info.org/wiki-Asterisk+festival+installation for the
+ original mentioning of it]
2) You may wish to obtain and install the asterisk-perl
module by James Golovich <james@gnuinter.net>, from
diff --git a/contrib/firmware/iax/iaxy.bin b/contrib/firmware/iax/iaxy.bin
index 1bd4ee208..709cfb0ed 100755
--- a/contrib/firmware/iax/iaxy.bin
+++ b/contrib/firmware/iax/iaxy.bin
Binary files differ
diff --git a/contrib/scripts/astgenkey.8 b/contrib/scripts/astgenkey.8
new file mode 100755
index 000000000..6dc793eb1
--- /dev/null
+++ b/contrib/scripts/astgenkey.8
@@ -0,0 +1,129 @@
+.\" $Header$
+.\"
+.\" transcript compatibility for postscript use.
+.\"
+.\" synopsis: .P! <file.ps>
+.\"
+.de P!
+.fl
+\!!1 setgray
+.fl
+\\&.\"
+.fl
+\!!0 setgray
+.fl \" force out current output buffer
+\!!save /psv exch def currentpoint translate 0 0 moveto
+\!!/showpage{}def
+.fl \" prolog
+.sy sed \-e 's/^/!/' \\$1\" bring in postscript file
+\!!psv restore
+.
+.de pF
+.ie \\*(f1 .ds f1 \\n(.f
+.el .ie \\*(f2 .ds f2 \\n(.f
+.el .ie \\*(f3 .ds f3 \\n(.f
+.el .ie \\*(f4 .ds f4 \\n(.f
+.el .tm ? font overflow
+.ft \\$1
+..
+.de fP
+.ie !\\*(f4 \{\
+. ft \\*(f4
+. ds f4\"
+' br \}
+.el .ie !\\*(f3 \{\
+. ft \\*(f3
+. ds f3\"
+' br \}
+.el .ie !\\*(f2 \{\
+. ft \\*(f2
+. ds f2\"
+' br \}
+.el .ie !\\*(f1 \{\
+. ft \\*(f1
+. ds f1\"
+' br \}
+.el .tm ? font underflow
+..
+.ds f1\"
+.ds f2\"
+.ds f3\"
+.ds f4\"
+'\" t
+.ta 8n 16n 24n 32n 40n 48n 56n 64n 72n
+.TH ASTGENKEY 8 "May 14th, 2005" "Asterisk" "Linux Programmer's Manual"
+.SH NAME
+.B astgenkey
+-- generates keys for for Asterisk IAX2 RSA authentication
+.SH SYNOPSIS
+.PP
+.B astgenkey
+[ -q ] [ -n ] [ \fIkeyname\fP ]
+
+.SH DESCRIPTION
+.B genzaptelconf
+This script generates an RSA private and public key pair in PEM format
+for use by Asterisk. The private key should be kept a secret, as it can
+be used to fake your system's identity. Thus by default (without the
+option
+.I -n
+) the script will create a passphrase-encrypted copy of your secret key:
+without entering the passphrase you won't be able to use it.
+
+However if you want to use such a key with Asterisk, you'll have to start
+it interactively, because the scripts that start asterisk can't use that
+encrypted key.
+
+The key is identified by a name. If you don't write the name on the
+command-line you'll be prompted for one. The outputs of the script are:
+
+.I name\fB.pub
+.RS
+The public key: not secret. Send this to the other side.
+.RE
+
+.I name\fB.key
+.RS
+The private key: secret.
+.RE
+
+Those files should be copied to
+.I /var/lib/asterisk/keys
+
+(The private key: on your system. The public key: on other systems)
+
+To see the currently-installed keys from the asterisk CLI, use the command
+
+.RS
+show keys
+.RE
+
+.SH OPTIONS
+.B -q
+.RS
+Run quietly.
+.RE
+
+.B -n
+.RS
+Don't encrypt the private key.
+.RE
+
+.SH FILES
+.I /var/lib/asterisk/keys
+.RS
+.RE
+
+.SH "SEE ALSO"
+asterisk(8), genrsa(1), rsa(1),
+
+http://www.voip-info.org/wiki-Asterisk+iax+rsa+auth
+
+.SH "AUTHOR"
+This manual page was written by Tzafrir Cohen <tzafrir.cohen@xorcom.com>
+Permission is granted to copy, distribute and/or modify this document under
+the terms of the GNU General Public License, Version 2 any
+later version published by the Free Software Foundation.
+
+On Debian systems, the complete text of the GNU General Public
+License can be found in /usr/share/common-licenses/GPL.
diff --git a/contrib/scripts/autosupport b/contrib/scripts/autosupport
new file mode 100755
index 000000000..e13d839dc
--- /dev/null
+++ b/contrib/scripts/autosupport
@@ -0,0 +1,155 @@
+#!/bin/sh
+#
+# Collect support information
+#
+# Copyright (C) 2005, Digium, Inc.
+#
+# Written by John Bigelow (support@digium.com)
+#
+# Distributed under the terms of the GNU General Public
+# License
+#
+
+OUTPUT=$HOME/digiuminfo
+
+if [ $UID -ne 0 ]; then
+
+ echo "You must be root to run this."
+
+exit 1
+fi
+
+echo
+echo "This will gather information about your system such as:"
+echo "pci listing, dmesg, running processes, and kernel version"
+echo "To continue press 'y', to quit press any other key"
+read ans
+
+if [ "$ans" = "y" ]; then
+
+ rm -f $OUTPUT
+
+ echo "------------------" >> $OUTPUT;
+ echo "PCI LIST " >> $OUTPUT;
+ echo "------------------" >> $OUTPUT;
+ lspci -vb >> $OUTPUT;
+ echo >> $OUTPUT;
+ echo >> $OUTPUT;
+
+ echo "------------------" >> $OUTPUT;
+ echo "INTERRUPTS" >> $OUTPUT;
+ echo "------------------" >> $OUTPUT;
+ cat /proc/interrupts >> $OUTPUT;
+ echo >> $OUTPUT;
+ echo >> $OUTPUT;
+
+ echo "------------------" >> $OUTPUT;
+ echo "DMESG OUTPUT" >> $OUTPUT;
+ echo "------------------" >> $OUTPUT;
+ dmesg >> $OUTPUT;
+ echo >> $OUTPUT;
+ echo >> $OUTPUT;
+
+ echo "------------------" >> $OUTPUT;
+ echo "RUNNING PROCESSES" >> $OUTPUT;
+ echo "------------------" >> $OUTPUT;
+ ps aux >> $OUTPUT;
+ echo >> $OUTPUT;
+ echo >> $OUTPUT;
+
+ echo "------------------" >> $OUTPUT;
+ echo "KERNEL VERSION" >> $OUTPUT;
+ echo "------------------" >> $OUTPUT;
+ uname -a >> $OUTPUT;
+ echo >> $OUTPUT;
+ echo >> $OUTPUT;
+
+ echo "------------------" >> $OUTPUT;
+ echo "CPU INFO" >> $OUTPUT;
+ echo "------------------" >> $OUTPUT;
+ cat /proc/cpuinfo >> $OUTPUT;
+ echo >> $OUTPUT;
+ echo >> $OUTPUT;
+
+ echo "------------------" >> $OUTPUT;
+ echo "HDPARM STATUS" >> $OUTPUT;
+ echo "------------------" >> $OUTPUT;
+ hdparm /dev/hda >> $OUTPUT;
+ hdparm -i /dev/hda >> $OUTPUT;
+ echo >> $OUTPUT;
+ echo >> $OUTPUT;
+
+ echo "------------------" >> $OUTPUT;
+ echo "ZAPTEL CONFIG" >> $OUTPUT;
+ echo "------------------" >> $OUTPUT;
+ grep -v '^#' /etc/zaptel.conf >> $OUTPUT;
+ echo >> $OUTPUT;
+ echo >> $OUTPUT;
+
+ echo "------------------" >> $OUTPUT;
+ echo "ZAPATA CONFIG" >> $OUTPUT;
+ echo "------------------" >> $OUTPUT;
+ grep -v '^;' /etc/asterisk/zapata.conf >> $OUTPUT;
+ echo >> $OUTPUT;
+ echo >> $OUTPUT;
+
+ echo "------------------" >> $OUTPUT;
+ echo "EXTENSIONS CONFIG" >> $OUTPUT;
+ echo "------------------" >> $OUTPUT;
+ grep -v '^;' /etc/asterisk/extensions.conf >> $OUTPUT;
+ echo >> $OUTPUT;
+ echo >> $OUTPUT;
+
+else
+ echo "terminated";
+exit
+fi
+
+echo
+echo "Digium may require root level access to the system to help debug";
+echo "the problem you are experiencing. Do you want to provide login";
+echo "information at this time?";
+echo "Press 'y' for yes and any other key to exit and save the previous info collected"
+read login
+
+if [ "$login" = "y" ]; then
+
+ echo "------------------" >> $OUTPUT;
+ echo "LOGIN INFORMATION" >> $OUTPUT;
+ echo "------------------" >> $OUTPUT;
+
+ echo
+ echo "What is your root password?"
+ read rootpass
+
+ echo
+ echo "Root pass: "$rootpass >> $OUTPUT
+
+ echo
+ echo "What is your PUBLIC IP address?"
+ read ip
+
+ echo "IP address: "$ip >> $OUTPUT
+
+ echo
+ echo "Please provide any other login information that the technician"
+ echo "may need to know to login to the system'(press enter if not)'"
+ read adinfo
+
+ echo "Additional login info: "$adinfo >> $OUTPUT
+
+ echo
+ echo "All information has been stored in $OUTPUT,"
+ echo "Please attach this file to an email ticket you already"
+ echo "have open with Digium Tech Support."
+
+else
+ echo
+ echo "All information except login info has been stored in $OUTPUT,"
+ echo "Please send this file to an email ticket you already"
+ echo "have open with Digium Tech Support."
+exit
+fi
+
+
+
diff --git a/contrib/scripts/autosupport.8 b/contrib/scripts/autosupport.8
new file mode 100755
index 000000000..e356fcdbb
--- /dev/null
+++ b/contrib/scripts/autosupport.8
@@ -0,0 +1,41 @@
+.TH AUTOSUPPORT 8 "Jul 5th, 2005" "Asterisk" "Linux Programmer's Manual"
+.SH NAME
+.B autosupport
+\(em interactive script to provide Digium[tm]'s support with information
+.SH SYNOPSIS
+.PP
+.B autosupport
+
+.SH DESCRIPTION
+.B autoasupport
+is a script that is normally run by a user contacting Digium's support
+to automate gathering support information.
+
+It will probe the system for some configuration and run-time information,
+and will also prompt the user for some optional access information (IP
+address, login and password).
+
+The information is written to /root/digiuminfo which the user is expected
+to attach to a support ticket to Digium.
+
+The script must be run as root as it reads Asterisk's configuration and
+the disk information using hdparm(8).
+
+.SH FILES
+.B /root/digiuminfo
+.RS
+The output of the script goes there
+.RE
+
+.SH SEE ALSO
+asterisk(8)
+
+.SH "AUTHOR"
+autosupport was written by John Bigelow <support@digium.com>.
+This manual page was written by Tzafrir Cohen <tzafrir.cohen@xorcom.com>
+Permission is granted to copy, distribute and/or modify this document under
+the terms of the GNU General Public License, Version 2 any
+later version published by the Free Software Foundation.
+
+On Debian systems, the complete text of the GNU General Public
+License can be found in /usr/share/common-licenses/GPL.
diff --git a/contrib/scripts/safe_asterisk.8 b/contrib/scripts/safe_asterisk.8
new file mode 100755
index 000000000..277fa5f8d
--- /dev/null
+++ b/contrib/scripts/safe_asterisk.8
@@ -0,0 +1,62 @@
+.TH SAFE_ASTERISK 8 "Jun 30th, 2005" "Asterisk" "Linux Programmer's Manual"
+.SH NAME
+.B safe_asterisk
+\(em A wrapper to run the asterisk executable in a loop
+.SH SYNOPSIS
+.PP
+.B safe_asterisk
+.I [ asterisk_params ]
+
+.SH DESCRIPTION
+.B safe_asterisk
+is a script that runs asterisk in a loop, which can be useful if you
+fear asterisk may crash.
+
+The script does not run in the background like a standard service. Rather,
+it runs in its own linux virtual console (9, by default).
+It also uses the option '-c' of asterisk(8) to avoid detaching asterisk
+from that terminal.
+
+safe_asterisk also runs asterisk with unlimited core file size, and thus
+asterisk will dump core in case of a crash.
+
+To get a "picture" of console 9, from another terminal (e.g: from a
+remote shell session) you can use:
+
+ screendump 9
+
+The init script of the Debian package should be able to run safe_asterisk
+as the asterisk service, if so configured. See coments in
+/etc/default/asterisk
+
+.SH FILES
+.B /tmp
+.RS
+safe_asterisk runs in that directory, rather than in / as usual.
+.RE
+
+.B /tmp/core
+.RS
+If core files were generated there, they may be
+.RE
+
+.SH BUGS
+While showing the output on a console is useful, using screen(1) as
+the terminal may be better.
+
+The script does not read configuration from standard location under /etc
+
+It uses fixed locations under /tmp , and thus may be exposed to a
+symlink attacks.
+
+.SH SEE ALSO
+asterisk(8), screendump(9)
+
+.SH "AUTHOR"
+This manual page was written by Tzafrir Cohen <tzafrir.cohen@xorcom.com>
+Permission is granted to copy, distribute and/or modify this document under
+the terms of the GNU General Public License, Version 2 any
+later version published by the Free Software Foundation.
+
+On Debian systems, the complete text of the GNU General Public
+License can be found in /usr/share/common-licenses/GPL.
diff --git a/db1-ast/hash/ndbm.c b/db1-ast/hash/ndbm.c
index 20840e976..d702f737a 100755
--- a/db1-ast/hash/ndbm.c
+++ b/db1-ast/hash/ndbm.c
@@ -105,15 +105,20 @@ dbm_fetch(db, key)
DBM *db;
datum key;
{
- datum retval;
+ datum retdata;
int status;
+ DBT dbtkey, dbtretdata;
- status = (db->get)(db, (DBT *)&key, (DBT *)&retval, 0);
+ dbtkey.data = key.dptr;
+ dbtkey.size = key.dsize;
+ status = (db->get)(db, &dbtkey, &dbtretdata, 0);
if (status) {
- retval.dptr = NULL;
- retval.dsize = 0;
+ dbtretdata.data = NULL;
+ dbtretdata.size = 0;
}
- return (retval);
+ retdata.dptr = dbtretdata.data;
+ retdata.dsize = dbtretdata.size;
+ return (retdata);
}
/*
@@ -126,11 +131,14 @@ dbm_firstkey(db)
DBM *db;
{
int status;
- datum retdata, retkey;
+ datum retkey;
+ DBT dbtretkey, dbtretdata;
- status = (db->seq)(db, (DBT *)&retkey, (DBT *)&retdata, R_FIRST);
+ status = (db->seq)(db, &dbtretkey, &dbtretdata, R_FIRST);
if (status)
- retkey.dptr = NULL;
+ dbtretkey.data = NULL;
+ retkey.dptr = dbtretkey.data;
+ retkey.dsize = dbtretkey.size;
return (retkey);
}
@@ -144,11 +152,14 @@ dbm_nextkey(db)
DBM *db;
{
int status;
- datum retdata, retkey;
+ datum retkey;
+ DBT dbtretkey, dbtretdata;
- status = (db->seq)(db, (DBT *)&retkey, (DBT *)&retdata, R_NEXT);
+ status = (db->seq)(db, &dbtretkey, &dbtretdata, R_NEXT);
if (status)
- retkey.dptr = NULL;
+ dbtretkey.data = NULL;
+ retkey.dptr = dbtretkey.data;
+ retkey.dsize = dbtretkey.size;
return (retkey);
}
/*
@@ -162,8 +173,11 @@ dbm_delete(db, key)
datum key;
{
int status;
+ DBT dbtkey;
- status = (db->del)(db, (DBT *)&key, 0);
+ dbtkey.data = key.dptr;
+ dbtkey.size = key.dsize;
+ status = (db->del)(db, &dbtkey, 0);
if (status)
return (-1);
else
@@ -177,12 +191,18 @@ dbm_delete(db, key)
* 1 if DBM_INSERT and entry exists
*/
extern int
-dbm_store(db, key, content, flags)
+dbm_store(db, key, data, flags)
DBM *db;
- datum key, content;
+ datum key, data;
int flags;
{
- return ((db->put)(db, (DBT *)&key, (DBT *)&content,
+ DBT dbtkey, dbtdata;
+
+ dbtkey.data = key.dptr;
+ dbtkey.size = key.dsize;
+ dbtdata.data = data.dptr;
+ dbtdata.size = data.dsize;
+ return ((db->put)(db, &dbtkey, &dbtdata,
(flags == DBM_INSERT) ? R_NOOVERWRITE : 0));
}
diff --git a/dlfcn.c b/dlfcn.c
index 60244968e..6ef390c4a 100755
--- a/dlfcn.c
+++ b/dlfcn.c
@@ -270,7 +270,7 @@ static const struct mach_header *get_mach_header_from_NSModule(NSModule * mod)
* trying to locate a module. We first look at the values of LD_LIBRARY_PATH
* and DYLD_LIBRARY_PATH, and then finally fall back to looking into
* /usr/lib and /lib. Since both of the environments variables can contain a
- * list of colon seperated paths, we simply concat them and the two other paths
+ * list of colon separated paths, we simply concat them and the two other paths
* into one big string, which we then can easily parse.
* Splitting this string into the actual path list is done by getSearchPath()
*/
diff --git a/dns.c b/dns.c
index 349bd2ebd..65a31ac58 100755
--- a/dns.c
+++ b/dns.c
@@ -19,6 +19,7 @@
#include <asterisk/logger.h>
#include <asterisk/channel.h>
#include <asterisk/dns.h>
+#include "asterisk/endian.h"
#define MAX_SIZE 4096
diff --git a/doc/README.cdr b/doc/README.cdr
index 2b0c8f289..cb71ba03e 100755
--- a/doc/README.cdr
+++ b/doc/README.cdr
@@ -2,25 +2,38 @@ Asterisk billing support - Call Detail Records
----------------------------------------------
Asterisk generates Call Detail Records in a database or in a comma
separated text file.
+
* cdr_csv supports comma separated text file storage, this is the
default driver
+ * cdr_manager supports CDR information via the AMI, The Asterisk Manager
+ interface
* cdr_odbc supports UnixODBC databases, see http://www.unixodbc.org
for an updated list of supported databases, from MySQL to MsSQL
and text files.
+ * cdr_tds supports FreeTDS databases (Among them MS SQL)
+ * cdr_sqlite supports SQlite
+ * cdr_pgsql supports PostgreSQL
+
+In the asterisk-addons cvs archive, there's a cdr_mysql driver for
+MySQL.
Applications
------------
- * Asterisk cmd setaccount: Set account code for billing
- * Asterisk cmd NoCDR: Make sure no CDR is saved for a specific call
- * Asterisk cmd resetCDR: Reset CDR
- * Asterisk cmd authenticate - Authenticates and sets the account code
- * Asterisk cmd SetCDRUserField - Set CDR user field
- * Asterisk cmd AppendCDRUserField - Append data to CDR User field
+ * setaccount Set account code for billing
+ * setAMAflags Sets AMA flags
+ * NoCDR Make sure no CDR is saved for a specific call
+ * resetCDR Reset CDR
+ * forkCDR Save current CDR and start a new CDR for this call
+ * authenticate Authenticates and sets the account code
+ * SetCDRUserField Set CDR user field
+ * AppendCDRUserField Append data to CDR User field
For more information, use the "show application" command.
+You can set default account codes and AMA flags for devices in
+channel configuration files, like sip.conf, iax.conf etc.
Fields of the CDR in Asterisk
@@ -59,5 +72,4 @@ will report a short call time. If you want detailed records you must
turn off IAX transfer, but unless your servers are very close together, you
will definitely get a latency hit from doing so.
-----------------
-2004-01-17/v0.7.1
+
diff --git a/doc/README.iax b/doc/README.iax
index 10f6a8089..1a35d6b15 100755
--- a/doc/README.iax
+++ b/doc/README.iax
@@ -133,10 +133,12 @@ The first line of the "general" section is always:
Following the first line are a number of other possibilities:
-> port = <portnum>
+> bindport = <portnum>
-This sets the port that IAX will bind to. The default IAX port number is
-5036. It is recommended that this value not be altered in general.
+This sets the port that IAX will bind to. The default IAX version 1
+port number is 5036. For IAX version 2, that is now the default in
+Asterisk, the default port is 4569.
+It is recommended that this value not be altered in general.
> bindaddr = <ipaddr>
@@ -170,12 +172,15 @@ disallow the LPC10 codec just because it doesn't sound very good.
These parameters control the operation of the jitter buffer. The
jitterbuffer should always be enabled unless you expect all your
-connections to be over a LAN. The drop count is the maximum number of
-voice packets to allow to drop (out of 100). Useful values are 3-10. The
-maxjitterbuffer is the maximum amount of jitter buffer to permit to be
-used. The "maxexcessbuffer" is the maximum amount of excess jitter buffer
-that is permitted before the jitter buffer is slowly shrunk to eliminate
-latency.
+connections to be over a LAN.
+* drop count is the maximum number of voice packets to allow to drop
+ (out of 100). Useful values are 3-10.
+* maxjitterbuffer is the maximum amount of jitter buffer to permit to be
+ used.
+* maxexcessbuffer is the maximum amount of excess jitter buffer
+ that is permitted before the jitter buffer is slowly shrunk to eliminate
+ latency.
+* minexcessbuffer is the minimum amout of excess jitter buffer
> accountcode = <code>
> amaflags = [default|omit|billing|documentation]
@@ -208,13 +213,20 @@ The name is a required field, and is the remote peer name that we wish to
identify ourselves as. A secret may be provided as well. The secret is
generally a shared password between the local server and the remote
server. However, if the secret is in square brackets ([]'s) then it is
-interpreted as the name of a key to use. In that case, the local Asterisk
+interpreted as the name of a RSA key to use. In that case, the local Asterisk
server must have the *private* key (/var/lib/asterisk/keys/<name>.key) and
the remote server will have to have the corresponding public key.
The "host" is a required field and is the hostname or IP address of the
remote Asterisk server. The port specification is optional and is by
-default 5036 if not specified.
+default 4569 for iax2 if not specified.
+
+> notransfer = yes | no
+
+If an IAX phone calls another IAX phone by using a Asterisk server,
+Asterisk will transfer the call to go peer to peer. If you do not
+want this, turn on notransfer with a "yes". This is also settable
+for peers and users.
-------------
@@ -232,7 +244,7 @@ should be an alphanumeric string.
> type = [user|peer|friend]
This line tells Asterisk how to interpret this entity. Users are things
-that connect to us, while peers are people we connect to, and a friend is
+that connect to us, while peers are phones we connect to, and a friend is
shorthand for creating a user and a peer with identical information
----------------
@@ -262,8 +274,8 @@ the final result being the decision. For example:
would deny anyone in 192.168.0.0 with a netmask of 24 bits (class C),
whereas:
-> deny = 192.168.0.0/255.255.255.0
-> permit = 0.0.0.0/0.0.0.0
+> deny = 192.168.0.0/24
+> permit = 0.0.0.0/0
would not deny anyone since the final rule would permit anyone, thus
overriding the denial.
@@ -281,8 +293,8 @@ perspective of your server.
You may select which authentication methods are permitted to be used by
the user to authenticate to us. Multiple methods may be specified,
-separated by commas. If md5 or plaintext authentication is selected, a
-secret must be provided. If RSA authentication is specified, then one or
+separated by commas. If md5 or plaintext authentication is selected, a
+secret must be provided. If RSA authentication is specified, then one or
more key names must be specified with "inkeys"
If no secret is specified and no authentication method is specified, then
@@ -328,3 +340,30 @@ or has timed out.
Specifies the context name to be passed to the peer for it to use when routing
the call through its dial plan. This entry will be used only if a context
is not included in the IAX2 channel name passed to the Dial command.
+
+> qualify = [yes | no | <value>]
+
+Qualify turns on checking of availability of the remote peer. If the
+peer becomes unavailable, no calls are placed to the peer until
+it is reachable again. This is also helpful in certain NAT situations.
+
+> jitterbuffer = [yes | no]
+
+Turns on or off the jitterbuffer for this peer
+
+> mailbox = <mailbox>[@mailboxcontext]
+
+Specifies a mailbox to check for voicemail notification.
+
+> permit = <ipaddr>/<netmask>
+> deny = <ipaddr>/<netmask>
+
+Permit and deny rules may be applied to users, allowing them to connect
+from certain IP addresses and not others. The permit and deny rules are
+interpreted in sequence and all are evaluated on a given IP address, with
+the final result being the decision. See the user section above
+for examples.
+
+----------------------------------------------------------------------
+For more examples of a configuration, please see the iax.conf.sample in
+your the /configs directory of you source code distribution
diff --git a/doc/README.tds b/doc/README.tds
new file mode 100755
index 000000000..e1c27fba3
--- /dev/null
+++ b/doc/README.tds
@@ -0,0 +1,18 @@
+PLEASE NOTE
+
+The cdr_tds module is NOT compatible with version 0.63 of FreeTDS.
+
+The cdr_tds module is known to work with FreeTDS version 0.62.1;
+it should also work with 0.62.2, 0.62.3 and 0.62.4, which are bug
+fix releases.
+
+The cdr_tds module uses the raw "libtds" API of FreeTDS. It appears
+that from 0.63 onwards, this is not considered a published API
+of FreeTDS and is subject to change without notice.
+
+Between 0.62.x and 0.63 of FreeTDS, many incompatible changes
+have been made to the libtds API.
+
+For newer versions of FreeTDS, it is recommended that you use the
+ODBC driver.
+
diff --git a/doc/README.variables b/doc/README.variables
index dfb6de3d1..9fbfb1dd0 100755
--- a/doc/README.variables
+++ b/doc/README.variables
@@ -55,7 +55,7 @@ ${CALLERIDNUM} Caller ID Number only
${CALLINGPRES} PRI Caller ID presentation for incoming calls
${CHANNEL} Current channel name
${CONTEXT} Current context
-${DATETIME} Current date time in the format: YYYY-MM-DD_HH:MM:SS
+${DATETIME} Current date time in the format: DDMMYYYY-HH:MM:SS
${DNID} Dialed Number Identifier
${ENUM} Result of application EnumLookup
${EPOCH} Current unix style epoch
@@ -75,12 +75,15 @@ ${TIMESTAMP} Current date time in the format: YYYYMMDD-HHMMSS
${TXTCIDNAME} Result of application TXTCIDName
${UNIQUEID} Current call unique identifier
+NOTE: Attempting to set any of these "special" variables will not change
+ their value, but will not display any warning either.
+
The dial() application sets the following variables:
${DIALEDPEERNAME} Dialed peer name
${DIALEDPEERNUMBER} Dialed peer number
-${DIALEDTIME} Time for the call (seconds)
-${ANSWEREDTIME} Time from dial to answer (seconds)
+${DIALEDTIME} Total time for the call in seconds (Network time).
+${ANSWEREDTIME} Time from answer to end of call in seconds (Billable time).
${DIALSTATUS} Status of the call, one of:
CHANUNAVAIL | CONGESTION | BUSY | NOANSWER | ANSWER | CANCEL
diff --git a/doc/cdr.txt b/doc/cdr.txt
index 580619737..dac7df30a 100755
--- a/doc/cdr.txt
+++ b/doc/cdr.txt
@@ -88,7 +88,7 @@ MSSQL: Asterisk can currently store CDRs into an MSSQL database in
[lastdata] [varchar] (80) NOT NULL ,
[duration] [int] NOT NULL ,
[billsec] [int] NOT NULL ,
- [disposition] [varchar] (45) NOT NULL ,
+ [disposition] [int] NOT NULL ,
[amaflags] [int] NOT NULL ,
[accountcode] [varchar] (20) NOT NULL ,
[uniqueid] [varchar] (32) NOT NULL ,
diff --git a/dsp.c b/dsp.c
index e637aa65b..a7566f0da 100755
--- a/dsp.c
+++ b/dsp.c
@@ -1124,7 +1124,7 @@ static int __ast_dsp_call_progress(struct ast_dsp *dsp, short *s, int len)
if (pass > dsp->gsamp_size - dsp->gsamps)
pass = dsp->gsamp_size - dsp->gsamps;
for (x=0;x<pass;x++) {
- for (y=0;y<dsp->freqcount;y++)
+ for (y=0;y<=dsp->freqcount;y++)
goertzel_sample(&dsp->freqs[y], s[x]);
dsp->genergy += s[x] * s[x];
}
@@ -1136,8 +1136,9 @@ static int __ast_dsp_call_progress(struct ast_dsp *dsp, short *s, int len)
for (y=0;y<7;y++)
hz[y] = goertzel_result(&dsp->freqs[y]);
#if 0
- printf("Got whole dsp state: 350: %e, 440: %e, 480: %e, 620: %e, 950: %e, 1400: %e, 1800: %e, Energy: %e\n",
- hz_350, hz_440, hz_480, hz_620, hz_950, hz_1400, hz_1800, dsp->genergy);
+ printf("\n350: 425: 440: 480: 620: 950: 1400: 1800: Energy: \n");
+ printf("%.2e %.2e %.2e %.2e %.2e %.2e %.2e %.2e %.2e\n",
+ hz[HZ_350], hz[HZ_425], hz[HZ_440], hz[HZ_480], hz[HZ_620], hz[HZ_950], hz[HZ_1400], hz[HZ_1800], dsp->genergy);
#endif
switch(dsp->progmode) {
case PROG_MODE_NA:
@@ -1308,10 +1309,10 @@ int ast_dsp_busydetect(struct ast_dsp *dsp)
}
#endif
if (avgtone > dsp->historicnoise[x]) {
- if (avgtone - (avgtone / BUSY_PERCENT) <= dsp->historicsilence[x])
+ if (avgtone - (avgtone / BUSY_PERCENT) <= dsp->historicnoise[x])
hittone++;
} else {
- if (avgtone + (avgtone / BUSY_PERCENT) >= dsp->historicsilence[x])
+ if (avgtone + (avgtone / BUSY_PERCENT) >= dsp->historicnoise[x])
hittone++;
}
}
@@ -1465,7 +1466,7 @@ struct ast_frame *ast_dsp_process(struct ast_channel *chan, struct ast_dsp *dsp,
shortdata[x] = AST_ALAW(odata[x]);
break;
default:
- ast_log(LOG_WARNING, "Inband DTMF is not supported on codec %s. Use RFC2833\n", ast_codec2str(af->subclass));
+ ast_log(LOG_WARNING, "Inband DTMF is not supported on codec %s. Use RFC2833\n", ast_getformatname(af->subclass));
return af;
}
silence = __ast_dsp_silence(dsp, shortdata, len, NULL);
diff --git a/enum.c b/enum.c
index 690587163..9591c6b6b 100755
--- a/enum.c
+++ b/enum.c
@@ -47,7 +47,7 @@
#define TOPLEV "e164.arpa."
static struct enum_search {
- char toplev[80];
+ char toplev[512];
struct enum_search *next;
} *toplevs;
@@ -79,11 +79,11 @@ static int parse_ie(unsigned char *data, int maxdatalen, unsigned char *src, int
static int parse_naptr(unsigned char *dst, int dstsize, char *tech, int techsize, unsigned char *answer, int len, char *naptrinput)
{
unsigned char *oanswer = answer;
- unsigned char flags[80] = "";
- unsigned char services[80] = "";
- unsigned char regexp[80] = "";
- unsigned char repl[80] = "";
- unsigned char temp[80] = "";
+ unsigned char flags[512] = "";
+ unsigned char services[512] = "";
+ unsigned char regexp[512] = "";
+ unsigned char repl[512] = "";
+ unsigned char temp[512] = "";
unsigned char delim;
unsigned char *delim2;
unsigned char *pattern, *subst, *d;
@@ -244,16 +244,31 @@ static int txt_callback(void *context, u_char *answer, int len, u_char *fullansw
printf("ENUMTXT Called\n");
#endif
- if (answer != NULL) {
- c->txtlen = strlen(answer);
- strncpy(c->txt, answer, sizeof(c->txt) - 1);
- c->txt[sizeof(c->txt) - 1] = 0;
- return 1;
- } else {
+ if (answer == NULL) {
c->txt = NULL;
c->txtlen = 0;
return 0;
}
+
+ /* skip over first byte, as for some reason it's a vertical tab character */
+ answer += 1;
+ len -= 1;
+
+ /* answer is not null-terminated, but should be */
+ /* this is safe to do, as answer has extra bytes on the end we can
+ safely overwrite with a null */
+ answer[len] = '\0';
+ /* now increment len so that len includes the null, so that we can
+ compare apples to apples */
+ len +=1;
+
+ /* finally, copy the answer into c->txt */
+ strncpy(c->txt, answer, len < c->txtlen ? len-1 : (c->txtlen)-1);
+
+ /* just to be safe, let's make sure c->txt is null terminated */
+ c->txt[(c->txtlen)-1] = '\0';
+
+ return 1;
}
static int enum_callback(void *context, u_char *answer, int len, u_char *fullanswer)
@@ -274,8 +289,8 @@ static int enum_callback(void *context, u_char *answer, int len, u_char *fullans
int ast_get_enum(struct ast_channel *chan, const char *number, char *dst, int dstlen, char *tech, int techlen)
{
struct enum_context context;
- char tmp[259 + 80];
- char naptrinput[80] = "+";
+ char tmp[259 + 512];
+ char naptrinput[512] = "+";
int pos = strlen(number) - 1;
int newpos = 0;
int ret = -1;
@@ -331,8 +346,8 @@ int ast_get_enum(struct ast_channel *chan, const char *number, char *dst, int ds
int ast_get_txt(struct ast_channel *chan, const char *number, char *dst, int dstlen, char *tech, int techlen, char *txt, int txtlen)
{
struct enum_context context;
- char tmp[259 + 80];
- char naptrinput[80] = "+";
+ char tmp[259 + 512];
+ char naptrinput[512] = "+";
int pos = strlen(number) - 1;
int newpos = 0;
int ret = -1;
diff --git a/file.c b/file.c
index 034fe1fb0..88285b7f0 100755
--- a/file.c
+++ b/file.c
@@ -714,23 +714,31 @@ int ast_fileexists(char *filename, char *fmt, char *preflang)
*c = '\0';
postfix = c+1;
prefix = tmp;
+ snprintf(filename2, sizeof(filename2), "%s/%s/%s", prefix, preflang, postfix);
} else {
postfix = tmp;
prefix="";
+ snprintf(filename2, sizeof(filename2), "%s/%s", preflang, postfix);
}
- snprintf(filename2, sizeof(filename2), "%s/%s/%s", prefix, preflang, postfix);
res = ast_filehelper(filename2, NULL, fmt, ACTION_EXISTS);
if (res < 1) {
char *stringp=NULL;
strncpy(lang2, preflang, sizeof(lang2)-1);
stringp=lang2;
strsep(&stringp, "_");
+ /* If language is a specific locality of a language (like es_MX), strip the locality and try again */
if (strcmp(lang2, preflang)) {
- snprintf(filename2, sizeof(filename2), "%s/%s/%s", prefix, lang2, postfix);
+ if (ast_strlen_zero(prefix)) {
+ snprintf(filename2, sizeof(filename2), "%s/%s", lang2, postfix);
+ } else {
+ snprintf(filename2, sizeof(filename2), "%s/%s/%s", prefix, lang2, postfix);
+ }
res = ast_filehelper(filename2, NULL, fmt, ACTION_EXISTS);
}
}
}
+
+ /* Fallback to no language (usually winds up being American English) */
if (res < 1) {
res = ast_filehelper(filename, NULL, fmt, ACTION_EXISTS);
}
@@ -844,8 +852,12 @@ struct ast_filestream *ast_writefile(char *filename, char *type, char *comment,
return NULL;
}
/* set the O_TRUNC flag if and only if there is no O_APPEND specified */
- if (!(flags & O_APPEND))
+ if (flags & O_APPEND){
+ /* We really can't use O_APPEND as it will break WAV header updates */
+ flags &= ~O_APPEND;
+ }else{
myflags = O_TRUNC;
+ }
myflags |= O_WRONLY | O_CREAT;
@@ -920,7 +932,7 @@ struct ast_filestream *ast_writefile(char *filename, char *type, char *comment,
return fs;
}
-char ast_waitstream(struct ast_channel *c, char *breakon)
+int ast_waitstream(struct ast_channel *c, char *breakon)
{
/* XXX Maybe I should just front-end ast_waitstream_full ? XXX */
int res;
@@ -976,10 +988,18 @@ char ast_waitstream(struct ast_channel *c, char *breakon)
return (c->_softhangup ? -1 : 0);
}
-char ast_waitstream_fr(struct ast_channel *c, char *breakon, char *forward, char *rewind, int ms)
+int ast_waitstream_fr(struct ast_channel *c, char *breakon, char *forward, char *rewind, int ms)
{
int res;
struct ast_frame *fr;
+
+ if (!breakon)
+ breakon = "";
+ if (!forward)
+ forward = "";
+ if (!rewind)
+ rewind = "";
+
while(c->stream) {
res = ast_sched_wait(c->sched);
if ((res < 0) && !c->timingfunc) {
@@ -1037,13 +1057,16 @@ char ast_waitstream_fr(struct ast_channel *c, char *breakon, char *forward, char
return (c->_softhangup ? -1 : 0);
}
-char ast_waitstream_full(struct ast_channel *c, char *breakon, int audiofd, int cmdfd)
+int ast_waitstream_full(struct ast_channel *c, char *breakon, int audiofd, int cmdfd)
{
int res;
int ms;
int outfd;
struct ast_frame *fr;
struct ast_channel *rchan;
+
+ if (!breakon)
+ breakon = "";
while(c->stream) {
ms = ast_sched_wait(c->sched);
@@ -1055,6 +1078,9 @@ char ast_waitstream_full(struct ast_channel *c, char *breakon, int audiofd, int
ms = 1000;
rchan = ast_waitfor_nandfds(&c, 1, &cmdfd, (cmdfd > -1) ? 1 : 0, NULL, &outfd, &ms);
if (!rchan && (outfd < 0) && (ms)) {
+ /* Continue */
+ if (errno == EINTR)
+ continue;
ast_log(LOG_WARNING, "Wait failed (%s)\n", strerror(errno));
return -1;
} else if (outfd > -1) {
diff --git a/formats/format_g726.c b/formats/format_g726.c
index 9788a28b4..04d3a84df 100755
--- a/formats/format_g726.c
+++ b/formats/format_g726.c
@@ -24,11 +24,7 @@
#include <unistd.h>
#include <errno.h>
#include <string.h>
-#ifdef __linux__
-#include <endian.h>
-#else
-#include <machine/endian.h>
-#endif
+#include "asterisk/endian.h"
#define RATE_40 0
#define RATE_32 1
diff --git a/formats/format_g729.c b/formats/format_g729.c
index 746874d7d..3d89d64a8 100755
--- a/formats/format_g729.c
+++ b/formats/format_g729.c
@@ -25,11 +25,7 @@
#include <unistd.h>
#include <errno.h>
#include <string.h>
-#ifdef __linux__
-#include <endian.h>
-#else
-#include <machine/endian.h>
-#endif
+#include "asterisk/endian.h"
/* Some Ideas for this code came from makeg729e.c by Jeffrey Chilton */
@@ -130,7 +126,7 @@ static struct ast_frame *g729_read(struct ast_filestream *s, int *whennext)
s->fr.mallocd = 0;
s->fr.data = s->g729;
if ((res = read(s->fd, s->g729, 20)) != 20) {
- if (res)
+ if (res && (res != 10))
ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
return NULL;
}
diff --git a/formats/format_gsm.c b/formats/format_gsm.c
index f4b5aa189..575ef59a3 100755
--- a/formats/format_gsm.c
+++ b/formats/format_gsm.c
@@ -25,11 +25,7 @@
#include <unistd.h>
#include <errno.h>
#include <string.h>
-#ifdef __linux__
-#include <endian.h>
-#else
-#include <machine/endian.h>
-#endif
+#include "asterisk/endian.h"
#include "msgsm.h"
/* Some Ideas for this code came from makegsme.c by Jeffrey Chilton */
diff --git a/formats/format_h263.c b/formats/format_h263.c
index 1482e5b5d..ee216c31b 100755
--- a/formats/format_h263.c
+++ b/formats/format_h263.c
@@ -25,11 +25,7 @@
#include <unistd.h>
#include <errno.h>
#include <string.h>
-#ifdef __linux__
-#include <endian.h>
-#else
-#include <machine/endian.h>
-#endif
+#include "asterisk/endian.h"
/* Some Ideas for this code came from makeh263e.c by Jeffrey Chilton */
diff --git a/formats/format_ilbc.c b/formats/format_ilbc.c
index 61b9d5958..f7cd50ebf 100755
--- a/formats/format_ilbc.c
+++ b/formats/format_ilbc.c
@@ -27,11 +27,7 @@
#include <unistd.h>
#include <errno.h>
#include <string.h>
-#ifdef __linux__
-#include <endian.h>
-#else
-#include <machine/endian.h>
-#endif
+#include "asterisk/endian.h"
/* Some Ideas for this code came from makeg729e.c by Jeffrey Chilton */
diff --git a/formats/format_jpeg.c b/formats/format_jpeg.c
index 56c5ef8d8..6a9432567 100755
--- a/formats/format_jpeg.c
+++ b/formats/format_jpeg.c
@@ -27,11 +27,7 @@
#include <unistd.h>
#include <errno.h>
#include <string.h>
-#ifdef __linux__
-#include <endian.h>
-#else
-#include <machine/endian.h>
-#endif
+#include "asterisk/endian.h"
static char *desc = "JPEG (Joint Picture Experts Group) Image Format";
diff --git a/formats/format_pcm.c b/formats/format_pcm.c
index a3ad65143..fc7b73001 100755
--- a/formats/format_pcm.c
+++ b/formats/format_pcm.c
@@ -25,11 +25,7 @@
#include <unistd.h>
#include <errno.h>
#include <string.h>
-#ifdef __linux__
-#include <endian.h>
-#else
-#include <machine/endian.h>
-#endif
+#include "asterisk/endian.h"
#define BUF_SIZE 160 /* 160 samples */
diff --git a/formats/format_pcm_alaw.c b/formats/format_pcm_alaw.c
index eda446ca4..13eb7c068 100755
--- a/formats/format_pcm_alaw.c
+++ b/formats/format_pcm_alaw.c
@@ -27,11 +27,7 @@
#include <unistd.h>
#include <errno.h>
#include <string.h>
-#ifdef __linux__
-#include <endian.h>
-#else
-#include <machine/endian.h>
-#endif
+#include "asterisk/endian.h"
#define BUF_SIZE 160 /* 160 samples */
diff --git a/formats/format_sln.c b/formats/format_sln.c
index 7e77876b2..94a728565 100755
--- a/formats/format_sln.c
+++ b/formats/format_sln.c
@@ -23,11 +23,7 @@
#include <unistd.h>
#include <errno.h>
#include <string.h>
-#ifdef __linux__
-#include <endian.h>
-#else
-#include <machine/endian.h>
-#endif
+#include "asterisk/endian.h"
#define BUF_SIZE 320 /* 320 samples */
@@ -160,6 +156,7 @@ static int slinear_seek(struct ast_filestream *fs, long sample_offset, int whenc
off_t offset=0,min,cur,max;
min = 0;
+ sample_offset <<= 1;
cur = lseek(fs->fd, 0, SEEK_CUR);
max = lseek(fs->fd, 0, SEEK_END);
if (whence == SEEK_SET)
diff --git a/formats/format_vox.c b/formats/format_vox.c
index 1a09dac52..61f329aaa 100755
--- a/formats/format_vox.c
+++ b/formats/format_vox.c
@@ -25,11 +25,7 @@
#include <unistd.h>
#include <errno.h>
#include <string.h>
-#ifdef __linux__
-#include <endian.h>
-#else
-#include <machine/endian.h>
-#endif
+#include "asterisk/endian.h"
#define BUF_SIZE 80 /* 160 samples */
diff --git a/formats/format_wav.c b/formats/format_wav.c
index 0e87f2de9..d0a904be4 100755
--- a/formats/format_wav.c
+++ b/formats/format_wav.c
@@ -25,11 +25,8 @@
#include <unistd.h>
#include <errno.h>
#include <string.h>
-#ifdef __linux__
-#include <endian.h>
-#else
-#include <machine/endian.h>
-#endif
+#include "asterisk/endian.h"
+
/* Some Ideas for this code came from makewave.c by Jeffrey Chilton */
diff --git a/formats/format_wav_gsm.c b/formats/format_wav_gsm.c
index 9fcc3c9ce..6039e7d19 100755
--- a/formats/format_wav_gsm.c
+++ b/formats/format_wav_gsm.c
@@ -25,11 +25,7 @@
#include <unistd.h>
#include <errno.h>
#include <string.h>
-#ifdef __linux__
-#include <endian.h>
-#else
-#include <machine/endian.h>
-#endif
+#include "asterisk/endian.h"
#include "msgsm.h"
/* Some Ideas for this code came from makewave.c by Jeffrey Chilton */
@@ -51,7 +47,6 @@ struct ast_filestream {
weird MS format */
/* This is what a filestream means to us */
int fd; /* Descriptor */
- int bytes;
struct ast_frame fr; /* Frame information */
char waste[AST_FRIENDLY_OFFSET]; /* Buffer for sending frames, etc */
char empty; /* Empty character */
@@ -219,7 +214,7 @@ static int update_header(int fd)
end = lseek(fd, 0, SEEK_END);
/* in a gsm WAV, data starts 60 bytes in */
bytes = end - 60;
- datalen = htoll(bytes);
+ datalen = htoll((bytes + 1) & ~0x1);
filelen = htoll(52 + ((bytes + 1) & ~0x1));
if (cur < 0) {
ast_log(LOG_WARNING, "Unable to find our position\n");
@@ -398,7 +393,7 @@ static void wav_close(struct ast_filestream *s)
ast_mutex_unlock(&wav_lock);
ast_update_use_count();
/* Pad to even length */
- if (s->bytes & 0x1)
+ if (lseek(s->fd, 0, SEEK_END) & 0x1)
write(s->fd, &zero, 1);
close(s->fd);
free(s);
@@ -458,7 +453,6 @@ static int wav_write(struct ast_filestream *fs, struct ast_frame *f)
ast_log(LOG_WARNING, "Bad write (%d/65): %s\n", res, strerror(errno));
return -1;
}
- fs->bytes += 65;
update_header(fs->fd);
len += 65;
} else {
@@ -469,7 +463,6 @@ static int wav_write(struct ast_filestream *fs, struct ast_frame *f)
ast_log(LOG_WARNING, "Bad write (%d/65): %s\n", res, strerror(errno));
return -1;
}
- fs->bytes += 65;
update_header(fs->fd);
} else {
/* Copy the data and do nothing */
diff --git a/frame.c b/frame.c
index 72197d5c1..a1bb27cb5 100755
--- a/frame.c
+++ b/frame.c
@@ -3,9 +3,9 @@
*
* Frame manipulation routines
*
- * Copyright (C) 1999, Mark Spencer
+ * Copyright (C) 1999-2004, Mark Spencer
*
- * Mark Spencer <markster@linux-support.net>
+ * Mark Spencer <markster@digium.com>
*
* This program is free software, distributed under the terms of
* the GNU General Public License
@@ -15,6 +15,7 @@
#include <asterisk/frame.h>
#include <asterisk/logger.h>
#include <asterisk/options.h>
+#include <asterisk/channel.h>
#include <asterisk/cli.h>
#include <asterisk/term.h>
#include <asterisk/utils.h>
@@ -33,6 +34,13 @@ AST_MUTEX_DEFINE_STATIC(framelock);
#define SMOOTHER_SIZE 8000
+struct ast_format_list {
+ int visible; /* Can we see this entry */
+ int bits; /* bitmask value */
+ char *name; /* short name */
+ char *desc; /* Description */
+};
+
struct ast_smoother {
int size;
int format;
@@ -75,7 +83,7 @@ void ast_smoother_set_flags(struct ast_smoother *s, int flags)
s->flags = flags;
}
-int ast_smoother_feed(struct ast_smoother *s, struct ast_frame *f)
+int __ast_smoother_feed(struct ast_smoother *s, struct ast_frame *f, int swap)
{
if (f->frametype != AST_FRAME_VOICE) {
ast_log(LOG_WARNING, "Huh? Can't smooth a non-voice frame!\n");
@@ -121,7 +129,10 @@ int ast_smoother_feed(struct ast_smoother *s, struct ast_frame *f)
return 0;
}
}
- memcpy(s->data + s->len, f->data, f->datalen);
+ if (swap)
+ ast_memcpy_byteswap(s->data+s->len, f->data, f->samples);
+ else
+ memcpy(s->data + s->len, f->data, f->datalen);
/* If either side is empty, reset the delivery time */
if (!s->len || (!f->delivery.tv_sec && !f->delivery.tv_usec) ||
(!s->delivery.tv_sec && !s->delivery.tv_usec))
@@ -346,7 +357,7 @@ struct ast_frame *ast_fr_fdread(int fd)
/* Forget about being mallocd */
f->mallocd = 0;
/* Re-write the source */
- f->src = __FUNCTION__;
+ f->src = (char *)__FUNCTION__;
if (f->datalen > sizeof(buf) - sizeof(struct ast_frame)) {
/* Really bad read */
ast_log(LOG_WARNING, "Strange read (%d bytes)\n", f->datalen);
@@ -391,141 +402,147 @@ int ast_fr_fdhangup(int fd)
return ast_fr_fdwrite(fd, &hangup);
}
+void ast_memcpy_byteswap(void *dst, void *src, int samples)
+{
+ int i;
+ unsigned short *dst_s = dst;
+ unsigned short *src_s = src;
+
+ for (i=0; i<samples; i++)
+ dst_s[i] = (src_s[i]<<8)|(src_s[i]>>8);
+}
+
+static struct ast_format_list AST_FORMAT_LIST[] = {
+ { 1, AST_FORMAT_G723_1 , "g723" , "G.723.1"},
+ { 1, AST_FORMAT_GSM, "gsm" , "GSM"},
+ { 1, AST_FORMAT_ULAW, "ulaw", "G.711 u-law" },
+ { 1, AST_FORMAT_ALAW, "alaw", "G.711 A-law" },
+ { 1, AST_FORMAT_G726, "g726", "G.726" },
+ { 1, AST_FORMAT_ADPCM, "adpcm" , "ADPCM"},
+ { 1, AST_FORMAT_SLINEAR, "slin", "16 bit Signed Linear PCM"},
+ { 1, AST_FORMAT_LPC10, "lpc10", "LPC10" },
+ { 1, AST_FORMAT_G729A, "g729", "G.729A" },
+ { 1, AST_FORMAT_SPEEX, "speex", "SpeeX" },
+ { 1, AST_FORMAT_ILBC, "ilbc", "iLBC"},
+ { 0, 0, "nothing", "undefined" },
+ { 0, 0, "nothing", "undefined" },
+ { 0, 0, "nothing", "undefined" },
+ { 0, 0, "nothing", "undefined" },
+ { 0, AST_FORMAT_MAX_AUDIO, "maxaudio", "Maximum audio format" },
+ { 1, AST_FORMAT_JPEG, "jpeg", "JPEG image"},
+ { 1, AST_FORMAT_PNG, "png", "PNG image"},
+ { 1, AST_FORMAT_H261, "h261", "H.261 Video" },
+ { 1, AST_FORMAT_H263, "h263", "H.263 Video" },
+ { 0, 0, "nothing", "undefined" },
+ { 0, 0, "nothing", "undefined" },
+ { 0, 0, "nothing", "undefined" },
+ { 0, 0, "nothing", "undefined" },
+ { 0, AST_FORMAT_MAX_VIDEO, "maxvideo", "Maximum video format" },
+};
+
+struct ast_format_list *ast_get_format_list_index(int index) {
+ return &AST_FORMAT_LIST[index];
+}
+
+struct ast_format_list *ast_get_format_list(size_t *size) {
+ *size = (sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list));
+ return AST_FORMAT_LIST;
+}
+
char* ast_getformatname(int format)
{
- if (format == AST_FORMAT_G723_1)
- return "G723";
- else if (format == AST_FORMAT_GSM)
- return "GSM";
- else if (format == AST_FORMAT_ULAW)
- return "ULAW";
- else if (format == AST_FORMAT_ALAW)
- return "ALAW";
- else if (format == AST_FORMAT_G726)
- return "G726";
- else if (format == AST_FORMAT_SLINEAR)
- return "SLINR";
- else if (format == AST_FORMAT_LPC10)
- return "LPC10";
- else if (format == AST_FORMAT_ADPCM)
- return "ADPCM";
- else if (format == AST_FORMAT_G729A)
- return "G729A";
- else if (format == AST_FORMAT_SPEEX)
- return "SPEEX";
- else if (format == AST_FORMAT_ILBC)
- return "ILBC";
- else if (format == AST_FORMAT_JPEG)
- return "JPEG";
- else if (format == AST_FORMAT_PNG)
- return "PNG";
- else if (format == AST_FORMAT_H261)
- return "H261";
- else if (format == AST_FORMAT_H263)
- return "H263";
- return "UNKN";
-}
-
-char* ast_getformatname_multiple(char *buf, unsigned n, int format) {
- unsigned u=1;
+ int x = 0;
+ char *ret = "unknown";
+ for (x = 0 ; x < sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list) ; x++) {
+ if(AST_FORMAT_LIST[x].visible && AST_FORMAT_LIST[x].bits == format) {
+ ret = AST_FORMAT_LIST[x].name;
+ break;
+ }
+ }
+ return ret;
+}
+
+char *ast_getformatname_multiple(char *buf, size_t size, int format) {
+
+ int x = 0;
unsigned len;
- char *b = buf;
+ char *end = buf;
char *start = buf;
- if (!n) return buf;
- snprintf(b,n,"0x%x(",format);
- len = strlen(b);
- b += len;
- n -= len;
- start = b;
- while (u) {
- if (u&format) {
- snprintf(b,n,"%s|",ast_getformatname(u));
- len = strlen(b);
- b += len;
- n -= len;
+ if (!size) return buf;
+ snprintf(end, size, "0x%x (", format);
+ len = strlen(end);
+ end += len;
+ size -= len;
+ start = end;
+ for (x = 0 ; x < sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list) ; x++) {
+ if (AST_FORMAT_LIST[x].visible && (AST_FORMAT_LIST[x].bits & format)) {
+ snprintf(end, size,"%s|",AST_FORMAT_LIST[x].name);
+ len = strlen(end);
+ end += len;
+ size -= len;
}
- u *= 2;
}
- if (start==b)
- snprintf(start,n,"EMPTY)");
- else if (n>1)
- b[-1]=')';
+ if (start == end)
+ snprintf(start, size, "nothing)");
+ else if (size > 1)
+ *(end -1) = ')';
return buf;
}
+static struct ast_codec_alias_table {
+ char *alias;
+ char *realname;
+
+} ast_codec_alias_table[] = {
+ {"slinear","slin"},
+ {"g723.1","g723"},
+};
+
+static char *ast_expand_codec_alias(char *in) {
+ int x = 0;
+
+ for (x = 0; x < sizeof(ast_codec_alias_table) / sizeof(struct ast_codec_alias_table) ; x++) {
+ if(!strcmp(in,ast_codec_alias_table[x].alias))
+ return ast_codec_alias_table[x].realname;
+ }
+ return in;
+}
+
int ast_getformatbyname(char *name)
{
- if (!strcasecmp(name, "g723.1"))
- return AST_FORMAT_G723_1;
- else if (!strcasecmp(name, "gsm"))
- return AST_FORMAT_GSM;
- else if (!strcasecmp(name, "ulaw"))
- return AST_FORMAT_ULAW;
- else if (!strcasecmp(name, "alaw"))
- return AST_FORMAT_ALAW;
- else if (!strcasecmp(name, "g726"))
- return AST_FORMAT_G726;
- else if (!strcasecmp(name, "slinear"))
- return AST_FORMAT_SLINEAR;
- else if (!strcasecmp(name, "lpc10"))
- return AST_FORMAT_LPC10;
- else if (!strcasecmp(name, "adpcm"))
- return AST_FORMAT_ADPCM;
- else if (!strcasecmp(name, "g729"))
- return AST_FORMAT_G729A;
- else if (!strcasecmp(name, "speex"))
- return AST_FORMAT_SPEEX;
- else if (!strcasecmp(name, "ilbc"))
- return AST_FORMAT_ILBC;
- else if (!strcasecmp(name, "h261"))
- return AST_FORMAT_H261;
- else if (!strcasecmp(name, "h263"))
- return AST_FORMAT_H263;
- else if (!strcasecmp(name, "all"))
- return 0x7FFFFFFF;
- return 0;
+ int x = 0, all = 0, format = 0;
+
+ all = strcasecmp(name, "all") ? 0 : 1;
+ for (x = 0 ; x < sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list) ; x++) {
+ if(AST_FORMAT_LIST[x].visible && (all ||
+ !strcasecmp(AST_FORMAT_LIST[x].name,name) ||
+ !strcasecmp(AST_FORMAT_LIST[x].name,ast_expand_codec_alias(name)))) {
+ format |= AST_FORMAT_LIST[x].bits;
+ if(!all)
+ break;
+ }
+ }
+
+ return format;
}
char *ast_codec2str(int codec) {
- static char codecs[25][30] = {
- /* Audio formats */
- "G.723.1", /* 0 */
- "GSM", /* 1 */
- "G.711 u-law", /* 2 */
- "G.711 A-law", /* 3 */
- "G.726", /* 4 */
- "ADPCM", /* 5 */
- "16 bit Signed Linear PCM", /* 6 */
- "LPC10", /* 7 */
- "G.729A audio", /* 8 */
- "SpeeX", /* 9 */
- "iLBC", /* 10 */
- "undefined", /* 11 */
- "undefined", /* 12 */
- "undefined", /* 13 */
- "undefined", /* 14 */
- "Maximum audio format", /* 15 */
- /* Image formats */
- "JPEG image", /* 16 */
- "PNG image", /* 17 */
- "H.261 Video", /* 18 */
- "H.263 Video", /* 19 */
- "undefined", /* 20 */
- "undefined", /* 21 */
- "undefined", /* 22 */
- "undefined", /* 23 */
- "Maximum video format", /* 24 */
- };
- if ((codec >= 0) && (codec <= 24))
- return codecs[codec];
- else
- return "unknown";
+ int x = 0;
+ char *ret = "unknown";
+ for (x = 0 ; x < sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list) ; x++) {
+ if(AST_FORMAT_LIST[x].visible && AST_FORMAT_LIST[x].bits == codec) {
+ ret = AST_FORMAT_LIST[x].desc;
+ break;
+ }
+ }
+ return ret;
}
static int show_codecs(int fd, int argc, char *argv[])
{
int i, found=0;
-
+ char hex[25];
+
if ((argc < 2) || (argc > 3))
return RESULT_SHOWUSAGE;
@@ -533,22 +550,30 @@ static int show_codecs(int fd, int argc, char *argv[])
ast_cli(fd, "Disclaimer: this command is for informational purposes only.\n"
"\tIt does not indicate anything about your configuration.\n");
+ ast_cli(fd, "%11s %9s %10s TYPE %5s %s\n","INT","BINARY","HEX","NAME","DESC");
+ ast_cli(fd, "--------------------------------------------------------------------------------\n");
if ((argc == 2) || (!strcasecmp(argv[1],"audio"))) {
found = 1;
- for (i=0;i<11;i++)
- ast_cli(fd, "%11u (1 << %2d) %s\n",1 << i,i,ast_codec2str(i));
+ for (i=0;i<11;i++) {
+ snprintf(hex,25,"(0x%x)",1<<i);
+ ast_cli(fd, "%11u (1 << %2d) %10s audio %5s (%s)\n",1 << i,i,hex,ast_getformatname(1<<i),ast_codec2str(1<<i));
+ }
}
if ((argc == 2) || (!strcasecmp(argv[1],"image"))) {
found = 1;
- for (i=16;i<18;i++)
- ast_cli(fd, "%11u (1 << %2d) %s\n",1 << i,i,ast_codec2str(i));
+ for (i=16;i<18;i++) {
+ snprintf(hex,25,"(0x%x)",1<<i);
+ ast_cli(fd, "%11u (1 << %2d) %10s image %5s (%s)\n",1 << i,i,hex,ast_getformatname(1<<i),ast_codec2str(1<<i));
+ }
}
if ((argc == 2) || (!strcasecmp(argv[1],"video"))) {
found = 1;
- for (i=18;i<20;i++)
- ast_cli(fd, "%11u (1 << %2d) %s\n",1 << i,i,ast_codec2str(i));
+ for (i=18;i<20;i++) {
+ snprintf(hex,25,"(0x%x)",1<<i);
+ ast_cli(fd, "%11u (1 << %2d) %10s video %5s (%s)\n",1 << i,i,hex,ast_getformatname(1<<i),ast_codec2str(1<<i));
+ }
}
if (! found)
@@ -583,7 +608,7 @@ static int show_codec_n(int fd, int argc, char *argv[])
for (i=0;i<32;i++)
if (codec & (1 << i)) {
found = 1;
- ast_cli(fd, "%11u (1 << %2d) %s\n",1 << i,i,ast_codec2str(i));
+ ast_cli(fd, "%11u (1 << %2d) %s\n",1 << i,i,ast_codec2str(1<<i));
}
if (! found)
@@ -607,7 +632,7 @@ void ast_frame_dump(char *name, struct ast_frame *f, char *prefix)
char subclass[40] = "Unknown Subclass";
char csub[80];
char moreinfo[40] = "";
- char cn[40];
+ char cn[60];
char cp[40];
char cmn[40];
if (name)
@@ -672,9 +697,13 @@ void ast_frame_dump(char *name, struct ast_frame *f, char *prefix)
case AST_CONTROL_RADIO_UNKEY:
strcpy(subclass, "Unkey Radio");
break;
+ case -1:
+ strcpy(subclass, "Stop generators");
+ break;
default:
snprintf(subclass, sizeof(subclass), "Unknown control '%d'", f->subclass);
}
+ break;
case AST_FRAME_NULL:
strcpy(ftype, "Null Frame");
strcpy(subclass, "N/A");
@@ -793,3 +822,186 @@ int init_framer(void)
ast_cli_register(&cli_show_codec_n);
return 0;
}
+
+void ast_codec_pref_shift(struct ast_codec_pref *pref, char *buf, size_t size, int right)
+{
+ int x = 0, differential = 65, mem = 0;
+ char *from = NULL, *to = NULL;
+
+ if(right) {
+ from = pref->order;
+ to = buf;
+ mem = size;
+ } else {
+ to = pref->order;
+ from = buf;
+ mem = 32;
+ }
+
+ memset(to, 0, mem);
+ for (x = 0; x < 32 ; x++) {
+ if(!from[x])
+ break;
+ to[x] = right ? (from[x] + differential) : (from[x] - differential);
+ }
+}
+
+int ast_codec_pref_string(struct ast_codec_pref *pref, char *buf, size_t size)
+{
+ int x = 0, codec = 0;
+ size_t total_len = 0, slen = 0;
+ char *formatname = 0;
+
+ memset(buf,0,size);
+ total_len = size;
+ buf[0] = '(';
+ total_len--;
+ for(x = 0; x < 32 ; x++) {
+ if(total_len <= 0)
+ break;
+ if(!(codec = ast_codec_pref_index(pref,x)))
+ break;
+ if((formatname = ast_getformatname(codec))) {
+ slen = strlen(formatname);
+ if(slen > total_len)
+ break;
+ strncat(buf,formatname,total_len);
+ total_len -= slen;
+ }
+ if(total_len && x < 31 && ast_codec_pref_index(pref , x + 1)) {
+ strncat(buf,"|",total_len);
+ total_len--;
+ }
+ }
+ if(total_len) {
+ strncat(buf,")",total_len);
+ total_len--;
+ }
+
+ return size - total_len;
+}
+
+int ast_codec_pref_index(struct ast_codec_pref *pref, int index)
+{
+ int slot = 0;
+
+
+ if((index >= 0) && (index < sizeof(pref->order))) {
+ slot = pref->order[index];
+ }
+
+ return slot ? AST_FORMAT_LIST[slot-1].bits : 0;
+}
+
+/*--- ast_codec_pref_remove: Remove codec from pref list ---*/
+void ast_codec_pref_remove(struct ast_codec_pref *pref, int format)
+{
+ struct ast_codec_pref oldorder;
+ int x=0, y=0;
+ size_t size = 0;
+ int slot = 0;
+
+ if(!pref->order[0])
+ return;
+
+ size = sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list);
+
+ memcpy(&oldorder,pref,sizeof(struct ast_codec_pref));
+ memset(pref,0,sizeof(struct ast_codec_pref));
+
+ for (x = 0; x < size; x++) {
+ slot = oldorder.order[x];
+ if(! slot)
+ break;
+ if(AST_FORMAT_LIST[slot-1].bits != format)
+ pref->order[y++] = slot;
+ }
+
+}
+
+/*--- ast_codec_pref_append: Append codec to list ---*/
+int ast_codec_pref_append(struct ast_codec_pref *pref, int format)
+{
+ size_t size = 0;
+ int x = 0, newindex = -1;
+
+ ast_codec_pref_remove(pref, format);
+ size = sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list);
+
+ for (x = 0; x < size; x++) {
+ if(AST_FORMAT_LIST[x].bits == format) {
+ newindex = x + 1;
+ break;
+ }
+ }
+
+ if(newindex) {
+ for (x = 0; x < size; x++) {
+ if(!pref->order[x]) {
+ pref->order[x] = newindex;
+ break;
+ }
+ }
+ }
+
+ return x;
+}
+
+
+/*--- sip_codec_choose: Pick a codec ---*/
+int ast_codec_choose(struct ast_codec_pref *pref, int formats, int find_best)
+{
+ size_t size = 0;
+ int x = 0, ret = 0, slot = 0;
+
+ size = sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list);
+ for (x = 0; x < size; x++) {
+ slot = pref->order[x];
+
+ if(!slot)
+ break;
+ if ( formats & AST_FORMAT_LIST[slot-1].bits ) {
+ ret = AST_FORMAT_LIST[slot-1].bits;
+ break;
+ }
+ }
+ if(ret)
+ return ret;
+
+ return find_best ? ast_best_codec(formats) : 0;
+}
+
+void ast_parse_allow_disallow(struct ast_codec_pref *pref, int *mask, char *list, int allowing)
+{
+ int format_i = 0;
+ char *next_format = NULL, *last_format = NULL;
+
+ last_format = ast_strdupa(list);
+ while(last_format) {
+ if((next_format = strchr(last_format, ','))) {
+ *next_format = '\0';
+ next_format++;
+ }
+ if ((format_i = ast_getformatbyname(last_format)) > 0) {
+ if (mask) {
+ if (allowing)
+ (*mask) |= format_i;
+ else
+ (*mask) &= ~format_i;
+ }
+ /* can't consider 'all' a prefered codec*/
+ if(pref && strcasecmp(last_format, "all")) {
+ if(allowing)
+ ast_codec_pref_append(pref, format_i);
+ else
+ ast_codec_pref_remove(pref, format_i);
+ } else if(!allowing) /* disallow all must clear your prefs or it makes no sense */
+ memset(pref, 0, sizeof(struct ast_codec_pref));
+ } else
+ ast_log(LOG_WARNING, "Cannot %s unknown format '%s'\n", allowing ? "allow" : "disallow", last_format);
+
+ last_format = next_format;
+ }
+}
+
+
diff --git a/include/asterisk/acl.h b/include/asterisk/acl.h
index bcc7543d5..f55791dfe 100755
--- a/include/asterisk/acl.h
+++ b/include/asterisk/acl.h
@@ -35,6 +35,7 @@ extern int ast_get_ip(struct sockaddr_in *sin, char *value);
extern int ast_ouraddrfor(struct in_addr *them, struct in_addr *us);
extern int ast_lookup_iface(char *iface, struct in_addr *address);
extern struct ast_ha *ast_duplicate_ha_list(struct ast_ha *original);
+extern int ast_find_ourip(struct in_addr *ourip, struct sockaddr_in bindaddr);
//! Compares the source address and port of two sockaddr_in
static inline int inaddrcmp(struct sockaddr_in *sin1, struct sockaddr_in *sin2)
diff --git a/include/asterisk/adsi.h b/include/asterisk/adsi.h
index 87b18c31f..cef71492b 100755
--- a/include/asterisk/adsi.h
+++ b/include/asterisk/adsi.h
@@ -164,7 +164,7 @@ extern int adsi_unload_session(struct ast_channel *chan);
/* ADSI Layer 2 transmission functions */
extern int adsi_transmit_messages(struct ast_channel *chan, unsigned char **msg, int *msglen, int *msgtype);
extern int adsi_transmit_message(struct ast_channel *chan, unsigned char *msg, int msglen, int msgtype);
-
+extern int adsi_transmit_message_full(struct ast_channel *chan, unsigned char *msg, int msglen, int msgtype, int dowait);
//! Read some encoded DTMF data.
/*!
* Returns number of bytes received
diff --git a/include/asterisk/app.h b/include/asterisk/app.h
index 4b26a73ea..6330467da 100755
--- a/include/asterisk/app.h
+++ b/include/asterisk/app.h
@@ -62,12 +62,19 @@ int ast_play_and_wait(struct ast_channel *chan, char *fn);
//! Record a file for a max amount of time (in seconds), in a given list of formats separated by '|', outputting the duration of the recording, and with a maximum
// permitted silence time in milliseconds of 'maxsilence' under 'silencethreshold' or use '-1' for either or both parameters for defaults.
-int ast_play_and_record(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime_sec, char *fmt, int *duration, int silencethreshold, int maxsilence_ms);
+// calls ast_unlock_path() on 'path' if passed
+int ast_play_and_record(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime_sec, char *fmt, int *duration, int silencethreshold, int maxsilence_ms, const char *path);
//! Record a message and prepend the message to the given record file after playing the optional playfile (or a beep), storing the duration in 'duration' and with a maximum
// permitted silence time in milliseconds of 'maxsilence' under 'silencethreshold' or use '-1' for either or both parameters for defaults.
int ast_play_and_prepend(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime_sec, char *fmt, int *duration, int beep, int silencethreshold, int maxsilence_ms);
+/* Lock a path */
+int ast_lock_path(const char *path);
+
+/* Unlock a path */
+int ast_unlock_path(const char *path);
+
#if defined(__cplusplus) || defined(c_plusplus)
}
#endif
diff --git a/include/asterisk/cdr.h b/include/asterisk/cdr.h
index 90d9433e3..c274d8a81 100755
--- a/include/asterisk/cdr.h
+++ b/include/asterisk/cdr.h
@@ -254,6 +254,6 @@ extern char ast_default_accountcode[20];
#define ast_cdr_add_flag(cdr, flag) ((cdr)->flags |= (flag))
#define ast_cdr_del_flag(cdr, flag) ((cdr)->flags &= ~(flag))
-extern void ast_cdr_append(struct ast_cdr *cdr, struct ast_cdr *newcdr);
+extern struct ast_cdr *ast_cdr_append(struct ast_cdr *cdr, struct ast_cdr *newcdr);
#endif /* _CDR_H */
diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h
index 75627cda7..6dbc70a65 100755
--- a/include/asterisk/channel.h
+++ b/include/asterisk/channel.h
@@ -19,7 +19,11 @@
#include <asterisk/chanvars.h>
#include <unistd.h>
#include <setjmp.h>
+#ifdef POLLCOMPAT
+#include <asterisk/poll-compat.h>
+#else
#include <sys/poll.h>
+#endif
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
@@ -639,11 +643,11 @@ struct ast_channel *ast_get_channel_by_name_locked(char *channame);
* \param c channel to wait for a digit on
* \param ms how many milliseconds to wait
* Wait for a digit. Returns <0 on error, 0 on no entry, and the digit on success. */
-char ast_waitfordigit(struct ast_channel *c, int ms);
+int ast_waitfordigit(struct ast_channel *c, int ms);
/* Same as above with audio fd for outputing read audio and ctrlfd to monitor for
reading. Returns 1 if ctrlfd becomes available */
-char ast_waitfordigit_full(struct ast_channel *c, int ms, int audiofd, int ctrlfd);
+int ast_waitfordigit_full(struct ast_channel *c, int ms, int audiofd, int ctrlfd);
//! Reads multiple digits
/*!
diff --git a/include/asterisk/endian.h b/include/asterisk/endian.h
new file mode 100755
index 000000000..cef9d7ba9
--- /dev/null
+++ b/include/asterisk/endian.h
@@ -0,0 +1,59 @@
+/*
+ * Asterisk -- A telephony toolkit for Linux.
+ *
+ * Asterisk architecture endianess compatibility definitions
+ *
+ * Copyright (C) 1999 - 2005, Digium, Inc.
+ *
+ * Mark Spencer <markster@digium.com>
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU Lesser General Public License. Other components of
+ * Asterisk are distributed under The GNU General Public License
+ * only.
+ */
+
+#ifndef _ASTERISK_ENDIAN_H
+#define _ASTERISK_ENDIAN_H
+
+/*
+ * Autodetect system endianess
+ */
+
+#ifdef SOLARIS
+#include "solaris-compat/compat.h"
+#endif
+
+#ifndef __BYTE_ORDER
+#ifdef __linux__
+#include <endian.h>
+#elif defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__)
+#if defined(__OpenBSD__)
+#include <machine/types.h>
+#endif /* __OpenBSD__ */
+#include <machine/endian.h>
+#define __BYTE_ORDER BYTE_ORDER
+#define __LITTLE_ENDIAN LITTLE_ENDIAN
+#define __BIG_ENDIAN BIG_ENDIAN
+#else
+#ifdef __LITTLE_ENDIAN__
+#define __BYTE_ORDER __LITTLE_ENDIAN
+#endif /* __LITTLE_ENDIAN */
+
+#if defined(i386) || defined(__i386__)
+#define __BYTE_ORDER __LITTLE_ENDIAN
+#endif /* defined i386 */
+
+#if defined(sun) && defined(unix) && defined(sparc)
+#define __BYTE_ORDER __BIG_ENDIAN
+#endif /* sun unix sparc */
+
+#endif /* linux */
+
+#endif /* __BYTE_ORDER */
+
+#ifndef __BYTE_ORDER
+#error Need to know endianess
+#endif /* __BYTE_ORDER */
+
+#endif /* _ASTERISK_ENDIAN_H */
diff --git a/include/asterisk/file.h b/include/asterisk/file.h
index eb2c78e35..dadd59b0b 100755
--- a/include/asterisk/file.h
+++ b/include/asterisk/file.h
@@ -25,7 +25,7 @@ extern "C" {
//! Convenient for waiting
-#define AST_DIGIT_ANY "0123456789#*"
+#define AST_DIGIT_ANY "0123456789#*"
#define SEEK_FORCECUR 10
@@ -121,7 +121,7 @@ int ast_filecopy(char *oldname, char *newname, char *fmt);
* Wait for a stream to stop or for any one of a given digit to arrive, Returns 0
* if the stream finishes, the character if it was interrupted, and -1 on error
*/
-char ast_waitstream(struct ast_channel *c, char *breakon);
+int ast_waitstream(struct ast_channel *c, char *breakon);
//! Same as waitstream but allows stream to be forwarded or rewound
/*!
@@ -134,11 +134,11 @@ char ast_waitstream(struct ast_channel *c, char *breakon);
* Wait for a stream to stop or for any one of a given digit to arrive, Returns 0
* if the stream finishes, the character if it was interrupted, and -1 on error
*/
-char ast_waitstream_fr(struct ast_channel *c, char *breakon, char *forward, char *rewind, int ms);
+int ast_waitstream_fr(struct ast_channel *c, char *breakon, char *forward, char *rewind, int ms);
/* Same as waitstream, but with audio output to fd and monitored fd checking. Returns
1 if monfd is ready for reading */
-char ast_waitstream_full(struct ast_channel *c, char *breakon, int audiofd, int monfd);
+int ast_waitstream_full(struct ast_channel *c, char *breakon, int audiofd, int monfd);
//! Starts reading from a file
/*!
diff --git a/include/asterisk/frame.h b/include/asterisk/frame.h
index c80ca72f5..0716c953d 100755
--- a/include/asterisk/frame.h
+++ b/include/asterisk/frame.h
@@ -23,40 +23,12 @@ extern "C" {
#include <sys/types.h>
#include <sys/time.h>
-/*
- * Autodetect system endianess
- */
-#ifndef __BYTE_ORDER
-#ifdef __linux__
-#include <endian.h>
-#elif defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__)
-#if defined(__OpenBSD__)
-#include <machine/types.h>
-#endif /* __OpenBSD__ */
-#include <machine/endian.h>
-#define __BYTE_ORDER BYTE_ORDER
-#define __LITTLE_ENDIAN LITTLE_ENDIAN
-#define __BIG_ENDIAN BIG_ENDIAN
-#else
-#ifdef __LITTLE_ENDIAN__
-#define __BYTE_ORDER __LITTLE_ENDIAN
-#endif /* __LITTLE_ENDIAN */
-
-#if defined(i386) || defined(__i386__)
-#define __BYTE_ORDER __LITTLE_ENDIAN
-#endif /* defined i386 */
-
-#if defined(sun) && defined(unix) && defined(sparc)
-#define __BYTE_ORDER __BIG_ENDIAN
-#endif /* sun unix sparc */
-
-#endif /* linux */
+#include "asterisk/endian.h"
-#endif /* __BYTE_ORDER */
+struct ast_codec_pref {
+ char order[32];
+};
-#ifndef __BYTE_ORDER
-#error Need to know endianess
-#endif /* __BYTE_ORDER */
//! Data structure associated with a single frame of data
/* A frame of data read used to communicate between
@@ -324,6 +296,18 @@ int ast_fr_fdwrite(int fd, struct ast_frame *frame);
*/
int ast_fr_fdhangup(int fd);
+void ast_memcpy_byteswap(void *dst, void *src, int samples);
+
+/* Helpers for byteswapping native samples to/from
+ little-endian and big-endian. */
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define ast_frame_byteswap_le(fr) do { ; } while(0)
+#define ast_frame_byteswap_be(fr) do { struct ast_frame *__f = (fr); ast_memcpy_byteswap(__f->data, __f->data, __f->samples); } while(0)
+#else
+#define ast_frame_byteswap_le(fr) do { struct ast_frame *__f = (fr); ast_memcpy_byteswap(__f->data, __f->data, __f->samples); } while(0)
+#define ast_frame_byteswap_be(fr) do { ; } while(0)
+#endif
+
//! Get the name of a format
/*!
* \param format id of format
@@ -337,11 +321,10 @@ extern char* ast_getformatname(int format);
* \param n size of buf (bytes)
* \param format the format (combined IDs of codecs)
* Prints a list of readable codec names corresponding to "format".
- * ex: for format=AST_FORMAT_GSM|AST_FORMAT_SPEEX|AST_FORMAT_ILBC it will return "0x602(GSM|SPEEX|ILBC)"
+ * ex: for format=AST_FORMAT_GSM|AST_FORMAT_SPEEX|AST_FORMAT_ILBC it will return "0x602 (GSM|SPEEX|ILBC)"
* \return The return value is buf.
*/
-extern char* ast_getformatname_multiple(char *buf, unsigned n, int format);
-
+extern char* ast_getformatname_multiple(char *buf, size_t size, int format);
/*!
* \param name string of format
@@ -364,16 +347,52 @@ extern int ast_best_codec(int fmts);
struct ast_smoother;
+extern struct ast_format_list *ast_get_format_list_index(int index);
+extern struct ast_format_list *ast_get_format_list(size_t *size);
extern struct ast_smoother *ast_smoother_new(int bytes);
extern void ast_smoother_set_flags(struct ast_smoother *smoother, int flags);
extern int ast_smoother_get_flags(struct ast_smoother *smoother);
extern void ast_smoother_free(struct ast_smoother *s);
extern void ast_smoother_reset(struct ast_smoother *s, int bytes);
-extern int ast_smoother_feed(struct ast_smoother *s, struct ast_frame *f);
+extern int __ast_smoother_feed(struct ast_smoother *s, struct ast_frame *f, int swap);
extern struct ast_frame *ast_smoother_read(struct ast_smoother *s);
+#define ast_smoother_feed(s,f) __ast_smoother_feed(s, f, 0)
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define ast_smoother_feed_be(s,f) __ast_smoother_feed(s, f, 1)
+#define ast_smoother_feed_le(s,f) __ast_smoother_feed(s, f, 0)
+#else
+#define ast_smoother_feed_be(s,f) __ast_smoother_feed(s, f, 0)
+#define ast_smoother_feed_le(s,f) __ast_smoother_feed(s, f, 1)
+#endif
extern void ast_frame_dump(char *name, struct ast_frame *f, char *prefix);
+/* Initialize a codec preference to "no preference" */
+extern void ast_codec_pref_init(struct ast_codec_pref *pref);
+
+/* Codec located at a particular place in the preference index */
+extern int ast_codec_pref_index(struct ast_codec_pref *pref, int index);
+
+/* Remove a codec from a preference list */
+extern void ast_codec_pref_remove(struct ast_codec_pref *pref, int format);
+
+/* Append a codec to a preference list, removing it first if it was already there */
+extern int ast_codec_pref_append(struct ast_codec_pref *pref, int format);
+
+/* Select the best format according to preference list from supplied options.
+ If "find_best" is non-zero then if nothing is found, the "Best" format of
+ the format list is selected, otherwise 0 is returned. */
+extern int ast_codec_choose(struct ast_codec_pref *pref, int formats, int find_best);
+
+/* Parse an "allow" or "deny" line and update the mask and pref if provided */
+extern void ast_parse_allow_disallow(struct ast_codec_pref *pref, int *mask, char *list, int allowing);
+
+/* Dump codec preference list into a string */
+extern int ast_codec_pref_string(struct ast_codec_pref *pref, char *buf, size_t size);
+
+/* Shift a codec preference list up or down 65 bytes so that it becomes an ASCII string */
+extern void ast_codec_pref_shift(struct ast_codec_pref *pref, char *buf, size_t size, int right);
+
#if defined(__cplusplus) || defined(c_plusplus)
}
#endif
diff --git a/include/asterisk/io.h b/include/asterisk/io.h
index 56fdd8aeb..62e1f458f 100755
--- a/include/asterisk/io.h
+++ b/include/asterisk/io.h
@@ -14,7 +14,7 @@
#ifndef _IO_H
#define _IO_H
-#ifdef __APPLE__
+#ifdef POLLCOMPAT
#include <asterisk/poll-compat.h>
#else
#include <sys/poll.h> /* For POLL* constants */
diff --git a/include/asterisk/lock.h b/include/asterisk/lock.h
index 059bc89c6..350ea8822 100755
--- a/include/asterisk/lock.h
+++ b/include/asterisk/lock.h
@@ -188,17 +188,19 @@ static inline int __ast_pthread_mutex_lock(char *filename, int lineno, char *fun
filename, lineno, func, mutex_name);
#endif
ast_mutex_init(t);
- }
+ }
#endif /* definded(AST_MUTEX_INIT_W_CONSTRUCTORS) || defined(AST_MUTEX_INIT_ON_FIRST_USE) */
#ifdef DETECT_DEADLOCKS
{
- time_t seconds seconds = time(NULL);
+ time_t seconds = time(NULL);
+ time_t current;
do {
res = pthread_mutex_trylock(&t->mutex);
if (res == EBUSY) {
- if ((time(NULL) - seconds) % 5) {
+ current = time(NULL);
+ if ((current - seconds) && (!((current - seconds) % 5))) {
fprintf(stderr, "%s line %d (%s): Deadlock? waited %d sec for mutex '%s'?\n",
- filename, lineno, func, (time(NULL) - seconds), mutex_name);
+ filename, lineno, func, (int)(current - seconds), mutex_name);
fprintf(stderr, "%s line %d (%s): '%s' was locked here.\n",
t->file, t->lineno, t->func, mutex_name);
}
diff --git a/include/asterisk/rtp.h b/include/asterisk/rtp.h
index b8436578c..2aee0d42a 100755
--- a/include/asterisk/rtp.h
+++ b/include/asterisk/rtp.h
@@ -97,6 +97,9 @@ void ast_rtp_get_current_formats(struct ast_rtp* rtp,
// Mapping an Asterisk code into a MIME subtype (string):
char* ast_rtp_lookup_mime_subtype(int isAstFormat, int code);
+/* Build a string of MIME subtype names from a capability list */
+char *ast_rtp_lookup_mime_multiple(char *buf, int size, const int capability, const int isAstFormat);
+
void ast_rtp_setnat(struct ast_rtp *rtp, int nat);
int ast_rtp_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc);
diff --git a/include/asterisk/sched.h b/include/asterisk/sched.h
index fc8c797b1..f8f178799 100755
--- a/include/asterisk/sched.h
+++ b/include/asterisk/sched.h
@@ -62,7 +62,7 @@ typedef int (*ast_sched_cb)(void *data);
* Schedule an event to take place at some point in the future. callback
* will be called with data as the argument, when milliseconds into the
* future (approximately)
- * Returns 0 on success, -1 on failure
+ * Returns a schedule item ID on success, -1 on failure
*/
extern int ast_sched_add(struct sched_context *con, int when, ast_sched_cb callback, void *data);
@@ -102,6 +102,14 @@ extern int ast_sched_runq(struct sched_context *con);
*/
extern void ast_sched_dump(struct sched_context *con);
+/*!Returns the number of seconds before an event takes place */
+/*!
+ * \param con Context to use
+ * \param id Id to dump
+ */
+extern long ast_sched_when(struct sched_context *con,int id);
+
+
#if defined(__cplusplus) || defined(c_plusplus)
}
#endif
diff --git a/include/asterisk/utils.h b/include/asterisk/utils.h
index bfbdd951c..8be32fe20 100755
--- a/include/asterisk/utils.h
+++ b/include/asterisk/utils.h
@@ -48,8 +48,8 @@ extern int ast_utils_init(void);
#define PTHREAD_ATTR_STACKSIZE 2097152
#endif /* PTHREAD_ATTR_STACKSIZE */
extern int ast_pthread_create(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *), void *data);
+extern char *ast_strcasestr(const char *, const char *);
#endif /* LINUX */
-extern char *ast_strcasestr(const char *, const char *);
#endif
diff --git a/include/asterisk/vmodem.h b/include/asterisk/vmodem.h
index 69886154b..cf809870c 100755
--- a/include/asterisk/vmodem.h
+++ b/include/asterisk/vmodem.h
@@ -111,9 +111,9 @@ struct ast_modem_pvt {
char context[AST_MAX_EXTENSION];
/*! Multiple Subscriber Number */
char msn[AST_MAX_EXTENSION];
- /*! Multiple Subscriber Number we listen to (; seperated list) */
+ /*! Multiple Subscriber Number we listen to (; separated list) */
char incomingmsn[AST_MAX_EXTENSION];
- /*! Multiple Subscriber Number we accept for outgoing calls (; seperated list) */
+ /*! Multiple Subscriber Number we accept for outgoing calls (; separated list) */
char outgoingmsn[AST_MAX_EXTENSION];
/*! Group(s) we belong to if available */
unsigned int group;
diff --git a/indications.c b/indications.c
index 9598c5438..985c601c1 100755
--- a/indications.c
+++ b/indications.c
@@ -13,7 +13,7 @@
* This set of function allow us to play a list of tones on a channel.
* Each element has two frequencies, which are mixed together and a
* duration. For silence both frequencies can be set to 0.
- * The playtones can be given as a comma seperated string.
+ * The playtones can be given as a comma separated string.
*/
#include <stdio.h>
diff --git a/loader.c b/loader.c
index 2a539f30c..91c9cf0c6 100755
--- a/loader.c
+++ b/loader.c
@@ -27,7 +27,7 @@
#include <asterisk/enum.h>
#include <asterisk/rtp.h>
#include <asterisk/lock.h>
-#ifdef __APPLE__
+#ifdef DLFCNCOMPAT
#include <asterisk/dlfcn-compat.h>
#else
#include <dlfcn.h>
@@ -67,7 +67,7 @@ static int printdigest(unsigned char *d)
strcat(buf, buf2);
}
strcat(buf, "\n");
- ast_log(LOG_DEBUG, buf);
+ ast_log(LOG_DEBUG, "%s", buf);
return 0;
}
@@ -103,6 +103,7 @@ AST_MUTEX_DEFINE_STATIC(modlock);
AST_MUTEX_DEFINE_STATIC(reloadlock);
static struct module *module_list=NULL;
+static int modlistver = 0;
int ast_unload_resource(char *resource_name, int force)
{
@@ -142,6 +143,7 @@ int ast_unload_resource(char *resource_name, int force)
ml = m;
m = m->next;
}
+ modlistver = rand();
ast_mutex_unlock(&modlock);
ast_update_use_count();
return res;
@@ -150,6 +152,8 @@ int ast_unload_resource(char *resource_name, int force)
void ast_module_reload(const char *name)
{
struct module *m;
+ int oldversion;
+ int (*reload)(void);
/* We'll do the logger and manager the favor of calling its reload here first */
@@ -168,14 +172,20 @@ void ast_module_reload(const char *name)
time(&ast_lastreloadtime);
ast_mutex_lock(&modlock);
+ oldversion = modlistver;
m = module_list;
while(m) {
if (!name || !strcasecmp(name, m->resource)) {
- if (m->reload) {
+ reload = m->reload;
+ ast_mutex_unlock(&modlock);
+ if (reload) {
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "Reloading module '%s' (%s)\n", m->resource, m->description());
- m->reload();
+ reload();
}
+ ast_mutex_lock(&modlock);
+ if (oldversion != modlistver)
+ break;
}
m = m->next;
}
@@ -328,7 +338,8 @@ int ast_load_resource(char *resource_name)
;
i->next = m;
}
-
+
+ modlistver = rand();
ast_mutex_unlock(&modlock);
if ((res = m->load_module())) {
ast_log(LOG_WARNING, "%s: load_module failed, returning %d\n", m->resource, res);
diff --git a/logger.c b/logger.c
index 25bf5d3d0..51862c1ee 100755
--- a/logger.c
+++ b/logger.c
@@ -48,6 +48,13 @@ static int syslog_level_map[] = {
#define MAX_MSG_QUEUE 200
+#if defined(__linux__) && defined (__NR_gettid)
+#include <asm/unistd.h>
+#define GETTID() syscall(__NR_gettid)
+#else
+#define GETTID() getpid()
+#endif
+
static char dateformat[256] = "%b %e %T"; /* Original Asterisk Format */
AST_MUTEX_DEFINE_STATIC(msglist_lock);
AST_MUTEX_DEFINE_STATIC(loglock);
@@ -58,7 +65,7 @@ static struct msglist {
struct msglist *next;
} *list = NULL, *last = NULL;
-static char hostname[256];
+static char hostname[MAXHOSTNAMELEN];
struct logchannel {
int logmask;
@@ -154,7 +161,7 @@ static struct logchannel *make_logchannel(char *channel, char *components, int l
chan->facility = -1;
cptr = facilitynames;
while (cptr->c_name) {
- if (!strncasecmp(facility, cptr->c_name, sizeof(cptr->c_name))) {
+ if (!strcasecmp(facility, cptr->c_name)) {
chan->facility = cptr->c_val;
break;
}
@@ -223,7 +230,7 @@ static void init_logger_chain(void)
ast_mutex_lock(&loglock);
if ((s = ast_variable_retrieve(cfg, "general", "appendhostname"))) {
if(ast_true(s)) {
- if(gethostname(hostname, sizeof(hostname))) {
+ if(gethostname(hostname, sizeof(hostname)-1)) {
strncpy(hostname, "unknown", sizeof(hostname)-1);
ast_log(LOG_WARNING, "What box has no hostname???\n");
}
@@ -351,6 +358,8 @@ int reload_logger(int rotate)
ast_mutex_unlock(&loglock);
+ pending_logger_reload = 0;
+
queue_log_init();
if (eventlog) {
@@ -362,7 +371,7 @@ int reload_logger(int rotate)
} else
ast_log(LOG_ERROR, "Unable to create event log: %s\n", strerror(errno));
init_logger_chain();
- pending_logger_reload = 0;
+
return -1;
}
@@ -455,8 +464,8 @@ void close_logger(void)
{
struct msglist *m, *tmp;
- m = list;
ast_mutex_lock(&msglist_lock);
+ m = list;
while(m) {
if (m->msg) {
free(m->msg);
@@ -471,9 +480,39 @@ void close_logger(void)
return;
}
+static void strip_coloring(char *str)
+{
+ char *src, *dest, *end;
+
+ if (!str)
+ return;
+
+ /* find the first potential escape sequence in the string */
+
+ src = strchr(str, '\033');
+ if (!src)
+ return;
+
+ dest = src;
+ while (*src) {
+ /* at the top of this loop, *src will always be an ESC character */
+ if ((src[1] == '[') && ((end = strchr(src + 2, 'm'))))
+ src = end + 1;
+ else
+ *dest++ = *src++;
+
+ /* copy characters, checking for ESC as we go */
+ while (*src && (*src != '\033'))
+ *dest++ = *src++;
+ }
+
+ *dest = '\0';
+}
+
static void ast_log_vsyslog(int level, const char *file, int line, const char *function, const char *fmt, va_list args)
{
char buf[BUFSIZ];
+ char *s;
if (level >= SYSLOG_NLEVELS) {
/* we are locked here, so cannot ast_log() */
@@ -481,13 +520,15 @@ static void ast_log_vsyslog(int level, const char *file, int line, const char *f
return;
}
if (level == __LOG_VERBOSE) {
- snprintf(buf, sizeof(buf), "VERBOSE[%ld]: ", (long)pthread_self());
+ snprintf(buf, sizeof(buf), "VERBOSE[%ld]: ", (long)GETTID());
level = __LOG_DEBUG;
} else {
snprintf(buf, sizeof(buf), "%s[%ld]: %s:%d in %s: ",
- levels[level], (long)pthread_self(), file, line, function);
+ levels[level], (long)GETTID(), file, line, function);
}
- vsnprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), fmt, args);
+ s = buf + strlen(buf);
+ vsnprintf(s, sizeof(buf) - strlen(buf), fmt, args);
+ strip_coloring(s);
syslog(syslog_level_map[level], "%s", buf);
}
@@ -543,7 +584,7 @@ void ast_log(int level, const char *file, int line, const char *function, const
snprintf(buf, sizeof(buf), "%s %s[%ld]: %s:%s %s: ",
date,
term_color(tmp1, levels[level], colors[level], 0, sizeof(tmp1)),
- (long)pthread_self(),
+ (long)GETTID(),
term_color(tmp2, file, COLOR_BRWHITE, 0, sizeof(tmp2)),
term_color(tmp3, linestr, COLOR_BRWHITE, 0, sizeof(tmp3)),
term_color(tmp4, function, COLOR_BRWHITE, 0, sizeof(tmp4)));
@@ -556,10 +597,11 @@ void ast_log(int level, const char *file, int line, const char *function, const
}
} else if ((chan->logmask & (1 << level)) && (chan->fileptr)) {
snprintf(buf, sizeof(buf), "%s %s[%ld]: ", date,
- levels[level], (long)pthread_self());
+ levels[level], (long)GETTID());
fprintf(chan->fileptr, buf);
va_start(ap, fmt);
vsnprintf(buf, sizeof(buf), fmt, ap);
+ strip_coloring(buf);
va_end(ap);
fputs(buf, chan->fileptr);
fflush(chan->fileptr);
@@ -642,7 +684,7 @@ extern void ast_verbose(const char *fmt, ...)
} /* else
fprintf(stdout, stuff + opos); */
- ast_log(LOG_VERBOSE, stuff);
+ ast_log(LOG_VERBOSE, "%s", stuff);
if (fmt[strlen(fmt)-1] != '\n')
replacelast = 1;
@@ -656,8 +698,8 @@ extern void ast_verbose(const char *fmt, ...)
int ast_verbose_dmesg(void (*v)(const char *string, int opos, int replacelast, int complete))
{
struct msglist *m;
- m = list;
ast_mutex_lock(&msglist_lock);
+ m = list;
while(m) {
/* Send all the existing entries that we have queued (i.e. they're likely to have missed) */
v(m->msg, 0, 0, 1);
diff --git a/manager.c b/manager.c
index 4f5e568ad..53e600873 100755
--- a/manager.c
+++ b/manager.c
@@ -1,6 +1,8 @@
/*
* Asterisk -- A telephony toolkit for Linux.
*
+ * The Asterisk Management Interface - AMI
+ *
* Channel Management and more
*
* Copyright (C) 1999-2004, Digium, Inc.
@@ -118,6 +120,9 @@ static char *authority_to_str(int authority, char *res, int reslen)
running_total += strlen(perms[i].label);
}
}
+ if (ast_strlen_zero(res)) {
+ strncpy(res, "<none>", reslen);
+ }
return res;
}
@@ -243,7 +248,7 @@ static void destroy_session(struct mansession *s)
ast_mutex_destroy(&s->lock);
free(s);
} else
- ast_log(LOG_WARNING, "Trying to delete non-existant session %p?\n", s);
+ ast_log(LOG_WARNING, "Trying to delete nonexistent session %p?\n", s);
ast_mutex_unlock(&sessionlock);
}
@@ -463,7 +468,7 @@ static int authenticate(struct mansession *s, struct message *m)
set_eventmask(s, events);
return 0;
}
- ast_log(LOG_NOTICE, "%s tried to authenticate with non-existant user '%s'\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), user);
+ ast_log(LOG_NOTICE, "%s tried to authenticate with nonexistent user '%s'\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), user);
ast_destroy(cfg);
return -1;
}
@@ -570,6 +575,13 @@ static int action_hangup(struct mansession *s, struct message *m)
return 0;
}
+static char mandescr_setvar[] =
+"Description: Set a local channel variable.\n"
+"Variables: (Names marked with * are required)\n"
+" *Channel: Channel to set variable for\n"
+" *Variable: Variable name\n"
+" *Value: Value\n";
+
static int action_setvar(struct mansession *s, struct message *m)
{
struct ast_channel *c = NULL;
@@ -606,6 +618,13 @@ static int action_setvar(struct mansession *s, struct message *m)
return 0;
}
+static char mandescr_getvar[] =
+"Description: Get the value of a local channel variable.\n"
+"Variables: (Names marked with * are required)\n"
+" *Channel: Channel to read variable from\n"
+" *Variable: Variable name\n"
+" ActionID: Optional Action id for message matching.\n";
+
static int action_getvar(struct mansession *s, struct message *m)
{
struct ast_channel *c = NULL;
@@ -758,7 +777,7 @@ static int action_redirect(struct mansession *s, struct message *m)
}
chan = ast_get_channel_by_name_locked(name);
if (!chan) {
- astman_send_error(s, m, "Channel not existant");
+ astman_send_error(s, m, "Channel not existent");
return 0;
}
if (!ast_strlen_zero(name2))
@@ -785,6 +804,11 @@ static int action_redirect(struct mansession *s, struct message *m)
return 0;
}
+static char mandescr_command[] =
+"Description: Run a CLI command.\n"
+"Variables: (Names marked with * are required)\n"
+" *Command: Asterisk CLI command to run\n"
+" ActionID: Optional Action id for message matching.\n";
static int action_command(struct mansession *s, struct message *m)
{
char *cmd = astman_get_header(m, "Command");
@@ -922,10 +946,10 @@ static int action_originate(struct mansession *s, struct message *m)
}
}
} else if (!ast_strlen_zero(app)) {
- res = ast_pbx_outgoing_app(tech, AST_FORMAT_SLINEAR, data, to, app, appdata, &reason, 0, !ast_strlen_zero(callerid) ? callerid : NULL, variable, account);
+ res = ast_pbx_outgoing_app(tech, AST_FORMAT_SLINEAR, data, to, app, appdata, &reason, 1, !ast_strlen_zero(callerid) ? callerid : NULL, variable, account);
} else {
if (exten && context && pi)
- res = ast_pbx_outgoing_exten(tech, AST_FORMAT_SLINEAR, data, to, context, exten, pi, &reason, 0, !ast_strlen_zero(callerid) ? callerid : NULL, variable, account);
+ res = ast_pbx_outgoing_exten(tech, AST_FORMAT_SLINEAR, data, to, context, exten, pi, &reason, 1, !ast_strlen_zero(callerid) ? callerid : NULL, variable, account);
else {
astman_send_error(s, m, "Originate with 'Exten' requires 'Context' and 'Priority'");
return 0;
@@ -938,6 +962,16 @@ static int action_originate(struct mansession *s, struct message *m)
return 0;
}
+static char mandescr_mailboxstatus[] =
+"Description: Checks a voicemail account for status.\n"
+"Variables: (Names marked with * are required)\n"
+" *Mailbox: Full mailbox ID <mailbox>@<vm-context>\n"
+" ActionID: Optional ActionID for message matching.\n"
+"Returns number of messages.\n"
+" Message: Mailbox Status\n"
+" Mailbox: <mailboxid>\n"
+" Waiting: <count>\n"
+"\n";
static int action_mailboxstatus(struct mansession *s, struct message *m)
{
char *mailbox = astman_get_header(m, "Mailbox");
@@ -961,6 +995,17 @@ static int action_mailboxstatus(struct mansession *s, struct message *m)
return 0;
}
+static char mandescr_mailboxcount[] =
+"Description: Checks a voicemail account for new messages.\n"
+"Variables: (Names marked with * are required)\n"
+" *Mailbox: Full mailbox ID <mailbox>@<vm-context>\n"
+" ActionID: Optional ActionID for message matching.\n"
+"Returns number of new and old messages.\n"
+" Message: Mailbox Message Count\n"
+" Mailbox: <mailboxid>\n"
+" NewMessages: <count>\n"
+" OldMessages: <count>\n"
+"\n";
static int action_mailboxcount(struct mansession *s, struct message *m)
{
char *mailbox = astman_get_header(m, "Mailbox");
@@ -988,6 +1033,17 @@ static int action_mailboxcount(struct mansession *s, struct message *m)
return 0;
}
+static char mandescr_extensionstate[] =
+"Description: Report the extension state for given extension.\n"
+" If the extension has a hint, will use devicestate to check\n"
+" the status of the device connected to the extension.\n"
+"Variables: (Names marked with * are required)\n"
+" *Exten: Extension to check state on\n"
+" *Context: Context for extension\n"
+" ActionId: Optional ID for this transaction\n"
+"Will return an \"Extension Status\" message.\n"
+"The response will include the hint for the extension and the status.\n";
+
static int action_extensionstate(struct mansession *s, struct message *m)
{
char *exten = astman_get_header(m, "Exten");
@@ -1020,6 +1076,13 @@ static int action_extensionstate(struct mansession *s, struct message *m)
return 0;
}
+static char mandescr_timeout[] =
+"Description: Hangup a channel after a certain time.\n"
+"Variables: (Names marked with * are required)\n"
+" *Channel: Channel name to hangup\n"
+" *Timeout: Maximum duration of the call (sec)\n"
+"Acknowledges set time with 'Timeout Set' message\n";
+
static int action_timeout(struct mansession *s, struct message *m)
{
struct ast_channel *c = NULL;
@@ -1153,6 +1216,7 @@ static int get_input(struct mansession *s, char *output)
res = poll(fds, 1, -1);
if (res < 0) {
ast_log(LOG_WARNING, "Select returned error: %s\n", strerror(errno));
+ return -1;
} else if (res > 0) {
ast_mutex_lock(&s->lock);
res = read(s->fd, s->inbuf + s->inlen, sizeof(s->inbuf) - 1 - s->inlen);
@@ -1392,15 +1456,15 @@ int init_manager(void)
ast_manager_register2("Logoff", 0, action_logoff, "Logoff Manager", mandescr_logoff);
ast_manager_register2("Hangup", EVENT_FLAG_CALL, action_hangup, "Hangup Channel", mandescr_hangup);
ast_manager_register( "Status", EVENT_FLAG_CALL, action_status, "Status" );
- ast_manager_register( "Setvar", EVENT_FLAG_CALL, action_setvar, "Set Channel Variable" );
- ast_manager_register( "Getvar", EVENT_FLAG_CALL, action_getvar, "Gets a Channel Variable" );
+ ast_manager_register2( "Setvar", EVENT_FLAG_CALL, action_setvar, "Set Channel Variable", mandescr_setvar );
+ ast_manager_register2( "Getvar", EVENT_FLAG_CALL, action_getvar, "Gets a Channel Variable", mandescr_getvar );
ast_manager_register( "Redirect", EVENT_FLAG_CALL, action_redirect, "Redirect" );
ast_manager_register2("Originate", EVENT_FLAG_CALL, action_originate, "Originate Call", mandescr_originate);
- ast_manager_register( "MailboxStatus", EVENT_FLAG_CALL, action_mailboxstatus, "Check Mailbox" );
- ast_manager_register( "Command", EVENT_FLAG_COMMAND, action_command, "Execute Command" );
- ast_manager_register( "ExtensionState", EVENT_FLAG_CALL, action_extensionstate, "Check Extension Status" );
- ast_manager_register( "AbsoluteTimeout", EVENT_FLAG_CALL, action_timeout, "Set Absolute Timeout" );
- ast_manager_register( "MailboxCount", EVENT_FLAG_CALL, action_mailboxcount, "Check Mailbox Message Count" );
+ ast_manager_register2( "Command", EVENT_FLAG_COMMAND, action_command, "Execute Command", mandescr_command );
+ ast_manager_register2( "ExtensionState", EVENT_FLAG_CALL, action_extensionstate, "Check Extension Status", mandescr_extensionstate );
+ ast_manager_register2( "AbsoluteTimeout", EVENT_FLAG_CALL, action_timeout, "Set Absolute Timeout", mandescr_timeout );
+ ast_manager_register2( "MailboxStatus", EVENT_FLAG_CALL, action_mailboxstatus, "Check Mailbox", mandescr_mailboxstatus );
+ ast_manager_register2( "MailboxCount", EVENT_FLAG_CALL, action_mailboxcount, "Check Mailbox Message Count", mandescr_mailboxcount );
ast_manager_register2("ListCommands", 0, action_listcommands, "List available manager commands", mandescr_listcommands);
ast_cli_register(&show_mancmd_cli);
diff --git a/md5.c b/md5.c
index 17a00c6fc..ba29ee255 100755
--- a/md5.c
+++ b/md5.c
@@ -1,16 +1,6 @@
/* MD5 checksum routines used for authentication. Not covered by GPL, but
in the public domain as per the copyright below */
-#if defined( __OpenBSD__ )
-# include <machine/types.h>
-# include <sys/endian.h>
-#elif defined( __FreeBSD__ ) || defined( __NetBSD__ )
-# include <sys/types.h>
-# include <sys/endian.h>
-#elif defined( BSD ) && ( BSD >= 199103 ) || defined(__APPLE__)
-# include <machine/endian.h>
-#else
-# include <endian.h>
-#endif
+#include "asterisk/endian.h"
# if __BYTE_ORDER == __BIG_ENDIAN || BYTE_ORDER == BIG_ENDIAN
# define HIGHFIRST 1
# endif
diff --git a/pbx.c b/pbx.c
index 16888bdbf..16d08f649 100755
--- a/pbx.c
+++ b/pbx.c
@@ -235,7 +235,8 @@ static struct pbx_builtin {
"typed in is valid, it will not have to timeout to be tested, so typically\n"
"at the expiry of this timeout, the extension will be considered invalid\n"
"(and thus control would be passed to the 'i' extension, or if it doesn't\n"
- "exist the call would be terminated). Always returns 0.\n"
+ "exist the call would be terminated). The default timeout is 5 seconds.\n"
+ "Always returns 0.\n"
},
{ "Goto", pbx_builtin_goto,
@@ -305,7 +306,8 @@ static struct pbx_builtin {
"falling through a series of priorities for a channel in which the user may\n"
"begin typing an extension. If the user does not type an extension in this\n"
"amount of time, control will pass to the 't' extension if it exists, and\n"
- "if not the call would be terminated.\nAlways returns 0.\n"
+ "if not the call would be terminated. The default timeout is 10 seconds.\n"
+ "Always returns 0.\n"
},
{ "Ringing", pbx_builtin_ringing,
@@ -481,7 +483,7 @@ int pbx_exec(struct ast_channel *c, /* Channel */
/* Go no deeper than this through includes (not counting loops) */
-#define AST_PBX_MAX_STACK 64
+#define AST_PBX_MAX_STACK 128
#define HELPER_EXISTS 0
#define HELPER_SPAWN 1
@@ -577,6 +579,7 @@ static void pbx_destroy(struct ast_pbx *p)
match=1;\
pattern++;\
while(match && *data && *pattern && (*pattern != '/')) {\
+ while (*data == '-' && (*(data+1) != '\0')) data++;\
switch(toupper(*pattern)) {\
case '[': \
{\
@@ -816,6 +819,9 @@ static struct ast_exten *pbx_find_extension(struct ast_channel *chan, char *cont
return NULL;
}
+/*--- pbx_retrieve_variable: Support for Asterisk built-in variables and
+ functions in the dialplan
+ ---*/
static void pbx_substitute_variables_temp(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen)
{
char *first,*second;
@@ -829,52 +835,61 @@ static void pbx_substitute_variables_temp(struct ast_channel *c, const char *var
if (c)
headp=&c->varshead;
+
*ret=NULL;
- /* Now we have the variable name on cp3 */
- if (!strncasecmp(var,"LEN(",4)) {
- int len=strlen(var);
- int len_len=4;
- if (strrchr(var,')')) {
- char cp3[80];
- strncpy(cp3, var, sizeof(cp3) - 1);
- cp3[len-len_len-1]='\0';
- sprintf(workspace,"%d",(int)strlen(cp3));
- *ret = workspace;
- } else {
- /* length is zero */
- *ret = "0";
+
+ if (!strncasecmp(var,"LEN(",4)) { /* ${LEN(<string>)} */
+ char *endparen, *string = ast_strdupa(var + 4);
+ int len = 0;
+ if (!string) {
+ ast_log(LOG_WARNING, "Out of memory!\n");
+ return;
}
- } else if ((first=strchr(var,':'))) {
+ if ((endparen = strrchr(string,')'))) {
+ *endparen = '\0';
+ len = strlen(string);
+ }
+ sprintf(workspace, "%d", len);
+ *ret = workspace;
+ } else if ((first=strchr(var,':'))) { /* : Remove characters counting from end or start of string */
strncpy(tmpvar, var, sizeof(tmpvar) - 1);
first = strchr(tmpvar, ':');
if (!first)
first = tmpvar + strlen(tmpvar);
*first='\0';
pbx_substitute_variables_temp(c,tmpvar,ret,workspace,workspacelen - 1);
- if (!(*ret)) return;
- offset=atoi(first+1);
- if ((second=strchr(first+1,':'))) {
+ if (!(*ret))
+ return;
+ offset=atoi(first+1); /* The number of characters,
+ positive: remove # of chars from start
+ negative: keep # of chars from end */
+
+ if ((second=strchr(first+1,':'))) {
*second='\0';
- offset2=atoi(second+1);
- } else
- offset2=strlen(*ret)-offset;
- if (abs(offset)>strlen(*ret)) {
- if (offset>=0)
+ offset2 = atoi(second+1); /* Number of chars to copy */
+ } else if (offset >= 0) {
+ offset2 = strlen(*ret)-offset; /* Rest of string */
+ } else {
+ offset2 = abs(offset);
+ }
+
+ if (abs(offset) > strlen(*ret)) { /* Offset beyond string */
+ if (offset >= 0)
offset=strlen(*ret);
else
offset=-strlen(*ret);
}
- if ((offset<0 && offset2>-offset) || (offset>=0 && offset+offset2>strlen(*ret))) {
- if (offset>=0)
+ if ((offset < 0 && offset2 > -offset) || (offset >= 0 && offset+offset2 > strlen(*ret))) {
+ if (offset >= 0)
offset2=strlen(*ret)-offset;
else
offset2=strlen(*ret)+offset;
}
- if (offset>=0)
- *ret+=offset;
+ if (offset >= 0)
+ *ret += offset;
else
- *ret+=strlen(*ret)+offset;
- (*ret)[offset2] = '\0';
+ *ret += strlen(*ret)+offset;
+ (*ret)[offset2] = '\0'; /* Cut at offset2 position */
} else if (c && !strcmp(var, "CALLERIDNUM")) {
if (c->callerid)
strncpy(workspace, c->callerid, workspacelen - 1);
@@ -1258,7 +1273,7 @@ static int pbx_extension_helper(struct ast_channel *c, char *context, char *exte
pbx_substitute_variables(passdata, sizeof(passdata), c, e);
if (option_debug)
ast_log(LOG_DEBUG, "Launching '%s'\n", app->name);
- else if (option_verbose > 2)
+ if (option_verbose > 2)
ast_verbose( VERBOSE_PREFIX_3 "Executing %s(\"%s\", \"%s\") %s\n",
term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)),
term_color(tmp2, c->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
@@ -1503,11 +1518,12 @@ int ast_extension_state_add(char *context, char *exten,
if (cblist->callback == callback) {
cblist->data = data;
ast_mutex_unlock(&hintlock);
+ return 0;
}
cblist = cblist->next;
}
- /* Now inserts the callback */
+ /* Now insert the callback */
cblist = malloc(sizeof(struct ast_state_cb));
if (!cblist) {
ast_mutex_unlock(&hintlock);
@@ -1760,7 +1776,7 @@ int ast_spawn_extension(struct ast_channel *c, char *context, char *exten, int p
int ast_pbx_run(struct ast_channel *c)
{
int firstpass = 1;
- char digit;
+ int digit;
char exten[256];
int pos;
int waittime;
@@ -2760,6 +2776,7 @@ static int handle_show_dialplan(int fd, int argc, char *argv[])
e = ast_walk_context_extensions(c, NULL);
while (e) {
struct ast_exten *p;
+ int prio;
/* looking for extension? is this our extension? */
if (exten &&
@@ -2786,11 +2803,18 @@ static int handle_show_dialplan(int fd, int argc, char *argv[])
snprintf(buf, sizeof(buf), "'%s' =>",
ast_get_extension_name(e));
- snprintf(buf2, sizeof(buf2),
- "%d. %s(%s)",
- ast_get_extension_priority(e),
- ast_get_extension_app(e),
- (char *)ast_get_extension_app_data(e));
+ prio = ast_get_extension_priority(e);
+ if (prio == PRIORITY_HINT) {
+ snprintf(buf2, sizeof(buf2),
+ "hint: %s",
+ ast_get_extension_app(e));
+ } else {
+ snprintf(buf2, sizeof(buf2),
+ "%d. %s(%s)",
+ prio,
+ ast_get_extension_app(e),
+ (char *)ast_get_extension_app_data(e));
+ }
ast_cli(fd, " %-17s %-45s [%s]\n", buf, buf2,
ast_get_extension_registrar(e));
@@ -2800,11 +2824,18 @@ static int handle_show_dialplan(int fd, int argc, char *argv[])
while (p) {
bzero((void *)buf2, sizeof(buf2));
- snprintf(buf2, sizeof(buf2),
- "%d. %s(%s)",
- ast_get_extension_priority(p),
- ast_get_extension_app(p),
- (char *)ast_get_extension_app_data(p));
+ prio = ast_get_extension_priority(p);
+ if (prio == PRIORITY_HINT) {
+ snprintf(buf2, sizeof(buf2),
+ "hint: %s",
+ ast_get_extension_app(p));
+ } else {
+ snprintf(buf2, sizeof(buf2),
+ "%d. %s(%s)",
+ prio,
+ ast_get_extension_app(p),
+ (char *)ast_get_extension_app_data(p));
+ }
ast_cli(fd," %-17s %-45s [%s]\n",
"", buf2,
@@ -4006,7 +4037,7 @@ static void *async_wait(void *data)
app = pbx_findapp(as->app);
if (app) {
if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Lauching %s(%s) on %s\n", as->app, as->appdata, chan->name);
+ ast_verbose(VERBOSE_PREFIX_3 "Launching %s(%s) on %s\n", as->app, as->appdata, chan->name);
pbx_exec(chan, app, as->appdata, 1);
} else
ast_log(LOG_WARNING, "No such application '%s'\n", as->app);
@@ -4142,7 +4173,7 @@ static void *ast_pbx_run_app(void *data)
app = pbx_findapp(tmp->app);
if (app) {
if (option_verbose > 3)
- ast_verbose(VERBOSE_PREFIX_4 "Lauching %s(%s) on %s\n", tmp->app, tmp->data, tmp->chan->name);
+ ast_verbose(VERBOSE_PREFIX_4 "Launching %s(%s) on %s\n", tmp->app, tmp->data, tmp->chan->name);
pbx_exec(tmp->chan, app, tmp->data, 1);
} else
ast_log(LOG_WARNING, "No such application '%s'\n", tmp->app);
@@ -4381,7 +4412,8 @@ static int pbx_builtin_answer(struct ast_channel *chan, void *data)
static int pbx_builtin_setlanguage(struct ast_channel *chan, void *data)
{
/* Copy the language as specified */
- strncpy(chan->language, (char *)data, sizeof(chan->language)-1);
+ if (data)
+ strncpy(chan->language, (char *)data, sizeof(chan->language)-1);
return 0;
}
@@ -4567,7 +4599,7 @@ static int pbx_builtin_background(struct ast_channel *chan, void *data)
res = ast_waitstream(chan, AST_DIGIT_ANY);
ast_stopstream(chan);
} else {
- ast_log(LOG_WARNING, "ast_streamfile failed on %s fro %s\n", chan->name, (char*)data);
+ ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", chan->name, (char*)data);
res = 0;
}
}
@@ -4588,6 +4620,10 @@ static int pbx_builtin_atimeout(struct ast_channel *chan, void *data)
static int pbx_builtin_rtimeout(struct ast_channel *chan, void *data)
{
+ /* If the channel is not in a PBX, return now */
+ if (!chan->pbx)
+ return 0;
+
/* Set the timeout for how long to wait between digits */
chan->pbx->rtimeout = atoi((char *)data);
if (option_verbose > 2)
@@ -4597,6 +4633,10 @@ static int pbx_builtin_rtimeout(struct ast_channel *chan, void *data)
static int pbx_builtin_dtimeout(struct ast_channel *chan, void *data)
{
+ /* If the channel is not in a PBX, return now */
+ if (!chan->pbx)
+ return 0;
+
/* Set the timeout for how long to wait between digits */
chan->pbx->dtimeout = atoi((char *)data);
if (option_verbose > 2)
@@ -5048,7 +5088,7 @@ int ast_context_verify_includes(struct ast_context *con)
for (inc = ast_walk_context_includes(con, NULL); inc; inc = ast_walk_context_includes(con, inc))
if (!ast_context_find(inc->rname)) {
res = -1;
- ast_log(LOG_WARNING, "Context '%s' tries includes non-existant context '%s'\n",
+ ast_log(LOG_WARNING, "Context '%s' tries includes nonexistent context '%s'\n",
ast_get_context_name(con), inc->rname);
}
return res;
diff --git a/pbx/pbx_config.c b/pbx/pbx_config.c
index b067e2fe4..d67ff3185 100755
--- a/pbx/pbx_config.c
+++ b/pbx/pbx_config.c
@@ -1687,19 +1687,16 @@ static int pbx_load_module(void)
else
data = "";
}
- cidmatch = strchr(ext, '/');
- if (cidmatch) {
- *cidmatch = '\0';
- cidmatch++;
- }
- stringp=ext;
- strsep(&stringp, "/");
-
+ pbx_substitute_variables_helper(NULL, ext, realext, sizeof(realext)-1);
+ stringp = realext;
+ ext = strsep(&stringp, "/");
+ cidmatch = stringp;
if (!data)
data="";
while(*appl && (*appl < 33)) appl++;
- pbx_substitute_variables_helper(NULL, ext, realext, sizeof(realext) - 1);
if (ipri) {
+ if (!strcmp(realext, "_."))
+ ast_log(LOG_WARNING, "The use of '_.' for an extension is strongly discouraged and can have unexpected behavior. Please use '_X.' instead at line %d\n", v->lineno);
if (ast_add_extension2(con, 0, realext, ipri, cidmatch, appl, strdup(data), FREE, registrar)) {
ast_log(LOG_WARNING, "Unable to register extension at line %d\n", v->lineno);
}
diff --git a/pbx/pbx_spool.c b/pbx/pbx_spool.c
index fd51926b0..fcf50c271 100755
--- a/pbx/pbx_spool.c
+++ b/pbx/pbx_spool.c
@@ -92,10 +92,8 @@ static int apply_outgoing(struct outgoing *o, char *fn, FILE *f)
char buf[256];
char *c, *c2;
int lineno = 0;
- while(!feof(f)) {
- fgets(buf, sizeof(buf), f);
+ while(fgets(buf, sizeof(buf), f)) {
lineno++;
- if (!feof(f)) {
/* Trim comments */
c = buf;
while ((c = strchr(c, '#'))) {
@@ -184,7 +182,6 @@ static int apply_outgoing(struct outgoing *o, char *fn, FILE *f)
} else
ast_log(LOG_NOTICE, "Syntax error at line %d of %s\n", lineno, fn);
}
- }
}
strncpy(o->fn, fn, sizeof(o->fn) - 1);
if (ast_strlen_zero(o->tech) || ast_strlen_zero(o->dest) || (ast_strlen_zero(o->app) && ast_strlen_zero(o->exten))) {
diff --git a/redhat/asterisk.spec b/redhat/asterisk.spec
index a7f328983..f92ecfdb2 100755
--- a/redhat/asterisk.spec
+++ b/redhat/asterisk.spec
@@ -59,6 +59,8 @@ ln -sf /var/spool/asterisk/vm /var/lib/asterisk/sounds/vm
%attr(0755,root,root) /usr/sbin/safe_asterisk
%attr(0755,root,root) /usr/sbin/astgenkey
%attr(0755,root,root) /usr/sbin/astman
+%attr(0755,root,root) /usr/sbin/autosupport
+
#
# Sound files
diff --git a/res/res_adsi.c b/res/res_adsi.c
index 2ee440e6a..ec160e4b3 100755
--- a/res/res_adsi.c
+++ b/res/res_adsi.c
@@ -310,7 +310,7 @@ int adsi_begin_download(struct ast_channel *chan, char *service, char *fdn, char
/* Setup the resident soft key stuff, a piece at a time */
/* Upload what scripts we can for voicemail ahead of time */
bytes += adsi_download_connect(buf + bytes, service, fdn, sec, version);
- if (adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD))
+ if (adsi_transmit_message_full(chan, buf, bytes, ADSI_MSG_DOWNLOAD, 0))
return -1;
if (ast_readstring(chan, ack, 1, 10000, 10000, ""))
return -1;
@@ -328,12 +328,12 @@ int adsi_end_download(struct ast_channel *chan)
/* Setup the resident soft key stuff, a piece at a time */
/* Upload what scripts we can for voicemail ahead of time */
bytes += adsi_download_disconnect(buf + bytes);
- if (adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD))
+ if (adsi_transmit_message_full(chan, buf, bytes, ADSI_MSG_DOWNLOAD, 0))
return -1;
return 0;
}
-int adsi_transmit_message(struct ast_channel *chan, unsigned char *msg, int msglen, int msgtype)
+int adsi_transmit_message_full(struct ast_channel *chan, unsigned char *msg, int msglen, int msgtype, int dowait)
{
unsigned char *msgs[5] = { NULL, NULL, NULL, NULL, NULL };
int msglens[5];
@@ -342,6 +342,7 @@ int adsi_transmit_message(struct ast_channel *chan, unsigned char *msg, int msgl
int res;
int x;
int writeformat, readformat;
+ int waitforswitch = 0;
writeformat = chan->writeformat;
readformat = chan->readformat;
@@ -349,11 +350,17 @@ int adsi_transmit_message(struct ast_channel *chan, unsigned char *msg, int msgl
newdatamode = chan->adsicpe & ADSI_FLAG_DATAMODE;
for (x=0;x<msglen;x+=(msg[x+1]+2)) {
- if (msg[x] == ADSI_SWITCH_TO_DATA)
+ if (msg[x] == ADSI_SWITCH_TO_DATA) {
+ ast_log(LOG_DEBUG, "Switch to data is sent!\n");
+ waitforswitch++;
newdatamode = ADSI_FLAG_DATAMODE;
+ }
- if (msg[x] == ADSI_SWITCH_TO_VOICE)
+ if (msg[x] == ADSI_SWITCH_TO_VOICE) {
+ ast_log(LOG_DEBUG, "Switch to voice is sent!\n");
+ waitforswitch++;
newdatamode = 0;
+ }
}
msgs[0] = msg;
@@ -381,6 +388,12 @@ int adsi_transmit_message(struct ast_channel *chan, unsigned char *msg, int msgl
return -1;
}
res = __adsi_transmit_messages(chan, msgs, msglens, msgtypes);
+
+ if (dowait) {
+ ast_log(LOG_DEBUG, "Wait for switch is '%d'\n", waitforswitch);
+ while(waitforswitch-- && ((res = ast_waitfordigit(chan, 1000)) > 0)) { res = 0; ast_log(LOG_DEBUG, "Waiting for 'B'...\n"); }
+ }
+
if (!res)
chan->adsicpe = (chan->adsicpe & ~ADSI_FLAG_DATAMODE) | newdatamode;
@@ -389,9 +402,16 @@ int adsi_transmit_message(struct ast_channel *chan, unsigned char *msg, int msgl
if (readformat)
ast_set_read_format(chan, readformat);
+ if (!res)
+ res = ast_safe_sleep(chan, 100 );
return res;
}
+int adsi_transmit_message(struct ast_channel *chan, unsigned char *msg, int msglen, int msgtype)
+{
+ return adsi_transmit_message_full(chan, msg, msglen, msgtype, 1);
+}
+
static inline int ccopy(unsigned char *dst, unsigned char *src, int max)
{
int x=0;
@@ -571,11 +591,11 @@ int adsi_get_cpeid(struct ast_channel *chan, unsigned char *cpeid, int voice)
int bytes = 0;
int res;
bytes += adsi_data_mode(buf);
- adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
+ adsi_transmit_message_full(chan, buf, bytes, ADSI_MSG_DISPLAY, 0);
bytes = 0;
bytes += adsi_query_cpeid(buf);
- adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
+ adsi_transmit_message_full(chan, buf, bytes, ADSI_MSG_DISPLAY, 0);
/* Get response */
memset(buf, 0, sizeof(buf));
@@ -590,7 +610,7 @@ int adsi_get_cpeid(struct ast_channel *chan, unsigned char *cpeid, int voice)
if (voice) {
bytes = 0;
bytes += adsi_voice_mode(buf, 0);
- adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
+ adsi_transmit_message_full(chan, buf, bytes, ADSI_MSG_DISPLAY, 0);
/* Ignore the resulting DTMF B announcing it's in voice mode */
ast_waitfordigit(chan, 1000);
}
@@ -603,11 +623,11 @@ int adsi_get_cpeinfo(struct ast_channel *chan, int *width, int *height, int *but
int bytes = 0;
int res;
bytes += adsi_data_mode(buf);
- adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
+ adsi_transmit_message_full(chan, buf, bytes, ADSI_MSG_DISPLAY, 0);
bytes = 0;
bytes += adsi_query_cpeinfo(buf);
- adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
+ adsi_transmit_message_full(chan, buf, bytes, ADSI_MSG_DISPLAY, 0);
/* Get width */
memset(buf, 0, sizeof(buf));
@@ -655,7 +675,7 @@ int adsi_get_cpeinfo(struct ast_channel *chan, int *width, int *height, int *but
if (voice) {
bytes = 0;
bytes += adsi_voice_mode(buf, 0);
- adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
+ adsi_transmit_message_full(chan, buf, bytes, ADSI_MSG_DISPLAY, 0);
/* Ignore the resulting DTMF B announcing it's in voice mode */
ast_waitfordigit(chan, 1000);
}
@@ -904,7 +924,7 @@ int adsi_channel_restore(struct ast_channel *chan)
}
bytes += adsi_set_keys(dsp + bytes, keyd);
}
- adsi_transmit_message(chan, dsp, bytes, ADSI_MSG_DISPLAY);
+ adsi_transmit_message_full(chan, dsp, bytes, ADSI_MSG_DISPLAY, 0);
return 0;
}
@@ -921,7 +941,7 @@ int adsi_print(struct ast_channel *chan, char **lines, int *aligns, int voice)
if (voice) {
bytes += adsi_voice_mode(buf + bytes, 0);
}
- res = adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
+ res = adsi_transmit_message_full(chan, buf, bytes, ADSI_MSG_DISPLAY, 0);
if (voice) {
/* Ignore the resulting DTMF B announcing it's in voice mode */
ast_waitfordigit(chan, 1000);
@@ -946,7 +966,7 @@ int adsi_load_session(struct ast_channel *chan, unsigned char *app, int ver, int
bytes += adsi_data_mode(dsp + bytes);
/* Prepare key setup messages */
- if (adsi_transmit_message(chan, dsp, bytes, ADSI_MSG_DISPLAY))
+ if (adsi_transmit_message_full(chan, dsp, bytes, ADSI_MSG_DISPLAY, 0))
return -1;
if (app) {
res = ast_readstring(chan, resp, 1, 1200, 1200, "");
@@ -983,7 +1003,7 @@ int adsi_unload_session(struct ast_channel *chan)
bytes += adsi_voice_mode(dsp + bytes, 0);
/* Prepare key setup messages */
- if (adsi_transmit_message(chan, dsp, bytes, ADSI_MSG_DISPLAY))
+ if (adsi_transmit_message_full(chan, dsp, bytes, ADSI_MSG_DISPLAY, 0))
return -1;
return 0;
}
diff --git a/res/res_agi.c b/res/res_agi.c
index 04cf9eec5..830a11278 100755
--- a/res/res_agi.c
+++ b/res/res_agi.c
@@ -11,12 +11,12 @@
* the GNU General Public License
*/
+#include <sys/types.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
-#include <sys/types.h>
#include <asterisk/file.h>
#include <asterisk/logger.h>
#include <asterisk/channel.h>
@@ -119,7 +119,7 @@ static int launch_netscript(char *agiurl, char *argv[], int *fds, int *efd, int
struct pollfd pfds[1];
char *host;
char *c; int port = AGI_PORT;
- char *script;
+ char *script = "";
struct sockaddr_in sin;
struct hostent *hp;
struct ast_hostent ahp;
@@ -136,7 +136,7 @@ static int launch_netscript(char *agiurl, char *argv[], int *fds, int *efd, int
if ((c = strchr(host, ':'))) {
*c = '\0';
c++;
- port = atoi(c + 1);
+ port = atoi(c);
}
if (efd) {
ast_log(LOG_WARNING, "AGI URI's don't support Enhanced AGI yet\n");
@@ -185,6 +185,9 @@ static int launch_netscript(char *agiurl, char *argv[], int *fds, int *efd, int
return -1;
}
ast_log(LOG_DEBUG, "Wow, connected!\n");
+ /* Send the script parameter */
+ if (!ast_strlen_zero(script))
+ fdprintf(s, "agi_network_script: %s\n", script);
fds[0] = s;
fds[1] = s;
*opid = -1;
@@ -255,9 +258,11 @@ static int launch_script(char *script, char *argv[], int *fds, int *efd, int *op
} else {
close(STDERR_FILENO + 1);
}
+
/* Close everything but stdin/out/error */
for (x=STDERR_FILENO + 2;x<1024;x++)
close(x);
+
/* Execute script */
execv(script, argv);
/* Can't use ast_log since FD's are closed */
@@ -393,11 +398,11 @@ static int handle_tddmode(struct ast_channel *chan, AGI *agi, int argc, char *ar
if (!strncasecmp(argv[2],"mate",4)) x = 2;
if (!strncasecmp(argv[2],"tdd",3)) x = 1;
res = ast_channel_setoption(chan,AST_OPTION_TDD,&x,sizeof(char),0);
- fdprintf(agi->fd, "200 result=%d\n", res);
- if (res >= 0)
- return RESULT_SUCCESS;
+ if (res == RESULT_SUCCESS)
+ fdprintf(agi->fd, "200 result=1\n");
else
- return RESULT_FAILURE;
+ fdprintf(agi->fd, "200 result=0\n");
+ return RESULT_SUCCESS;
}
static int handle_sendimage(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
@@ -430,10 +435,9 @@ static int handle_streamfile(struct ast_channel *chan, AGI *agi, int argc, char
return RESULT_SHOWUSAGE;
fs = ast_openstream(chan, argv[2], chan->language);
- if(!fs){
+ if (!fs){
fdprintf(agi->fd, "200 result=%d endpos=%ld\n", 0, sample_offset);
- ast_log(LOG_WARNING, "Unable to open %s\n", argv[2]);
- return RESULT_FAILURE;
+ return RESULT_SUCCESS;
}
ast_seekstream(fs, 0, SEEK_END);
max_length = ast_tellstream(fs);
@@ -472,7 +476,7 @@ static int handle_saynumber(struct ast_channel *chan, AGI *agi, int argc, char *
int num;
if (argc != 4)
return RESULT_SHOWUSAGE;
- if (sscanf(argv[2], "%i", &num) != 1)
+ if (sscanf(argv[2], "%d", &num) != 1)
return RESULT_SHOWUSAGE;
res = ast_say_number_full(chan, num, argv[3], chan->language, (char *) NULL, agi->audio, agi->ctrl);
if (res == 1)
@@ -559,10 +563,7 @@ static int handle_getdata(struct ast_channel *chan, AGI *agi, int argc, char *ar
fdprintf(agi->fd, "200 result=-1\n");
else
fdprintf(agi->fd, "200 result=%s\n", data);
- if (res >= 0)
- return RESULT_SUCCESS;
- else
- return RESULT_FAILURE;
+ return RESULT_SUCCESS;
}
static int handle_setcontext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
diff --git a/res/res_config_odbc.c b/res/res_config_odbc.c
index 3f8490530..82e9e681b 100755
--- a/res/res_config_odbc.c
+++ b/res/res_config_odbc.c
@@ -44,7 +44,7 @@ static struct ast_config *config_odbc (char *file, struct ast_config *new_config
odbc_obj *obj;
SQLINTEGER err=0, commented=0, cat_metric=0, var_metric=0, last_cat_metric=0;
SQLBIGINT id;
- char sql[255] = "", filename[128], category[128], var_name[128], var_val[128];
+ char sql[255]="", filename[128]="", category[128]="", var_name[128]="", var_val[512]="";
SQLSMALLINT rowcount=0;
SQLHSTMT stmt;
char last[80] = "";
diff --git a/res/res_crypto.c b/res/res_crypto.c
index 912d7c8c0..16c879de1 100755
--- a/res/res_crypto.c
+++ b/res/res_crypto.c
@@ -174,6 +174,7 @@ static struct ast_key *try_load_key (char *dir, char *fname, int ifd, int ofd, i
while(!feof(f)) {
/* Calculate a "whatever" quality md5sum of the key */
char buf[256];
+ memset(buf, 0, 256);
fgets(buf, sizeof(buf), f);
if (!feof(f)) {
MD5Update(&md5, buf, strlen(buf));
@@ -441,7 +442,7 @@ int ast_check_signature(struct ast_key *key, char *msg, char *sig)
static void crypto_load(int ifd, int ofd)
{
struct ast_key *key, *nkey, *last;
- DIR *dir;
+ DIR *dir = NULL;
struct dirent *ent;
int note = 0;
/* Mark all keys for deletion */
diff --git a/res/res_features.c b/res/res_features.c
index b2fd1a866..753864d54 100755
--- a/res/res_features.c
+++ b/res/res_features.c
@@ -38,6 +38,15 @@
#include <sys/signal.h>
#include <netinet/in.h>
+#ifdef __AST_DEBUG_MALLOC
+static void FREE(void *ptr)
+{
+ free(ptr);
+}
+#else
+#define FREE free
+#endif
+
#define DEFAULT_PARK_TIME 45000
#define DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000
@@ -49,6 +58,9 @@ static int parkingtime = DEFAULT_PARK_TIME;
/* Context for which parking is made accessible */
static char parking_con[AST_MAX_EXTENSION] = "parkedcalls";
+/* Context for dialback for parking (KLUDGE) */
+static char parking_con_dial[AST_MAX_EXTENSION] = "park-dial";
+
/* Extension you type to park the call */
static char parking_ext[AST_MAX_EXTENSION] = "700";
@@ -103,6 +115,8 @@ struct parkeduser {
int priority;
int parkingtime;
int notquiteyet;
+ char peername[1024];
+ unsigned char moh_trys;
struct parkeduser *next;
};
@@ -152,6 +166,7 @@ int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeou
struct ast_context *con;
pu = malloc(sizeof(struct parkeduser));
if (pu) {
+ memset(pu,0,sizeof(struct parkeduser));
ast_mutex_lock(&parking_lock);
for (x=parking_start;x<=parking_stop;x++) {
cur = parkinglot;
@@ -179,6 +194,8 @@ int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeou
pu->parkingtime = parkingtime;
if (extout)
*extout = x;
+ if (peer)
+ strncpy(pu->peername, peer->name, sizeof(pu->peername) - 1);
/* Remember what had been dialed, so that if the parking
expires, we try to come back to the same place */
if (!ast_strlen_zero(chan->macrocontext))
@@ -223,12 +240,6 @@ int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeou
if (adsipark && adsi_available(peer)) {
adsi_unload_session(peer);
}
- if (pu->notquiteyet) {
- /* Wake up parking thread if we're really done */
- ast_moh_start(pu->chan, NULL);
- pu->notquiteyet = 0;
- pthread_kill(parking_thread, SIGURG);
- }
}
con = ast_context_find(parking_con);
if (!con) {
@@ -239,8 +250,15 @@ int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeou
}
if (con) {
snprintf(exten, sizeof(exten), "%d", x);
- ast_add_extension2(con, 1, exten, 1, NULL, parkedcall, strdup(exten), free, registrar);
+ ast_add_extension2(con, 1, exten, 1, NULL, parkedcall, strdup(exten), FREE, registrar);
}
+ if (pu->notquiteyet) {
+ /* Wake up parking thread if we're really done */
+ ast_moh_start(pu->chan, NULL);
+ pu->notquiteyet = 0;
+ pthread_kill(parking_thread, SIGURG);
+ }
+
return 0;
} else {
ast_log(LOG_WARNING, "No more parking spaces\n");
@@ -302,6 +320,12 @@ int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast
int allowdisconnect_in,allowdisconnect_out,allowredirect_in,allowredirect_out;
char *monitor_exec;
+ if (chan && peer) {
+ pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
+ pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
+ } else if (chan)
+ pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
+
if (monitor_ok) {
if (!monitor_app) {
if (!(monitor_app = pbx_findapp("Monitor")))
@@ -480,6 +504,8 @@ int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast
}
/* XXX Maybe we should have another message here instead of invalid extension XXX */
} else if (ast_exists_extension(transferee, transferer_real_context, newext, 1, transferer->callerid)) {
+ pbx_builtin_setvar_helper(peer, "BLINDTRANSFER", chan->name);
+ pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", peer->name);
ast_moh_stop(transferee);
res=ast_autoservice_stop(transferee);
if (!transferee->pbx) {
@@ -540,20 +566,21 @@ static void *do_parking_thread(void *ignore)
struct timeval tv;
struct ast_frame *f;
char exten[AST_MAX_EXTENSION];
+ char *peername,*cp;
+ char returnexten[AST_MAX_EXTENSION];
struct ast_context *con;
int x;
- int gc=0;
fd_set rfds, efds;
fd_set nrfds, nefds;
FD_ZERO(&rfds);
FD_ZERO(&efds);
+
for (;;) {
ms = -1;
max = -1;
ast_mutex_lock(&parking_lock);
pl = NULL;
pu = parkinglot;
- gettimeofday(&tv, NULL);
FD_ZERO(&nrfds);
FD_ZERO(&nefds);
while(pu) {
@@ -563,21 +590,42 @@ static void *do_parking_thread(void *ignore)
pu = pu->next;
continue;
}
- if (gc < 5 && !pu->chan->generator) {
- gc++;
- ast_moh_start(pu->chan,NULL);
- }
+ gettimeofday(&tv, NULL);
tms = (tv.tv_sec - pu->start.tv_sec) * 1000 + (tv.tv_usec - pu->start.tv_usec) / 1000;
if (tms > pu->parkingtime) {
- /* They've been waiting too long, send them back to where they came. Theoretically they
- should have their original extensions and such, but we copy to be on the safe side */
- strncpy(pu->chan->exten, pu->exten, sizeof(pu->chan->exten)-1);
- strncpy(pu->chan->context, pu->context, sizeof(pu->chan->context)-1);
- pu->chan->priority = pu->priority;
- if (option_verbose > 1)
- ast_verbose(VERBOSE_PREFIX_2 "Timeout for %s parked on %d. Returning to %s,%s,%d\n", pu->chan->name, pu->parkingnum, pu->chan->context, pu->chan->exten, pu->chan->priority);
/* Stop music on hold */
ast_moh_stop(pu->chan);
+ /* Get chan, exten from derived kludge */
+ if (pu->peername[0]) {
+ peername = ast_strdupa(pu->peername);
+ cp = strrchr(peername, '-');
+ if (cp)
+ *cp = 0;
+ con = ast_context_find(parking_con_dial);
+ if (!con) {
+ con = ast_context_create(NULL, parking_con_dial, registrar);
+ if (!con) {
+ ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial);
+ }
+ }
+ if (con) {
+ snprintf(returnexten, sizeof(returnexten), "%s||t", peername);
+ ast_add_extension2(con, 1, peername, 1, NULL, "Dial", strdup(returnexten), free, registrar);
+ }
+ strncpy(pu->chan->exten, peername, sizeof(pu->chan->exten) - 1);
+ strncpy(pu->chan->context, parking_con_dial, sizeof(pu->chan->context) - 1);
+ pu->chan->priority = 1;
+
+ } else {
+ /* They've been waiting too long, send them back to where they came. Theoretically they
+ should have their original extensions and such, but we copy to be on the safe side */
+ strncpy(pu->chan->exten, pu->exten, sizeof(pu->chan->exten)-1);
+ strncpy(pu->chan->context, pu->context, sizeof(pu->chan->context)-1);
+ pu->chan->priority = pu->priority;
+ }
+
+ if (option_verbose > 1)
+ ast_verbose(VERBOSE_PREFIX_2 "Timeout for %s parked on %d. Returning to %s,%s,%d\n", pu->chan->name, pu->parkingnum, pu->chan->context, pu->chan->exten, pu->chan->priority);
/* Start up the PBX, or hang them up */
if (ast_pbx_start(pu->chan)) {
ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", pu->chan->name);
@@ -599,14 +647,17 @@ static void *do_parking_thread(void *ignore)
ast_log(LOG_WARNING, "Whoa, no parking context?\n");
free(pt);
} else {
- for (x=0;x<AST_MAX_FDS;x++) {
+ for (x=0; x<AST_MAX_FDS; x++) {
if ((pu->chan->fds[x] > -1) && (FD_ISSET(pu->chan->fds[x], &rfds) || FD_ISSET(pu->chan->fds[x], &efds))) {
if (FD_ISSET(pu->chan->fds[x], &efds))
pu->chan->exception = 1;
+ else
+ pu->chan->exception = 0;
pu->chan->fdno = x;
/* See if they need servicing */
f = ast_read(pu->chan);
if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
+
/* There's a problem, hang them up*/
if (option_verbose > 1)
ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", pu->chan->name);
@@ -630,12 +681,17 @@ static void *do_parking_thread(void *ignore)
} else {
/* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
ast_frfree(f);
+ if (pu->moh_trys < 3 && !pu->chan->generatordata) {
+ ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source. Restarting.\n");
+ ast_moh_start(pu->chan, NULL);
+ pu->moh_trys++;
+ }
goto std; /* XXX Ick: jumping into an else statement??? XXX */
}
}
}
if (x >= AST_MAX_FDS) {
-std: for (x=0;x<AST_MAX_FDS;x++) {
+std: for (x=0; x<AST_MAX_FDS; x++) {
/* Keep this one for next one */
if (pu->chan->fds[x] > -1) {
FD_SET(pu->chan->fds[x], &nrfds);
@@ -784,7 +840,7 @@ static int park_exec(struct ast_channel *chan, void *data)
dres = 0;
}
if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to non-existant parked call %d\n", chan->name, park);
+ ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park);
res = -1;
}
LOCAL_USER_REMOVE(u);
@@ -926,7 +982,7 @@ int load_module(void)
return -1;
}
}
- ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, parkcall, strdup(""),free, registrar);
+ ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, parkcall, strdup(""), FREE, registrar);
ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
res = ast_register_application(parkedcall, park_exec, synopsis, descrip);
if (!res)
diff --git a/res/res_indications.c b/res/res_indications.c
index b289612d5..9dd696334 100755
--- a/res/res_indications.c
+++ b/res/res_indications.c
@@ -53,6 +53,14 @@ static char help_show_indications[] =
" Show either a condensed for of all country/indications, or the\n"
" indications for the specified countries.\n";
+char *playtones_desc=
+"PlayTones(<arg>): Plays a tone list. Execution will continue with the next step immediately,\n"
+"while the tones continue to play.\n"
+"Arg is either the tone name defined in the indications.conf configuration file, or a directly\n"
+"specified list of frequencies and durations.\n"
+"See the sample indications.conf for a description of the specification of a tonelist.\n\n"
+"Use the StopPlayTones application to stop the tones playing. \n";
+
/*
* Implementation of functions provided by this module
*/
@@ -367,11 +375,12 @@ int unload_module(void)
ast_cli_unregister(&add_indication_cli);
ast_cli_unregister(&remove_indication_cli);
ast_cli_unregister(&show_indications_cli);
- ast_unregister_application("Playlist");
- ast_unregister_application("StopPlaylist");
+ ast_unregister_application("PlayTones");
+ ast_unregister_application("StopPlayTones");
return 0;
}
+
int load_module(void)
{
if (ind_load_module()) return -1;
@@ -379,8 +388,8 @@ int load_module(void)
ast_cli_register(&add_indication_cli);
ast_cli_register(&remove_indication_cli);
ast_cli_register(&show_indications_cli);
- ast_register_application("Playtones", handle_playtones, "Play a tone list","Play a tone list, either registered (through indications.conf) or a direct list of tones and durations.");
- ast_register_application("StopPlaytones", handle_stopplaytones, "Stop playing a tone list","Stop playing a tone list");
+ ast_register_application("PlayTones", handle_playtones, "Play a tone list", playtones_desc);
+ ast_register_application("StopPlayTones", handle_stopplaytones, "Stop playing a tone list","Stop playing a tone list");
return 0;
}
diff --git a/res/res_monitor.c b/res/res_monitor.c
index c36460c5a..76f15b8ee 100755
--- a/res/res_monitor.c
+++ b/res/res_monitor.c
@@ -33,22 +33,24 @@ static char *monitor_descrip = "Monitor([file_format|[fname_base]|[options]]):\n
"Used to start monitoring a channel. The channel's input and output\n"
"voice packets are logged to files until the channel hangs up or\n"
"monitoring is stopped by the StopMonitor application.\n"
-" file_format -- optional, if not set, defaults to \"wav\"\n"
-" fname_base -- if set, changes the filename used to the one specified.\n"
-" options:\n"
-" 'm' - when the recording ends mix the two leg files into one and\n"
-" delete the two leg files. If MONITOR_EXEC is set, the\n"
-" application refernced in it will be executed instead of\n"
-" soxmix and the raw leg files will NOT be deleted automatically.\n"
-" soxmix or MONITOR_EXEC is handed 3 arguments, the two leg files\n"
-" and a target mixed file name which is the same as the leg file names\n"
-" only without the in/out designator.\n"
-" If MONITOR_EXEC_ARGS is set, the contents will be passed on as\n"
-" additional arguements to MONITOR_EXEC\n"
-" Both MONITOR_EXEC and the Mix flag can be set from the\n"
-" administrator interface\n\n"
+" file_format optional, if not set, defaults to \"wav\"\n"
+" fname_base if set, changes the filename used to the one specified.\n"
+" options:\n"
+" m - when the recording ends mix the two leg files into one and\n"
+" delete the two leg files. If the variable MONITOR_EXEC is set, the\n"
+" application referenced in it will be executed instead of\n"
+" soxmix and the raw leg files will NOT be deleted automatically.\n"
+" soxmix or MONITOR_EXEC is handed 3 arguments, the two leg files\n"
+" and a target mixed file name which is the same as the leg file names\n"
+" only without the in/out designator.\n"
+" If MONITOR_EXEC_ARGS is set, the contents will be passed on as\n"
+" additional arguements to MONITOR_EXEC\n"
+" Both MONITOR_EXEC and the Mix flag can be set from the\n"
+" administrator interface\n"
"\n"
-" 'b' - Don't begin recording unless a call is bridged to another channel\n"
+" b - Don't begin recording unless a call is bridged to another channel\n"
+"\nReturns -1 if monitor files can't be opened or if the channel is already\n"
+"monitored, otherwise 0.\n"
;
static char *stopmonitor_synopsis = "Stop monitoring a channel";
@@ -58,10 +60,9 @@ static char *stopmonitor_descrip = "StopMonitor\n"
static char *changemonitor_synopsis = "Change monitoring filename of a channel";
-static char *changemonitor_descrip = "ChangeMonitor\n"
+static char *changemonitor_descrip = "ChangeMonitor(filename_base)\n"
"Changes monitoring filename of a channel. Has no effect if the channel is not monitored\n"
- "The option string may contain the following:\n"
- " filename_base -- if set, changes the filename used to the one specified.\n";
+ "The argument is the new filename base to use for monitoring this channel.\n";
/* Start monitoring a channel */
int ast_monitor_start( struct ast_channel *chan, const char *format_spec,
@@ -90,6 +91,11 @@ int ast_monitor_start( struct ast_channel *chan, const char *format_spec,
}
monitor = malloc(sizeof(struct ast_channel_monitor));
+ if (!monitor) {
+ if (need_lock)
+ ast_mutex_unlock(&chan->lock);
+ return -1;
+ }
memset(monitor, 0, sizeof(struct ast_channel_monitor));
/* Determine file names */
@@ -98,9 +104,9 @@ int ast_monitor_start( struct ast_channel *chan, const char *format_spec,
/* try creating the directory just in case it doesn't exist */
if (directory) {
char *name = strdup(fname_base);
- snprintf(tmp, sizeof(tmp), "mkdir -p %s",dirname(name));
+ snprintf(tmp, sizeof(tmp), "mkdir -p \"%s\"",dirname(name));
free(name);
- system(tmp);
+ ast_safe_system(tmp);
}
snprintf(monitor->read_filename, FILENAME_MAX, "%s/%s-in",
directory ? "" : AST_MONITOR_DIR, fname_base);
@@ -238,9 +244,9 @@ int ast_monitor_stop(struct ast_channel *chan, int need_lock)
execute_args = "";
}
- snprintf(tmp, sizeof(tmp), "%s %s/%s-in.%s %s/%s-out.%s %s/%s.%s %s &", execute, dir, name, format, dir, name, format, dir, name, format,execute_args);
+ snprintf(tmp, sizeof(tmp), "%s \"%s/%s-in.%s\" \"%s/%s-out.%s\" \"%s/%s.%s\" %s &", execute, dir, name, format, dir, name, format, dir, name, format,execute_args);
if (delfiles) {
- snprintf(tmp2,sizeof(tmp2), "( %s& rm -f %s/%s-* ) &",tmp, dir ,name); /* remove legs when done mixing */
+ snprintf(tmp2,sizeof(tmp2), "( %s& rm -f \"%s/%s-\"* ) &",tmp, dir ,name); /* remove legs when done mixing */
strncpy(tmp, tmp2, sizeof(tmp) - 1);
}
ast_verbose("monitor executing %s\n",tmp);
@@ -281,12 +287,12 @@ int ast_monitor_change_fname(struct ast_channel *chan, const char *fname_base, i
char *name = strdup(fname_base);
snprintf(tmp, sizeof(tmp), "mkdir -p %s",dirname(name));
free(name);
- system(tmp);
+ ast_safe_system(tmp);
}
snprintf(chan->monitor->filename_base, FILENAME_MAX, "%s/%s", directory ? "" : AST_MONITOR_DIR, fname_base);
} else {
- ast_log(LOG_WARNING, "Cannot change monitor filename of channel %s to %s, monitoring not started", chan->name, fname_base);
+ ast_log(LOG_WARNING, "Cannot change monitor filename of channel %s to %s, monitoring not started\n", chan->name, fname_base);
}
if (need_lock)
@@ -362,6 +368,20 @@ static int change_monitor_exec(struct ast_channel *chan, void *data)
return ast_monitor_change_fname(chan, (const char*)data, 1);
}
+static char start_monitor_action_help[] =
+"Description: The 'Monitor' action may be used to record the audio on a\n"
+" specified channel. The following parameters may be used to control\n"
+" this:\n"
+" Channel - Required. Used to specify the channel to record.\n"
+" File - Optional. Is the name of the file created in the\n"
+" monitor spool directory. Defaults to the same name\n"
+" as the channel (with slashes replaced with dashes).\n"
+" Format - Optional. Is the audio recording format. Defaults\n"
+" to \"wav\".\n"
+" Mix - Optional. Boolean parameter as to whether to mix\n"
+" the input and output channels together after the\n"
+" recording is finished.\n";
+
static int start_monitor_action(struct mansession *s, struct message *m)
{
struct ast_channel *c = NULL;
@@ -391,6 +411,11 @@ static int start_monitor_action(struct mansession *s, struct message *m)
if ((!fname) || (ast_strlen_zero(fname))) {
// No filename base specified, default to channel name as per CLI
fname = malloc (FILENAME_MAX);
+ if (!fname) {
+ astman_send_error(s, m, "Could not start monitoring channel");
+ ast_mutex_unlock(&c->lock);
+ return 0;
+ }
memset(fname, 0, FILENAME_MAX);
strncpy(fname, c->name, FILENAME_MAX-1);
// Channels have the format technology/channel_name - have to replace that /
@@ -414,6 +439,11 @@ static int start_monitor_action(struct mansession *s, struct message *m)
return 0;
}
+static char stop_monitor_action_help[] =
+"Description: The 'StopMonitor' action may be used to end a previously\n"
+" started 'Monitor' action. The only parameter is 'Channel', the name\n"
+" of the channel monitored.\n";
+
static int stop_monitor_action(struct mansession *s, struct message *m)
{
struct ast_channel *c = NULL;
@@ -445,6 +475,14 @@ static int stop_monitor_action(struct mansession *s, struct message *m)
return 0;
}
+static char change_monitor_action_help[] =
+"Description: The 'ChangeMonitor' action may be used to change the file\n"
+" started by a previous 'Monitor' action. The following parameters may\n"
+" be used to control this:\n"
+" Channel - Required. Used to specify the channel to record.\n"
+" File - Required. Is the new name of the file created in the\n"
+" monitor spool directory.\n";
+
static int change_monitor_action(struct mansession *s, struct message *m)
{
struct ast_channel *c = NULL;
@@ -491,9 +529,9 @@ int load_module(void)
ast_register_application("Monitor", start_monitor_exec, monitor_synopsis, monitor_descrip);
ast_register_application("StopMonitor", stop_monitor_exec, stopmonitor_synopsis, stopmonitor_descrip);
ast_register_application("ChangeMonitor", change_monitor_exec, changemonitor_synopsis, changemonitor_descrip);
- ast_manager_register("Monitor", EVENT_FLAG_CALL, start_monitor_action, monitor_synopsis);
- ast_manager_register("StopMonitor", EVENT_FLAG_CALL, stop_monitor_action, stopmonitor_synopsis);
- ast_manager_register("ChangeMonitor", EVENT_FLAG_CALL, change_monitor_action, changemonitor_synopsis);
+ ast_manager_register2("Monitor", EVENT_FLAG_CALL, start_monitor_action, monitor_synopsis, start_monitor_action_help);
+ ast_manager_register2("StopMonitor", EVENT_FLAG_CALL, stop_monitor_action, stopmonitor_synopsis, stop_monitor_action_help);
+ ast_manager_register2("ChangeMonitor", EVENT_FLAG_CALL, change_monitor_action, changemonitor_synopsis, change_monitor_action_help);
return 0;
}
@@ -502,6 +540,10 @@ int unload_module(void)
{
ast_unregister_application("Monitor");
ast_unregister_application("StopMonitor");
+ ast_unregister_application("ChangeMonitor");
+ ast_manager_unregister("Monitor");
+ ast_manager_unregister("StopMonitor");
+ ast_manager_unregister("ChangeMonitor");
return 0;
}
diff --git a/res/res_musiconhold.c b/res/res_musiconhold.c
index 2dc39a5c6..b67805347 100755
--- a/res/res_musiconhold.c
+++ b/res/res_musiconhold.c
@@ -108,6 +108,21 @@ AST_MUTEX_DEFINE_STATIC(moh_lock);
#define MPG_123 "/usr/bin/mpg123"
#define MAX_MP3S 256
+
+static void ast_moh_free_class(struct mohclass **class)
+{
+ struct mohdata *members, *mtmp;
+
+ members = (*class)->members;
+ while(members) {
+ mtmp = members;
+ members = members->next;
+ free(mtmp);
+ }
+ free(*class);
+ *class = NULL;
+}
+
static int spawn_mp3(struct mohclass *class)
{
int fds[2];
@@ -224,8 +239,11 @@ static int spawn_mp3(struct mohclass *class)
/* Stdout goes to pipe */
dup2(fds[1], STDOUT_FILENO);
/* Close unused file descriptors */
- for (x=3;x<8192;x++)
- close(x);
+ for (x=3;x<8192;x++) {
+ if (-1 != fcntl(x, F_GETFL)) {
+ close(x);
+ }
+ }
/* Child */
chdir(class->dir);
if(class->custom) {
@@ -352,6 +370,7 @@ static int moh0_exec(struct ast_channel *chan, void *data)
return -1;
}
while(!ast_safe_sleep(chan, 10000));
+ ast_moh_stop(chan);
return -1;
}
@@ -363,7 +382,7 @@ static int moh1_exec(struct ast_channel *chan, void *data)
return -1;
}
if (ast_moh_start(chan, NULL)) {
- ast_log(LOG_WARNING, "Unable to start music on hold (class '%s') on channel %s\n", (char *)data, chan->name);
+ ast_log(LOG_WARNING, "Unable to start music on hold for %d seconds on channel %s\n", atoi((char *)data), chan->name);
return -1;
}
res = ast_safe_sleep(chan, atoi(data) * 1000);
@@ -570,12 +589,12 @@ static int moh_register(char *classname, char *mode, char *param, char *miscargs
ast_log(LOG_WARNING, "Unable to create moh...\n");
if (moh->pseudofd > -1)
close(moh->pseudofd);
- free(moh);
+ ast_moh_free_class(&moh);
return -1;
}
} else {
ast_log(LOG_WARNING, "Don't know how to do a mode '%s' music on hold\n", mode);
- free(moh);
+ ast_moh_free_class(&moh);
return -1;
}
ast_mutex_lock(&moh_lock);
diff --git a/res/res_odbc.c b/res/res_odbc.c
index c8efb0620..9c237ddd6 100755
--- a/res/res_odbc.c
+++ b/res/res_odbc.c
@@ -99,10 +99,12 @@ static int load_odbc_config(void)
if (!strcmp(cat, "ENV")) {
for (v = ast_variable_browse(config, cat); v; v = v->next) {
env_var = malloc(strlen(v->name) + strlen(v->value) + 2);
- sprintf(env_var, "%s=%s", v->name, v->value);
- ast_log(LOG_NOTICE, "Adding ENV var: %s=%s\n", v->name, v->value);
- putenv(env_var);
- free(env_var);
+ if (env_var) {
+ sprintf(env_var, "%s=%s", v->name, v->value);
+ ast_log(LOG_NOTICE, "Adding ENV var: %s=%s\n", v->name, v->value);
+ putenv(env_var);
+ free(env_var);
+ }
}
cat = ast_category_browse(config, cat);
@@ -145,39 +147,27 @@ static int load_odbc_config(void)
int odbc_dump_fd(int fd, odbc_obj * obj)
{
- ast_cli(fd, "\n\nName: %s\nDSN: %s\nConnected: %s\n\n", obj->name, obj->dsn, obj->up ? "yes" : "no");
+ ast_cli(fd, "Name: %s\nDSN: %s\nConnected: %s\n", obj->name, obj->dsn, obj->up ? "yes" : "no");
+ return 0;
+}
+
+static int odbc_connect_usage(int fd)
+{
+ ast_cli(fd, "usage odbc connect <DSN>\n");
return 0;
}
-static int odbc_usage(int fd)
+static int odbc_disconnect_usage(int fd)
{
- ast_cli(fd, "\n\nusage odbc <command> <arg1> .. <argn>\n\n");
+ ast_cli(fd, "usage odbc disconnect <DSN>\n");
return 0;
}
-static int odbc_command(int fd, int argc, char **argv)
+static int odbc_show_command(int fd, int argc, char **argv)
{
odbc_obj *obj;
int x = 0;
- if (!argv[1])
- return odbc_usage(fd);
-
- ast_cli(fd, "\n\n");
-
- if (!strcmp(argv[1], "connect") || !strcmp(argv[1], "disconnect")) {
- if (!argv[2])
- return odbc_usage(fd);
-
- obj = odbc_read(ODBC_REGISTRY, argv[2]);
- if (obj) {
- if (!strcmp(argv[1], "connect"))
- odbc_obj_connect(obj);
-
- if (!strcmp(argv[1], "disconnect"))
- odbc_obj_disconnect(obj);
- }
-
- } else if (!strcmp(argv[1], "show")) {
+ if (!strcmp(argv[1], "show")) {
if (!argv[2] || (argv[2] && !strcmp(argv[2], "all"))) {
for (x = 0; x < MAX_ODBC_HANDLES; x++) {
if (!ODBC_REGISTRY[x].used)
@@ -190,18 +180,62 @@ static int odbc_command(int fd, int argc, char **argv)
if (obj)
odbc_dump_fd(fd, obj);
}
+ }
+ return 0;
+}
- } else {
- return odbc_usage(fd);
+static int odbc_disconnect_command(int fd, int argc, char **argv){
+ odbc_obj *obj;
+ if (!strcmp(argv[1], "disconnect")) {
+ if (!argv[2])
+ return odbc_disconnect_usage(fd);
+
+ obj = odbc_read(ODBC_REGISTRY, argv[2]);
+ if (obj) {
+ odbc_obj_disconnect(obj);
+ }
}
- ast_cli(fd, "\n");
return 0;
}
-static struct ast_cli_entry odbc_command_struct = {
- {"odbc", NULL}, odbc_command,
- "Execute ODBC Command", "obdc <command> <arg1> .. <argn>", NULL
-};
+static int odbc_connect_command(int fd, int argc, char **argv){
+ odbc_obj *obj;
+ if (!argv[1])
+ return odbc_connect_usage(fd);
+
+ if (!strcmp(argv[1], "connect") || !strcmp(argv[1], "disconnect")) {
+ if (!argv[2])
+ return odbc_connect_usage(fd);
+
+ obj = odbc_read(ODBC_REGISTRY, argv[2]);
+ if (obj) {
+ odbc_obj_connect(obj);
+ }
+ }
+ return 0;
+}
+
+static char connect_usage[] =
+"Usage: odbc connect <DSN>\n"
+" Connect to ODBC DSN\n";
+
+static char disconnect_usage[] =
+"Usage: odbc connect <DSN>\n"
+" Disconnect from ODBC DSN\n";
+
+static char show_usage[] =
+"Usage: odbc show {DSN}\n"
+" Show ODBC {DSN}\n"
+" Specifying DSN will show that DSN else, all DSNs are shown\n";
+
+static struct ast_cli_entry odbc_connect_struct =
+ { { "odbc", "connect", NULL }, odbc_connect_command, "Connect to ODBC DSN", connect_usage };
+
+static struct ast_cli_entry odbc_disconnect_struct =
+ { { "odbc", "disconnect", NULL }, odbc_disconnect_command, "Disconnect from ODBC DSN", disconnect_usage };
+
+static struct ast_cli_entry odbc_show_struct =
+ { { "odbc", "show", NULL }, odbc_show_command, "Show ODBC DSN(s)", show_usage };
/* api calls */
@@ -222,6 +256,8 @@ odbc_obj *new_odbc_obj(char *name, char *dsn, char *username, char *password)
static odbc_obj *new;
new = malloc(sizeof(odbc_obj));
+ if (!new)
+ return NULL;
memset(new, 0, sizeof(odbc_obj));
new->env = SQL_NULL_HANDLE;
@@ -362,7 +398,9 @@ int unload_module(void)
{
STANDARD_HANGUP_LOCALUSERS;
odbc_destroy();
- ast_cli_unregister(&odbc_command_struct);
+ ast_cli_unregister(&odbc_disconnect_struct);
+ ast_cli_unregister(&odbc_connect_struct);
+ ast_cli_unregister(&odbc_show_struct);
ast_log(LOG_NOTICE, "res_odbc unloaded.\n");
return 0;
}
@@ -371,7 +409,9 @@ int load_module(void)
{
odbc_init();
load_odbc_config();
- ast_cli_register(&odbc_command_struct);
+ ast_cli_register(&odbc_disconnect_struct);
+ ast_cli_register(&odbc_connect_struct);
+ ast_cli_register(&odbc_show_struct);
ast_log(LOG_NOTICE, "res_odbc loaded.\n");
return 0;
}
diff --git a/res/res_osp.c b/res/res_osp.c
index 74a41afff..05b4be12f 100755
--- a/res/res_osp.c
+++ b/res/res_osp.c
@@ -496,6 +496,7 @@ int ast_osp_lookup(struct ast_channel *chan, char *provider, char *extension, ch
char source[OSP_MAX] = ""; /* Same length as osp->source */
char uniqueid[32] = "";
char callednum[2048]="";
+ char callingnum[2048]="";
char destination[2048]="";
char token[2000];
char tmp[256]="", *l, *n;
@@ -559,7 +560,8 @@ int ast_osp_lookup(struct ast_channel *chan, char *provider, char *extension, ch
tokenlen = sizeof(token);
result->numresults = counts - 1;
if (!OSPPTransactionGetFirstDestination(result->handle, 0, NULL, NULL, &timelimit, &callidlen, uniqueid,
- sizeof(callednum), callednum, sizeof(destination), destination, 0, NULL, &tokenlen, token)) {
+ sizeof(callednum), callednum, sizeof(callingnum), callingnum,
+ sizeof(destination), destination, 0, NULL, &tokenlen, token)) {
ast_log(LOG_DEBUG, "Got destination '%s' and '%s' for '%s' (provider '%s')\n",
destination, callednum, extension, provider);
do {
@@ -583,8 +585,10 @@ int ast_osp_lookup(struct ast_channel *chan, char *provider, char *extension, ch
}
if (!res && result->numresults) {
result->numresults--;
- if (OSPPTransactionGetNextDestination(result->handle, OSPC_FAIL_INCOMPATIBLE_DEST, 0, NULL, NULL, &timelimit, &callidlen, uniqueid,
- sizeof(callednum), callednum, sizeof(destination), destination, 0, NULL, &tokenlen, token)) {
+ if (OSPPTransactionGetNextDestination(result->handle, OSPC_FAIL_INCOMPATIBLE_DEST, 0,
+ NULL, NULL, &timelimit, &callidlen, uniqueid,
+ sizeof(callednum), callednum, sizeof(callingnum), callingnum,
+ sizeof(destination), destination, 0, NULL, &tokenlen, token)) {
break;
}
}
@@ -624,6 +628,7 @@ int ast_osp_next(struct ast_osp_result *result, int cause)
unsigned int callidlen;
char uniqueid[32] = "";
char callednum[2048]="";
+ char callingnum[2048]="";
char destination[2048]="";
char token[2000];
OSPE_DEST_PROT prot;
@@ -639,8 +644,10 @@ int ast_osp_next(struct ast_osp_result *result, int cause)
tokenlen = sizeof(token);
while(!res && result->numresults) {
result->numresults--;
- if (!OSPPTransactionGetNextDestination(result->handle, OSPC_FAIL_INCOMPATIBLE_DEST, 0, NULL, NULL, &timelimit, &callidlen, uniqueid,
- sizeof(callednum), callednum, sizeof(destination), destination, 0, NULL, &tokenlen, token)) {
+ if (!OSPPTransactionGetNextDestination(result->handle, OSPC_FAIL_INCOMPATIBLE_DEST, 0, NULL, NULL,
+ &timelimit, &callidlen, uniqueid,
+ sizeof(callednum), callednum, sizeof(callingnum), callingnum,
+ sizeof(destination), destination, 0, NULL, &tokenlen, token)) {
ast_base64encode(result->token, token, tokenlen, sizeof(result->token) - 1);
if ((strlen(destination) > 2) && !OSPPTransactionGetDestProtocol(result->handle, &prot)) {
res = 1;
@@ -700,10 +707,21 @@ int ast_osp_terminate(int handle, int cause, time_t start, time_t duration)
unsigned int dummy = 0;
int res = -1;
enum OSPEFAILREASON reason;
+
+ time_t endTime = 0;
+ time_t alertTime = 0;
+ time_t connectTime = 0;
+ unsigned isPddInfoPresent = 0;
+ unsigned pdd = 0;
+ unsigned releaseSource = 0;
+ unsigned char *confId = "";
+
reason = cause2reason(cause);
if (OSPPTransactionRecordFailure(handle, reason))
ast_log(LOG_WARNING, "Failed to record call termination for handle %d\n", handle);
- else if (OSPPTransactionReportUsage(handle, duration, start, 0, 0, 0, 0, &dummy, NULL))
+ else if (OSPPTransactionReportUsage(handle, duration, start,
+ endTime,alertTime,connectTime,isPddInfoPresent,pdd,releaseSource,confId,
+ 0, 0, 0, 0, &dummy, NULL))
ast_log(LOG_WARNING, "Failed to report duration for handle %d\n", handle);
else {
ast_log(LOG_DEBUG, "Completed recording handle %d\n", handle);
diff --git a/rtp.c b/rtp.c
index fff3deed0..c069b85bb 100755
--- a/rtp.c
+++ b/rtp.c
@@ -53,7 +53,7 @@ static int dtmftimeout = 3000; /* 3000 samples */
static int rtpstart = 0;
static int rtpend = 0;
#ifdef SO_NO_CHECK
-static int checksums = 1;
+static int nochecksums = 0;
#endif
/* The value of each payload format mapping: */
@@ -188,8 +188,13 @@ static struct ast_frame *send_dtmf(struct ast_rtp *rtp)
return &null_frame;
}
ast_log(LOG_DEBUG, "Sending dtmf: %d (%c), at %s\n", rtp->resp, rtp->resp, ast_inet_ntoa(iabuf, sizeof(iabuf), rtp->them.sin_addr));
- rtp->f.frametype = AST_FRAME_DTMF;
- rtp->f.subclass = rtp->resp;
+ if (rtp->resp == 'X') {
+ rtp->f.frametype = AST_FRAME_CONTROL;
+ rtp->f.subclass = AST_CONTROL_FLASH;
+ } else {
+ rtp->f.frametype = AST_FRAME_DTMF;
+ rtp->f.subclass = rtp->resp;
+ }
rtp->f.datalen = 0;
rtp->f.samples = 0;
rtp->f.mallocd = 0;
@@ -218,6 +223,8 @@ static struct ast_frame *process_cisco_dtmf(struct ast_rtp *rtp, unsigned char *
resp = '#';
} else if (event < 16) {
resp = 'A' + (event - 12);
+ } else if (event < 17) {
+ resp = 'X';
}
if (rtp->resp && (rtp->resp != resp)) {
f = send_dtmf(rtp);
@@ -252,6 +259,8 @@ static struct ast_frame *process_rfc2833(struct ast_rtp *rtp, unsigned char *dat
resp = '#';
} else if (event < 16) {
resp = 'A' + (event - 12);
+ } else if (event < 17) {
+ resp = 'X';
}
if (rtp->resp && (rtp->resp != resp)) {
f = send_dtmf(rtp);
@@ -333,7 +342,7 @@ struct ast_frame *ast_rtcp_read(struct ast_rtp *rtp)
unsigned int rtcpdata[1024];
char iabuf[INET_ADDRSTRLEN];
- if (!rtp->rtcp)
+ if (!rtp || !rtp->rtcp)
return &null_frame;
len = sizeof(sin);
@@ -342,9 +351,7 @@ struct ast_frame *ast_rtcp_read(struct ast_rtp *rtp)
0, (struct sockaddr *)&sin, &len);
if (res < 0) {
- if (errno == EAGAIN)
- ast_log(LOG_NOTICE, "RTP: Received packet with bad UDP checksum\n");
- else
+ if (errno != EAGAIN)
ast_log(LOG_WARNING, "RTP Read error: %s\n", strerror(errno));
if (errno == EBADF)
CRASH;
@@ -360,7 +367,7 @@ struct ast_frame *ast_rtcp_read(struct ast_rtp *rtp)
/* Send to whoever sent to us */
if ((rtp->rtcp->them.sin_addr.s_addr != sin.sin_addr.s_addr) ||
(rtp->rtcp->them.sin_port != sin.sin_port)) {
- memcpy(&rtp->them, &sin, sizeof(rtp->them));
+ memcpy(&rtp->rtcp->them, &sin, sizeof(rtp->rtcp->them));
ast_log(LOG_DEBUG, "RTP NAT: Using address %s:%d\n", ast_inet_ntoa(iabuf, sizeof(iabuf), rtp->rtcp->them.sin_addr), ntohs(rtp->rtcp->them.sin_port));
}
}
@@ -397,8 +404,10 @@ struct ast_frame *ast_rtp_read(struct ast_rtp *rtp)
struct sockaddr_in sin;
int len;
unsigned int seqno;
+ int version;
int payloadtype;
int hdrlen = 12;
+ int padding;
int mark;
int ext;
char iabuf[INET_ADDRSTRLEN];
@@ -416,9 +425,7 @@ struct ast_frame *ast_rtp_read(struct ast_rtp *rtp)
rtpheader = (unsigned int *)(rtp->rawdata + AST_FRIENDLY_OFFSET);
if (res < 0) {
- if (errno == EAGAIN)
- ast_log(LOG_NOTICE, "RTP: Received packet with bad UDP checksum\n");
- else
+ if (errno != EAGAIN)
ast_log(LOG_WARNING, "RTP Read error: %s\n", strerror(errno));
if (errno == EBADF)
CRASH;
@@ -445,11 +452,24 @@ struct ast_frame *ast_rtp_read(struct ast_rtp *rtp)
/* Get fields */
seqno = ntohl(rtpheader[0]);
+
+ /* Check RTP version */
+ version = (seqno & 0xC0000000) >> 30;
+ if (version != 2)
+ return &null_frame;
+
payloadtype = (seqno & 0x7f0000) >> 16;
+ padding = seqno & (1 << 29);
mark = seqno & (1 << 23);
ext = seqno & (1 << 28);
seqno &= 0xffff;
timestamp = ntohl(rtpheader[1]);
+
+ if (padding) {
+ /* Remove padding bytes */
+ res -= rtp->rawdata[AST_FRIENDLY_OFFSET + res - 1];
+ }
+
if (ext) {
/* RTP Extension present */
hdrlen += 4;
@@ -469,17 +489,17 @@ struct ast_frame *ast_rtp_read(struct ast_rtp *rtp)
/* This is special in-band data that's not one of our codecs */
if (rtpPT.code == AST_RTP_DTMF) {
/* It's special -- rfc2833 process it */
- if (rtp->lasteventseqn <= seqno) {
+ if (rtp->lasteventseqn <= seqno || rtp->resp == 0 || (rtp->lasteventseqn >= 65530 && seqno <= 6)) {
f = process_rfc2833(rtp, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen);
rtp->lasteventseqn = seqno;
- }
+ } else f = NULL;
if (f) return f; else return &null_frame;
} else if (rtpPT.code == AST_RTP_CISCO_DTMF) {
/* It's really special -- process it the Cisco way */
- if (rtp->lasteventseqn <= seqno) {
+ if (rtp->lasteventseqn <= seqno || rtp->resp == 0 || (rtp->lasteventseqn >= 65530 && seqno <= 6)) {
f = process_cisco_dtmf(rtp, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen);
rtp->lasteventseqn = seqno;
- }
+ } else f = NULL;
if (f) return f; else return &null_frame;
} else if (rtpPT.code == AST_RTP_CN) {
/* Comfort Noise */
@@ -531,6 +551,7 @@ struct ast_frame *ast_rtp_read(struct ast_rtp *rtp)
break;
case AST_FORMAT_SLINEAR:
rtp->f.samples = rtp->f.datalen / 2;
+ ast_frame_byteswap_be(&rtp->f);
break;
case AST_FORMAT_GSM:
rtp->f.samples = 160 * (rtp->f.datalen / 33);
@@ -609,7 +630,9 @@ static struct {
table for transmission */
static struct rtpPayloadType static_RTP_PT[MAX_RTP_PT] = {
[0] = {1, AST_FORMAT_ULAW},
+#ifdef USE_DEPRECATED_G726
[2] = {1, AST_FORMAT_G726}, /* Technically this is G.721, but if Cisco can do it, so can we... */
+#endif
[3] = {1, AST_FORMAT_GSM},
[4] = {1, AST_FORMAT_G723_1},
[5] = {1, AST_FORMAT_ADPCM}, /* 8 kHz */
@@ -629,6 +652,7 @@ static struct rtpPayloadType static_RTP_PT[MAX_RTP_PT] = {
[97] = {1, AST_FORMAT_ILBC},
[101] = {0, AST_RTP_DTMF},
[110] = {1, AST_FORMAT_SPEEX},
+ [111] = {1, AST_FORMAT_G726},
[121] = {0, AST_RTP_CISCO_DTMF}, /* Must be type 121 */
};
@@ -729,7 +753,7 @@ struct rtpPayloadType ast_rtp_lookup_pt(struct ast_rtp* rtp, int pt)
}
/* Looks up an RTP code out of our *static* outbound list */
-int ast_rtp_lookup_code(struct ast_rtp* rtp, int isAstFormat, int code) {
+int ast_rtp_lookup_code(struct ast_rtp* rtp, const int isAstFormat, const int code) {
int pt;
@@ -763,7 +787,7 @@ int ast_rtp_lookup_code(struct ast_rtp* rtp, int isAstFormat, int code) {
return -1;
}
-char* ast_rtp_lookup_mime_subtype(int isAstFormat, int code) {
+char* ast_rtp_lookup_mime_subtype(const int isAstFormat, const int code) {
int i;
for (i = 0; i < sizeof mimeTypes/sizeof mimeTypes[0]; ++i) {
@@ -775,6 +799,41 @@ char* ast_rtp_lookup_mime_subtype(int isAstFormat, int code) {
return "";
}
+char *ast_rtp_lookup_mime_multiple(char *buf, int size, const int capability, const int isAstFormat)
+{
+ int format;
+ unsigned len;
+ char *end = buf;
+ char *start = buf;
+
+ if (!buf || !size)
+ return NULL;
+
+ snprintf(end, size, "0x%x (", capability);
+
+ len = strlen(end);
+ end += len;
+ size -= len;
+ start = end;
+
+ for (format = 1; format < AST_RTP_MAX; format <<= 1) {
+ if (capability & format) {
+ const char *name = ast_rtp_lookup_mime_subtype(isAstFormat, format);
+ snprintf(end, size, "%s|", name);
+ len = strlen(end);
+ end += len;
+ size -= len;
+ }
+ }
+
+ if (start == end)
+ snprintf(start, size, "nothing)");
+ else if (size > 1)
+ *(end -1) = ')';
+
+ return buf;
+ }
+
static int rtp_socket(void)
{
int s;
@@ -784,9 +843,8 @@ static int rtp_socket(void)
flags = fcntl(s, F_GETFL);
fcntl(s, F_SETFL, flags | O_NONBLOCK);
#ifdef SO_NO_CHECK
- if (checksums) {
- setsockopt(s, SOL_SOCKET, SO_NO_CHECK, &checksums, sizeof(checksums));
- }
+ if (nochecksums)
+ setsockopt(s, SOL_SOCKET, SO_NO_CHECK, &nochecksums, sizeof(nochecksums));
#endif
}
return s;
@@ -978,7 +1036,6 @@ int ast_rtp_senddigit(struct ast_rtp *rtp, char digit)
unsigned int *rtpheader;
int hdrlen = 12;
int res;
- int ms;
int x;
int payload;
char data[256];
@@ -1010,10 +1067,6 @@ int ast_rtp_senddigit(struct ast_rtp *rtp, char digit)
rtp->dtmfmute.tv_usec -= 1000000;
rtp->dtmfmute.tv_sec += 1;
}
-
- ms = calc_txstamp(rtp, NULL);
- /* Default prediction */
- rtp->lastts = rtp->lastts + ms * 8;
/* Get a pointer to the header */
rtpheader = (unsigned int *)data;
@@ -1021,7 +1074,7 @@ int ast_rtp_senddigit(struct ast_rtp *rtp, char digit)
rtpheader[1] = htonl(rtp->lastts);
rtpheader[2] = htonl(rtp->ssrc);
rtpheader[3] = htonl((digit << 24) | (0xa << 16) | (0));
- for (x=0;x<4;x++) {
+ for (x=0;x<6;x++) {
if (rtp->them.sin_port && rtp->them.sin_addr.s_addr) {
res = sendto(rtp->s, (void *)rtpheader, hdrlen + 4, 0, (struct sockaddr *)&rtp->them, sizeof(rtp->them));
if (res <0)
@@ -1030,13 +1083,15 @@ int ast_rtp_senddigit(struct ast_rtp *rtp, char digit)
printf("Sent %d bytes of RTP data to %s:%d\n", res, ast_inet_ntoa(iabuf, sizeof(iabuf), rtp->them.sin_addr), ntohs(rtp->them.sin_port));
#endif
}
- if (x ==0) {
+ if (x == 2) {
/* Clear marker bit and increment seqno */
rtpheader[0] = htonl((2 << 30) | (payload << 16) | (rtp->seqno++));
/* Make duration 800 (100ms) */
rtpheader[3] |= htonl((800));
/* Set the End bit for the last 3 */
rtpheader[3] |= htonl((1 << 23));
+ } else if ( x < 5) {
+ rtpheader[0] = htonl((2 << 30) | (payload << 16) | (rtp->seqno++));
}
}
return 0;
@@ -1181,6 +1236,19 @@ int ast_rtp_write(struct ast_rtp *rtp, struct ast_frame *_f)
switch(subclass) {
+ case AST_FORMAT_SLINEAR:
+ if (!rtp->smoother) {
+ rtp->smoother = ast_smoother_new(320);
+ }
+ if (!rtp->smoother) {
+ ast_log(LOG_WARNING, "Unable to create smoother :(\n");
+ return -1;
+ }
+ ast_smoother_feed_be(rtp->smoother, _f);
+
+ while((f = ast_smoother_read(rtp->smoother)))
+ ast_rtp_raw_write(rtp, f, codec);
+ break;
case AST_FORMAT_ULAW:
case AST_FORMAT_ALAW:
if (!rtp->smoother) {
@@ -1524,9 +1592,6 @@ void ast_rtp_reload(void)
char *s;
rtpstart = 5000;
rtpend = 31000;
-#ifdef SO_NO_CHECK
- checksums = 1;
-#endif
cfg = ast_load("rtp.conf");
if (cfg) {
if ((s = ast_variable_retrieve(cfg, "general", "rtpstart"))) {
@@ -1545,12 +1610,12 @@ void ast_rtp_reload(void)
}
if ((s = ast_variable_retrieve(cfg, "general", "rtpchecksums"))) {
#ifdef SO_NO_CHECK
- if (ast_true(s))
- checksums = 1;
+ if (ast_false(s))
+ nochecksums = 1;
else
- checksums = 0;
+ nochecksums = 0;
#else
- if (ast_true(s))
+ if (ast_false(s))
ast_log(LOG_WARNING, "Disabling RTP checksums is not supported on this operating system!\n");
#endif
}
diff --git a/say.c b/say.c
index 879c56da8..cc1406b60 100755
--- a/say.c
+++ b/say.c
@@ -47,6 +47,9 @@ int ast_say_digit_str(struct ast_channel *chan, char *fn2, char *ints, char *lan
case ('#'):
snprintf(fn, sizeof(fn), "digits/pound");
break;
+ case ('-'):
+ snprintf(fn, sizeof(fn), "digits/minus");
+ break;
default:
if((fn2[num] >= '0') && (fn2[num] <= '9')){ /* Must be in {0-9} */
snprintf(fn, sizeof(fn), "digits/%c", fn2[num]);
@@ -165,31 +168,31 @@ int ast_say_phonetic_str(struct ast_channel *chan, char *fn2, char *ints, char *
snprintf(fn, sizeof(fn), "digits/%c", fn2[num]);
break;
case ('!'):
- strncpy(fn, "exclaimation-point", sizeof(fn));
- break;
+ strncpy(fn, "letters/exclaimation-point", sizeof(fn));
+ break;
case ('@'):
- strncpy(fn, "at", sizeof(fn));
+ strncpy(fn, "letters/at", sizeof(fn));
break;
case ('$'):
- strncpy(fn, "dollar", sizeof(fn));
+ strncpy(fn, "letters/dollar", sizeof(fn));
break;
case ('-'):
- strncpy(fn, "dash", sizeof(fn));
+ strncpy(fn, "letters/dash", sizeof(fn));
break;
case ('.'):
- strncpy(fn, "dot", sizeof(fn));
+ strncpy(fn, "letters/dot", sizeof(fn));
break;
case ('='):
- strncpy(fn, "equals", sizeof(fn));
+ strncpy(fn, "letters/equals", sizeof(fn));
break;
case ('+'):
- strncpy(fn, "plus", sizeof(fn));
+ strncpy(fn, "letters/plus", sizeof(fn));
break;
case ('/'):
- strncpy(fn, "slash", sizeof(fn));
+ strncpy(fn, "letters/slash", sizeof(fn));
break;
case (' '):
- strncpy(fn, "space", sizeof(fn));
+ strncpy(fn, "letters/space", sizeof(fn));
break;
case ('%'):
play=0;
@@ -278,31 +281,31 @@ int ast_say_character_str_full(struct ast_channel *chan, char *fn2, char *ints,
snprintf(fn, sizeof(fn), "digits/%c", fn2[num]);
break;
case ('!'):
- strncpy(fn, "exclaimation-point", sizeof(fn));
- break;
+ strncpy(fn, "letters/exclaimation-point", sizeof(fn));
+ break;
case ('@'):
- strncpy(fn, "at", sizeof(fn));
+ strncpy(fn, "letters/at", sizeof(fn));
break;
case ('$'):
- strncpy(fn, "dollar", sizeof(fn));
+ strncpy(fn, "letters/dollar", sizeof(fn));
break;
case ('-'):
- strncpy(fn, "dash", sizeof(fn));
+ strncpy(fn, "letters/dash", sizeof(fn));
break;
case ('.'):
- strncpy(fn, "dot", sizeof(fn));
+ strncpy(fn, "letters/dot", sizeof(fn));
break;
case ('='):
- strncpy(fn, "equals", sizeof(fn));
+ strncpy(fn, "letters/equals", sizeof(fn));
break;
case ('+'):
- strncpy(fn, "plus", sizeof(fn));
+ strncpy(fn, "letters/plus", sizeof(fn));
break;
case ('/'):
- strncpy(fn, "slash", sizeof(fn));
+ strncpy(fn, "letters/slash", sizeof(fn));
break;
case (' '):
- strncpy(fn, "space", sizeof(fn));
+ strncpy(fn, "letters/space", sizeof(fn));
break;
default:
ltr = fn2[num];
@@ -345,36 +348,36 @@ int ast_say_phonetic_str_full(struct ast_channel *chan, char *fn2, char *ints, c
snprintf(fn, sizeof(fn), "digits/%c", fn2[num]);
break;
case ('!'):
- strncpy(fn, "exclaimation-point", sizeof(fn));
- break;
+ strncpy(fn, "letters/exclaimation-point", sizeof(fn));
+ break;
case ('@'):
- strncpy(fn, "at", sizeof(fn));
+ strncpy(fn, "letters/at", sizeof(fn));
break;
case ('$'):
- strncpy(fn, "dollar", sizeof(fn));
+ strncpy(fn, "letters/dollar", sizeof(fn));
break;
case ('-'):
- strncpy(fn, "dash", sizeof(fn));
+ strncpy(fn, "letters/dash", sizeof(fn));
break;
case ('.'):
- strncpy(fn, "dot", sizeof(fn));
+ strncpy(fn, "letters/dot", sizeof(fn));
break;
case ('='):
- strncpy(fn, "equals", sizeof(fn));
+ strncpy(fn, "letters/equals", sizeof(fn));
break;
case ('+'):
- strncpy(fn, "plus", sizeof(fn));
+ strncpy(fn, "letters/plus", sizeof(fn));
break;
case ('/'):
- strncpy(fn, "slash", sizeof(fn));
+ strncpy(fn, "letters/slash", sizeof(fn));
break;
case (' '):
- strncpy(fn, "space", sizeof(fn));
+ strncpy(fn, "letters/space", sizeof(fn));
break;
default: /* '9' falls here... */
ltr = fn2[num];
if ('A' <= ltr && ltr <= 'Z') ltr += 'a' - 'A'; /* file names are all lower-case */
- snprintf(fn, sizeof(fn), "phonetic/%c", ltr);
+ snprintf(fn, sizeof(fn), "phonetic/%c_p", ltr);
}
/* snprintf(fn, sizeof(fn), "digits/%c", fn2[num]); */
res = ast_streamfile(chan, fn, lang);
@@ -579,7 +582,7 @@ static int ast_say_number_full_en(struct ast_channel *chan, int num, char *ints,
}
if (!res) {
if(!ast_streamfile(chan, fn, language)) {
- if (audiofd && ctrlfd)
+ if ((audiofd > -1) && (ctrlfd > -1))
res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
else
res = ast_waitstream(chan, ints);
@@ -682,7 +685,7 @@ static int ast_say_number_full_da(struct ast_channel *chan, int num, char *ints,
}
if (!res) {
if(!ast_streamfile(chan, fn, language)) {
- if (audiofd && ctrlfd)
+ if ((audiofd > -1) && (ctrlfd > -1))
res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
else
res = ast_waitstream(chan, ints);
@@ -791,14 +794,14 @@ static int ast_say_number_full_de(struct ast_channel *chan, int num, char *ints,
}
if (!res) {
if(!ast_streamfile(chan, fn, language)) {
- if (audiofd && ctrlfd)
+ if ((audiofd > -1) && (ctrlfd > -1))
res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
else
res = ast_waitstream(chan, ints);
}
ast_stopstream(chan);
if(!ast_streamfile(chan, fna, language)) {
- if (audiofd && ctrlfd)
+ if ((audiofd > -1) && (ctrlfd > -1))
res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
else
res = ast_waitstream(chan, ints);
@@ -881,7 +884,7 @@ static int ast_say_number_full_es(struct ast_channel *chan, int num, char *ints,
if (!res) {
if(!ast_streamfile(chan, fn, language)) {
- if (audiofd && ctrlfd)
+ if ((audiofd > -1) && (ctrlfd > -1))
res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
else
res = ast_waitstream(chan, ints);
@@ -967,7 +970,7 @@ static int ast_say_number_full_fr(struct ast_channel *chan, int num, char *ints,
}
if (!res) {
if(!ast_streamfile(chan, fn, language)) {
- if (audiofd && ctrlfd)
+ if ((audiofd > -1) && (ctrlfd > -1))
res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
else
res = ast_waitstream(chan, ints);
@@ -1113,7 +1116,7 @@ static int ast_say_number_full_it(struct ast_channel *chan, int num, char *ints,
}
if (!res) {
if(!ast_streamfile(chan, fn, language)) {
- if (audiofd && ctrlfd)
+ if ((audiofd > -1) && (ctrlfd > -1))
res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
else
res = ast_waitstream(chan, ints);
@@ -1183,7 +1186,7 @@ static int ast_say_number_full_nl(struct ast_channel *chan, int num, char *ints,
if (!res) {
if(!ast_streamfile(chan, fn, language)) {
- if (audiofd && ctrlfd)
+ if ((audiofd > -1) && (ctrlfd > -1))
res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
else
res = ast_waitstream(chan, ints);
@@ -1238,7 +1241,7 @@ static void pl_odtworz_plik(struct ast_channel *chan, char *language, int audiof
strcat(file_name, fn);
ast_log(LOG_DEBUG, "Trying to play: %s\n", file_name);
if (!ast_streamfile(chan, file_name, language)) {
- if (audiofd && ctrlfd)
+ if ((audiofd > -1) && (ctrlfd > -1))
ast_waitstream_full(chan, ints, audiofd, ctrlfd);
else
ast_waitstream(chan, ints);
@@ -1566,19 +1569,19 @@ static int ast_say_number_full_pt(struct ast_channel *chan, int num, char *ints,
playh = 1;
num = num % 1000000;
}
- if (!res && playh) {
- res = wait_file(chan, ints, "digits/pt-e", language);
- ast_stopstream(chan);
- playh = 0;
- }
if (!res) {
if(!ast_streamfile(chan, fn, language)) {
- if (audiofd && ctrlfd)
+ if ((audiofd > -1) && (ctrlfd > -1))
res = ast_waitstream_full(chan, ints, audiofd, ctrlfd); else
res = ast_waitstream(chan, ints);
}
ast_stopstream(chan);
}
+ if (!res && playh) {
+ res = wait_file(chan, ints, "digits/pt-e", language);
+ ast_stopstream(chan);
+ playh = 0;
+ }
}
return res;
}
@@ -1638,7 +1641,7 @@ static int ast_say_number_full_se(struct ast_channel *chan, int num, char *ints,
}
if (!res) {
if(!ast_streamfile(chan, fn, language)) {
- if (audiofd && ctrlfd)
+ if ((audiofd > -1) && (ctrlfd > -1))
res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
else
res = ast_waitstream(chan, ints);
@@ -1699,7 +1702,7 @@ static int ast_say_number_full_tw(struct ast_channel *chan, int num, char *ints,
}
if (!res) {
if(!ast_streamfile(chan, fn, language)) {
- if (audiofd && ctrlfd)
+ if ((audiofd > -1) && (ctrlfd > -1))
res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
else
res = ast_waitstream(chan, ints);
@@ -1808,7 +1811,7 @@ static int ast_say_number_full_cz(struct ast_channel *chan, int num, char *ints,
}
if (!res) {
if(!ast_streamfile(chan, fn, language)) {
- if (audiofd && ctrlfd) {
+ if ((audiofd > -1) && (ctrlfd > -1)) {
res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
} else {
res = ast_waitstream(chan, ints);
@@ -1987,7 +1990,7 @@ int ast_say_date_with_format_en(struct ast_channel *chan, time_t time, char *int
/* Between 21 and 29 - two sounds */
res = wait_file(chan,ints, "digits/20",lang);
if (!res) {
- snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_mday - 20);
+ snprintf(nextmsg,sizeof(nextmsg), "digits/h-%d", tm.tm_mday - 20);
res = wait_file(chan,ints,nextmsg,lang);
}
}
@@ -2976,20 +2979,7 @@ int ast_say_date_with_format_pt(struct ast_channel *chan, time_t time, char *int
case 'H':
case 'k':
/* 24-Hour */
- res = ast_say_number(chan, -tm.tm_hour, ints, lang, NULL);
- if (!res) {
- if (tm.tm_hour != 0) {
- int remainder = tm.tm_hour;
- if (tm.tm_hour > 20) {
- res = wait_file(chan,ints, "digits/20",lang);
- remainder -= 20;
- }
- if (!res) {
- snprintf(nextmsg,sizeof(nextmsg), "digits/%d", remainder);
- res = wait_file(chan,ints,nextmsg,lang);
- }
- }
- }
+ res = ast_say_number(chan, tm.tm_hour, ints, lang, NULL);
break;
case 'M':
/* Minute */
diff --git a/sched.c b/sched.c
index 786a26be6..e8c2238d8 100755
--- a/sched.c
+++ b/sched.c
@@ -287,7 +287,7 @@ int ast_sched_del(struct sched_context *con, int id)
}
ast_mutex_unlock(&con->lock);
if (!s) {
- ast_log(LOG_NOTICE, "Attempted to delete non-existant schedule entry %d!\n", id);
+ ast_log(LOG_NOTICE, "Attempted to delete nonexistent schedule entry %d!\n", id);
#ifdef DO_CRASH
CRASH;
#endif
@@ -399,3 +399,28 @@ int ast_sched_runq(struct sched_context *con)
ast_mutex_unlock(&con->lock);
return x;
}
+
+long ast_sched_when(struct sched_context *con,int id)
+{
+ struct sched *s;
+ long secs;
+ struct timeval now;
+ DEBUG(ast_log(LOG_DEBUG, "ast_sched_when()\n"));
+
+ ast_mutex_lock(&con->lock);
+ s=con->schedq;
+ while (s!=NULL) {
+ if (s->id==id) break;
+ s=s->next;
+ }
+ secs=-1;
+ if (s!=NULL) {
+ if (gettimeofday(&now, NULL)) {
+ ast_log(LOG_NOTICE, "gettimeofday() failed!\n");
+ } else {
+ secs=s->when.tv_sec-now.tv_sec;
+ }
+ }
+ ast_mutex_unlock(&con->lock);
+ return secs;
+}
diff --git a/sounds.txt b/sounds.txt
index 579792026..0b438abdd 100755
--- a/sounds.txt
+++ b/sounds.txt
@@ -70,6 +70,8 @@
%dir-nomore.gsm%There are no more compatible entries in the directory.
+%hello-world.gsm%Hello World.
+
%invalid.gsm%I am sorry, that's not a valid extension. Please try again.
%pbx-invalid.gsm%I am sorry, that's not a valid extension. Please try again.
@@ -248,6 +250,8 @@
;digits directory - File Name Sound File Script
+%minus.gsm%minus
+
%0.gsm%zero
%1.gsm%one
@@ -447,6 +451,8 @@
%vm-advopts.gsm%press 3 for advanced options
+%vm-saveoper.gsm%press 1 to accept this recording, or continue to hold
+
%vm-toreply.gsm%press 1 to send a reply
%vm-tocallback.gsm%press 2 to call the person who sent this message
diff --git a/sounds/digits/minus.gsm b/sounds/digits/minus.gsm
new file mode 100755
index 000000000..c413e1a1f
--- /dev/null
+++ b/sounds/digits/minus.gsm
Binary files differ
diff --git a/sounds/hello-world.gsm b/sounds/hello-world.gsm
new file mode 100755
index 000000000..b437ad872
--- /dev/null
+++ b/sounds/hello-world.gsm
Binary files differ
diff --git a/sounds/vm-saveoper.gsm b/sounds/vm-saveoper.gsm
new file mode 100755
index 000000000..1fa92a22a
--- /dev/null
+++ b/sounds/vm-saveoper.gsm
Binary files differ
diff --git a/stdtime/localtime.c b/stdtime/localtime.c
index 1f6309e3f..7c474acf1 100755
--- a/stdtime/localtime.c
+++ b/stdtime/localtime.c
@@ -89,7 +89,9 @@ static const char elsieid[] = "@(#)localtime.c 7.57";
static char wildabbr[] = "WILDABBR";
-static const char gmt[] = "GMT";
+/* FreeBSD defines 'zone' in 'struct tm' as non-const, so don't declare this
+ string as const. */
+static char gmt[] = "GMT";
struct ttinfo { /* time type information */
long tt_gmtoff; /* GMT offset in seconds */
diff --git a/tdd.c b/tdd.c
index 6ff6c0fbd..e2a6cc839 100755
--- a/tdd.c
+++ b/tdd.c
@@ -77,8 +77,8 @@ struct tdd_state *tdd_new(void)
{
struct tdd_state *tdd;
tdd = malloc(sizeof(struct tdd_state));
- memset(tdd, 0, sizeof(struct tdd_state));
if (tdd) {
+ memset(tdd, 0, sizeof(struct tdd_state));
tdd->fskd.spb = 176; /* 45.5 baud */
tdd->fskd.hdlc = 0; /* Async */
tdd->fskd.nbit = 5; /* 5 bits */
diff --git a/utils.c b/utils.c
index 2557c3180..90fb14ffb 100755
--- a/utils.c
+++ b/utils.c
@@ -399,7 +399,7 @@ char *ast_strcasestr(const char *haystack, const char *needle)
offset = strstr(upper(haystack, u1, u1len), upper(needle, u2, u2len));
if (offset) {
/* Return the offset into the original string */
- return ((char *)((unsigned int)haystack + (unsigned int)(offset - u1)));
+ return ((char *)((unsigned long)haystack + (unsigned long)(offset - u1)));
} else {
return NULL;
}
diff --git a/utils/astman.c b/utils/astman.c
deleted file mode 100755
index ebeeb67f1..000000000
--- a/utils/astman.c
+++ /dev/null
@@ -1,683 +0,0 @@
-/*
- * ASTerisk MANager
- * Copyright (C) 2002, Linux Support Services, Inc.
- *
- * Distributed under the terms of the GNU General Public License
- */
-
-#include <newt.h>
-#include <stdio.h>
-#include <sys/time.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <sys/socket.h>
-#include <sys/select.h>
-#include <fcntl.h>
-#include <string.h>
-#include <stdio.h>
-#include <errno.h>
-#include <unistd.h>
-#include <stdlib.h>
-
-#include <asterisk/md5.h>
-#include <asterisk/manager.h>
-
-#undef gethostbyname
-
-#define MAX_HEADERS 80
-#define MAX_LEN 256
-
-static struct ast_mansession {
- struct sockaddr_in sin;
- int fd;
- char inbuf[MAX_LEN];
- int inlen;
-} session;
-
-static struct ast_chan {
- char name[80];
- char exten[20];
- char context[20];
- char priority[20];
- char callerid[40];
- char state[10];
- struct ast_chan *next;
-} *chans;
-
-static struct ast_chan *find_chan(char *name)
-{
- struct ast_chan *prev = NULL, *chan = chans;
- while(chan) {
- if (!strcmp(name, chan->name))
- return chan;
- prev = chan;
- chan = chan->next;
- }
- chan = malloc(sizeof(struct ast_chan));
- if (chan) {
- memset(chan, 0, sizeof(struct ast_chan));
- strncpy(chan->name, name, sizeof(chan->name) - 1);
- if (prev)
- prev->next = chan;
- else
- chans = chan;
- }
- return chan;
-}
-
-static void del_chan(char *name)
-{
- struct ast_chan *prev = NULL, *chan = chans;
- while(chan) {
- if (!strcmp(name, chan->name)) {
- if (prev)
- prev->next = chan->next;
- else
- chans = chan->next;
- return;
- }
- prev = chan;
- chan = chan->next;
- }
-}
-
-static void fdprintf(int fd, char *fmt, ...)
-{
- char stuff[4096];
- va_list ap;
- va_start(ap, fmt);
- vsnprintf(stuff, sizeof(stuff), fmt, ap);
- va_end(ap);
- write(fd, stuff, strlen(stuff));
-}
-
-static char *get_header(struct message *m, char *var)
-{
- char cmp[80];
- int x;
- snprintf(cmp, sizeof(cmp), "%s: ", var);
- for (x=0;x<m->hdrcount;x++)
- if (!strncasecmp(cmp, m->headers[x], strlen(cmp)))
- return m->headers[x] + strlen(cmp);
- return "";
-}
-
-static int event_newstate(struct ast_mansession *s, struct message *m)
-{
- struct ast_chan *chan;
- chan = find_chan(get_header(m, "Channel"));
- strncpy(chan->state, get_header(m, "State"), sizeof(chan->state) - 1);
- return 0;
-}
-
-static int event_newexten(struct ast_mansession *s, struct message *m)
-{
- struct ast_chan *chan;
- chan = find_chan(get_header(m, "Channel"));
- strncpy(chan->exten, get_header(m, "Extension"), sizeof(chan->exten) - 1);
- strncpy(chan->context, get_header(m, "Context"), sizeof(chan->context) - 1);
- strncpy(chan->priority, get_header(m, "Priority"), sizeof(chan->priority) - 1);
- return 0;
-}
-
-static int event_newchannel(struct ast_mansession *s, struct message *m)
-{
- struct ast_chan *chan;
- chan = find_chan(get_header(m, "Channel"));
- strncpy(chan->state, get_header(m, "State"), sizeof(chan->state) - 1);
- strncpy(chan->callerid, get_header(m, "Callerid"), sizeof(chan->callerid) - 1);
- return 0;
-}
-
-static int event_status(struct ast_mansession *s, struct message *m)
-{
- struct ast_chan *chan;
- chan = find_chan(get_header(m, "Channel"));
- strncpy(chan->state, get_header(m, "State"), sizeof(chan->state) - 1);
- strncpy(chan->callerid, get_header(m, "Callerid"), sizeof(chan->callerid) - 1);
- strncpy(chan->exten, get_header(m, "Extension"), sizeof(chan->exten) - 1);
- strncpy(chan->context, get_header(m, "Context"), sizeof(chan->context) - 1);
- strncpy(chan->priority, get_header(m, "Priority"), sizeof(chan->priority) - 1);
- return 0;
-}
-
-static int event_hangup(struct ast_mansession *s, struct message *m)
-{
- del_chan(get_header(m, "Channel"));
- return 0;
-}
-
-static int event_ignore(struct ast_mansession *s, struct message *m)
-{
- return 0;
-}
-
-static int event_rename(struct ast_mansession *s, struct message *m)
-{
- struct ast_chan *chan;
- chan = find_chan(get_header(m, "Oldname"));
- strncpy(chan->name, get_header(m, "Newname"), sizeof(chan->name) - 1);
- return 0;
-}
-static struct event {
- char *event;
- int (*func)(struct ast_mansession *s, struct message *m);
-} events[] = {
- { "Newstate", event_newstate },
- { "Newchannel", event_newchannel },
- { "Newexten", event_newexten },
- { "Hangup", event_hangup },
- { "Rename", event_rename },
- { "Status", event_status },
- { "Link", event_ignore },
- { "Unlink", event_ignore },
- { "StatusComplete", event_ignore }
-};
-
-static int process_message(struct ast_mansession *s, struct message *m)
-{
- int x;
- char event[80] = "";
- strncpy(event, get_header(m, "Event"), sizeof(event) - 1);
- if (!strlen(event)) {
- fprintf(stderr, "Missing event in request");
- return 0;
- }
- for (x=0;x<sizeof(events) / sizeof(events[0]);x++) {
- if (!strcasecmp(event, events[x].event)) {
- if (events[x].func(s, m))
- return -1;
- break;
- }
- }
- if (x >= sizeof(events) / sizeof(events[0]))
- fprintf(stderr, "Ignoring unknown event '%s'", event);
-#if 0
- for (x=0;x<m->hdrcount;x++) {
- printf("Header: %s\n", m->headers[x]);
- }
-#endif
- return 0;
-}
-
-static void rebuild_channels(newtComponent c)
-{
- void *prev = NULL;
- struct ast_chan *chan;
- char tmpn[42];
- char tmp[256];
- int x=0;
- prev = newtListboxGetCurrent(c);
- newtListboxClear(c);
- chan = chans;
- while(chan) {
- snprintf(tmpn, sizeof(tmpn), "%s (%s)", chan->name, chan->callerid);
- if (strlen(chan->exten))
- snprintf(tmp, sizeof(tmp), "%-30s %8s -> %s@%s:%s",
- tmpn, chan->state,
- chan->exten, chan->context, chan->priority);
- else
- snprintf(tmp, sizeof(tmp), "%-30s %8s",
- tmpn, chan->state);
- newtListboxAppendEntry(c, tmp, chan);
- x++;
- chan = chan->next;
- }
- if (!x)
- newtListboxAppendEntry(c, " << No Active Channels >> ", NULL);
- newtListboxSetCurrentByKey(c, prev);
-}
-
-static int has_input(struct ast_mansession *s)
-{
- int x;
- for (x=1;x<s->inlen;x++)
- if ((s->inbuf[x] == '\n') && (s->inbuf[x-1] == '\r'))
- return 1;
- return 0;
-}
-
-static int get_input(struct ast_mansession *s, char *output)
-{
- /* output must have at least sizeof(s->inbuf) space */
- int res;
- int x;
- struct timeval tv = {0, 0};
- fd_set fds;
- for (x=1;x<s->inlen;x++) {
- if ((s->inbuf[x] == '\n') && (s->inbuf[x-1] == '\r')) {
- /* Copy output data up to and including \r\n */
- memcpy(output, s->inbuf, x + 1);
- /* Add trailing \0 */
- output[x+1] = '\0';
- /* Move remaining data back to the front */
- memmove(s->inbuf, s->inbuf + x + 1, s->inlen - x);
- s->inlen -= (x + 1);
- return 1;
- }
- }
- if (s->inlen >= sizeof(s->inbuf) - 1) {
- fprintf(stderr, "Dumping long line with no return from %s: %s\n", inet_ntoa(s->sin.sin_addr), s->inbuf);
- s->inlen = 0;
- }
- FD_ZERO(&fds);
- FD_SET(s->fd, &fds);
- res = select(s->fd + 1, &fds, NULL, NULL, &tv);
- if (res < 0) {
- fprintf(stderr, "Select returned error: %s\n", strerror(errno));
- } else if (res > 0) {
- res = read(s->fd, s->inbuf + s->inlen, sizeof(s->inbuf) - 1 - s->inlen);
- if (res < 1)
- return -1;
- s->inlen += res;
- s->inbuf[s->inlen] = '\0';
- } else {
- return 2;
- }
- return 0;
-}
-
-static int input_check(struct ast_mansession *s, struct message **mout)
-{
- static struct message m;
- int res;
-
- if (mout)
- *mout = NULL;
-
- for(;;) {
- res = get_input(s, m.headers[m.hdrcount]);
- if (res == 1) {
-#if 0
- fprintf(stderr, "Got header: %s", m.headers[m.hdrcount]);
- fgetc(stdin);
-#endif
- /* Strip trailing \r\n */
- if (strlen(m.headers[m.hdrcount]) < 2)
- continue;
- m.headers[m.hdrcount][strlen(m.headers[m.hdrcount]) - 2] = '\0';
- if (!strlen(m.headers[m.hdrcount])) {
- if (mout && strlen(get_header(&m, "Response"))) {
- *mout = &m;
- return 0;
- }
- if (process_message(s, &m))
- break;
- memset(&m, 0, sizeof(&m));
- } else if (m.hdrcount < MAX_HEADERS - 1)
- m.hdrcount++;
- } else if (res < 0) {
- return -1;
- } else if (res == 2)
- return 0;
- }
- return -1;
-}
-
-static struct message *wait_for_response(int timeout)
-{
- struct message *m;
- struct timeval tv;
- int res;
- fd_set fds;
- for (;;) {
- tv.tv_sec = timeout / 1000;
- tv.tv_usec = (timeout % 1000) * 1000;
- FD_SET(session.fd, &fds);
- res = select(session.fd + 1, &fds, NULL, NULL, &tv);
- if (res < 1)
- break;
- if (input_check(&session, &m) < 0) {
- return NULL;
- }
- if (m)
- return m;
- }
- return NULL;
-}
-
-static int manager_action(char *action, char *fmt, ...)
-{
- struct ast_mansession *s;
- char tmp[4096];
- va_list ap;
-
- s = &session;
- fdprintf(s->fd, "Action: %s\r\n", action);
- va_start(ap, fmt);
- vsnprintf(tmp, sizeof(tmp), fmt, ap);
- va_end(ap);
- write(s->fd, tmp, strlen(tmp));
- fdprintf(s->fd, "\r\n");
- return 0;
-}
-
-static int show_message(char *title, char *msg)
-{
- newtComponent form;
- newtComponent label;
- newtComponent ok;
- struct newtExitStruct es;
-
- newtCenteredWindow(60,7, title);
-
- label = newtLabel(4,1,msg);
- ok = newtButton(27, 3, "OK");
- form = newtForm(NULL, NULL, 0);
- newtFormAddComponents(form, label, ok, NULL);
- newtFormRun(form, &es);
- newtPopWindow();
- newtFormDestroy(form);
- return 0;
-}
-
-static newtComponent showform;
-static int show_doing(char *title, char *tmp)
-{
- struct newtExitStruct es;
- newtComponent label;
- showform = newtForm(NULL, NULL, 0);
- newtCenteredWindow(70,4, title);
- label = newtLabel(3,1,tmp);
- newtFormAddComponents(showform,label, NULL);
- newtFormSetTimer(showform, 200);
- newtFormRun(showform, &es);
- return 0;
-}
-
-static int hide_doing(void)
-{
- newtPopWindow();
- newtFormDestroy(showform);
- return 0;
-}
-
-static void try_status(void)
-{
- struct message *m;
- manager_action("Status", "");
- m = wait_for_response(10000);
- if (!m) {
- show_message("Status Failed", "Timeout waiting for response");
- } else if (strcasecmp(get_header(m, "Response"), "Success")) {
- show_message("Status Failed Failed", get_header(m, "Message"));
- }
-}
-
-
-static void try_hangup(newtComponent c)
-{
- struct ast_chan *chan;
- struct message *m;
-
- chan = newtListboxGetCurrent(c);
- if (chan) {
- manager_action("Hangup", "Channel: %s\r\n", chan->name);
- m = wait_for_response(10000);
- if (!m) {
- show_message("Hangup Failed", "Timeout waiting for response");
- } else if (strcasecmp(get_header(m, "Response"), "Success")) {
- show_message("Hangup Failed", get_header(m, "Message"));
- }
- }
-
-}
-
-static int get_user_input(char *msg, char *buf, int buflen)
-{
- newtComponent form;
- newtComponent ok;
- newtComponent cancel;
- newtComponent inpfield;
- const char *input;
- int res = -1;
- struct newtExitStruct es;
-
- newtCenteredWindow(60,7, msg);
-
- inpfield = newtEntry(5, 2, "", 50, &input, 0);
- ok = newtButton(22, 3, "OK");
- cancel = newtButton(32, 3, "Cancel");
- form = newtForm(NULL, NULL, 0);
- newtFormAddComponents(form, inpfield, ok, cancel, NULL);
- newtFormRun(form, &es);
- strncpy(buf, input, buflen - 1);
- if (es.u.co == ok)
- res = 0;
- else
- res = -1;
- newtPopWindow();
- newtFormDestroy(form);
- return res;
-}
-
-static void try_redirect(newtComponent c)
-{
- struct ast_chan *chan;
- char dest[256];
- struct message *m;
- char channame[256];
- char tmp[80];
- char *context;
-
- chan = newtListboxGetCurrent(c);
- if (chan) {
- strncpy(channame, chan->name, sizeof(channame) - 1);
- snprintf(tmp, sizeof(tmp), "Enter new extension for %s", channame);
- if (get_user_input(tmp, dest, sizeof(dest)))
- return;
- if ((context = strchr(dest, '@'))) {
- *context = '\0';
- context++;
- manager_action("Redirect", "Channel: %s\r\nContext: %s\r\nExten: %s\r\nPriority: 1\r\n", chan->name,context,dest);
- } else {
- manager_action("Redirect", "Channel: %s\r\nExten: %s\r\nPriority: 1\r\n", chan->name, dest);
- }
- m = wait_for_response(10000);
- if (!m) {
- show_message("Hangup Failed", "Timeout waiting for response");
- } else if (strcasecmp(get_header(m, "Response"), "Success")) {
- show_message("Hangup Failed", get_header(m, "Message"));
- }
- }
-
-}
-
-static int manage_calls(char *host)
-{
- newtComponent form;
- newtComponent quit;
- newtComponent hangup;
- newtComponent redirect;
- newtComponent channels;
- struct newtExitStruct es;
- char tmp[80];
-
- /* If there's one thing you learn from this code, it is this...
- Never, ever fly Air France. Their customer service is absolutely
- the worst. I've never heard the words "That's not my problem" as
- many times as I have from their staff -- It should, without doubt
- be their corporate motto if it isn't already. Don't bother giving
- them business because you're just a pain in their side and they
- will be sure to let you know the first time you speak to them.
-
- If you ever want to make me happy just tell me that you, too, will
- never fly Air France again either (in spite of their excellent
- cuisine). */
- snprintf(tmp, sizeof(tmp), "Asterisk Manager at %s", host);
- newtCenteredWindow(74, 20, tmp);
- form = newtForm(NULL, NULL, 0);
- newtFormWatchFd(form, session.fd, NEWT_FD_READ);
- newtFormSetTimer(form, 100);
- quit = newtButton(62, 16, "Quit");
- redirect = newtButton(35, 16, "Redirect");
- hangup = newtButton(50, 16, "Hangup");
- channels = newtListbox(1,1,14, NEWT_FLAG_SCROLL);
- newtFormAddComponents(form, channels, redirect, hangup, quit, NULL);
- newtListboxSetWidth(channels, 72);
-
- show_doing("Getting Status", "Retrieving system status...");
- try_status();
- hide_doing();
-
- for(;;) {
- newtFormRun(form, &es);
- if (has_input(&session) || (es.reason == NEWT_EXIT_FDREADY)) {
- if (input_check(&session, NULL)) {
- show_message("Disconnected", "Disconnected from remote host");
- break;
- }
- } else if (es.reason == NEWT_EXIT_COMPONENT) {
- if (es.u.co == quit)
- break;
- if (es.u.co == hangup) {
- try_hangup(channels);
- } else if (es.u.co == redirect) {
- try_redirect(channels);
- }
- }
- rebuild_channels(channels);
- }
- newtFormDestroy(form);
- return 0;
-}
-
-static int login(char *hostname)
-{
- newtComponent form;
- newtComponent cancel;
- newtComponent login;
- newtComponent username;
- newtComponent password;
- newtComponent label;
- newtComponent ulabel;
- newtComponent plabel;
- const char *user;
- const char *pass;
- struct message *m;
- struct newtExitStruct es;
- char tmp[55];
- struct hostent *hp;
- int res = -1;
-
- session.fd = socket(AF_INET, SOCK_STREAM, 0);
- if (session.fd < 0) {
- snprintf(tmp, sizeof(tmp), "socket() failed: %s\n", strerror(errno));
- show_message("Socket failed", tmp);
- return -1;
- }
-
- snprintf(tmp, sizeof(tmp), "Looking up %s\n", hostname);
- show_doing("Connecting....", tmp);
-
-
- hp = gethostbyname(hostname);
- if (!hp) {
- snprintf(tmp, sizeof(tmp), "No such address: %s\n", hostname);
- show_message("Host lookup failed", tmp);
- return -1;
- }
- hide_doing();
- snprintf(tmp, sizeof(tmp), "Connecting to %s", hostname);
- show_doing("Connecting...", tmp);
-
- session.sin.sin_family = AF_INET;
- session.sin.sin_port = htons(DEFAULT_MANAGER_PORT);
- memcpy(&session.sin.sin_addr, hp->h_addr, sizeof(session.sin.sin_addr));
-
- if (connect(session.fd,(struct sockaddr*)&session.sin, sizeof(session.sin))) {
- snprintf(tmp, sizeof(tmp), "%s failed: %s\n", hostname, strerror(errno));
- show_message("Connect Failed", tmp);
- return -1;
- }
-
- hide_doing();
-
- login = newtButton(5, 6, "Login");
- cancel = newtButton(25, 6, "Cancel");
- newtCenteredWindow(40, 10, "Asterisk Manager Login");
- snprintf(tmp, sizeof(tmp), "Host: %s", hostname);
- label = newtLabel(4,1, tmp);
-
- ulabel = newtLabel(4,2,"Username:");
- plabel = newtLabel(4,3,"Password:");
-
- username = newtEntry(14, 2, "", 20, &user, 0);
- password = newtEntry(14, 3, "", 20, &pass, NEWT_FLAG_HIDDEN);
-
- form = newtForm(NULL, NULL, 0);
- newtFormAddComponents(form, username, password, login, cancel, label, ulabel, plabel,NULL);
- newtFormRun(form, &es);
- if (es.reason == NEWT_EXIT_COMPONENT) {
- if (es.u.co == login) {
- snprintf(tmp, sizeof(tmp), "Logging in '%s'...", user);
- show_doing("Logging in", tmp);
- /* Check to see if the remote host supports MD5 Authentication */
- manager_action("Challenge", "AuthType: MD5\r\n");
- m = wait_for_response(10000);
- if (m && !strcasecmp(get_header(m, "Response"), "Success")) {
- char *challenge = get_header(m, "Challenge");
- int x;
- int len = 0;
- char md5key[256] = "";
- struct MD5Context md5;
- unsigned char digest[16];
- MD5Init(&md5);
- MD5Update(&md5, challenge, strlen(challenge));
- MD5Update(&md5, pass, strlen(pass));
- MD5Final(digest, &md5);
- for (x=0; x<16; x++)
- len += sprintf(md5key + len, "%2.2x", digest[x]);
- manager_action("Login",
- "AuthType: MD5\r\n"
- "Username: %s\r\n"
- "Key: %s\r\n",
- user, md5key);
- m = wait_for_response(10000);
- hide_doing();
- if (!strcasecmp(get_header(m, "Response"), "Success")) {
- res = 0;
- } else {
- show_message("Login Failed", get_header(m, "Message"));
- }
- } else {
- memset(m, 0, sizeof(m));
- manager_action("Login",
- "Username: %s\r\n"
- "Secret: %s\r\n",
- user, pass);
- m = wait_for_response(10000);
- hide_doing();
- if (m) {
- if (!strcasecmp(get_header(m, "Response"), "Success")) {
- res = 0;
- } else {
- show_message("Login Failed", get_header(m, "Message"));
- }
- }
- }
- }
- }
- newtFormDestroy(form);
- return res;
-}
-
-int main(int argc, char *argv[])
-{
- if (argc < 2) {
- fprintf(stderr, "Usage: astman <host>\n");
- exit(1);
- }
- newtInit();
- newtCls();
- newtDrawRootText(0, 0, "Asterisk Manager (C)2002, Linux Support Services, Inc.");
- newtPushHelpLine("Welcome to the Asterisk Manager!");
- if (login(argv[1])) {
- newtFinished();
- exit(1);
- }
- manage_calls(argv[1]);
- newtFinished();
- return 0;
-}