aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
author(no author) <(no author)@f38db490-d61c-443f-a65b-d21fe96a405b>2005-01-23 23:57:41 +0000
committer(no author) <(no author)@f38db490-d61c-443f-a65b-d21fe96a405b>2005-01-23 23:57:41 +0000
commit7d97c27137f894688512e675a70cdf81d467e1c7 (patch)
tree352cc78f938b7c42f5489f0f3a890daa6c4a87d9
parent27a9c96742202c8188b53a0173649de479256b69 (diff)
This commit was manufactured by cvs2svn to create tag 'v1-0-5'.
git-svn-id: http://svn.digium.com/svn/asterisk/tags/v1-0-5@4884 f38db490-d61c-443f-a65b-d21fe96a405b
-rwxr-xr-xCHANGES62
-rwxr-xr-xCREDITS2
-rwxr-xr-xMakefile28
-rwxr-xr-xacl.c7
-rwxr-xr-xapp.c17
-rwxr-xr-xapps/app_alarmreceiver.c2
-rwxr-xr-xapps/app_chanisavail.c11
-rwxr-xr-xapps/app_dial.c13
-rwxr-xr-xapps/app_festival.c6
-rwxr-xr-xapps/app_forkcdr.c5
-rwxr-xr-xapps/app_getcpeid.c10
-rwxr-xr-xapps/app_hasnewvoicemail.c28
-rwxr-xr-xapps/app_macro.c3
-rwxr-xr-xapps/app_meetme.c18
-rwxr-xr-xapps/app_parkandannounce.c2
-rwxr-xr-xapps/app_queue.c95
-rwxr-xr-xapps/app_read.c3
-rwxr-xr-xapps/app_record.c2
-rwxr-xr-xapps/app_sms.c13
-rwxr-xr-xapps/app_test.c13
-rwxr-xr-xapps/app_userevent.c2
-rwxr-xr-xapps/app_voicemail.c353
-rwxr-xr-xast_expr.y68
-rwxr-xr-xasterisk.c48
-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.c25
-rwxr-xr-xchannel.c24
-rwxr-xr-xchannels/chan_agent.c21
-rwxr-xr-xchannels/chan_alsa.c2
-rwxr-xr-xchannels/chan_h323.c28
-rwxr-xr-xchannels/chan_iax2.c131
-rwxr-xr-xchannels/chan_local.c7
-rwxr-xr-xchannels/chan_mgcp.c117
-rwxr-xr-xchannels/chan_modem.c15
-rwxr-xr-xchannels/chan_phone.c4
-rwxr-xr-xchannels/chan_sip.c719
-rwxr-xr-xchannels/chan_skinny.c2
-rwxr-xr-xchannels/chan_zap.c91
-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.c2
-rwxr-xr-xcli.c43
-rwxr-xr-xcodecs/Makefile3
-rwxr-xr-xcodecs/gsm/Makefile4
-rwxr-xr-xconfigs/agents.conf.sample4
-rwxr-xr-xconfigs/queues.conf.sample11
-rwxr-xr-xconfigs/sip.conf.sample13
-rwxr-xr-xconfigs/voicemail.conf.sample6
-rwxr-xr-xconfigs/zapata.conf.sample7
-rwxr-xr-xcontrib/README.festival17
-rwxr-xr-xcontrib/firmware/iax/iaxy.binbin39241 -> 39386 bytes
-rwxr-xr-xdb1-ast/hash/ndbm.c50
-rwxr-xr-xdoc/README.iax71
-rwxr-xr-xdoc/README.variables4
-rwxr-xr-xdoc/cdr.txt2
-rwxr-xr-xdsp.c13
-rwxr-xr-xformats/format_wav_gsm.c2
-rwxr-xr-xframe.c449
-rwxr-xr-xinclude/asterisk/cdr.h2
-rwxr-xr-xinclude/asterisk/channel.h4
-rwxr-xr-xinclude/asterisk/frame.h38
-rwxr-xr-xloader.c19
-rwxr-xr-xlogger.c21
-rwxr-xr-xpbx.c45
-rwxr-xr-xres/res_agi.c12
-rwxr-xr-xres/res_config_odbc.c2
-rwxr-xr-xres/res_crypto.c3
-rwxr-xr-xres/res_features.c9
-rwxr-xr-xres/res_indications.c15
-rwxr-xr-xres/res_monitor.c61
-rwxr-xr-xres/res_musiconhold.c10
-rwxr-xr-xres/res_odbc.c114
-rwxr-xr-xrtp.c39
-rwxr-xr-xsay.c36
-rwxr-xr-xsounds.txt2
-rwxr-xr-xsounds/vm-saveoper.gsmbin0 -> 16533 bytes
-rwxr-xr-xtdd.c2
-rwxr-xr-xutils/astman.c683
83 files changed, 2188 insertions, 1927 deletions
diff --git a/CHANGES b/CHANGES
index 066275c0a..1b2e0e1fd 100755
--- a/CHANGES
+++ b/CHANGES
@@ -1,8 +1,68 @@
+ NOTE: Corrections or additions to the ChangeLog may be submitted
+ to http://bugs.digium.com. A complete listing of changes
+ is available through the Asterisk-CVS mailing list hosted
+ at http://lists.digium.com.
+
+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/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/Makefile b/Makefile
index 5a6a51c49..d6ff5fe99 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
@@ -307,7 +310,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
@@ -405,7 +408,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 +"
@@ -518,7 +521,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 +540,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/acl.c b/acl.c
index 6c460969f..935ec808d 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");
diff --git a/app.c b/app.c
index f653aa909..61cb63cd4 100755
--- a/app.c
+++ b/app.c
@@ -706,10 +706,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,14 +720,11 @@ 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, "");
- }
}
-
return res;
}
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_dial.c b/apps/app_dial.c
index 7f3c3d768..ce50a10da 100755
--- a/apps/app_dial.c
+++ b/apps/app_dial.c
@@ -281,6 +281,9 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, struct localu
ast_hangup(o->chan);
o->chan = NULL;
numnochan++;
+ } else {
+ /* After calling, set callerid to extension */
+ ast_set_callerid(o->chan, ast_strlen_zero(in->macroexten) ? in->exten : in->macroexten, 0);
}
}
/* Hangup the original channel now, in case we needed it */
@@ -336,7 +339,8 @@ 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 */
@@ -383,6 +387,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,6 +397,7 @@ 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->frametype == AST_FRAME_VOICE) || (f->frametype == AST_FRAME_DTMF))) {
@@ -841,9 +848,11 @@ static int dial_exec(struct ast_channel *chan, void *data)
free(tmp);
cur = rest;
continue;
- } else
+ } else {
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", numsubst);
+ ast_set_callerid(tmp->chan, ast_strlen_zero(chan->macroexten) ? chan->exten : chan->macroexten, 0);
+ }
/* Put them in the list of outgoing thingies... We're ready now.
XXX If we're forcibly removed, these outgoing calls won't get
hung up XXX */
diff --git a/apps/app_festival.c b/apps/app_festival.c
index e7e0bd426..7b6f68634 100755
--- a/apps/app_festival.c
+++ b/apps/app_festival.c
@@ -305,9 +305,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 +325,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 +334,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 +344,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 +447,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..bf493d523 100755
--- a/apps/app_forkcdr.c
+++ b/apps/app_forkcdr.c
@@ -23,7 +23,8 @@
static char *tdesc = "Fork The CDR into 2 seperate 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..ae9846871 100755
--- a/apps/app_meetme.c
+++ b/apps/app_meetme.c
@@ -524,7 +524,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 +559,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;
@@ -1043,10 +1044,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);
@@ -1454,14 +1455,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..bb8a7fb89 100755
--- a/apps/app_parkandannounce.c
+++ b/apps/app_parkandannounce.c
@@ -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_queue.c b/apps/app_queue.c
index 542ede246..4d56b820d 100755
--- a/apps/app_queue.c
+++ b/apps/app_queue.c
@@ -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,7 +545,7 @@ 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;
if (qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime)) {
@@ -552,6 +553,7 @@ 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;
}
/* Request the peer */
@@ -563,6 +565,7 @@ 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;
}
tmp->chan->appl = "AppQueue";
@@ -593,6 +596,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 +614,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 +639,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 +650,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 +714,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 +752,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 +807,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 +819,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 +845,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;
@@ -912,6 +930,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 +1041,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 +1124,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,7 +1651,7 @@ 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) ) {
@@ -1634,6 +1659,12 @@ check_turns:
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);
@@ -1691,7 +1722,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 +1812,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 +1849,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 +1903,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_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..882236822 100755
--- a/apps/app_sms.c
+++ b/apps/app_sms.c
@@ -26,6 +26,7 @@
#include <sys/types.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 +37,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 +319,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 +521,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 +693,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 +773,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 +1209,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_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..82de783b3 100755
--- a/apps/app_userevent.c
+++ b/apps/app_userevent.c
@@ -54,12 +54,12 @@ 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) {
diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c
index fe13a7fca..391130eaa 100755
--- a/apps/app_voicemail.c
+++ b/apps/app_voicemail.c
@@ -178,6 +178,7 @@ static int advanced_options(struct ast_channel *chan, struct ast_vm_user *vmu, s
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 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 =
@@ -705,6 +709,18 @@ 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];
+ for (x=0;x<MAXMSG;x++) {
+ make_file(fn, sizeof(fn), dir, x);
+ if (ast_fileexists(fn, NULL, NULL) < 1)
+ break;
+ }
+ return x-1;
+}
+
static int
inbuf(struct baseio *bio, FILE *fi)
{
@@ -989,7 +1005,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;
@@ -1076,7 +1092,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;
@@ -1356,7 +1372,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 +1419,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);
@@ -1434,6 +1450,12 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, int silent, int
break;
msgnum++;
} while(msgnum < MAXMSG);
+ 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 (msgnum < MAXMSG) {
/* Store information */
snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
@@ -1502,7 +1524,8 @@ 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 {
res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
if (!res)
@@ -1525,16 +1548,56 @@ 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];
+
+ 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;
}
+
static int say_and_wait(struct ast_channel *chan, int num, char *language)
{
int d;
@@ -2073,23 +2136,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;
@@ -2272,7 +2322,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 +2333,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 +2595,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);
}
@@ -2586,8 +2650,25 @@ static void close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
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 +3030,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 +3058,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");
@@ -3048,19 +3140,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 +3189,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 +3247,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 +3377,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);
@@ -3333,22 +3441,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 +3451,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 +3467,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 +3627,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 +3643,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 +3857,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);
}
@@ -4582,11 +4639,9 @@ static int play_record_review(struct ast_channel *chan, char *playfile, char *re
cmd = ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, silencethreshold, maxsilence);
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 +4694,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 +4743,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 +4765,7 @@ static int vm_delete(char *file)
return ast_filedelete(file, NULL);
}
+
int usecount(void)
{
int res;
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..113e5a172 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);
}
}
@@ -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);
}
@@ -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");
@@ -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) {
@@ -1728,10 +1731,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();
@@ -1796,6 +1795,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);
@@ -1905,15 +1908,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/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..f6af7ff58 100755
--- a/cdr/cdr_pgsql.c
+++ b/cdr/cdr_pgsql.c
@@ -180,20 +180,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 +273,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)
@@ -308,6 +299,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/channel.c b/channel.c
index 2f6f28d7f..d5fe12988 100755
--- a/channel.c
+++ b/channel.c
@@ -1888,7 +1888,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);
}
@@ -2205,7 +2205,7 @@ int ast_do_masquerade(struct ast_channel *original)
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 +2304,12 @@ 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;
+
+ /* 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 +2365,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 +2393,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 +2427,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 +2444,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);
}
@@ -2899,8 +2907,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..5d3781017 100755
--- a/channels/chan_agent.c
+++ b/channels/chan_agent.c
@@ -519,9 +519,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)) {
diff --git a/channels/chan_alsa.c b/channels/chan_alsa.c
index acf80b857..fa09cbe0b 100755
--- a/channels/chan_alsa.c
+++ b/channels/chan_alsa.c
@@ -863,7 +863,7 @@ 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);
}
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..16c911d6a 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 */
@@ -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 */
@@ -862,7 +866,7 @@ static int find_callno(unsigned short callno, unsigned short dcallno, struct soc
ast_log(LOG_WARNING, "No more space\n");
return -1;
}
- iaxs[x] = new_iax(sin, lockpeer);
+ iaxs[x] = new_iax(sin, lockpeer, host);
update_max_nontrunk();
if (iaxs[x]) {
if (option_debug)
@@ -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) {
@@ -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,33 @@ 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 diff = ms % (f->samples / 8);
+ if(diff)
+ ms += f->samples/8 - 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 */
@@ -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);
@@ -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,
@@ -5079,10 +5122,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 {
@@ -5148,7 +5191,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 +5215,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 +5386,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 +5664,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 +5938,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 +5983,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;
@@ -5993,12 +6047,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 +6306,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 +6319,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 +6442,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;
@@ -6553,7 +6611,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) {
diff --git a/channels/chan_local.c b/channels/chan_local.c
index fc8fd8820..439bd3dfe 100755
--- a/channels/chan_local.c
+++ b/channels/chan_local.c
@@ -304,6 +304,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 +375,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;
@@ -441,6 +445,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..102c28b14 100755
--- a/channels/chan_mgcp.c
+++ b/channels/chan_mgcp.c
@@ -686,8 +686,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)
@@ -862,8 +861,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 +872,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,7 +887,6 @@ static int mgcp_hangup(struct ast_channel *ast)
p->dsp = NULL;
}
}
- ast_mutex_lock(&sub->lock);
sub->owner = NULL;
if (strlen(sub->cxident)) {
@@ -967,7 +966,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 +1077,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 +1092,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 +1106,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)
@@ -1313,7 +1310,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 +1321,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 +1334,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) {
@@ -1658,7 +1658,7 @@ 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:
+ /* Scan through the RTP payload types specified in a "m=" line: */
ast_rtp_pt_clear(sub->rtp);
codecs = m + len;
while(strlen(codecs)) {
@@ -1670,18 +1670,18 @@ static int process_sdp(struct mgcp_subchannel *sub, struct mgcp_request *req)
codecs += len;
}
- // Next, scan through each "a=rtpmap:" line, noting each
- // specified RTP payload type (with corresponding MIME subtype):
+ /* 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
+ /* Note: should really look at the 'freq' and '#chans' params too */
ast_rtp_set_rtpmap_type(sub->rtp, codec, "audio", mimeSubtype);
free(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 +1696,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 +1711,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 +1734,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 +1784,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;
}
@@ -1947,7 +1946,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 +1980,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;
@@ -2115,7 +2114,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;
@@ -2411,7 +2410,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)
@@ -2860,7 +2859,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 +2867,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 +2878,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 +2927,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,9 +3047,13 @@ 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)) {
@@ -3081,11 +3086,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 +3143,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,8 +3153,8 @@ 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 */
@@ -3257,10 +3260,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;
@@ -3385,8 +3388,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 +3520,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,7 +3557,7 @@ 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->context, context, sizeof(e->context) - 1);
strncpy(e->callerid, callerid, sizeof(e->callerid) - 1);
@@ -3748,6 +3750,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))
@@ -4226,4 +4230,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_phone.c b/channels/chan_phone.c
index bacfaa3c4..d817776e7 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"
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index be81665c8..51f6dada5 100755
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -129,7 +129,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 +170,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);
@@ -222,10 +225,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 +257,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 */
@@ -321,7 +323,7 @@ static struct sip_pvt {
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[256]; /* Authorization domain */
char lastmsg[256]; /* Last Message sent/received */
int amaflags; /* AMA Flags */
int pendinginvite; /* Any pending invite */
@@ -391,6 +393,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;
@@ -432,6 +435,7 @@ struct sip_peer {
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;
@@ -506,6 +510,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[256]; /* Authorization realm */
+ char nonce[256]; /* Authorization nonce */
+ char domain[256]; /* Authorization domain */
+ char opaque[256]; /* Opaque nonsense */
+ char qop[80]; /* Quality of Protection. */
+
+ char lastmsg[256]; /* Last Message sent/received */
struct sip_registry *next;
};
@@ -688,6 +701,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 +841,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)
{
@@ -1327,7 +1350,7 @@ static int create_addr(struct sip_pvt *r, char *opeer)
r->promiscredir = p->promiscredir;
strncpy(r->context, p->context,sizeof(r->context)-1);
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;
@@ -1405,71 +1428,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 */
@@ -1842,7 +1802,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 +1966,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 +1974,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);
@@ -2311,9 +2278,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
@@ -2540,33 +2509,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;
@@ -2786,7 +2754,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",
@@ -2801,17 +2770,17 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
ast_getformatname_multiple(s3, slen, p->noncodeccapability));
}
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 +2790,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);
}
}
}
@@ -3139,6 +3110,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 +3137,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
@@ -3340,13 +3314,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 +3331,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 +3389,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 +3409,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 +3455,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 +3463,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 +3576,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 +3590,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;
@@ -3707,9 +3688,11 @@ static void initreqprep(struct sip_request *req, struct sip_pvt *p, char *cmd, c
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 +3765,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 +3829,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))
@@ -3928,8 +3913,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 +3942,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 +3994,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 +4016,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 +4032,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 +4068,49 @@ 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);
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 +4126,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 +4155,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 +4170,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 +4285,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 +4370,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 +4396,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 +4549,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;
@@ -5110,9 +5135,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 */
@@ -5292,7 +5321,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 +5388,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 +5445,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;
}
@@ -5480,6 +5511,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;
@@ -5726,6 +5758,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;
@@ -5770,38 +5805,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 +6062,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"))) {
@@ -6210,27 +6231,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 +6354,15 @@ 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) {
+ strncpy(p->registry->realm, realm, sizeof(p->realm)-1);
+ strncpy(p->registry->nonce, nonce, sizeof(p->nonce)-1);
+ strncpy(p->registry->domain, domain, sizeof(p->domain)-1);
+ strncpy(p->registry->opaque, opaque, sizeof(p->opaque)-1);
+ strncpy(p->registry->qop, qop, sizeof(p->qop)-1);
+ }
build_reply_digest(p, orig_header, digest, digest_len);
return 0;
}
@@ -6487,6 +6524,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 +6551,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 */
@@ -6660,6 +6701,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,20 +6769,25 @@ 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);
@@ -6757,6 +6804,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 */
@@ -6860,8 +6922,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 +7045,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 +7173,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 */
@@ -7156,7 +7263,7 @@ static int handle_request(struct sip_pvt *p, struct sip_request *req, struct soc
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) {
@@ -7282,12 +7389,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 +7522,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 +7547,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 +7577,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 +7616,20 @@ 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;
+ }
+ }
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) {
@@ -7584,8 +7717,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 +7982,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 +8009,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 +8151,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
@@ -8047,6 +8194,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,17 +8269,9 @@ 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);
} else if (!strcasecmp(v->name, "restrictcid")) {
@@ -8165,6 +8306,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 +8331,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 +8346,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,12 +8369,14 @@ 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);
@@ -8241,6 +8387,7 @@ static struct sip_peer *build_peer(char *name, struct ast_variable *v)
peer->defaddr.sin_family = AF_INET;
peer->expiry = expiry;
}
+ peer->prefs = prefs;
oldha = peer->ha;
peer->ha = NULL;
peer->addr.sin_family = AF_INET;
@@ -8353,17 +8500,9 @@ 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;
@@ -8427,7 +8566,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);
@@ -8450,11 +8589,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 +8723,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")) {
@@ -8771,6 +8897,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;
@@ -8949,7 +9076,6 @@ static int sip_do_reload(void)
struct sip_peer *peer;
delete_users();
reload_config();
-
prune_peers();
/* And start the monitor for the first time */
ast_mutex_lock(&regl.lock);
@@ -8993,9 +9119,9 @@ int load_module()
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 +9130,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 */
diff --git a/channels/chan_skinny.c b/channels/chan_skinny.c
index c58315b4d..920899664 100755
--- a/channels/chan_skinny.c
+++ b/channels/chan_skinny.c
@@ -1700,7 +1700,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);
diff --git a/channels/chan_zap.c b/channels/chan_zap.c
index b4149cfc9..3aa5678fe 100755
--- a/channels/chan_zap.c
+++ b/channels/chan_zap.c
@@ -153,6 +153,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 +264,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 +546,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;
@@ -758,7 +764,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 +775,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 +1536,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;
}
@@ -2886,6 +2887,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 +2912,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);
@@ -5018,9 +5043,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 */
@@ -6056,7 +6083,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 +6092,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 +6114,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 +6522,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 +6540,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 */
@@ -7012,6 +7042,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 +7061,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 +7134,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 +7385,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);
@@ -8033,13 +8063,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 +8077,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 +8091,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 +8104,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 +8119,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 +8267,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 +9602,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..34f251fb0 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)
diff --git a/cli.c b/cli.c
index 613e3a22f..f72d087f2 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;
}
@@ -863,10 +871,10 @@ 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;
@@ -999,8 +1007,7 @@ 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) {
@@ -1035,7 +1042,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,10 +1066,10 @@ 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;
if ((dup = parse_args(text, &x, argv))) {
join(matchstr, sizeof(matchstr), argv);
diff --git a/codecs/Makefile b/codecs/Makefile
index 82d8f458e..9a3dc8c28 100755
--- a/codecs/Makefile
+++ b/codecs/Makefile
@@ -19,10 +19,11 @@
#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/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")
LIBG723=g723.1/libg723.a
LIBG723B=g723.1b/libg723b.a
diff --git a/codecs/gsm/Makefile b/codecs/gsm/Makefile
index a21bd7e52..06e96414a 100755
--- a/codecs/gsm/Makefile
+++ b/codecs/gsm/Makefile
@@ -42,12 +42,14 @@ ifneq (${PROC},x86_64)
ifneq (${PROC},ultrasparc)
ifneq ($(shell uname -m),ppc)
ifneq ($(shell uname -m),alpha)
+ifneq (${PROC},sparc64)
OPTIMIZE+=-march=$(PROC)
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.
@@ -489,7 +491,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/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/queues.conf.sample b/configs/queues.conf.sample
index 7ba488ad3..3a682d1e1 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
@@ -113,6 +114,10 @@
;
; joinempty = yes
;
+; If you wish to remove callers from the queue if there are no agents present, set this to yes
+;
+; 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)
;
diff --git a/configs/sip.conf.sample b/configs/sip.conf.sample
index de46d9439..f3fc87580 100755
--- a/configs/sip.conf.sample
+++ b/configs/sip.conf.sample
@@ -131,7 +131,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,6 +228,18 @@ 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
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..74e132ee0 100755
--- a/contrib/firmware/iax/iaxy.bin
+++ b/contrib/firmware/iax/iaxy.bin
Binary files differ
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/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.variables b/doc/README.variables
index dfb6de3d1..b703b54ae 100755
--- a/doc/README.variables
+++ b/doc/README.variables
@@ -79,8 +79,8 @@ 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/formats/format_wav_gsm.c b/formats/format_wav_gsm.c
index 9fcc3c9ce..5b4d31f6a 100755
--- a/formats/format_wav_gsm.c
+++ b/formats/format_wav_gsm.c
@@ -219,7 +219,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");
diff --git a/frame.c b/frame.c
index 72197d5c1..019ed8fdf 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;
@@ -391,141 +399,137 @@ int ast_fr_fdhangup(int fd)
return ast_fr_fdwrite(fd, &hangup);
}
+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 +537,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)
@@ -607,7 +619,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 +684,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 +809,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/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..516e3a9a8 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>
+#if defined(__APPLE__)
+#include <asterisk/poll-compat.h>
+#else
#include <sys/poll.h>
+#endif
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
diff --git a/include/asterisk/frame.h b/include/asterisk/frame.h
index c80ca72f5..c97973226 100755
--- a/include/asterisk/frame.h
+++ b/include/asterisk/frame.h
@@ -58,6 +58,11 @@ extern "C" {
#error Need to know endianess
#endif /* __BYTE_ORDER */
+struct ast_codec_pref {
+ char order[32];
+};
+
+
//! Data structure associated with a single frame of data
/* A frame of data read used to communicate between
between channels and applications */
@@ -337,11 +342,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,6 +368,8 @@ 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);
@@ -374,6 +380,32 @@ extern struct ast_frame *ast_smoother_read(struct ast_smoother *s);
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/loader.c b/loader.c
index 2a539f30c..0720d0670 100755
--- a/loader.c
+++ b/loader.c
@@ -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..cafe4d70d 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);
@@ -455,8 +462,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);
@@ -481,11 +488,11 @@ 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);
syslog(syslog_level_map[level], "%s", buf);
@@ -543,7 +550,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,7 +563,7 @@ 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);
@@ -642,7 +649,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 +663,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/pbx.c b/pbx.c
index 16888bdbf..09f173e1e 100755
--- a/pbx.c
+++ b/pbx.c
@@ -481,7 +481,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 +577,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 '[': \
{\
@@ -1258,7 +1259,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)),
@@ -2760,6 +2761,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 +2788,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 +2809,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,
@@ -4381,7 +4397,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 +4584,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;
}
}
diff --git a/res/res_agi.c b/res/res_agi.c
index 04cf9eec5..8f96c8ca2 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;
@@ -432,8 +435,7 @@ static int handle_streamfile(struct ast_channel *chan, AGI *agi, int argc, char
fs = ast_openstream(chan, argv[2], chan->language);
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);
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..5cd2da58c 100755
--- a/res/res_features.c
+++ b/res/res_features.c
@@ -152,6 +152,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;
@@ -302,6 +303,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 +487,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) {
diff --git a/res/res_indications.c b/res/res_indications.c
index b289612d5..e998be582 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=
+"PlayTone(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 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,7 +388,7 @@ 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("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..7f92a848d 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,7 +287,7 @@ 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);
@@ -391,6 +397,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 /
@@ -502,6 +513,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..6cf30db4e 100755
--- a/res/res_musiconhold.c
+++ b/res/res_musiconhold.c
@@ -224,8 +224,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 +355,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 +367,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);
diff --git a/res/res_odbc.c b/res/res_odbc.c
index c8efb0620..90caa655d 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,64 @@ 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;
+ int x = 0;
+ 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;
+ int x = 0;
+ 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 +258,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 +400,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 +411,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/rtp.c b/rtp.c
index fff3deed0..9b40b7980 100755
--- a/rtp.c
+++ b/rtp.c
@@ -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);
@@ -397,6 +406,7 @@ 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 mark;
@@ -445,6 +455,12 @@ 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;
mark = seqno & (1 << 23);
ext = seqno & (1 << 28);
@@ -469,17 +485,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 */
@@ -978,7 +994,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 +1025,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 +1032,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 +1041,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;
diff --git a/say.c b/say.c
index 879c56da8..480b08e8e 100755
--- a/say.c
+++ b/say.c
@@ -579,7 +579,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 +682,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 +791,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 +881,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 +967,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 +1113,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 +1183,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 +1238,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 +1566,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 +1638,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 +1699,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 +1808,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);
diff --git a/sounds.txt b/sounds.txt
index 579792026..19fc612a7 100755
--- a/sounds.txt
+++ b/sounds.txt
@@ -447,6 +447,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/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/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/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;
-}