[asterisk-commits] branch rizzo/base r8864 - in /team/rizzo/base: ./ agi/ apps/ cdr/ channels/ c...

asterisk-commits at lists.digium.com asterisk-commits at lists.digium.com
Tue Jan 31 14:20:23 MST 2006


Author: rizzo
Date: Sun Jan 29 08:57:22 2006
New Revision: 8864

URL: http://svn.digium.com/view/asterisk?rev=8864&view=rev
Log:
snapshot of all of my local changes.
The detailed list is very long, but a summary is as follows:

- various code cleanup to compile with -Werror

- massive cleanup to file.c

- show thread command

- fix cli completion

- remove macros in extension match code,
  document it and prepare for possible extensions


- remove localized definition of struct localuser in
  preparation for putting the usecount support in
  the wrapper functions.

- cleanup of loader.c in preparation to loading modules
  with RTLD_NOW | RTLD_LOCAL

- cleanup and simplification of the code in chan_sip.c,
  including a per-peer register command, modified SIP packet
  parsing/building code,, etc.

- massive cleanup of cli-related functions in pbx_config.c
  removing redundant code

- improved algorithm in channel.c for ast_waitfor*()

- introduce a 'boost' command in chan_oss.c plus fix
  to open the device on answer().

- rewrite of app_dial into app_dial2.c

- rewrite of say.c into say2.c and files in say/
  (this might probably go away replaced by a better
  implementation of say based on config files)

- extend app_playback to play numbers as well (experimental)
  possibly replacing the entire say routines

- better algorithm to select a parking slot in
  res_features

- wraparound detection code in include/asterisk/time.h

- experimental code for atomic fetchadd on i386 (very efficient)
  and other platforms (lock based, same performance as now);

- a lot of comments everywhere




Added:
    team/rizzo/base/apps/app_dial2.c
    team/rizzo/base/say/
    team/rizzo/base/say/say_cz.c
    team/rizzo/base/say/say_da.c
    team/rizzo/base/say/say_de.c
    team/rizzo/base/say/say_en_GB.c
    team/rizzo/base/say/say_es.c
    team/rizzo/base/say/say_fr.c
    team/rizzo/base/say/say_gr.c
    team/rizzo/base/say/say_he.c
    team/rizzo/base/say/say_it.c
    team/rizzo/base/say/say_nl.c
    team/rizzo/base/say/say_no.c
    team/rizzo/base/say/say_pl.c
    team/rizzo/base/say/say_pt.c
    team/rizzo/base/say/say_ru.c
    team/rizzo/base/say/say_ru_old.c
    team/rizzo/base/say/say_se.c
    team/rizzo/base/say/say_tw.c
    team/rizzo/base/say2.c
Modified:
    team/rizzo/base/Makefile
    team/rizzo/base/agi/Makefile
    team/rizzo/base/app.c
    team/rizzo/base/apps/Makefile
    team/rizzo/base/apps/app_directory.c
    team/rizzo/base/apps/app_echo.c
    team/rizzo/base/apps/app_externalivr.c
    team/rizzo/base/apps/app_macro.c
    team/rizzo/base/apps/app_meetme.c
    team/rizzo/base/apps/app_playback.c
    team/rizzo/base/apps/app_queue.c
    team/rizzo/base/apps/app_sayunixtime.c
    team/rizzo/base/apps/app_sms.c
    team/rizzo/base/apps/app_voicemail.c
    team/rizzo/base/asterisk.c
    team/rizzo/base/autoservice.c
    team/rizzo/base/callerid.c
    team/rizzo/base/cdr.c
    team/rizzo/base/cdr/Makefile
    team/rizzo/base/channel.c
    team/rizzo/base/channels/chan_agent.c
    team/rizzo/base/channels/chan_features.c
    team/rizzo/base/channels/chan_iax2.c
    team/rizzo/base/channels/chan_local.c
    team/rizzo/base/channels/chan_oss.c
    team/rizzo/base/channels/chan_sip.c
    team/rizzo/base/channels/chan_zap.c
    team/rizzo/base/channels/iax2-provision.c
    team/rizzo/base/channels/iax2-provision.h
    team/rizzo/base/cli.c
    team/rizzo/base/codecs/gsm/Makefile
    team/rizzo/base/config.c
    team/rizzo/base/dnsmgr.c
    team/rizzo/base/file.c
    team/rizzo/base/formats/format_pcm_alaw.c
    team/rizzo/base/funcs/func_strings.c
    team/rizzo/base/include/asterisk.h
    team/rizzo/base/include/asterisk/cdr.h
    team/rizzo/base/include/asterisk/channel.h
    team/rizzo/base/include/asterisk/cli.h
    team/rizzo/base/include/asterisk/config.h
    team/rizzo/base/include/asterisk/lock.h
    team/rizzo/base/include/asterisk/module.h
    team/rizzo/base/include/asterisk/pbx.h
    team/rizzo/base/include/asterisk/rtp.h
    team/rizzo/base/include/asterisk/say.h
    team/rizzo/base/include/asterisk/time.h
    team/rizzo/base/include/asterisk/utils.h
    team/rizzo/base/loader.c
    team/rizzo/base/manager.c
    team/rizzo/base/pbx.c
    team/rizzo/base/pbx/pbx_config.c
    team/rizzo/base/pbx/pbx_dundi.c
    team/rizzo/base/pbx/pbx_loopback.c
    team/rizzo/base/res/res_agi.c
    team/rizzo/base/res/res_clioriginate.c
    team/rizzo/base/res/res_features.c
    team/rizzo/base/res/res_monitor.c
    team/rizzo/base/rtp.c
    team/rizzo/base/utils.c

Modified: team/rizzo/base/Makefile
URL: http://svn.digium.com/view/asterisk/team/rizzo/base/Makefile?rev=8864&r1=8863&r2=8864&view=diff
==============================================================================
--- team/rizzo/base/Makefile (original)
+++ team/rizzo/base/Makefile Sun Jan 29 08:57:22 2006
@@ -13,6 +13,22 @@
 
 .EXPORT_ALL_VARIABLES:
 
+# User-definable variables used here:
+#
+#	CROSS_COMPILE	path to the cross-compile tools
+#	DESTDIR		destination directory
+#	WITHOUT_xxx	build toggles
+#	MAKECMDGOALS	set of goals for the makefile (to be completed)
+#	OVERWRITE	overwrite config files on 'make samples'
+#	DEBUG		debug compiler flags
+#	OPTIMIZE	optimize compiler flags
+
+# you can also put initial values for these:
+#
+#	CFLAGS		compiler flags
+#	SOFLAGS		linker flags
+#
+
 # Create OPTIONS variable
 OPTIONS=
 # If cross compiling, define these to suit
@@ -37,14 +53,14 @@
 MAKETOPLEVEL?=$(MAKELEVEL)
 
 ifneq ($(findstring dont-optimize,$(MAKECMDGOALS)),dont-optimize)
-######### More GSM codec optimization
-######### Uncomment to enable MMXTM optimizations for x86 architecture CPU's
-######### which support MMX instructions.  This should be newer pentiums,
-######### ppro's, etc, as well as the AMD K6 and K7.  
-#K6OPT  = -DK6OPT
-
-#Tell gcc to optimize the code
-OPTIMIZE+=-O6
+  # More GSM codec optimization
+  # Uncomment to enable MMXTM optimizations for x86 architecture CPU's
+  # which support MMX instructions.  This should be newer pentiums,
+  # ppro's, etc, as well as the AMD K6 and K7.  
+  # K6OPT  = -DK6OPT
+
+  # Tell gcc to optimize the code
+  OPTIMIZE?=-O2
 else
   # Stack backtraces, while useful for debugging, are incompatible with optimizations
   ifeq (${OSARCH},Linux)
@@ -53,10 +69,10 @@
 endif
 
 #Overwite config files on "make samples"
-OVERWRITE=y
+OVERWRITE?=y
 
 #Include debug and macro symbols in the executables (-g) and profiling info (-pg)
-DEBUG=-g3 #-pg
+DEBUG?=-g3 #-pg
 
 #Set NOCRYPTO to yes if you do not want to have crypto support or 
 #dependencies
@@ -95,7 +111,7 @@
 # For example, make DESTDIR=/tmp/asterisk woud put things in
 # /tmp/asterisk/etc/asterisk
 # XXX watch out, put no spaces or comments after the value
-DESTDIR?=
+DESTDIR?=/tmp/test_ast
 #DESTDIR?=/tmp/asterisk
 
 # Original busydetect routine
@@ -225,11 +241,13 @@
 INCLUDE+=-Iinclude -I../include
 ASTCFLAGS+=-pipe  -Wall -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations $(DEBUG) $(INCLUDE) -D_REENTRANT -D_GNU_SOURCE #-DMAKE_VALGRIND_HAPPY
 ASTCFLAGS+=$(OPTIMIZE)
+ASTCFLAGS+= -Werror -Wunused -Wl,--export-dynamic
 ASTOBJ=-o asterisk
 
 ifeq ($(findstring BSD,$(OSARCH)),BSD)
   PROC=$(shell uname -m)
   ASTCFLAGS+=-I$(CROSS_COMPILE_TARGET)/usr/local/include -L$(CROSS_COMPILE_TARGET)/usr/local/lib
+  SOLINK+= -L$(CROSS_COMPILE_TARGET)/usr/local/lib
 endif
 
 ifneq ($(PROC),ultrasparc)
@@ -252,6 +270,8 @@
   BSDVERSION=$(shell make -V OSVERSION -f $(CROSS_COMPILE_TARGET)/usr/share/mk/bsd.port.subdir.mk)
   ASTCFLAGS+=$(shell if test $(BSDVERSION) -lt 500016 ; then echo "-D_THREAD_SAFE"; fi)
   LIBS+=$(shell if test  $(BSDVERSION) -lt 502102 ; then echo "-lc_r"; else echo "-pthread"; fi)
+  # XXX libexecinfo
+  # LIBS+= -L/usr/local/lib -lexecinfo
   ifneq ($(wildcard $(CROSS_COMPILE_TARGET)/usr/local/include/spandsp),)
     ASTCFLAGS+=-I$(CROSS_COMPILE_TARGET)/usr/local/include/spandsp
   endif
@@ -338,13 +358,13 @@
 ASTCFLAGS+= $(BUSYDETECT)
 ASTCFLAGS+= $(OPTIONS)
 ifneq ($(findstring dont-optimize,$(MAKECMDGOALS)),dont-optimize)
-ASTCFLAGS+= -fomit-frame-pointer 
+#ASTCFLAGS+= -fomit-frame-pointer 
 endif
 
 SUBDIRS=res channels pbx apps codecs formats agi cdr funcs utils stdtime
 
 OBJS=io.o sched.o logger.o frame.o loader.o config.o channel.o \
-	translate.o file.o say.o pbx.o cli.o md5.o term.o \
+	translate.o file.o say2.o pbx.o cli.o md5.o term.o \
 	ulaw.o alaw.o callerid.o fskmodem.o image.o app.o \
 	cdr.o tdd.o acl.o rtp.o udptl.o manager.o asterisk.o \
 	dsp.o chanvars.o indications.o autoservice.o db.o privacy.o \
@@ -352,6 +372,14 @@
 	utils.o plc.o jitterbuf.o dnsmgr.o devicestate.o \
 	netsock.o slinfactory.o ast_expr2.o ast_expr2f.o \
 	cryptostub.o
+
+SAY_SRCS=	say2.c	\
+		say/say_cz.c	say/say_da.c	say/say_de.c	\
+		say/say_en_GB.c	say/say_es.c	say/say_fr.c	\
+		say/say_gr.c	say/say_he.c	say/say_it.c	\
+		say/say_nl.c	say/say_no.c	say/say_pl.c	\
+		say/say_pt.c	say/say_ru.c	say/say_se.c	\
+		say/say_tw.c
 
 ifeq ($(wildcard $(CROSS_COMPILE_TARGET)/usr/include/sys/poll.h),)
   OBJS+= poll.o
@@ -380,7 +408,9 @@
 else
 #These are used for all but Darwin
   ASTLINK=-Wl,-E 
-  SOLINK=-shared -Xlinker -x
+  # XXX added -Wl,-E to SOLINK for debugging
+  #SOLINK=-shared -Xlinker -x -Wl,-E
+  SOLINK=-shared -Wl,-E
   ifeq ($(findstring BSD,$(OSARCH)),BSD)
     SOLINK+=-L$(CROSS_COMPILE_TARGET)/usr/local/lib
   endif
@@ -465,6 +495,14 @@
 ifneq ($(wildcard .tags-depend),)
   include .tags-depend
 endif
+
+say2.o: $(SAY_SRCS)
+
+ast_expr2f.o:
+	$(CC) -c $(CFLAGS:-Werror=) $*.c	# XXX gmake confused ?
+
+ast_expr2.o:
+	$(CC) -c $(CFLAGS:-Werror=) $*.c	# XXX gmake confused ?
 
 ast_expr2.c:
 	bison -d --name-prefix=ast_yy ast_expr2.y -o ast_expr2.c

Modified: team/rizzo/base/agi/Makefile
URL: http://svn.digium.com/view/asterisk/team/rizzo/base/agi/Makefile?rev=8864&r1=8863&r2=8864&view=diff
==============================================================================
--- team/rizzo/base/agi/Makefile (original)
+++ team/rizzo/base/agi/Makefile Sun Jan 29 08:57:22 2006
@@ -18,10 +18,6 @@
 LIBS=
 ifeq ($(OSARCH),SunOS)
   LIBS=-lsocket -lnsl ../strcompat.o
-endif
-
-ifeq ($(findstring BSD,${OSARCH}),BSD)
-  CFLAGS+=-I$(CROSS_COMPILE_TARGET)/usr/local/include -L$(CROSS_COMPILE_TARGET)/usr/local/lib
 endif
 
 all: depend $(AGIS)

Modified: team/rizzo/base/app.c
URL: http://svn.digium.com/view/asterisk/team/rizzo/base/app.c?rev=8864&r1=8863&r2=8864&view=diff
==============================================================================
--- team/rizzo/base/app.c (original)
+++ team/rizzo/base/app.c Sun Jan 29 08:57:22 2006
@@ -1546,14 +1546,13 @@
 
 	s = optstr;
 	while (*s) {
-		curarg = *s++ & 0x7f;
+		curarg = *s++ & 0x7f;	/* the array (in app.h) has 128 entries */
 		ast_set_flag(flags, options[curarg].flag);
 		argloc = options[curarg].arg_index;
 		if (*s == '(') {
 			/* Has argument */
 			arg = ++s;
-			while (*s && (*s != ')'))
-				s++;
+			s = strchr(s, ')');
 			if (*s) {
 				if (argloc)
 					args[argloc - 1] = arg;

Modified: team/rizzo/base/apps/Makefile
URL: http://svn.digium.com/view/asterisk/team/rizzo/base/apps/Makefile?rev=8864&r1=8863&r2=8864&view=diff
==============================================================================
--- team/rizzo/base/apps/Makefile (original)
+++ team/rizzo/base/apps/Makefile Sun Jan 29 08:57:22 2006
@@ -13,7 +13,7 @@
 
 APPS=app_adsiprog.so app_alarmreceiver.so app_authenticate.so app_cdr.so       \
      app_chanisavail.so app_chanspy.so app_controlplayback.so app_db.so        \
-     app_dial.so app_dictate.so app_directed_pickup.so app_directory.so        \
+     app_dial2.so app_dictate.so app_directed_pickup.so app_directory.so        \
      app_disa.so app_dumpchan.so app_echo.so app_exec.so app_externalivr.so    \
      app_festival.so app_forkcdr.so app_getcpeid.so app_hasnewvoicemail.so     \
      app_ices.so app_image.so app_lookupblacklist.so app_lookupcidname.so      \
@@ -27,6 +27,7 @@
      app_waitforring.so app_waitforsilence.so app_while.so app_zapateller.so   \
      app_morsecode.so
      
+#     app_say_number.so
 #
 # Obsolete things...
 #
@@ -51,7 +52,7 @@
 endif
 
 CURLLIBS=$(shell $(CROSS_COMPILE_BIN)curl-config --libs)
-ifneq ($(shell if [[ 0x`$(CROSS_COMPILE_BIN)curl-config --vernum` -ge 0x70907 ]]; then echo "OK" ; fi),)
+ifneq ($(shell if [ 0x`$(CROSS_COMPILE_BIN)curl-config --vernum` -ge 0x70907 ]; then echo "OK" ; fi),)
   ifneq (${CURLLIBS},)
     APPS+=app_curl.so
   endif 

Added: team/rizzo/base/apps/app_dial2.c
URL: http://svn.digium.com/view/asterisk/team/rizzo/base/apps/app_dial2.c?rev=8864&view=auto
==============================================================================
--- team/rizzo/base/apps/app_dial2.c (added)
+++ team/rizzo/base/apps/app_dial2.c Sun Jan 29 08:57:22 2006
@@ -1,0 +1,1670 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 1999 - 2005, Digium, Inc.
+ *
+ * Mark Spencer <markster at digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief dial() & retrydial() - Trivial application to dial a channel and send an URL on answer
+ *
+ * \author Mark Spencer <markster at digium.com>
+ * 
+ * \ingroup applications
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/signal.h>
+#include <netinet/in.h>
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision: 8379 $")
+
+#include "asterisk/lock.h"
+#include "asterisk/file.h"
+#include "asterisk/logger.h"
+#include "asterisk/channel.h"
+#include "asterisk/pbx.h"
+#include "asterisk/options.h"
+#include "asterisk/module.h"
+#include "asterisk/translate.h"
+#include "asterisk/say.h"
+#include "asterisk/config.h"
+#include "asterisk/features.h"
+#include "asterisk/musiconhold.h"
+#include "asterisk/callerid.h"
+#include "asterisk/utils.h"
+#include "asterisk/app.h"
+#include "asterisk/causes.h"
+#include "asterisk/manager.h"
+#include "asterisk/privacy.h"
+#include "asterisk/rtp.h"
+
+static char *tdesc = "Dialing Application";
+
+static char *app = "Dial";
+
+static char *synopsis = "Place a call and connect to the current channel";
+
+static char *descrip =
+"  Dial(Technology/resource[&Tech2/resource2...][|timeout][|options][|URL]):\n"
+"This applicaiton will place calls to one or more specified channels. As soon\n"
+"as one of the requested channels answers, the originating channel will be\n"
+"answered, if it has not already been answered. These two channels will then\n"
+"be active in a bridged call. All other channels that were requested will then\n"
+"be hung up.\n"
+"  Unless there is a timeout specified, the Dial application will wait\n"
+"indefinitely until one of the called channels answers, the user hangs up, or\n"
+"if all of the called channels are busy or unavailable. Dialplan executing will\n"
+"continue if no requested channels can be called, or if the timeout expires.\n\n"
+"  This application sets the following channel variables upon completion:\n"
+"    DIALEDTIME   - This is the time from dialing a channel until when it\n"
+"                   is disconnected.\n" 
+"    ANSWEREDTIME - This is the amount of time for actual call.\n"
+"    DIALSTATUS   - This is the status of the call:\n"
+"                   CHANUNAVAIL | CONGESTION | NOANSWER | BUSY | ANSWER | CANCEL\n" 
+"                   DONTCALL | TORTURE\n"
+"  For the Privacy and Screening Modes, the DIALSTATUS variable will be set to\n"
+"DONTCALL if the called party chooses to send the calling party to the 'Go Away'\n"
+"script. The DIALSTATUS variable will be set to TORTURE if the called party\n"
+"wants to send the caller to the 'torture' script.\n"
+"  This application will report normal termination if the originating channel\n"
+"hangs up, or if the call is bridged and either of the parties in the bridge\n"
+"ends the call.\n"
+"  The optional URL will be sent to the called party if the channel supports it.\n"
+"  If the OUTBOUND_GROUP variable is set, all peer channels created by this\n"
+"application will be put into that group (as in Set(GROUP()=...).\n\n"
+"  Options:\n"
+"    A(x) - Play an announcement to the called party, using 'x' as the file.\n"
+"    C    - Reset the CDR for this call.\n"
+"    d    - Allow the calling user to dial a 1 digit extension while waiting for\n"
+"           a call to be answered. Exit to that extension if it exists in the\n"
+"           current context, or the context defined in the EXITCONTEXT variable,\n"
+"           if it exists.\n"
+"    D([called][:calling]) - Send the specified DTMF strings *after* the called\n"
+"           party has answered, but before the call gets bridged. The 'called'\n"
+"           DTMF string is sent to the called party, and the 'calling' DTMF\n"
+"           string is sent to the calling party. Both parameters can be used\n"
+"           alone.\n"  	
+"    f    - Force the callerid of the *calling* channel to be set as the\n"
+"           extension associated with the channel using a dialplan 'hint'.\n"
+"           For example, some PSTNs do not allow CallerID to be set to anything\n"
+"           other than the number assigned to the caller.\n"
+"    g    - Proceed with dialplan execution at the current extension if the\n"
+"           destination channel hangs up.\n"
+"    G(context^exten^pri) - If the call is answered, transfer both parties to\n"
+"           the specified priority. Optionally, an extension, or extension and\n"
+"           context may be specified. Otherwise, the current extension is used.\n"
+"    h    - Allow the called party to hang up by sending the '*' DTMF digit.\n"
+"    H    - Allow the calling party to hang up by hitting the '*' DTMF digit.\n"
+"    j    - Jump to priority n+101 if all of the requested channels were busy.\n"
+"    L(x[:y][:z]) - Limit the call to 'x' ms. Play a warning when 'y' ms are\n"
+"           left. Repeat the warning every 'z' ms. The following special\n"
+"           variables can be used with this option:\n"
+"           * LIMIT_PLAYAUDIO_CALLER   yes|no (default yes)\n"
+"                                      Play sounds to the caller.\n"
+"           * LIMIT_PLAYAUDIO_CALLEE   yes|no\n"
+"                                      Play sounds to the callee.\n"
+"           * LIMIT_TIMEOUT_FILE       File to play when time is up.\n"
+"           * LIMIT_CONNECT_FILE       File to play when call begins.\n"
+"           * LIMIT_WARNING_FILE       File to play as warning if 'y' is defined.\n"
+"                                      The default is to say the time remaining.\n"
+"    m([class]) - Provide hold music to the calling party until a requested\n"
+"           channel answers. A specific MusicOnHold class can be\n"
+"           specified.\n"
+"    M(x[^arg]) - Execute the Macro for the *called* channel before connecting\n"
+"           to the calling channel. Arguments can be specified to the Macro\n"
+"           using '^' as a delimeter. The Macro can set the variable\n"
+"           MACRO_RESULT to specify the following actions after the Macro is\n" 
+"           finished executing.\n"
+"           * ABORT        Hangup both legs of the call.\n"
+"           * CONGESTION   Behave as if line congestion was encountered.\n"
+"           * BUSY         Behave as if a busy signal was encountered. This will also\n"
+"                          have the application jump to priority n+101 if the\n"
+"                          'j' option is set.\n"
+"           * CONTINUE     Hangup the called party and allow the calling party\n"
+"                          to continue dialplan execution at the next priority.\n"
+"           * GOTO:<context>^<exten>^<priority> - Transfer the call to the\n"
+"                          specified priority. Optionally, an extension, or\n"
+"                          extension and priority can be specified.\n"
+"    n    - This option is a modifier for the screen/privacy mode. It specifies\n"
+"           that no introductions are to be saved in the priv-callerintros\n"
+"           directory.\n"
+"    N    - This option is a modifier for the screen/privacy mode. It specifies\n"
+"           that if callerID is present, do not screen the call.\n"
+"    o    - Specify that the CallerID that was present on the *calling* channel\n"
+"           be set as the CallerID on the *called* channel. This was the\n"
+"           behavior of Asterisk 1.0 and earlier.\n"
+"    p    - This option enables screening mode. This is basically Privacy mode\n"
+"           without memory.\n"
+"    P([x]) - Enable privacy mode. Use 'x' as the family/key in the database if\n"
+"           it is provided. The current extension is used if a database\n"
+"           family/key is not specified.\n"
+"    r    - Indicate ringing to the calling party. Pass no audio to the calling\n"
+"           party until the called channel has answered.\n"
+"    S(x) - Hang up the call after 'x' seconds *after* the called party has\n"
+"           answered the call.\n"  	
+"    t    - Allow the called party to transfer the calling party by sending the\n"
+"           DTMF sequence defined in features.conf.\n"
+"    T    - Allow the calling party to transfer the called party by sending the\n"
+"           DTMF sequence defined in features.conf.\n"
+"    w    - Allow the called party to enable recording of the call by sending\n"
+"           the DTMF sequence defined for one-touch recording in features.conf.\n"
+"    W    - Allow the calling party to enable recording of the call by sending\n"
+"           the DTMF sequence defined for one-touch recording in features.conf.\n";
+
+/* RetryDial App by Anthony Minessale II <anthmct at yahoo.com> Jan/2005 */
+static char *rapp = "RetryDial";
+static char *rsynopsis = "Place a call, retrying on failure allowing optional exit extension.";
+static char *rdescrip =
+"  RetryDial(announce|sleep|retries|dialargs): This application will attempt to\n"
+"place a call using the normal Dial application. If no channel can be reached,\n"
+"the 'announce' file will be played. Then, it will wait 'sleep' number of\n"
+"seconds before retying the call. After 'retires' number of attempts, the\n"
+"calling channel will continue at the next priority in the dialplan. If the\n"
+"'retries' setting is set to 0, this application will retry endlessly.\n"
+"  While waiting to retry a call, a 1 digit extension may be dialed. If that\n"
+"extension exists in either the context defined in ${EXITCONTEXT} or the current\n"
+"one, The call will jump to that extension immediately.\n"
+"  The 'dialargs' are specified in the same format that arguments are provided\n"
+"to the Dial application.\n";
+
+enum {
+	OPT_ANNOUNCE =		(1 << 0),
+	OPT_RESETCDR =		(1 << 1),
+	OPT_DTMF_EXIT =		(1 << 2),
+	OPT_SENDDTMF =		(1 << 3),
+	OPT_FORCECLID =		(1 << 4),
+	OPT_GO_ON =		(1 << 5),
+	OPT_CALLEE_HANGUP =	(1 << 6),
+	OPT_CALLER_HANGUP =	(1 << 7),
+	OPT_PRIORITY_JUMP =	(1 << 8),
+	OPT_DURATION_LIMIT =	(1 << 9),
+	OPT_MUSICBACK =		(1 << 10),
+	OPT_CALLEE_MACRO =	(1 << 11),
+	OPT_SCREEN_NOINTRO =	(1 << 12),
+	OPT_SCREEN_NOCLID =	(1 << 13),
+	OPT_ORIGINAL_CLID =	(1 << 14),
+	OPT_SCREENING =		(1 << 15),
+	OPT_PRIVACY =		(1 << 16),
+	OPT_RINGBACK =		(1 << 17),
+	OPT_DURATION_STOP =	(1 << 18),
+	OPT_CALLEE_TRANSFER =	(1 << 19),
+	OPT_CALLER_TRANSFER =	(1 << 20),
+	OPT_CALLEE_MONITOR =	(1 << 21),
+	OPT_CALLER_MONITOR =	(1 << 22),
+	OPT_GOTO =		(1 << 23),
+} dial_exec_option_flags;
+
+#define DIAL_STILLGOING			(1 << 30)
+#define DIAL_NOFORWARDHTML		(1 << 31)
+
+enum {
+	OPT_ARG_ANNOUNCE = 0,
+	OPT_ARG_SENDDTMF,
+	OPT_ARG_GOTO,
+	OPT_ARG_DURATION_LIMIT,
+	OPT_ARG_MUSICBACK,
+	OPT_ARG_CALLEE_MACRO,
+	OPT_ARG_PRIVACY,
+	OPT_ARG_DURATION_STOP,
+	/* note: this entry _MUST_ be the last one in the enum */
+	OPT_ARG_ARRAY_SIZE,
+} dial_exec_option_args;
+
+AST_APP_OPTIONS(dial_exec_options, {
+	AST_APP_OPTION_ARG('A', OPT_ANNOUNCE, OPT_ARG_ANNOUNCE),
+	AST_APP_OPTION('C', OPT_RESETCDR),
+	AST_APP_OPTION('d', OPT_DTMF_EXIT),
+	AST_APP_OPTION_ARG('D', OPT_SENDDTMF, OPT_ARG_SENDDTMF),
+	AST_APP_OPTION('f', OPT_FORCECLID),
+	AST_APP_OPTION('g', OPT_GO_ON),
+	AST_APP_OPTION_ARG('G', OPT_GOTO, OPT_ARG_GOTO),
+	AST_APP_OPTION('h', OPT_CALLEE_HANGUP),
+	AST_APP_OPTION('H', OPT_CALLER_HANGUP),
+	AST_APP_OPTION('j', OPT_PRIORITY_JUMP),
+	AST_APP_OPTION_ARG('L', OPT_DURATION_LIMIT, OPT_ARG_DURATION_LIMIT),
+	AST_APP_OPTION_ARG('m', OPT_MUSICBACK, OPT_ARG_MUSICBACK),
+	AST_APP_OPTION_ARG('M', OPT_CALLEE_MACRO, OPT_ARG_CALLEE_MACRO),
+	AST_APP_OPTION('n', OPT_SCREEN_NOINTRO),
+	AST_APP_OPTION('N', OPT_SCREEN_NOCLID),
+	AST_APP_OPTION('o', OPT_ORIGINAL_CLID),
+	AST_APP_OPTION('p', OPT_SCREENING),
+	AST_APP_OPTION_ARG('P', OPT_PRIVACY, OPT_ARG_PRIVACY),
+	AST_APP_OPTION('r', OPT_RINGBACK),
+	AST_APP_OPTION_ARG('S', OPT_DURATION_STOP, OPT_ARG_DURATION_STOP),
+	AST_APP_OPTION('t', OPT_CALLEE_TRANSFER),
+	AST_APP_OPTION('T', OPT_CALLER_TRANSFER),
+	AST_APP_OPTION('w', OPT_CALLEE_MONITOR),
+	AST_APP_OPTION('W', OPT_CALLER_MONITOR),
+});
+
+/* We define a custom "local user" structure because we
+   use it not only for keeping track of what is in use but
+   also for keeping track of who we're dialing. */
+
+struct dial_localuser {
+	struct ast_channel *chan;
+	unsigned int flags;
+	int forwards;
+	struct dial_localuser *next;
+};
+
+LOCAL_USER_DECL;
+
+static void hanguptree(struct dial_localuser *outgoing, struct ast_channel *exception)
+{
+	/* Hang up a tree of stuff */
+	struct dial_localuser *oo;
+	while (outgoing) {
+		/* Hangup any existing lines we have open */
+		if (outgoing->chan && (outgoing->chan != exception))
+			ast_hangup(outgoing->chan);
+		oo = outgoing;
+		outgoing=outgoing->next;
+		free(oo);
+	}
+}
+
+#define AST_MAX_FORWARDS   8
+
+#define AST_MAX_WATCHERS 256
+
+/*
+ * argument to handle_cause() and other functions.
+ */
+struct cause_args {
+	struct ast_channel *chan;
+	int busy;
+	int congestion;
+	int nochan;
+};
+
+static void handle_cause(int cause, struct cause_args *num)
+{
+	struct ast_cdr *cdr = num->chan->cdr;
+
+	switch(cause) {
+	case AST_CAUSE_BUSY:
+		if (cdr)
+			ast_cdr_busy(cdr);
+		num->busy++;
+		break;
+	case AST_CAUSE_CONGESTION:
+		if (cdr)
+			ast_cdr_failed(cdr);
+		num->congestion++;
+		break;
+	case AST_CAUSE_UNREGISTERED:
+		if (cdr)
+			ast_cdr_failed(cdr);
+		num->nochan++;
+		break;
+	default:
+		num->nochan++;
+		break;
+	}
+}
+
+
+/* return first string if not empty, otherwise second */
+#define S_OR(a, b)	(!ast_strlen_zero(a) ? (a) : (b))
+
+/* free the buffer if allocated, and set the pointer to the second arg */
+#define S_REPLACE(s, new)	\
+	do {					\
+		if (s)				\
+			free(s);		\
+		s = (new);			\
+	} while (0)
+
+
+static int onedigit_goto(struct ast_channel *chan, const char *context, char exten, int pri) 
+{
+	char rexten[2] = { exten, '\0' };
+
+	if (context) {
+		if (!ast_goto_if_exists(chan, context, rexten, pri))
+			return 1;
+	} else {
+		if (!ast_goto_if_exists(chan, chan->context, rexten, pri))
+			return 1;
+		else if (!ast_strlen_zero(chan->macrocontext)) {
+			if (!ast_goto_if_exists(chan, chan->macrocontext, rexten, pri))
+				return 1;
+		}
+	}
+	return 0;
+}
+
+
+static char *get_cid_name(char *name, int namelen, struct ast_channel *chan)
+{
+	char *context = S_OR(chan->macrocontext, chan->context);
+	char *exten = S_OR(chan->macroexten, chan->exten);
+	if (ast_get_hint(NULL, 0, name, namelen, chan, context, exten))
+		return name;
+	else
+		return "";
+}
+
+static void senddialevent(struct ast_channel *src, struct ast_channel *dst)
+{
+	manager_event(EVENT_FLAG_CALL, "Dial", 
+			   "Source: %s\r\n"
+			   "Destination: %s\r\n"
+			   "CallerID: %s\r\n"
+			   "CallerIDName: %s\r\n"
+			   "SrcUniqueID: %s\r\n"
+			   "DestUniqueID: %s\r\n",
+			   src->name, dst->name, src->cid.cid_num ? src->cid.cid_num : "<unknown>",
+			   src->cid.cid_name ? src->cid.cid_name : "<unknown>", src->uniqueid,
+			   dst->uniqueid);
+}
+
+static void do_forward_base(struct dial_localuser *o, int *cause, struct cause_args *num, struct ast_flags *peerflags, char *tmpchan, int tmpchanlen)
+{
+	char *stuff;
+	char *tech;
+	struct ast_channel *winner = o->chan; /* the winner */
+	struct ast_channel *in = num->chan; /* the input channel */
+
+	ast_copy_string(tmpchan, winner->call_forward, tmpchanlen);
+	if ((stuff = strchr(tmpchan, '/'))) {
+		*stuff++ = '\0';
+		tech = tmpchan;
+	} else {
+		snprintf(tmpchan, tmpchanlen, "%s@%s", winner->call_forward, winner->context);
+		stuff = tmpchan;
+		tech = "Local";
+	}
+	/* Before processing channel, go ahead and check for forwarding */
+	o->forwards++;
+	if (o->forwards < AST_MAX_FORWARDS) {
+		if (option_verbose > 2)
+			ast_verbose(VERBOSE_PREFIX_3 "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, winner->name);
+		/* Setup parameters */
+		o->chan = ast_request(tech, in->nativeformats, stuff, cause);
+		if (!o->chan)
+			ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s' (cause = %d)\n", tech, stuff, *cause);
+	} else {
+		if (option_verbose > 2)
+			ast_verbose(VERBOSE_PREFIX_3 "Too many forwards from %s\n", o->chan->name);
+		*cause = AST_CAUSE_CONGESTION;
+		o->chan = NULL;
+	}
+}
+
+static void do_forward(struct dial_localuser *o, int *cause, struct cause_args *num, struct ast_flags *peerflags)
+{
+	char tmpchan[256];
+	struct ast_channel *winner = o->chan; /* the winner */
+	struct ast_channel *in = num->chan; /* the input channel */
+
+	do_forward_base(o, cause, num, peerflags, tmpchan, sizeof(tmpchan));
+
+	if (!o->chan) {
+		ast_clear_flag(o, DIAL_STILLGOING);	
+		handle_cause(*cause, num);
+	} else {
+		struct ast_channel *c = o->chan;
+		char *new_cid_num;
+		char *new_cid_name;
+		struct ast_channel *src;
+
+		ast_rtp_make_compatible(o->chan, in);
+		if (ast_test_flag(o, OPT_FORCECLID)) {
+			new_cid_num = S_OR(in->macroexten, in->exten);
+			new_cid_name = NULL; /* XXX no name ? */
+			src = winner;
+		} else {
+			new_cid_num = in->cid.cid_num;
+			new_cid_name = in->cid.cid_name;
+			src = in;
+		}
+
+		S_REPLACE(c->cid.cid_num, new_cid_num);
+		S_REPLACE(c->cid.cid_name, new_cid_name);
+		S_REPLACE(c->cid.cid_ani, ast_strdup(in->cid.cid_ani));
+		S_REPLACE(c->cid.cid_rdnis, ast_strdup(S_OR(in->macroexten, in->exten)));
+		ast_copy_string(c->accountcode, src->accountcode, sizeof(c->accountcode));
+		c->cdrflags = src->cdrflags;
+
+		if (ast_call(c, tmpchan, 0)) {
+			ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan);
+			ast_clear_flag(o, DIAL_STILLGOING);	
+			ast_hangup(c);
+			o->chan = NULL;
+			num->nochan++;
+		} else {
+			senddialevent(in, c);
+			/* After calling, set callerid to extension */
+			if (!ast_test_flag(peerflags, OPT_ORIGINAL_CLID)) {
+				char cidname[AST_MAX_EXTENSION];
+				ast_set_callerid(c, ast_strlen_zero(in->macroexten) ? in->exten : in->macroexten,
+					get_cid_name(cidname, sizeof(cidname), in), NULL);
+			}
+		}
+	}
+	/* Hangup the original channel now, in case we needed it */
+	ast_hangup(winner);
+}
+
+/* argument used for some functions. */
+struct privacy_args {
+	int sentringing;
+	int privdb_val;
+	char privcid[256];
+	char privintro[1024];
+	char status[256];
+};
+
+static struct ast_channel *wait_for_answer(struct ast_channel *in, struct dial_localuser *outgoing, int *to, struct ast_flags *peerflags,
+		struct privacy_args *pa, const struct cause_args *num_in, int priority_jump, int *result)
+{
+	struct cause_args num = *num_in;
+	int prestart = num.busy + num.congestion + num.nochan;
+	int cause;
+	int orig = *to;
+	struct ast_channel *peer = NULL;
+	struct ast_channel *watchers[AST_MAX_WATCHERS];
+	int single;
+
+	single = (outgoing && !outgoing->next && !ast_test_flag(outgoing, OPT_MUSICBACK | OPT_RINGBACK));
+	
+	if (single) {
+		/* Turn off hold music, etc */
+		ast_deactivate_generator(in);
+		/* If we are calling a single channel, make them compatible for in-band tone purpose */
+		ast_channel_make_compatible(outgoing->chan, in);
+	}
+	
+	
+	while (*to && !peer) {
+		struct ast_channel *winner;
+		int pos = 0;
+		int numlines = prestart;
+		struct dial_localuser *o;
+
+		watchers[pos++] = in;
+		for (o = outgoing; o; o = o->next) {
+			/* Keep track of important channels */
+			if (ast_test_flag(o, DIAL_STILLGOING) && o->chan)
+				watchers[pos++] = o->chan;
+			numlines++;
+		}
+		if (pos == 1) {	/* only the input channel available */
+			if (numlines == (num.busy + num.congestion + num.nochan)) {
+				if (option_verbose > 2)
+					ast_verbose(VERBOSE_PREFIX_3 "Everyone is busy/congested at this time (%d:%d/%d/%d)\n", numlines, num.busy, num.congestion, num.nochan);
+				if (num.busy)
+					strcpy(pa->status, "BUSY");	
+				else if (num.congestion)
+					strcpy(pa->status, "CONGESTION");
+				else if (num.nochan)
+					strcpy(pa->status, "CHANUNAVAIL");
+				if (ast_opt_priority_jumping || priority_jump)
+					ast_goto_if_exists(in, in->context, in->exten, in->priority + 101);
+			} else {
+				if (option_verbose > 2)
+					ast_verbose(VERBOSE_PREFIX_3 "No one is available to answer at this time (%d:%d/%d/%d)\n", numlines, num.busy, num.congestion, num.nochan);
+			}
+			*to = 0;
+			return NULL;
+		}
+		winner = ast_waitfor_n(watchers, pos, to);
+		for (o = outgoing; o; o = o->next) {
+			struct ast_frame *f;
+			struct ast_channel *c = o->chan;
+
+			if (c == NULL)
+				continue;
+			if (ast_test_flag(o, DIAL_STILLGOING) && c->_state == AST_STATE_UP) {
+				if (!peer) {
+					if (option_verbose > 2)
+						ast_verbose(VERBOSE_PREFIX_3 "%s answered %s\n", c->name, in->name);
+					peer = c;
+					ast_copy_flags(peerflags, o,
+						       OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER |
+						       OPT_CALLEE_HANGUP | OPT_CALLER_HANGUP |
+						       OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR |
+						       DIAL_NOFORWARDHTML);
+				}
+				continue;
+			}
+			if (c != winner)
+				continue;
+			if (!ast_strlen_zero(c->call_forward)) {
+				do_forward(o, &cause, &num, peerflags);
+				continue;
+			}
+			f = ast_read(winner);
+			if (f == NULL) {
+				in->hangupcause = o->chan->hangupcause;
+				ast_hangup(o->chan);
+				o->chan = NULL;
+				ast_clear_flag(o, DIAL_STILLGOING);
+				continue;
+			}
+			if (f->frametype == AST_FRAME_CONTROL) {
+				switch(f->subclass) {
+				case AST_CONTROL_ANSWER:
+					/* This is our guy if someone answered. */
+					if (!peer) {
+						if (option_verbose > 2)
+							ast_verbose(VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
+						peer = o->chan;
+						ast_copy_flags(peerflags, o,
+							       OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER |
+							       OPT_CALLEE_HANGUP | OPT_CALLER_HANGUP |
+							       OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR |
+							       DIAL_NOFORWARDHTML);
+					}
+					/* If call has been answered, then the eventual hangup is likely to be normal hangup */
+					in->hangupcause = AST_CAUSE_NORMAL_CLEARING;
+					o->chan->hangupcause = AST_CAUSE_NORMAL_CLEARING;
+					break;
+				case AST_CONTROL_BUSY:
+					if (option_verbose > 2)
+						ast_verbose(VERBOSE_PREFIX_3 "%s is busy\n", o->chan->name);
+					in->hangupcause = o->chan->hangupcause;
+					ast_hangup(o->chan);
+					o->chan = NULL;
+					ast_clear_flag(o, DIAL_STILLGOING);	
+					handle_cause(AST_CAUSE_BUSY, &num);
+					break;
+				case AST_CONTROL_CONGESTION:
+					if (option_verbose > 2)
+						ast_verbose(VERBOSE_PREFIX_3 "%s is circuit-busy\n", o->chan->name);
+					in->hangupcause = o->chan->hangupcause;
+					ast_hangup(o->chan);
+					o->chan = NULL;
+					ast_clear_flag(o, DIAL_STILLGOING);
+					handle_cause(AST_CAUSE_CONGESTION, &num);
+					break;
+				case AST_CONTROL_RINGING:
+					if (option_verbose > 2)
+						ast_verbose(VERBOSE_PREFIX_3 "%s is ringing\n", o->chan->name);
+					if (!pa->sentringing && !ast_test_flag(outgoing, OPT_MUSICBACK)) {
+						ast_indicate(in, AST_CONTROL_RINGING);
+						pa->sentringing++;
+					}
+					break;
+				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);
+					if (!ast_test_flag(outgoing, OPT_RINGBACK))
+						ast_indicate(in, AST_CONTROL_PROGRESS);
+					break;
+				case AST_CONTROL_VIDUPDATE:
+					if (option_verbose > 2)
+						ast_verbose (VERBOSE_PREFIX_3 "%s requested a video update, passing it to %s\n", o->chan->name,in->name);
+					ast_indicate(in, AST_CONTROL_VIDUPDATE);
+					break;
+				case AST_CONTROL_PROCEEDING:
+					if (option_verbose > 2)
+						ast_verbose (VERBOSE_PREFIX_3 "%s is proceeding passing it to %s\n", o->chan->name,in->name);
+					if (!ast_test_flag(outgoing, OPT_RINGBACK))
+						ast_indicate(in, AST_CONTROL_PROCEEDING);
+					break;
+				case AST_CONTROL_HOLD:
+					if (option_verbose > 2)
+						ast_verbose(VERBOSE_PREFIX_3 "Call on %s placed on hold\n", o->chan->name);
+					ast_indicate(in, AST_CONTROL_HOLD);
+					break;
+				case AST_CONTROL_UNHOLD:
+					if (option_verbose > 2)
+						ast_verbose(VERBOSE_PREFIX_3 "Call on %s left from hold\n", o->chan->name);
+					ast_indicate(in, AST_CONTROL_UNHOLD);
+					break;
+				case AST_CONTROL_OFFHOOK:
+				case AST_CONTROL_FLASH:
+					/* Ignore going off hook and flash */
+					break;
+				case -1:
+					if (!ast_test_flag(outgoing, OPT_RINGBACK | OPT_MUSICBACK)) {
+						if (option_verbose > 2)
+							ast_verbose(VERBOSE_PREFIX_3 "%s stopped sounds\n", o->chan->name);
+						ast_indicate(in, -1);
+						pa->sentringing = 0;
+					}
+					break;
+				default:
+					if (option_debug)
+						ast_log(LOG_DEBUG, "Dunno what to do with control type %d\n", f->subclass);
+				}
+			} else if (single) {
+				if (f->frametype == AST_FRAME_VOICE && 
+						!ast_test_flag(outgoing, OPT_RINGBACK|OPT_MUSICBACK)) {
+					if (ast_write(in, f)) 
+						ast_log(LOG_DEBUG, "Unable to forward voice frame\n");
+				} else if (f->frametype == AST_FRAME_IMAGE && 
+						!ast_test_flag(outgoing, OPT_RINGBACK|OPT_MUSICBACK)) {
+					if (ast_write(in, f))
+						ast_log(LOG_DEBUG, "Unable to forward image\n");
+				} else if (f->frametype == AST_FRAME_TEXT && 
+						!ast_test_flag(outgoing, OPT_RINGBACK|OPT_MUSICBACK)) {
+					if (ast_write(in, f))
+						ast_log(LOG_DEBUG, "Unable to send text\n");
+				} else if (f->frametype == AST_FRAME_HTML && !ast_test_flag(outgoing, DIAL_NOFORWARDHTML))
+					if (ast_channel_sendhtml(in, f->subclass, f->data, f->datalen) == -1)
+						ast_log(LOG_WARNING, "Unable to send URL\n");
+			}
+
+			ast_frfree(f);
+		} /* end for */
+		if (winner == in) {
+			struct ast_frame *f = ast_read(in);
+#if 0
+			if (f && (f->frametype != AST_FRAME_VOICE))
+				printf("Frame type: %d, %d\n", f->frametype, f->subclass);
+			else if (!f || (f->frametype != AST_FRAME_VOICE))
+				printf("Hangup received on %s\n", in->name);
+#endif
+			if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
+				/* Got hung up */
+				*to = -1;
+				strcpy(pa->status, "CANCEL");
+				if (f)
+					ast_frfree(f);
+				return NULL;
+			}
+			/* now f is guaranteed good */
+			if (f->frametype == AST_FRAME_DTMF) {
+				int done = 0;
+				if (ast_test_flag(peerflags, OPT_DTMF_EXIT)) {
+					const char *context = pbx_builtin_getvar_helper(in, "EXITCONTEXT");
+					if (onedigit_goto(in, context, (char) f->subclass, 1)) {
+						if (option_verbose > 2)
+							ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass);
+						*result = f->subclass;
+						done = 1;
+					}
+				}

[... 25701 lines stripped ...]


More information about the asterisk-commits mailing list