aboutsummaryrefslogtreecommitdiffstats
path: root/trunk/contrib
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/contrib')
-rw-r--r--trunk/contrib/README.festival47
-rw-r--r--trunk/contrib/asterisk-doxygen-header10
-rw-r--r--trunk/contrib/asterisk-ices.xml93
-rw-r--r--trunk/contrib/asterisk-ng-doxygen1274
-rw-r--r--trunk/contrib/dictionary.digium31
-rw-r--r--trunk/contrib/festival-1.4.1-diff76
-rw-r--r--trunk/contrib/festival-1.4.2.diff75
-rw-r--r--trunk/contrib/festival-1.4.3.diff93
-rw-r--r--trunk/contrib/festival-1.95.diff107
-rw-r--r--trunk/contrib/firmware/iax/iaxy.binbin0 -> 39402 bytes
-rw-r--r--trunk/contrib/i18n.testsuite.conf136
-rwxr-xr-xtrunk/contrib/init.d/rc.debian.asterisk85
-rwxr-xr-xtrunk/contrib/init.d/rc.gentoo.asterisk18
-rwxr-xr-xtrunk/contrib/init.d/rc.mandrake.asterisk185
-rwxr-xr-xtrunk/contrib/init.d/rc.mandrake.zaptel108
-rwxr-xr-xtrunk/contrib/init.d/rc.redhat.asterisk136
-rwxr-xr-xtrunk/contrib/init.d/rc.slackware.asterisk43
-rwxr-xr-xtrunk/contrib/init.d/rc.suse.asterisk127
-rw-r--r--trunk/contrib/scripts/README.messages-expire20
-rw-r--r--trunk/contrib/scripts/agents.php73
-rw-r--r--trunk/contrib/scripts/ast_grab_core70
-rw-r--r--trunk/contrib/scripts/astgenkey61
-rw-r--r--trunk/contrib/scripts/astgenkey.8129
-rw-r--r--trunk/contrib/scripts/autosupport163
-rw-r--r--trunk/contrib/scripts/autosupport.841
-rw-r--r--trunk/contrib/scripts/iax-friends.sql15
-rw-r--r--trunk/contrib/scripts/loadtest.tcl148
-rw-r--r--trunk/contrib/scripts/lookup.agi90
-rw-r--r--trunk/contrib/scripts/managerproxy.pl242
-rw-r--r--trunk/contrib/scripts/meetme.sql12
-rw-r--r--trunk/contrib/scripts/messages-expire.pl96
-rw-r--r--trunk/contrib/scripts/postgres_cdr.sql33
-rw-r--r--trunk/contrib/scripts/qview.pl100
-rw-r--r--trunk/contrib/scripts/realtime_pgsql.sql141
-rw-r--r--trunk/contrib/scripts/retrieve_extensions_from_mysql.pl113
-rw-r--r--trunk/contrib/scripts/retrieve_extensions_from_sql.pl158
-rw-r--r--trunk/contrib/scripts/retrieve_sip_conf_from_mysql.pl93
-rw-r--r--trunk/contrib/scripts/safe_asterisk184
-rw-r--r--trunk/contrib/scripts/safe_asterisk.869
-rw-r--r--trunk/contrib/scripts/safe_asterisk_restart110
-rw-r--r--trunk/contrib/scripts/sip-friends.sql14
-rw-r--r--trunk/contrib/scripts/vmail.cgi1099
-rw-r--r--trunk/contrib/scripts/vmdb.sql66
-rw-r--r--trunk/contrib/thirdparty/spexxilbcfix_xlite.regbin0 -> 452 bytes
-rw-r--r--trunk/contrib/thirdparty/spexxilbcfix_xpro.regbin0 -> 450 bytes
-rw-r--r--trunk/contrib/utils/README.rawplayer37
-rw-r--r--trunk/contrib/utils/eagi_proxy.c419
-rw-r--r--trunk/contrib/utils/rawplayer.c46
-rw-r--r--trunk/contrib/utils/zones2indications.c153
-rw-r--r--trunk/contrib/valgrind-RedHat-8.0.supp41
50 files changed, 6680 insertions, 0 deletions
diff --git a/trunk/contrib/README.festival b/trunk/contrib/README.festival
new file mode 100644
index 000000000..24912827c
--- /dev/null
+++ b/trunk/contrib/README.festival
@@ -0,0 +1,47 @@
+
+app_festival is an application that allows one to send text-to-speech commands
+to a background festival server, and to obtain the resulting waveform which
+gets sent down to the respective channel. app_festival also employs a waveform
+cache, so invariant text-to-speech strings ("Please press 1 for instructions")
+do not need to be dynamically generated all the time.
+
+You need :
+
+1) festival, patched to produce 8khz waveforms on output. Patch for Festival
+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
+either CPAN, or his site: http://asterisk.gnuinter.net,
+as this contains a good example of how variable text
+can be tts'd via asterisk, namely the examples/tts-*.agi
+files there. It has been noted that the current expression
+evaluation capabilities of asterisk are not best suited
+for the generation and manipulation of text. AGI scripting
+can be ideal for these sorts of needs. For simpler usage,
+fixed, pre-recorded messages may be more amenable for your
+purposes.
+
+3) Before running asterisk, you have to run festival-server with a command
+like :
+
+/usr/local/festival/bin/festival --server > /dev/null 2>&1 &
diff --git a/trunk/contrib/asterisk-doxygen-header b/trunk/contrib/asterisk-doxygen-header
new file mode 100644
index 000000000..a8eebd6c3
--- /dev/null
+++ b/trunk/contrib/asterisk-doxygen-header
@@ -0,0 +1,10 @@
+<HTML>
+ <HEAD>
+ <TITLE>Asterisk.org: Developer Documentation ($date)</TITLE>
+ <LINK HREF="doxygen.css" REL="stylesheet" TYPE="text/css">
+ </HEAD>
+ <BODY BGCOLOR="#FFFFFF">
+<div><font size="2" align="right">$datetime</font></div>
+
+<h2>Asterisk developer's documentation</h2>
+<hr/>
diff --git a/trunk/contrib/asterisk-ices.xml b/trunk/contrib/asterisk-ices.xml
new file mode 100644
index 000000000..abc028c75
--- /dev/null
+++ b/trunk/contrib/asterisk-ices.xml
@@ -0,0 +1,93 @@
+<?xml version="1.0"?>
+<ices>
+
+ <!-- run in background -->
+ <background>0</background>
+ <!-- where logs go. -->
+ <logpath>/var/log/ices</logpath>
+ <logfile>ices.log</logfile>
+ <!-- 1=error, 2=warn, 3=infoa ,4=debug -->
+ <loglevel>4</loglevel>
+ <!-- logfile is ignored if this is set to 1 -->
+ <consolelog>0</consolelog>
+
+ <!-- optional filename to write process id to -->
+ <!-- <pidfile>/home/ices/ices.pid</pidfile> -->
+
+ <stream>
+ <!-- metadata used for stream listing -->
+ <metadata>
+ <name>Example stream name</name>
+ <genre>Example genre</genre>
+ <description>A short description of your stream</description>
+ <url>http://mysite.org</url>
+ </metadata>
+
+ <!-- Input module.
+
+ This example uses the 'oss' module. It takes input from the
+ OSS audio device (e.g. line-in), and processes it for live
+ encoding. -->
+ <input>
+ <module>stdinpcm</module>
+ <param name="rate">8000</param>
+ <param name="channels">1</param>
+ <!-- Read metadata (from stdin by default, or -->
+ <!-- filename defined below (if the latter, only on SIGUSR1) -->
+ <param name="metadata">1</param>
+ <param name="metadatafilename">test</param>
+ </input>
+
+ <!-- Stream instance.
+
+ You may have one or more instances here. This allows you to
+ send the same input data to one or more servers (or to different
+ mountpoints on the same server). Each of them can have different
+ parameters. This is primarily useful for a) relaying to multiple
+ independent servers, and b) encoding/reencoding to multiple
+ bitrates.
+
+ If one instance fails (for example, the associated server goes
+ down, etc), the others will continue to function correctly.
+ This example defines a single instance doing live encoding at
+ low bitrate. -->
+
+ <instance>
+ <!-- Server details.
+
+ You define hostname and port for the server here, along
+ with the source password and mountpoint. -->
+
+ <hostname>localhost</hostname>
+ <port>8000</port>
+ <password>temppass</password>
+ <mount>/example.ogg</mount>
+ <yp>1</yp> <!-- allow stream to be advertised on YP, default 0 -->
+
+ <!-- Live encoding/reencoding:
+
+ channels and samplerate currently MUST match the channels
+ and samplerate given in the parameters to the oss input
+ module above or the remsaple/downmix section below. -->
+
+ <encode>
+ <quality>0</quality>
+ <samplerate>8000</samplerate>
+ <channels>1</channels>
+ </encode>
+
+ <!-- stereo->mono downmixing, enabled by setting this to 1 -->
+ <downmix>0</downmix>
+
+ <!-- resampling.
+
+ Set to the frequency (in Hz) you wish to resample to, -->
+
+ <!-- <resample>
+ <in-rate>44100</in-rate>
+ <out-rate>22050</out-rate>
+ </resample> -->
+ </instance>
+
+ </stream>
+</ices>
diff --git a/trunk/contrib/asterisk-ng-doxygen b/trunk/contrib/asterisk-ng-doxygen
new file mode 100644
index 000000000..f1259eea2
--- /dev/null
+++ b/trunk/contrib/asterisk-ng-doxygen
@@ -0,0 +1,1274 @@
+# Doxyfile 1.5.2
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file that
+# follow. The default is UTF-8 which is also the encoding used for all text before
+# the first occurrence of this tag. Doxygen uses libiconv (or the iconv built into
+# libc) for the transcoding. See http://www.gnu.org/software/libiconv for the list of
+# possible encodings.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME = "Asterisk - the Open Source PBX"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = doc/api
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian,
+# Italian, Japanese, Japanese-en (Japanese with English messages), Korean,
+# Korean-en, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian,
+# Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like the Qt-style comments (thus requiring an
+# explicit @brief command for a brief description.
+
+JAVADOC_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member
+# documentation.
+
+DETAILS_AT_TOP = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 3
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES = "extref=\xrefitem extref \"ExtRef\" \"External references\""
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for Java.
+# For instance, namespaces will be presented as packages, qualified scopes
+# will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to
+# include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT = NO
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING = YES
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = YES
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = YES
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 5
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from the
+# version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT =
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = ./ \
+ main \
+ include \
+ include/asterisk \
+ channels \
+ channels/misdn \
+ funcs \
+ main/stdtime \
+ apps \
+ cdr \
+ codecs \
+ formats \
+ pbx \
+ agi \
+ res
+
+# This tag can be used to specify the character encoding of the source files that
+# doxygen parses. Internally doxygen uses the UTF-8 encoding, which is also the default
+# input encoding. Doxygen uses libiconv (or the iconv built into libc) for the transcoding.
+# See http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py
+
+FILE_PATTERNS = *.c \
+ *.h
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the output.
+# The symbol name can be a fully qualified name, a word, or if the wildcard * is used,
+# a substring. Examples: ANamespace, AClass, AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH = ./ \
+ doc \
+ configs
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH = images
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output. If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = YES
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = NO
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default)
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES (the default)
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = YES
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code. Otherwise they will link to the documentstion.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = YES
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT =
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER = contrib/asterisk-doxygen-header
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
+# generated containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+,
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
+# probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW = YES
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT =
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT =
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT =
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION =
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader. This is useful
+# if you want to understand what is going on. On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = YES
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF = YES
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED = __GNUC__
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+
+CLASS_DIAGRAMS = NO
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see http://www.mcternan.me.uk/mscgen/) to
+# produce the chart and insert it in the documentation. The MSCGEN_PATH tag allows you to
+# specify the directory where the mscgen tool resides. If left empty the tool is assumed to
+# be found in the default search path.
+
+MSCGEN_PATH =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = NO
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will
+# generate a call dependency graph for every global function or class method.
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then doxygen will
+# generate a caller dependency graph for every global function or class method.
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The MAX_DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen will always
+# show the root nodes and its direct children regardless of this setting.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, which results in a white background.
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE = NO
diff --git a/trunk/contrib/dictionary.digium b/trunk/contrib/dictionary.digium
new file mode 100644
index 000000000..694605f54
--- /dev/null
+++ b/trunk/contrib/dictionary.digium
@@ -0,0 +1,31 @@
+#
+# Digium's Asterisk specific radius attributes
+# markster@digium.com
+#
+#
+
+VENDOR Digium 22736
+
+BEGIN-VENDOR Digium
+
+ATTRIBUTE Asterisk-Acc-Code 101 string Digium
+ATTRIBUTE Asterisk-Src 102 string Digium
+ATTRIBUTE Asterisk-Dst 103 string Digium
+ATTRIBUTE Asterisk-Dst-Ctx 104 string Digium
+ATTRIBUTE Asterisk-Clid 105 string Digium
+ATTRIBUTE Asterisk-Chan 106 string Digium
+ATTRIBUTE Asterisk-Dst-Chan 107 string Digium
+ATTRIBUTE Asterisk-Last-App 108 string Digium
+ATTRIBUTE Asterisk-Last-Data 109 string Digium
+ATTRIBUTE Asterisk-Start-Time 110 string Digium
+ATTRIBUTE Asterisk-Answer-Time 111 string Digium
+ATTRIBUTE Asterisk-End-Time 112 string Digium
+ATTRIBUTE Asterisk-Duration 113 integer Digium
+ATTRIBUTE Asterisk-Bill-Sec 114 integer Digium
+ATTRIBUTE Asterisk-Disposition 115 string Digium
+ATTRIBUTE Asterisk-AMA-Flags 116 string Digium
+ATTRIBUTE Asterisk-Unique-ID 117 string Digium
+ATTRIBUTE Asterisk-User-Field 118 string Digium
+
+END-VENDOR Digium
+
diff --git a/trunk/contrib/festival-1.4.1-diff b/trunk/contrib/festival-1.4.1-diff
new file mode 100644
index 000000000..23702a3a1
--- /dev/null
+++ b/trunk/contrib/festival-1.4.1-diff
@@ -0,0 +1,76 @@
+diff -ruN festival/lib/tts.scm myfestival/lib/tts.scm
+--- festival/lib/tts.scm Sun May 30 16:40:00 1999
++++ myfestival/lib/tts.scm Wed Apr 17 22:29:34 2002
+@@ -200,6 +200,15 @@
+ (utt.synth
+ (eval (list 'Utterance 'Text string)))))
+
++(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 maybe added to the server safe functions."
++ (utt.send.wave.asterisk
++ (utt.synth
++ (eval (list 'Utterance 'Text string)))))
++
+ (define (tts_return_to_client)
+ "(tts_return_to_client)
+ This function is called by clients who wish to return waveforms of
+diff -ruN festival/src/arch/festival/wave.cc myfestival/src/arch/festival/wave.cc
+--- festival/src/arch/festival/wave.cc Sat Jun 12 10:30:30 1999
++++ myfestival/src/arch/festival/wave.cc Thu Apr 18 10:55:32 2002
+@@ -375,6 +375,38 @@
+ type = "nist";
+ else
+ type = get_c_string(ltype);
++
++ w->save(tmpfile,type);
++ write(ft_server_socket,"WV\n",3);
++ socket_send_file(ft_server_socket,tmpfile);
++ unlink(tmpfile);
++
++ return utt;
++}
++
++static LISP utt_send_wave_asterisk(LISP utt)
++{
++ // Send the waveform to a client (must be acting as server)
++ EST_Utterance *u = utterance(utt);
++ EST_Wave *w;
++ EST_String tmpfile = make_tmp_filename();
++ LISP ltype;
++ EST_String type;
++
++ w = get_utt_wave(u);
++ if (ft_server_socket == -1)
++ {
++ cerr << "utt_send_wave_client: not in server mode" << endl;
++ festival_error();
++ }
++
++ ltype = ft_get_param("Wavefiletype");
++ if (ltype == NIL)
++ type = "nist";
++ else
++ type = get_c_string(ltype);
++ w->resample(8000);
++ w->rescale(5);
+ w->save(tmpfile,type);
+ write(ft_server_socket,"WV\n",3);
+ socket_send_file(ft_server_socket,tmpfile);
+@@ -434,6 +466,13 @@
+ "(utt.send.wave.client UTT)\n\
+ Sends wave in UTT to client. If not in server mode gives an error\n\
+ Note the client must be expecting to receive the waveform.");
++
++ init_subr_1("utt.send.wave.asterisk",utt_send_wave_asterisk,
++ "(utt.send.wave.asterisk UTT)\n\
++ Sends wave in UTT to client. If not in server mode gives an error\n\
++ Note the client must be expecting to receive the waveform. The waveform\n\
++ is rescaled and resampled according to what asterisk needs");
++
+ init_subr_2("utt.save.f0",utt_save_f0,
+ "(utt.save.f0 UTT FILENAME)\n\
+ Save F0 of UTT as esps track file in FILENAME.");
+
diff --git a/trunk/contrib/festival-1.4.2.diff b/trunk/contrib/festival-1.4.2.diff
new file mode 100644
index 000000000..d5d1e5d54
--- /dev/null
+++ b/trunk/contrib/festival-1.4.2.diff
@@ -0,0 +1,75 @@
+diff -u -r festival-1.4.2/lib/tts.scm festival-1.4.2-asterisk/lib/tts.scm
+--- festival-1.4.2/lib/tts.scm Wed Jan 8 09:54:14 2003
++++ festival-1.4.2-asterisk/lib/tts.scm Tue Jan 7 08:51:44 2003
+@@ -236,6 +236,15 @@
+ (utt.synth
+ (eval (list 'Utterance 'Text string))))))
+
++(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."
++ (utt.send.wave.asterisk
++ (utt.synth
++ (eval (list 'Utterance 'Text string)))))
++
+ (define (tts_return_to_client)
+ "(tts_return_to_client)
+ This function is called by clients who wish to return waveforms of
+diff -u -r festival-1.4.2/src/arch/festival/wave.cc festival-1.4.2-asterisk/src/arch/festival/wave.cc
+--- festival-1.4.2/src/arch/festival/wave.cc Mon Jun 4 07:40:10 2001
++++ festival-1.4.2-asterisk/src/arch/festival/wave.cc Tue Jan 7 08:53:09 2003
+@@ -377,6 +377,38 @@
+ type = "nist";
+ else
+ type = get_c_string(ltype);
++
++ w->save(tmpfile,type);
++ write(ft_server_socket,"WV\n",3);
++ socket_send_file(ft_server_socket,tmpfile);
++ unlink(tmpfile);
++
++ return utt;
++}
++
++static LISP utt_send_wave_asterisk(LISP utt)
++{
++ // Send the waveform to a client (must be acting as server)
++ EST_Utterance *u = utterance(utt);
++ EST_Wave *w;
++ EST_String tmpfile = make_tmp_filename();
++ LISP ltype;
++ EST_String type;
++
++ w = get_utt_wave(u);
++ if (ft_server_socket == -1)
++ {
++ cerr << "utt_send_wave_client: not in server mode" << endl;
++ festival_error();
++ }
++
++ ltype = ft_get_param("Wavefiletype");
++ if (ltype == NIL)
++ type = "nist";
++ else
++ type = get_c_string(ltype);
++ w->resample(8000);
++ w->rescale(5);
+ w->save(tmpfile,type);
+ write(ft_server_socket,"WV\n",3);
+ socket_send_file(ft_server_socket,tmpfile);
+@@ -454,6 +486,13 @@
+ "(utt.send.wave.client UTT)\n\
+ Sends wave in UTT to client. If not in server mode gives an error\n\
+ Note the client must be expecting to receive the waveform.");
++
++ init_subr_1("utt.send.wave.asterisk",utt_send_wave_asterisk,
++ "(utt.send.wave.asterisk UTT)\n\
++ Sends wave in UTT to client. If not in server mode gives an error\n\
++ Note the client must be expecting to receive the waveform. The waveform\n\
++ is rescaled and resampled according to what asterisk needs");
++
+ init_subr_1("send_sexpr_to_client", send_sexpr_to_client,
+ "(send_sexpr_to_client SEXPR)\n\
+ Sends given sexpression to currently connected client.");
diff --git a/trunk/contrib/festival-1.4.3.diff b/trunk/contrib/festival-1.4.3.diff
new file mode 100644
index 000000000..13a9d92b8
--- /dev/null
+++ b/trunk/contrib/festival-1.4.3.diff
@@ -0,0 +1,93 @@
+diff -u -r festival-1.4.3/lib/tts.scm festival-1.4.3-asterisk/lib/tts.scm
+--- festival-1.4.3/lib/tts.scm 2003-01-09 07:39:22.000000000 -0800
++++ festival-1.4.3-asterisk/lib/tts.scm 2003-08-14 12:07:00.000000000 -0700
+@@ -234,6 +234,17 @@
+ (utt.synth
+ (eval (list 'Utterance 'Text string))))))
+
++;; begin tts_textasterisk
++(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."
++ (utt.send.wave.asterisk
++ (utt.synth
++ (eval (list 'Utterance 'Text string)))))
++;; end tts_textasterisk
++
+ (define (tts_return_to_client)
+ "(tts_return_to_client)
+ This function is called by clients who wish to return waveforms of
+diff -u -r festival-1.4.3/src/arch/festival/wave.cc festival-1.4.3-asterisk/src/arch/festival/wave.cc
+--- festival-1.4.3/src/arch/festival/wave.cc 2003-01-13 11:09:55.000000000 -0800
++++ festival-1.4.3-asterisk/src/arch/festival/wave.cc 2003-08-14 12:10:53.000000000 -0700
+@@ -381,6 +381,7 @@
+ type = "nist";
+ else
+ type = get_c_string(ltype);
++
+ w->save(tmpfile,type);
+ #ifdef WIN32
+ send(ft_server_socket,"WV\n",3,0);
+@@ -393,6 +394,44 @@
+ return utt;
+ }
+
++// begin utt_send_wave_asterisk()
++static LISP utt_send_wave_asterisk(LISP utt)
++{
++ // Send the waveform to a client (must be acting as server)
++ EST_Utterance *u = utterance(utt);
++ EST_Wave *w;
++ EST_String tmpfile = make_tmp_filename();
++ LISP ltype;
++ EST_String type;
++
++ w = get_utt_wave(u);
++ if (ft_server_socket == -1)
++ {
++ cerr << "utt_send_wave_client: not in server mode" << endl;
++ festival_error();
++ }
++
++ ltype = ft_get_param("Wavefiletype");
++ if (ltype == NIL)
++ type = "nist";
++ else
++ type = get_c_string(ltype);
++ w->resample(8000);
++ w->rescale(5);
++
++ w->save(tmpfile,type);
++#ifdef WIN32
++ send(ft_server_socket,"WV\n",3,0);
++#else
++ write(ft_server_socket,"WV\n",3);
++#endif
++ socket_send_file(ft_server_socket,tmpfile);
++ unlink(tmpfile);
++
++ return utt;
++}
++// end utt_send_wave_asterisk()
++
+ static LISP send_sexpr_to_client(LISP l)
+ {
+ EST_String tmpfile = make_tmp_filename();
+@@ -465,6 +504,15 @@
+ "(utt.send.wave.client UTT)\n\
+ Sends wave in UTT to client. If not in server mode gives an error\n\
+ Note the client must be expecting to receive the waveform.");
++
++// begin asterisk mod
++ init_subr_1("utt.send.wave.asterisk",utt_send_wave_asterisk,
++ "(utt.send.wave.asterisk UTT)\n\
++ Sends wave in UTT to client. If not in server mode gives an error\n\
++ Note the client must be expecting to receive the waveform. The waveform\n\
++ is rescaled and resampled according to what asterisk needs");
++// end asterisk mod
++
+ init_subr_1("send_sexpr_to_client", send_sexpr_to_client,
+ "(send_sexpr_to_client SEXPR)\n\
+ Sends given sexpression to currently connected client.");
diff --git a/trunk/contrib/festival-1.95.diff b/trunk/contrib/festival-1.95.diff
new file mode 100644
index 000000000..2035d7f0f
--- /dev/null
+++ b/trunk/contrib/festival-1.95.diff
@@ -0,0 +1,107 @@
+diff -ur festival-195orig/festival/lib/multisyn/multisyn_pauses.scm festival-195/festival/lib/multisyn/multisyn_pauses.scm
+--- festival-195orig/festival/lib/multisyn/multisyn_pauses.scm 2004-06-21 08:19:30.000000000 -0600
++++ festival-195/festival/lib/multisyn/multisyn_pauses.scm 2005-01-12 18:53:27.000000000 -0700
+@@ -85,8 +85,8 @@
+ (let ((silence (car (cadr (car (PhoneSet.description '(silences))))))
+ (seg (item.relation (find_last_seg word) 'Segment))
+ pause_item)
+- (format t " inserting pause after: %s.\n" (item.name seg))
+- (format t " Inserting pause\n")
++; (format t " inserting pause after: %s.\n" (item.name seg))
++; (format t " Inserting pause\n")
+ ; if next seg is not silence insert one.
+ (if (or (not (item.next seg))
+ (not (string-equal (item.name (item.next seg)) silence)))
+diff -ur festival-195orig/festival/lib/tts.scm festival-195/festival/lib/tts.scm
+--- festival-195orig/festival/lib/tts.scm 2003-04-20 10:42:28.000000000 -0600
++++ festival-195/festival/lib/tts.scm 2005-01-04 09:21:31.000000000 -0700
+@@ -235,6 +235,17 @@
+ (utt.synth
+ (eval (list 'Utterance 'Text string))))))
+
++;; begin tts_textasterisk
++(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."
++ (utt.send.wave.asterisk
++ (utt.synth
++ (eval (list 'Utterance 'Text string)))))
++;; end tts_textasterisk
++
+ (define (tts_return_to_client)
+ "(tts_return_to_client)
+ This function is called by clients who wish to return waveforms of
+diff -ur festival-195orig/festival/src/arch/festival/wave.cc festival-195/festival/src/arch/festival/wave.cc
+--- festival-195orig/festival/src/arch/festival/wave.cc 2004-06-21 14:52:42.000000000 -0600
++++ festival-195/festival/src/arch/festival/wave.cc 2005-01-04 09:26:24.000000000 -0700
+@@ -482,6 +482,7 @@
+ type = "nist";
+ else
+ type = get_c_string(ltype);
++
+ w->save(tmpfile,type);
+ #ifdef WIN32
+ send(ft_server_socket,"WV\n",3,0);
+@@ -494,6 +495,44 @@
+ return utt;
+ }
+
++// begin utt_send_wave_asterisk()
++static LISP utt_send_wave_asterisk(LISP utt)
++{
++ // Send the waveform to a client (must be acting as server)
++ EST_Utterance *u = utterance(utt);
++ EST_Wave *w;
++ EST_String tmpfile = make_tmp_filename();
++ LISP ltype;
++ EST_String type;
++
++ w = get_utt_wave(u);
++ if (ft_server_socket == -1)
++ {
++ cerr << "utt_send_wave_asterisk: not in server mode" << endl;
++ festival_error();
++ }
++
++ ltype = ft_get_param("Wavefiletype");
++ if (ltype == NIL)
++ type = "nist";
++ else
++ type = get_c_string(ltype);
++ w->resample(8000);
++ w->rescale(5);
++
++ w->save(tmpfile,type);
++#ifdef WIN32
++ send(ft_server_socket,"WV\n",3,0);
++#else
++ write(ft_server_socket,"WV\n",3);
++#endif
++ socket_send_file(ft_server_socket,tmpfile);
++ unlink(tmpfile);
++
++ return utt;
++}
++// end utt_send_wave_asterisk()
++
+ static LISP send_sexpr_to_client(LISP l)
+ {
+ EST_String tmpfile = make_tmp_filename();
+@@ -595,6 +634,15 @@
+ "(utt.send.wave.client UTT)\n\
+ Sends wave in UTT to client. If not in server mode gives an error\n\
+ Note the client must be expecting to receive the waveform.");
++
++// begin asterisk mod
++ init_subr_1("utt.send.wave.asterisk",utt_send_wave_asterisk,
++ "(utt.send.wave.asterisk UTT)\n\
++ Sends wave in UTT to client. If not in server mode gives an error\n\
++ Note the client must be expecting to receive the waveform. The waveform\n\
++ is rescaled and resampled according to what asterisk needs");
++// end asterisk mod
++
+ init_subr_1("send_sexpr_to_client", send_sexpr_to_client,
+ "(send_sexpr_to_client SEXPR)\n\
+ Sends given sexpression to currently connected client.");
diff --git a/trunk/contrib/firmware/iax/iaxy.bin b/trunk/contrib/firmware/iax/iaxy.bin
new file mode 100644
index 000000000..6f06c4cdb
--- /dev/null
+++ b/trunk/contrib/firmware/iax/iaxy.bin
Binary files differ
diff --git a/trunk/contrib/i18n.testsuite.conf b/trunk/contrib/i18n.testsuite.conf
new file mode 100644
index 000000000..8c4d1f705
--- /dev/null
+++ b/trunk/contrib/i18n.testsuite.conf
@@ -0,0 +1,136 @@
+; Test Internationalisation of SayNumber()
+; #include this into a suitable context
+; English
+exten => 841,1,Answer
+exten => 841,2,Wait,1 ; Allow VoIP sessions time to initialise
+exten => 841,3,SetLanguage(en)
+exten => 841,4,SayNumber(183) ; one hundred eighty three (NB UK English would say one hundred & eighty three)
+exten => 841,5,Wait,1
+exten => 841,6,SayUnixTime() ; Say current date & time in "ABdY 'digits/at' IMp" format
+; French
+exten => 842,1,Answer
+exten => 842,2,Wait,1 ; Allow VoIP sessions time to initialise
+exten => 842,3,SetLanguage(fr)
+exten => 842,4,SayNumber(1) ; one
+exten => 842,5,Wait,1
+exten => 842,6,SayNumber(1,f) ; one (feminine)
+exten => 842,7,Wait,1
+exten => 842,8,SayNumber(181) ; hundred eighty three
+exten => 842,9,Wait,1
+exten => 842,10,SayNumber(281) ; two hundred eighty three
+exten => 842,11,Wait,1
+exten => 842,12,SayNumber(1061) ; thousand sixty three
+exten => 842,13,Wait,1
+exten => 842,14,SayNumber(2061) ; two thousand sixty three
+exten => 842,15,Wait,1
+exten => 842,16,SayUnixTime()
+; Spanish
+exten => 843,1,Answer
+exten => 843,2,Wait,1 ; Allow VoIP sessions time to initialise
+exten => 843,3,SetLanguage(es)
+exten => 843,4,Playback(digits/hundred)
+exten => 843,5,Wait,1
+exten => 843,6,SayNumber(1) ; one
+exten => 843,7,Wait,1
+exten => 843,8,SayNumber(1,f) ; one (feminine)
+exten => 843,9,Wait,1
+exten => 843,10,SayNumber(11) ; "dieci uno"
+exten => 843,11,Wait,1
+exten => 843,12,SayNumber(21) ; "veinti uno"
+exten => 843,13,Wait,1
+exten => 843,14,SayNumber(31) ; "thirty & one"
+exten => 843,15,Wait,1
+exten => 843,16,SayNumber(100) ; "cien"
+exten => 843,17,Wait,1
+exten => 843,18,SayNumber(101) ; "ciento uno"
+exten => 843,19,Wait,1
+exten => 843,20,SayNumber(200) ; "twohundred"
+exten => 843,21,Wait,1
+exten => 843,22,SayNumber(1000000) ; one million
+exten => 843,23,Wait,1
+exten => 843,24,SayNumber(2000000) ; two millions
+exten => 843,25,Wait,1
+exten => 843,26,SayUnixTime()
+; Portuguese
+exten => 844,1,Answer
+exten => 844,2,Wait,1 ; Allow VoIP sessions time to initialise
+exten => 844,3,SetLanguage(pt)
+exten => 844,4,SayNumber(1) ; one
+exten => 844,5,Wait,1
+exten => 844,6,SayNumber(1,f) ; one (feminine)
+exten => 844,7,Wait,1
+exten => 844,8,SayNumber(2) ; two
+exten => 844,9,Wait,1
+exten => 844,10,SayNumber(2,f) ; two (feminine)
+exten => 844,11,Wait,1
+exten => 844,12,SayNumber(183) ; hundred& eighty three
+exten => 844,13,Wait,1
+exten => 844,14,SayUnixTime()
+; Italian
+exten => 845,1,Answer
+exten => 845,2,Wait,1 ; Allow VoIP sessions time to initialise
+exten => 845,3,SetLanguage(it)
+exten => 845,4,SayNumber(21) ; "twentyone"
+exten => 845,5,Wait,1
+exten => 845,6,SayNumber(183) ; hundred eighty three
+exten => 845,7,Wait,1
+exten => 845,8,SayNumber(283) ; two hundred eighty three
+exten => 845,9,SayNumber(1063) ; thousand sixty three
+exten => 845,10,Wait,1
+exten => 845,11,SayNumber(2063) ; two thousands sixty three
+exten => 845,12,Wait,1
+exten => 845,13,SayUnixTime()
+; Dutch
+exten => 846,1,Answer
+exten => 846,2,Wait,1 ; Allow VoIP sessions time to initialise
+exten => 846,3,SetLanguage(nl)
+exten => 846,4,SayUnixTime(||ABdY'digits/at'R)
+exten => 846,5,Wait,1
+; Danish
+exten => 847,1,Answer
+exten => 847,2,Wait,1 ; Allow VoIP sessions time to initialise
+exten => 847,3,SetLanguage(da)
+exten => 847,4,SayNumber(68) ; eight-& sixty
+exten => 847,5,Wait,1
+exten => 847,6,SayNumber(2034) ; two thousand & four-& thirty
+exten => 847,7,Wait,1
+exten => 847,8,SayNumber(1000000) ; one million
+exten => 847,9,Wait,1
+exten => 847,10,SayNumber(2000000) ; two millions
+exten => 847,11,Wait,1
+exten => 847,12,SayUnixTime()
+; German
+exten => 848,1,Answer
+exten => 848,2,Wait,1 ; Allow VoIP sessions time to initialise
+exten => 848,3,SetLanguage(de)
+exten => 848,4,SayNumber(68) ; eight-& sixty
+exten => 848,5,Wait,1
+exten => 848,6,SayNumber(100) ; "hundert"
+exten => 848,7,Wait,1
+exten => 848,8,SayNumber(101) ; "einhundert-einS"
+exten => 848,9,Wait,1
+exten => 848,10,SayNumber(1000) ; "tausend"
+exten => 848,11,Wait,1
+exten => 848,12,SayNumber(1001) ; "eintausend-einS" X tausend-einS
+exten => 848,13,Wait,1
+exten => 848,14,SayNumber(2134) ; two thousand one hundred four-& thirty
+exten => 848,15,Wait,1
+exten => 848,16,SayNumber(1001000) ; one million one thousand X million tausend
+exten => 848,17,Wait,1
+exten => 848,18,SayNumber(2002000) ; two millions two thousand
+exten => 848,19,Wait,1
+exten => 848,20,SayUnixTime()
+; Swedish
+exten => 849,1,Answer
+exten => 849,2,Wait,1 ; Allow VoIP sessions time to initialise
+exten => 849,3,SetLanguage(se)
+exten => 849,4,SayUnixTime()
+exten => 849,5,Wait,1
+; Temp
+exten => 850,1,Answer
+exten => 850,2,Wait,1 ; Allow VoIP sessions time to initialise
+exten => 850,3,SetLanguage(de)
+exten => 850,4,Playback(digits/1)
+exten => 850,5,Wait,1
+exten => 850,6,Playback(digits/de-eins)
+exten => 850,7,Wait,1
diff --git a/trunk/contrib/init.d/rc.debian.asterisk b/trunk/contrib/init.d/rc.debian.asterisk
new file mode 100755
index 000000000..3926346d4
--- /dev/null
+++ b/trunk/contrib/init.d/rc.debian.asterisk
@@ -0,0 +1,85 @@
+#! /bin/sh
+# $Id$
+#
+# asterisk start the asterisk PBX
+#
+# Thu Nov 17 2005 Gregory Boehnlein <damin@nacs.net>
+# - Updated Version to 1.3
+# - Reversed behavior of LD_ASSUME_KERNEL=2.4.1
+# - Added detailed failure messages
+#
+# Sun Jul 18 2004 Gregory Boehnlein <damin@nacs.net>
+# - Updated Version to 1.2
+# - Added test for safe_asterisk
+# - Changed "stop gracefully" to "stop now"
+# - Added support for -U and -G command line options
+# - Modified "reload" to call asterisk -rx 'reload'
+
+PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
+NAME=asterisk
+DESC="Asterisk PBX"
+# Full path to asterisk binary
+DAEMON=/usr/sbin/asterisk
+
+# Full path to safe_asterisk script
+SAFE_ASTERISK=/usr/sbin/safe_asterisk
+
+# Uncomment this ONLY if you know what you are doing.
+# export LD_ASSUME_KERNEL=2.4.1
+
+# Uncomment the following and set them to the user/groups that you
+# want to run Asterisk as. NOTE: this requires substantial work to
+# be sure that Asterisk's environment has permission to write the
+# files required for its operation, including logs, its comm
+# socket, the asterisk database, etc.
+#AST_USER="asterisk"
+#AST_GROUP="asterisk"
+
+if ! [ -x $DAEMON ] ; then
+ echo "ERROR: /usr/sbin/asterisk not found"
+ exit 0
+fi
+
+if ! [ -d /etc/asterisk ] ; then
+ echo "ERROR: /etc/asterisk directory not found"
+ exit 0
+fi
+
+set -e
+
+case "$1" in
+ start)
+ echo -n "Starting $DESC: "
+ if [ -f $SAFE_ASTERISK ] ; then
+ DAEMON=$SAFE_ASTERISK
+ fi
+ if [ $AST_USER ] ; then
+ ASTARGS="-U $AST_USER"
+ fi
+ if [ $AST_GROUP ] ; then
+ ASTARGS="`echo $ASTARGS` -G $AST_GROUP"
+ fi
+ start-stop-daemon --start --exec $DAEMON -- $ASTARGS
+ echo "$NAME."
+ ;;
+ stop)
+ echo -n "Stopping $DESC: "
+ $DAEMON -rx 'stop now' > /dev/null 2> /dev/null && echo -n "$NAME"
+ echo "."
+ exit 0
+ ;;
+ reload)
+ echo "Reloading $DESC configuration files."
+ $DAEMON -rx 'reload' > /dev/null 2> /dev/null
+ ;;
+ restart|force-reload)
+ $DAEMON -rx 'restart gracefully' > /dev/null 2> /dev/null && echo -n "$NAME"
+ ;;
+ *)
+ N=/etc/init.d/$NAME
+ echo "Usage: $N {start|stop|restart|reload|force-reload}" >&2
+ exit 1
+ ;;
+esac
+
+exit 0
diff --git a/trunk/contrib/init.d/rc.gentoo.asterisk b/trunk/contrib/init.d/rc.gentoo.asterisk
new file mode 100755
index 000000000..3d963d6c0
--- /dev/null
+++ b/trunk/contrib/init.d/rc.gentoo.asterisk
@@ -0,0 +1,18 @@
+#!/sbin/runscript
+# $Id$
+
+depend() {
+ need net logger
+}
+
+start() {
+ ebegin "Starting Asterisk"
+ /usr/sbin/asterisk
+ eend $? "Failed to start Asterisk"
+}
+
+stop() {
+ ebegin "Stopping Asterisk"
+ kill $(cat /var/run/asterisk.pid)
+ eend $? "Failed to stop Asterisk"
+}
diff --git a/trunk/contrib/init.d/rc.mandrake.asterisk b/trunk/contrib/init.d/rc.mandrake.asterisk
new file mode 100755
index 000000000..1ffd25d37
--- /dev/null
+++ b/trunk/contrib/init.d/rc.mandrake.asterisk
@@ -0,0 +1,185 @@
+#!/bin/sh
+#
+# asterisk: Starts the asterisk service
+#
+# Version: @(#) /etc/rc.d/init.d/asterisk 1.0
+#
+# chkconfig: 2345 95 10
+# description: Starts the asterisk service
+#
+# processname: asterisk
+#
+
+# $Id$
+
+TTY=9 # TTY (if you want one) for Asterisk to run on
+CONSOLE=yes # Whether or not you want a console
+NOTIFY=root # Who to notify about crashes
+DUMPDROP=/tmp
+HOSTNAME=`hostname`
+if [ 0`readlink $0` = "0" ]; then
+ CONFIGFILE=/etc/sysconfig/`basename $0`
+else
+ CONFIG0=`readlink $0`
+ CONFIGFILE=/etc/sysconfig/`basename $CONFIG0`
+fi
+
+# Setup environment
+cd /usr/src
+if [ -f /usr/lib/asterisk/modules/chan_h323.so -a `grep -c ^noload=chan_h323.so /etc/asterisk/modules.conf` -eq 0 ]; then
+ OPENH323DIR=/usr/src/h323/openh323
+ PWLIBDIR=/usr/src/h323/pwlib
+else
+ OPENH323DIR=/usr/src/oh323/openh323
+ PWLIBDIR=/usr/src/oh323/pwlib
+fi
+
+# Put overrides in /etc/sysconfig/asterisk
+[ -f $CONFIGFILE ] && . $CONFIGFILE
+
+LD_LIBRARY_PATH=$OPENH323DIR/lib:$PWLIBDIR/lib
+export OPENH323DIR PWLIBDIR LD_LIBRARY_PATH
+
+# Source function library.
+. /etc/rc.d/init.d/functions
+
+#
+# Don't fork when running "safely"
+#
+ASTARGS="-p"
+if [ "$TTY" != "" ]; then
+ if [ -c /dev/tty${TTY} ]; then
+ TTY=tty${TTY}
+ elif [ -c /dev/vc/${TTY} ]; then
+ TTY=vc/${TTY}
+ else
+ echo "Cannot find your TTY (${TTY})" >&2
+ exit 1
+ fi
+ ASTARGS="${ASTARGS} -vvv"
+ if [ "$CONSOLE" != "no" ]; then
+ ASTARGS="${ASTARGS} -c"
+ fi
+fi
+if [ ! -w ${DUMPDROP} ]; then
+ echo "Cannot write to ${DUMPDROP}" >&2
+ exit 1
+fi
+
+#
+# Let Asterisk dump core
+#
+ulimit -c unlimited
+
+#launch_asterisk()
+#{
+#}
+
+SIGMSG=("None", "Hangup" "Interrupt" "Quit" "Illegal instruction" "Trace trap" "IOT Trap" "Bus Error" "Floating-point exception" "Killed" "User-defined signal 1" "Segmentation violation" "User-defined signal 2" "Broken pipe" "Alarm clock" "Termination" "Stack fault")
+
+run_asterisk()
+{
+ while :; do
+
+ if [ "$TTY" != "" ]; then
+ cd /tmp
+ stty sane < /dev/${TTY}
+ asterisk ${ASTARGS} > /dev/${TTY} 2>&1 < /dev/${TTY}
+ else
+ cd /tmp
+ asterisk ${ASTARGS}
+ fi
+ EXITSTATUS=$?
+ echo "Asterisk ended with exit status $EXITSTATUS"
+ if [ "$EXITSTATUS" = "0" ]; then
+ # Properly shutdown....
+ echo "Asterisk shutdown normally."
+ exit 0
+ elif [ $EXITSTATUS -gt 128 ]; then
+ EXITSIGNAL=$(($EXITSTATUS - 128))
+ EXITMSG=${SIGMSG[$EXITSIGNAL]}
+ echo "Asterisk exited on signal $EXITSIGNAL - $EXITMSG."
+ if [ "$NOTIFY" != "" ]; then
+ echo "Asterisk exited on signal $EXITSIGNAL - $EXITMSG. Might want to take a peek." | \
+ mail -s "Asterisk Died ($HOSTNAME)" $NOTIFY
+ fi
+ if [ -f /tmp/core ]; then
+ mv /tmp/core ${DUMPDROP}/core.`hostname`-`date -Iseconds` &
+ fi
+ else
+ echo "Asterisk died with code $EXITSTATUS. Aborting."
+ if [ -f /tmp/core ]; then
+ mv /tmp/core ${DUMPDROP}/core.`hostname`-`date -Iseconds` &
+ fi
+ exit 0
+ fi
+ echo "Automatically restarting Asterisk."
+ done
+}
+
+case "$1" in
+ start)
+ gprintf "Starting asterisk: "
+ run_asterisk >/dev/null 2>&1 &
+ sleep 2 # Give it time to die
+ succeeded=`pidof asterisk|awk '{print NF}'`
+ if [ $succeeded = "0" ]; then
+ failure
+ else
+ success
+ fi
+ echo
+ ;;
+ stop)
+ gprintf "Stopping asterisk: "
+ asterisk -r -x "stop gracefully" >/dev/null 2>&1
+ killall -9 mpg123 2>/dev/null
+ success
+ echo
+ ;;
+ restart)
+ $0 stop
+ usleep 100000
+ $0 start
+ ;;
+ reload)
+ gprintf "Reloading asterisk: "
+ asterisk -r -x "reload" >/dev/null 2>&1
+ success
+ echo
+ ;;
+ stopnow)
+ gprintf "Stopping asterisk: "
+ asterisk -r -x "stop now" >/dev/null 2>&1
+ success
+ echo
+ ;;
+ restartnow)
+ $0 stopnow
+ $0 start
+ ;;
+ fullrestart)
+ $0 stop
+ service zaptel restart
+ $0 start
+ ;;
+ fullrestartnow)
+ $0 stopnow
+ service zaptel restart
+ $0 start
+ ;;
+ status)
+ succeeded=`pidof asterisk|awk '{print NF}'`
+ if [ $succeeded = "0" ]; then
+ echo "Asterisk is not running"
+ else
+ echo "Asterisk is currently running with $succeeded threads"
+ fi
+ ;;
+ *)
+ gprintf "*** Usage: $0 {start|stop[now]|reload|[full]restart[now]|status}\n"
+ exit 1
+esac
+
+exit 0
+
diff --git a/trunk/contrib/init.d/rc.mandrake.zaptel b/trunk/contrib/init.d/rc.mandrake.zaptel
new file mode 100755
index 000000000..2feaef4c7
--- /dev/null
+++ b/trunk/contrib/init.d/rc.mandrake.zaptel
@@ -0,0 +1,108 @@
+#!/bin/sh
+#
+# zaptel: Loads Asterisk modules
+#
+# Version: @(#) /etc/rc.d/init.d/zaptel 1.0
+#
+# chkconfig: 2345 90 10
+# description: Loads and unloads zaptel modules at boot time and shutdown.
+#
+# hide: true
+
+# $Id$
+
+# Source function library.
+. /etc/rc.d/init.d/functions
+
+# Default modules - override in /etc/sysconfig/zaptel
+######################################
+MODULES="usb-uhci zaptel wcfxo wcusb"
+######################################
+
+# Resolve back to the basename (i.e. zaptel, not S90zaptel)
+if [ 0`readlink $0` = "0" ]; then
+ CONFIGFILE=/etc/sysconfig/`basename $0`
+else
+ CONFIG0=`readlink $0`
+ CONFIGFILE=/etc/sysconfig/`basename $CONFIG0`
+fi
+
+[ -f $CONFIGFILE ] && . $CONFIGFILE
+
+function probe() {
+ gprintf " $1"
+ modprobe -i $1
+ # It has to be in the module list, otherwise something is wrong
+ if lsmod | grep -c ^$1 >/dev/null; then
+ success
+ else
+ failure
+ fi
+ echo
+}
+
+function unprobe() {
+ gprintf " $1"
+ rmmod $1 >/dev/null 2>&1
+ # If it's still in the module list after removing it, there's something wrong.
+ if lsmod | grep -c ^$1 >/dev/null; then
+ failure
+ else
+ success
+ fi
+ echo
+}
+
+function reverse_modules() {
+ tmp=$MODULES
+ MODULES=''
+ for i in $tmp; do
+ MODULES="$i $MODULES" ;
+ done
+}
+
+# See how we were called.
+case "$1" in
+ start)
+ gprintf "Loading Asterisk modules:\n"
+ for i in $MODULES; do
+ probe $i
+ usleep 100000 ;
+ done
+ ztcfg
+ ;;
+ stop)
+ gprintf "Unloading Asterisk modules:\n"
+ reverse_modules
+ for i in $MODULES; do
+ unprobe $i
+ usleep 100000 ;
+ done
+ ;;
+ status)
+ #ztcfg -vv
+ OK=1
+ gprintf "Checking Asterisk modules"
+ for i in $MODULES; do
+ if [ `lsmod | grep -c $i` -eq 0 ]; then
+ OK=0
+ fi
+ done
+ if [ $OK -gt 0 ]; then
+ success
+ else
+ failure
+ fi
+ echo
+ ;;
+ restart)
+ $0 stop
+ $0 start
+ ;;
+ *)
+ gprintf "*** Usage: $0 {start|stop|status|restart}\n"
+ exit 1
+esac
+
+exit 0
+
diff --git a/trunk/contrib/init.d/rc.redhat.asterisk b/trunk/contrib/init.d/rc.redhat.asterisk
new file mode 100755
index 000000000..27d633e70
--- /dev/null
+++ b/trunk/contrib/init.d/rc.redhat.asterisk
@@ -0,0 +1,136 @@
+#!/bin/sh
+# $Id$
+#
+# asterisk Starts, Stops and Reloads Asterisk.
+#
+# chkconfig: 2345 90 60
+# description: Asterisk PBX and telephony daemon.
+# processname: asterisk
+# pidfile: /var/run/asterisk.pid
+#
+# Thu Nov 17 2005 Gregory Boehnlein <damin@nacs.net>
+# - Updated Version to 1.3
+# - Reversed behavior of LD_ASSUME_KERNEL=2.4.1
+# - Added detailed failure messages
+#
+# Sun Jul 18 2004 Gregory Boehnlein <damin@nacs.net>
+# - Updated Version to 1.2
+# - Added test for safe_asterisk
+# - Verified SIGTERM issued by "killproc" ensures "stop gracefully"
+# - Added support for -U and -G command line options
+# - Modified "reload" to call asterisk -rx 'reload'
+
+# Use this option to specify a different configuration directory
+#AST_CONFIG=/etc/asterisk
+
+# Installation directory
+AST_SBIN=/usr/sbin
+
+# Uncomment the following and set them to the user/groups that you
+# want to run Asterisk as. NOTE: this requires substantial work to
+# be sure that Asterisk's environment has permission to write the
+# files required for its operation, including logs, its comm
+# socket, the asterisk database, etc.
+#AST_USER="asterisk"
+#AST_GROUP="asterisk"
+
+# Source function library.
+. /etc/rc.d/init.d/functions
+
+if ! [ -x $AST_SBIN/asterisk ] ; then
+ echo "ERROR: $AST_SBIN/asterisk not found"
+ exit 0
+fi
+
+if ! [ -d $AST_CONFIG ] ; then
+ echo "ERROR: $AST_CONFIG directory not found"
+ exit 0
+fi
+
+# Uncomment this ONLY if you know what you are doing.
+# export LD_ASSUME_KERNEL=2.4.1
+
+# Full path to asterisk binary
+DAEMON=$AST_SBIN/asterisk
+
+# Full path to safe_asterisk script
+SAFE_ASTERISK=$AST_SBIN/safe_asterisk
+
+# Allow configuration overrides in /etc/sysconfig/asterisk
+CONFIG0=`readlink $0`
+if [ "$CONFIG0" = "" ]; then
+ CONFIGFILE=/etc/sysconfig/`basename $0`
+else
+ CONFIGFILE=/etc/sysconfig/`basename $CONFIG0`
+fi
+[ -x $CONFIGFILE ] && . $CONFIGFILE
+
+RETVAL=0
+
+start() {
+ # Start daemons.
+ echo -n $"Starting asterisk: "
+ if [ -f $SAFE_ASTERISK ] ; then
+ DAEMON=$SAFE_ASTERISK
+ fi
+ if [ $AST_USER ] ; then
+ ASTARGS="-U $AST_USER"
+ fi
+ if [ $AST_GROUP ] ; then
+ ASTARGS="$ASTARGS -G $AST_GROUP"
+ fi
+ if [ $AST_CONFIG ]; then
+ ASTARGS="$ASTARGS -C $AST_CONFIG"
+ fi
+ daemon $DAEMON $ASTARGS
+ RETVAL=$?
+ [ $RETVAL -eq 0 ] && touch /var/lock/subsys/asterisk
+ echo
+ return $RETVAL
+}
+
+stop() {
+ # Stop daemons.
+ echo -n $"Shutting down asterisk: "
+ killproc asterisk
+ RETVAL=$?
+ [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/asterisk
+ echo
+ return $RETVAL
+}
+
+restart() {
+ stop
+ start
+}
+
+reload() {
+ $DAEMON -rx 'reload' > /dev/null 2> /dev/null
+}
+
+# See how we were called.
+case "$1" in
+ start)
+ start
+ ;;
+ stop)
+ stop
+ ;;
+ restart)
+ restart
+ ;;
+ reload)
+ reload
+ ;;
+ condrestart)
+ [ -f /var/lock/subsys/asterisk ] && restart || :
+ ;;
+ status)
+ status asterisk
+ ;;
+ *)
+ echo "Usage: asterisk {start|stop|restart|reload|condrestart|status}"
+ exit 1
+esac
+
+exit $?
diff --git a/trunk/contrib/init.d/rc.slackware.asterisk b/trunk/contrib/init.d/rc.slackware.asterisk
new file mode 100755
index 000000000..0802bfcaa
--- /dev/null
+++ b/trunk/contrib/init.d/rc.slackware.asterisk
@@ -0,0 +1,43 @@
+#!/bin/sh
+#
+# Start/stop/restart Asterisk PBX
+#
+# Version: 1.0 - Paul Belanger <pabelanger@gmail.com>
+#
+# 03.29.2005 - Initial Version
+#
+# $Id$
+
+asterisk_start() {
+ if [ -x /usr/sbin/asterisk ]; then
+ echo "Starting Asterisk /usr/sbin/asterisk"
+ /usr/sbin/asterisk
+ fi
+}
+
+asterisk_stop() {
+ # If there is no PID file, ignore this request...
+ if [ -r /var/run/asterisk.pid ]; then
+ killall asterisk
+ fi
+}
+
+asterisk_restart() {
+ asterisk_stop
+ asterisk_start
+}
+
+case "$1" in
+ 'start')
+ asterisk_start
+ ;;
+ 'stop')
+ asterisk_stop
+ ;;
+ 'restart')
+ asterisk_restart
+ ;;
+ *)
+ echo "usage $0 start|stop|restart" ;;
+esac
+
diff --git a/trunk/contrib/init.d/rc.suse.asterisk b/trunk/contrib/init.d/rc.suse.asterisk
new file mode 100755
index 000000000..3eb1be55f
--- /dev/null
+++ b/trunk/contrib/init.d/rc.suse.asterisk
@@ -0,0 +1,127 @@
+#!/bin/sh
+# $Id: asterisk,v 1.3 2005/11/17 22:30:01 Gregory Boehnlein <damin@nacs.net>
+#
+# asterisk Starts, Stops and Reloads Asterisk.
+#
+# chkconfig: 2345 40 60
+# description: Asterisk PBX and telephony daemon.
+# processname: asterisk
+# pidfile: /var/run/asterisk.pid
+#
+# Thu Nov 17 2005 Gregory Boehnlein <damin@nacs.net>
+# - Updated Version to 1.3
+# - Reversed behavior of LD_ASSUME_KERNEL=2.4.1
+# - Added detailed failure messages
+#
+# Sun Jul 18 2004 Gregory Boehnlein <damin@nacs.net>
+# - Updated Version to 1.2
+# - Added test for safe_asterisk
+# - Verified SIGTERM issued by "killproc" ensures "stop gracefully"
+# - Added support for -U and -G command line options
+# - Modified "reload" to call asterisk -rx 'reload'
+
+### BEGIN INIT INFO
+# Provides: asterisk
+# Required-Start: +zaptel
+# Required-Stop:
+# Default-Start: 3 5
+# Default-Stop: 0 1 2 4 6
+# Description: zaptel - zaptel modules for Asterisk
+### END INIT INFO
+
+# Source function library.
+. /lib/lsb/init-functions
+
+if ! [ -x /usr/sbin/asterisk ] ; then
+ echo "ERROR: /usr/sbin/asterisk not found"
+ exit 0
+fi
+
+if ! [ -d /etc/asterisk ] ; then
+ echo "ERROR: /etc/asterisk directory not found"
+ exit 0
+fi
+
+# Uncomment this ONLY if you know what you are doing.
+# export LD_ASSUME_KERNEL=2.4.1
+
+# Full path to asterisk binary
+DAEMON=/usr/sbin/asterisk
+
+# Full path to safe_asterisk script
+SAFE_ASTERISK=/usr/sbin/safe_asterisk
+
+# Uncomment the following and set them to the user/groups that you
+# want to run Asterisk as. NOTE: this requires substantial work to
+# be sure that Asterisk's environment has permission to write the
+# files required for its operation, including logs, its comm
+# socket, the asterisk database, etc.
+#AST_USER="asterisk"
+#AST_GROUP="asterisk"
+
+RETVAL=0
+
+start() {
+ # Start daemons.
+ echo -n $"Starting asterisk: "
+ if [ -f $SAFE_ASTERISK ] ; then
+ DAEMON=$SAFE_ASTERISK
+ fi
+ if [ $AST_USER ] ; then
+ ASTARGS="-U $AST_USER"
+ fi
+ if [ $AST_GROUP ] ; then
+ ASTARGS="`echo $ASTARGS` -G $AST_GROUP"
+ fi
+ $DAEMON $ASTARGS
+ RETVAL=$?
+ [ $RETVAL -eq 0 ] && touch /var/lock/subsys/asterisk
+ echo
+ return $RETVAL
+}
+
+stop() {
+ # Stop daemons.
+ echo -n $"Shutting down asterisk: "
+ killproc asterisk
+ RETVAL=$?
+ [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/asterisk
+ echo
+ return $RETVAL
+}
+
+restart() {
+ stop
+ start
+}
+
+reload() {
+ $DAEMON -rx 'reload' > /dev/null 2> /dev/null
+}
+
+# See how we were called.
+case "$1" in
+ start)
+ start
+ ;;
+ stop)
+ stop
+ ;;
+ restart)
+ restart
+ ;;
+ reload)
+ reload
+ ;;
+ condrestart)
+ [ -f /var/lock/subsys/asterisk ] && restart || :
+ ;;
+ status)
+ status asterisk
+ ;;
+ *)
+ echo "Usage: asterisk {start|stop|restart|reload|condrestart|status}"
+ exit 1
+esac
+
+exit $?
diff --git a/trunk/contrib/scripts/README.messages-expire b/trunk/contrib/scripts/README.messages-expire
new file mode 100644
index 000000000..12f2b0e9c
--- /dev/null
+++ b/trunk/contrib/scripts/README.messages-expire
@@ -0,0 +1,20 @@
+messages-expire.pl
+
+messages-expire finds messages more than X days old and deletes them.
+Because the older messages will be the lower numbers in the folder (msg0000
+will be older than msg0005), just deleting msg0000 will not work.
+expire-messages then runs a routine that goes into every folder in every
+mailbox to reorganize. If the folder contains msg0000, no action is taken.
+If the folder does not, the rename routine takes the oldest message and
+names it msg0000, the next oldest message and names it msg0001 and so on.
+
+The file deletion is done by the -exec parameter to 'find'. It would be far
+more efficient to take the output from 'find' and just reorganize the
+directories from which we deleted a file. Something for the future...
+
+Keep in mind that messages are deleted at the beginning of the script you
+will have mailbox trouble if you check messages before the script
+reorganizes your mailbox.
+
+To use it, make sure the paths are right. Adjust $age (originally set to
+31) if necessary.
diff --git a/trunk/contrib/scripts/agents.php b/trunk/contrib/scripts/agents.php
new file mode 100644
index 000000000..51f8bdee3
--- /dev/null
+++ b/trunk/contrib/scripts/agents.php
@@ -0,0 +1,73 @@
+<?php
+
+ob_implicit_flush(false);
+
+$username = "drmac";
+$secret = "secret";
+
+$socket = fsockopen("127.0.0.1","5038", $errornum, $errorstr);
+
+$agents = array();
+$curr_agent = "";
+$better_status = array( 'AGENT_UNKNOWN' => 'Unknown',
+ 'AGENT_IDLE' => 'Idle',
+ 'AGENT_ONCALL' => 'On Call',
+ 'AGENT_LOGGEDOFF' => 'Not Logged In' );
+
+if(!$socket) {
+ print "Couldn't open socket. Error #" . $errornum . ": " . $errorstr;
+} else {
+ fputs($socket, "Action: Login\r\n");
+ fputs($socket, "UserName: $username\r\n");
+ fputs($socket, "Secret: $secret\r\n\r\n");
+ fputs($socket, "Action: Agents\r\n\r\n");
+ fputs($socket, "Action: Logoff\r\n\r\n");
+
+ while(!feof($socket)) {
+ $info = fscanf($socket, "%s\t%s\r\n");
+ switch($info[0]) {
+ case "Agent:":
+ $curr_agent = $info[1];
+ $agents[$curr_agent] = array();
+ break;
+ case "Name:":
+ $agents[$curr_agent]['Name'] = $info[1];
+ break;
+ case "Status:":
+ $agents[$curr_agent]['Status'] = $better_status[$info[1]];
+ break;
+ case "LoggedInChan:":
+ $agents[$curr_agent]['LoggedInChan'] = $info[1];
+ break;
+ case "LoggedInTime:":
+ if($info[1] != "0") {
+ $agents[$curr_agent]['LoggedInTime'] = date("D, M d Y g:ia", $info[1]);
+ } else {
+ $agents[$curr_agent]['LoggedInTime'] = "n/a";
+ }
+ break;
+ case "TalkingTo:":
+ $agents[$curr_agent]['TalkingTo'] = $info[1];
+ break;
+ default:
+ break;
+ }
+ }
+ fclose($socket);
+
+ print "<html><head><title>Agents Status</title></head>\n<body>\n";
+ print "<table width=\"800px\" border=\"1\">\n";
+ print " <tr><th>Agent #</th><th>Agent Name</th><th>Agent Location</th><th>Agent Status</th><th>Agent Talking To</th><th>Agent Login Time</th></tr>\n";
+
+ foreach( $agents as $agent=>$curr ) {
+ print " <tr>\n <td>" . $agent . "</td>\n";
+ print " <td>" . $curr['Name'] . "</td>\n";
+ print " <td>" . $curr['LoggedInChan'] . "</td>\n";
+ print " <td>" . $curr['Status'] . "</td>\n";
+ print " <td>" . $curr['TalkingTo'] . "</td>\n";
+ print " <td>" . $curr['LoggedInTime'] . "</td>\n </tr>\n";
+ }
+
+ print "</table>\n</body>\n</html>\n";
+}
+?>
diff --git a/trunk/contrib/scripts/ast_grab_core b/trunk/contrib/scripts/ast_grab_core
new file mode 100644
index 000000000..b2bd7b2ed
--- /dev/null
+++ b/trunk/contrib/scripts/ast_grab_core
@@ -0,0 +1,70 @@
+#!/bin/sh
+# $Id$
+# lame quickie script to snarf a core of a hung asterisk process.
+# bugs to ast_grab_core, blinky-lights.org (derrick daugherty)
+
+# we have found that gcore doesn't yield as useful a core file
+# as that yielded by a signal-caused core dump. So we are going to change
+# the strategy to sending a SEGV signal to the asterisk process,
+# and have it 'burn to the ground', leaving behind a core file.
+# the main difference is that you cannot control where the
+# core file will end up. We will assume that safe_asterisk was
+# used to start asterisk, and the core file should therefore end
+# up in /tmp (because safe_asterisk cd's there before starting asterisk).
+# if this is not the case, set DUMPDIR to the place where the core
+# file can be found.
+
+DATE=`date +%Y%m%d%H%M`
+DUMPDIR=/tmp
+HOSTNAME=`hostname`
+ADMINEMAIL="root@localhost"
+
+#the following should be improved
+if [ -e /etc/asterisk/asterisk.conf ]; then
+ RUNDIR=`awk -F"=>" '/astrundir/ {print $2}' /etc/asterisk/asterisk.conf`
+ PID=`cat ${RUNDIR}/asterisk.pid`
+elif [ -e /var/run/asterisk.pid ] ; then
+ PID=`cat /var/run/asterisk.pid`
+else
+ echo Could not find an asterisk.conf definition for astrundir, using \'ps\'
+ echo to try and determine process ID. This is not reliable.
+ PID=`ps auxwf|grep asterisk|grep vv|head -1|awk '{print $2}'`
+fi
+
+echo Snarfing asterisk core, this could take a few seconds depending
+echo on how much memory is in use.
+echo
+echo \*\*\* WARNING \*\*\* If the system is not already locked this will cause the
+echo \*\*\* WARNING \*\*\* process to STOP while memory is dumped to disk.
+echo
+
+/bin/kill -11 ${PID}
+
+echo Snarfed! ${DUMPDIR}/core.${PID}
+echo
+
+
+echo Trying for a backtrace of the captured core.
+/usr/bin/gdb /usr/sbin/asterisk ${DUMPDIR}/core.${PID} > ${DUMPDIR}/gdb_dump.${PID}.txt 2> /dev/null << EOF
+set prompt \n
+set print pretty\n
+echo --------------------------------------------------------------------------------\n
+echo INFO THREAD
+info thread
+echo --------------------------------------------------------------------------------\n
+echo THREAD APPLY ALL BT
+thread apply all bt
+echo --------------------------------------------------------------------------------\n
+echo THREAD APPLY ALL BT FULL
+thread apply all bt full
+quit
+EOF
+echo Done trying for a bt.
+
+
+echo Notifying admins of the core.
+/usr/bin/mail -s "${HOSTNAME} core dumped at ${DUMPDIR}/core.${PID}" ${ADMINEMAIL} < ${DUMPDIR}/gdb_dump.${PID}.txt
+echo Done.
+echo
+echo Reproducible deadlocks should be posted with a full backtrace and instructions
+echo to reproduce the issue at http://bugs.digium.com/ Thanks!
diff --git a/trunk/contrib/scripts/astgenkey b/trunk/contrib/scripts/astgenkey
new file mode 100644
index 000000000..637604896
--- /dev/null
+++ b/trunk/contrib/scripts/astgenkey
@@ -0,0 +1,61 @@
+#!/bin/sh
+#
+# Usage: astgenkey [ -q ] [ -n ] [keyname]
+#
+DES3=-des3
+if [ "$1" = "-q" ]; then
+ QUIET='y'
+ if [ "$2" = "-n" ]; then
+ DES3=
+ KEY=$3
+ else
+ KEY=$2
+ fi
+elif [ "$1" = "-n" ]; then
+ DES3=
+ if [ "$2" = "-q" ]; then
+ QUIET='y'
+ KEY=$3
+ else
+ KEY=$2
+ fi
+else
+ KEY=$1
+fi
+
+if [ "$QUIET" != 'y' ]; then
+ echo ""
+ echo "This script generates an RSA private and public key pair"
+ echo "in PEM format for use by Asterisk. You will be asked to"
+ echo "enter a passcode for your key multiple times. Please"
+ echo "enter the same code each time. The resulting files will"
+ echo "need to be moved to /var/lib/asterisk/keys if you want"
+ echo "to use them, and any private keys (.key files) will"
+ echo "need to be initialized at runtime either by running"
+ echo "Asterisk with the '-i' option, or with the 'init keys'"
+ echo "command once Asterisk is running."
+ echo ""
+ echo "Press ENTER to continue or ^C to cancel."
+ read BLAH
+fi
+
+while [ "$KEY" = "" ]; do
+ echo -n "Enter key name: "
+ read KEY
+done
+
+rm -f ${KEY}.key ${KEY}.pub
+
+echo "Generating SSL key '$KEY': "
+openssl genrsa -out ${KEY}.key ${DES3} 1024
+openssl rsa -in ${KEY}.key -pubout -out ${KEY}.pub
+
+if [ -f "${KEY}.key" ] && [ -f "${KEY}.pub" ]; then
+ if [ "$QUIET" != 'y' ]; then
+ echo "Key creation successful."
+ echo "Public key: ${KEY}.pub"
+ echo "Private key: ${KEY}.key"
+ fi
+else
+ echo "Unknown error creating keys."
+fi
diff --git a/trunk/contrib/scripts/astgenkey.8 b/trunk/contrib/scripts/astgenkey.8
new file mode 100644
index 000000000..8f8325982
--- /dev/null
+++ b/trunk/contrib/scripts/astgenkey.8
@@ -0,0 +1,129 @@
+.\" $Header$
+.\"
+.\" transcript compatibility for postscript use.
+.\"
+.\" synopsis: .P! <file.ps>
+.\"
+.de P!
+.fl
+\!!1 setgray
+.fl
+\\&.\"
+.fl
+\!!0 setgray
+.fl \" force out current output buffer
+\!!save /psv exch def currentpoint translate 0 0 moveto
+\!!/showpage{}def
+.fl \" prolog
+.sy sed \-e 's/^/!/' \\$1\" bring in postscript file
+\!!psv restore
+.
+.de pF
+.ie \\*(f1 .ds f1 \\n(.f
+.el .ie \\*(f2 .ds f2 \\n(.f
+.el .ie \\*(f3 .ds f3 \\n(.f
+.el .ie \\*(f4 .ds f4 \\n(.f
+.el .tm ? font overflow
+.ft \\$1
+..
+.de fP
+.ie !\\*(f4 \{\
+. ft \\*(f4
+. ds f4\"
+' br \}
+.el .ie !\\*(f3 \{\
+. ft \\*(f3
+. ds f3\"
+' br \}
+.el .ie !\\*(f2 \{\
+. ft \\*(f2
+. ds f2\"
+' br \}
+.el .ie !\\*(f1 \{\
+. ft \\*(f1
+. ds f1\"
+' br \}
+.el .tm ? font underflow
+..
+.ds f1\"
+.ds f2\"
+.ds f3\"
+.ds f4\"
+'\" t
+.ta 8n 16n 24n 32n 40n 48n 56n 64n 72n
+.TH ASTGENKEY 8 "May 14th, 2005" "Asterisk" "Linux Programmer's Manual"
+.SH NAME
+.B astgenkey
+-- generates keys for for Asterisk IAX2 RSA authentication
+.SH SYNOPSIS
+.PP
+.B astgenkey
+[ -q ] [ -n ] [ \fIkeyname\fP ]
+
+.SH DESCRIPTION
+.B astgenkey
+This script generates an RSA private and public key pair in PEM format
+for use by Asterisk. The private key should be kept a secret, as it can
+be used to fake your system's identity. Thus by default (without the
+option
+.I -n
+) the script will create a passphrase-encrypted copy of your secret key:
+without entering the passphrase you won't be able to use it.
+
+However if you want to use such a key with Asterisk, you'll have to start
+it interactively, because the scripts that start asterisk can't use that
+encrypted key.
+
+The key is identified by a name. If you don't write the name on the
+command-line you'll be prompted for one. The outputs of the script are:
+
+.I name\fB.pub
+.RS
+The public key: not secret. Send this to the other side.
+.RE
+
+.I name\fB.key
+.RS
+The private key: secret.
+.RE
+
+Those files should be copied to
+.I /var/lib/asterisk/keys
+
+(The private key: on your system. The public key: on other systems)
+
+To see the currently-installed keys from the asterisk CLI, use the command
+
+.RS
+show keys
+.RE
+
+.SH OPTIONS
+.B -q
+.RS
+Run quietly.
+.RE
+
+.B -n
+.RS
+Don't encrypt the private key.
+.RE
+
+.SH FILES
+.I /var/lib/asterisk/keys
+.RS
+.RE
+
+.SH "SEE ALSO"
+asterisk(8), genrsa(1), rsa(1),
+
+http://www.voip-info.org/wiki-Asterisk+iax+rsa+auth
+
+.SH "AUTHOR"
+This manual page was written by Tzafrir Cohen <tzafrir.cohen@xorcom.com>
+Permission is granted to copy, distribute and/or modify this document under
+the terms of the GNU General Public License, Version 2 any
+later version published by the Free Software Foundation.
+
+On Debian systems, the complete text of the GNU General Public
+License can be found in /usr/share/common-licenses/GPL.
diff --git a/trunk/contrib/scripts/autosupport b/trunk/contrib/scripts/autosupport
new file mode 100644
index 000000000..557ca6ce2
--- /dev/null
+++ b/trunk/contrib/scripts/autosupport
@@ -0,0 +1,163 @@
+#!/bin/sh
+#
+# Collect support information
+#
+# Copyright (C) 2005, Digium, Inc.
+#
+# Written by John Bigelow (support@digium.com)
+#
+# Distributed under the terms of the GNU General Public
+# License
+#
+
+OUTPUT=$HOME/digiuminfo
+
+if [ $UID -ne 0 ]; then
+
+ echo "You must be root to run this."
+
+exit 1
+fi
+
+echo
+echo "This will gather information about your system such as:"
+echo "pci listing, dmesg, running processes, and kernel version"
+echo "This may take up to half a minute to run. Please be patient."
+echo "To continue press 'y', to quit press any other key"
+read ans
+
+if [ "$ans" = "y" ]; then
+
+ rm -f $OUTPUT
+
+ echo "------------------" >> $OUTPUT;
+ echo "PCI LIST " >> $OUTPUT;
+ echo "------------------" >> $OUTPUT;
+ lspci -vb >> $OUTPUT;
+ echo >> $OUTPUT;
+ echo >> $OUTPUT;
+
+ echo "------------------" >> $OUTPUT;
+ echo "INTERRUPTS" >> $OUTPUT;
+ echo "------------------" >> $OUTPUT;
+ cat /proc/interrupts >> $OUTPUT;
+ echo >> $OUTPUT;
+ echo >> $OUTPUT;
+
+ echo "------------------" >> $OUTPUT;
+ echo "DMESG OUTPUT" >> $OUTPUT;
+ echo "------------------" >> $OUTPUT;
+ dmesg >> $OUTPUT;
+ echo >> $OUTPUT;
+ echo >> $OUTPUT;
+
+ echo "------------------" >> $OUTPUT;
+ echo "RUNNING PROCESSES" >> $OUTPUT;
+ echo "------------------" >> $OUTPUT;
+ ps aux >> $OUTPUT;
+ echo >> $OUTPUT;
+ echo >> $OUTPUT;
+
+ echo "------------------" >> $OUTPUT;
+ echo "KERNEL VERSION" >> $OUTPUT;
+ echo "------------------" >> $OUTPUT;
+ uname -a >> $OUTPUT;
+ echo >> $OUTPUT;
+ echo >> $OUTPUT;
+
+ echo "------------------" >> $OUTPUT;
+ echo "CPU INFO" >> $OUTPUT;
+ echo "------------------" >> $OUTPUT;
+ cat /proc/cpuinfo >> $OUTPUT;
+ echo >> $OUTPUT;
+ echo >> $OUTPUT;
+
+ echo "------------------" >> $OUTPUT;
+ echo "HDPARM STATUS" >> $OUTPUT;
+ echo "------------------" >> $OUTPUT;
+ hdparm /dev/hda >> $OUTPUT;
+ hdparm -i /dev/hda >> $OUTPUT;
+ echo >> $OUTPUT;
+ echo >> $OUTPUT;
+
+ echo "------------------" >> $OUTPUT;
+ echo "ZAPTEL CONFIG" >> $OUTPUT;
+ echo "------------------" >> $OUTPUT;
+ grep -v '^#' /etc/zaptel.conf >> $OUTPUT;
+ echo >> $OUTPUT;
+ echo >> $OUTPUT;
+
+ echo "------------------" >> $OUTPUT;
+ echo "ZAPATA CONFIG" >> $OUTPUT;
+ echo "------------------" >> $OUTPUT;
+ grep -v '^;' /etc/asterisk/zapata.conf >> $OUTPUT;
+ echo >> $OUTPUT;
+ echo >> $OUTPUT;
+
+ echo "------------------" >> $OUTPUT;
+ echo "EXTENSIONS CONFIG" >> $OUTPUT;
+ echo "------------------" >> $OUTPUT;
+ grep -v '^;' /etc/asterisk/extensions.conf >> $OUTPUT;
+ echo >> $OUTPUT;
+ echo >> $OUTPUT;
+
+ echo "------------------" >> $OUTPUT;
+ echo "ZTTEST" >> $OUTPUT;
+ echo "------------------" >> $OUTPUT;
+ /usr/src/zaptel/zttest -c 20 >> $OUTPUT;
+ echo >> $OUTPUT;
+ echo >> $OUTPUT;
+
+else
+ echo "terminated";
+exit
+fi
+
+echo
+echo "Digium may require root level access to the system to help debug";
+echo "the problem you are experiencing. Do you want to provide login";
+echo "information at this time?";
+echo "Press 'y' for yes and any other key to exit and save the previous info collected"
+read login
+
+if [ "$login" = "y" ]; then
+
+ echo "------------------" >> $OUTPUT;
+ echo "LOGIN INFORMATION" >> $OUTPUT;
+ echo "------------------" >> $OUTPUT;
+
+ echo
+ echo "What is your root password?"
+ read rootpass
+
+ echo
+ echo "Root pass: "$rootpass >> $OUTPUT
+
+ echo
+ echo "What is your PUBLIC IP address?"
+ read ip
+
+ echo "IP address: "$ip >> $OUTPUT
+
+ echo
+ echo "Please provide any other login information that the technician"
+ echo "may need to know to login to the system'(press enter if not)'"
+ read adinfo
+
+ echo "Additional login info: "$adinfo >> $OUTPUT
+
+ echo
+ echo "All information has been stored in $OUTPUT,"
+ echo "Please attach this file to an email ticket you already"
+ echo "have open with Digium Tech Support."
+
+else
+ echo
+ echo "All information except login info has been stored in $OUTPUT,"
+ echo "Please send this file to an email ticket you already"
+ echo "have open with Digium Tech Support."
+exit
+fi
+
+
+
diff --git a/trunk/contrib/scripts/autosupport.8 b/trunk/contrib/scripts/autosupport.8
new file mode 100644
index 000000000..e356fcdbb
--- /dev/null
+++ b/trunk/contrib/scripts/autosupport.8
@@ -0,0 +1,41 @@
+.TH AUTOSUPPORT 8 "Jul 5th, 2005" "Asterisk" "Linux Programmer's Manual"
+.SH NAME
+.B autosupport
+\(em interactive script to provide Digium[tm]'s support with information
+.SH SYNOPSIS
+.PP
+.B autosupport
+
+.SH DESCRIPTION
+.B autoasupport
+is a script that is normally run by a user contacting Digium's support
+to automate gathering support information.
+
+It will probe the system for some configuration and run-time information,
+and will also prompt the user for some optional access information (IP
+address, login and password).
+
+The information is written to /root/digiuminfo which the user is expected
+to attach to a support ticket to Digium.
+
+The script must be run as root as it reads Asterisk's configuration and
+the disk information using hdparm(8).
+
+.SH FILES
+.B /root/digiuminfo
+.RS
+The output of the script goes there
+.RE
+
+.SH SEE ALSO
+asterisk(8)
+
+.SH "AUTHOR"
+autosupport was written by John Bigelow <support@digium.com>.
+This manual page was written by Tzafrir Cohen <tzafrir.cohen@xorcom.com>
+Permission is granted to copy, distribute and/or modify this document under
+the terms of the GNU General Public License, Version 2 any
+later version published by the Free Software Foundation.
+
+On Debian systems, the complete text of the GNU General Public
+License can be found in /usr/share/common-licenses/GPL.
diff --git a/trunk/contrib/scripts/iax-friends.sql b/trunk/contrib/scripts/iax-friends.sql
new file mode 100644
index 000000000..717a27d07
--- /dev/null
+++ b/trunk/contrib/scripts/iax-friends.sql
@@ -0,0 +1,15 @@
+#
+# Table structure for table `iaxfriends`
+#
+
+CREATE TABLE `iaxfriends` (
+ `name` varchar(40) NOT NULL default '',
+ `secret` varchar(40) NOT NULL default '',
+ `context` varchar(40) NOT NULL default '',
+ `ipaddr` varchar(20) NOT NULL default '',
+ `port` int(6) NOT NULL default '0',
+ `regseconds` int(11) NOT NULL default '0',
+ `accountcode` varchar(20) NOT NULL default '',
+ PRIMARY KEY (`name`)
+) TYPE=MyISAM;
+
diff --git a/trunk/contrib/scripts/loadtest.tcl b/trunk/contrib/scripts/loadtest.tcl
new file mode 100644
index 000000000..9c50be338
--- /dev/null
+++ b/trunk/contrib/scripts/loadtest.tcl
@@ -0,0 +1,148 @@
+#!/usr/bin/tclsh
+#
+# Usage (as root):
+#
+# $ tclsh loadtest.tcl
+#
+# Copyleft 2005 by Chris Maj <cmaj_at_freedomcorpse_dot_com>
+#
+# Create a (huge) bunch of call files to dial via pbx_spool.
+# Defaults are selected with 'Enter' and, if all defaults
+# are selected, you'll dial Zap/1/s into default|s|1
+#
+
+
+# where Asterisk's pbx/pbx_spool.c will be looking for work
+set SPOOLDIR /var/spool/asterisk/outgoing
+# pbx_spool is fairly aggresive, so make files here first
+set TEMPDIR /tmp
+
+if { ![file writable $SPOOLDIR] } {
+ puts "Do you need to be root to write to $SPOOLDIR ?"
+ exit
+}
+
+if { ![file readable $TEMPDIR] } {
+ puts "Do you need to be root to read from $TEMPDIR ?"
+ exit
+}
+
+if { ![file writable $TEMPDIR] } {
+ puts "Do you need to be root to write to $TEMPDIR ?"
+ exit
+}
+
+# gets some input from the user
+proc get {var_ default_ prompt_} {
+ global $var_
+ puts $prompt_
+ if { $default_ != "" } {
+ puts -nonewline "(default: $default_) ? "
+ } else {
+ puts -nonewline "? "
+ }
+ flush stdout
+ gets stdin $var_
+ if { [set $var_] == "" && $default_ != "" } {
+ set $var_ $default_
+ }
+}
+
+# puts the user requested channels into a neat, ordered list
+proc splitchans {inch_} {
+ global changroup
+ set outch [list]
+ foreach range [split $inch_ {, }] {
+ set start [lindex [split $range -] 0]
+ set stop [lindex [split $range -] end]
+ if { [string is digit $start] && [string is digit $stop] } {
+ set ::changroup "channel"
+ for {set ch $start} {$ch <= $stop} {incr ch} {
+ if { [lsearch $outch $ch] == -1 } {
+ lappend outch $ch
+ }
+ }
+ } else {
+ set ::changroup "group"
+ foreach ch [split $range -] {
+ lappend outch $ch
+ }
+ }
+ }
+ return [lsort -dictionary $outch]
+}
+
+# writes out a file in the temporary directory,
+# then changes the mtime of the file before
+# sticking it into the outgoing spool directory
+# (where pbx_spool will be looking)
+proc spool {channel_ callcnt_ when_} {
+ set callstr "
+Channel: $::technology/$channel_/$::destination
+Context: $::context
+Extension: $::extension
+Priority: $::priority
+WaitTime: $::timeout
+RetryTime: $::retrytime
+MaxRetries: $::maxretries
+Callerid: $::clid
+SetVar: $::astvar
+Account: $::account
+"
+ set fn "loadtest.call$callcnt_.ch$channel_"
+ set fd [open $::TEMPDIR/$fn w]
+ puts $fd $callstr
+ close $fd
+ file mtime $::TEMPDIR/$fn $when_
+ file rename -force $::TEMPDIR/$fn $::SPOOLDIR/$fn
+}
+
+# prompt the user for some info
+get technology "Zap" "\nEnter technology type
+Zap, IAX, SIP, etc."
+get chans "1" "\nEnter channel(s) or group to test in formats like
+2\n1-4\n3 5 7 9\n1-23,25-47,49-71,73-95\ng4\ng2,g1"
+set channels [splitchans $chans]
+
+get destination "s" "\nEnter destination number"
+get context "default" "\nEnter context"
+get extension "s" "\nEnter extension"
+get priority "1" "\nEnter priority"
+get timeout "45" "\nEnter timeout for call to be answered in seconds"
+get maxretries "0" "\nEnter maximum number of retries"
+
+if { $maxretries > 0 } {
+ get retrytime "300" "\nEnter time between retries in seconds"
+} else {
+ set retrytime 300
+}
+
+get clid "" "\nEnter callerid"
+get astvar "" "\nEnter some extra variables"
+get account "loadtest" "\nEnter account code"
+get calls "1" "\nEnter number of test calls per $changroup"
+get period "60" "\nEnter period between placing calls on a particular $changroup in seconds"
+
+if { [llength $channels] > 1 } {
+ get rate "0" "\nEnter period between placing each call in seconds
+0 will send a call on each $changroup every $period seconds
+1 will send a call on $changroup [lindex $channels 0] at [expr {$period + 0}]s, [lindex $channels 1] at [expr {$period + 1 }]s, etc.
+5 will send a call on $changroup [lindex $channels 0] at [expr {$period + 0}]s, [lindex $channels 1] at [expr {$period + 5 }]s, etc."
+} else {
+ set rate 0
+}
+
+puts -nonewline "\nCreating spooled call files... "
+set now [clock seconds]
+set spoolcnt 0
+set spinner [list / - \\ |]
+for {set i 0} {$i < $calls} {incr i} {
+ foreach ch $channels {
+ set chidx [lsearch $channels $ch]
+ spool $ch [incr spoolcnt] [expr {$now + ($i * $period) + ($rate * $chidx)}]
+ puts -nonewline "\b"
+ puts -nonewline [lindex $spinner [expr {$spoolcnt % 4}]]
+ flush stdout
+ }
+}
+puts "\b$spoolcnt calls placed into $SPOOLDIR !"
diff --git a/trunk/contrib/scripts/lookup.agi b/trunk/contrib/scripts/lookup.agi
new file mode 100644
index 000000000..4b682b837
--- /dev/null
+++ b/trunk/contrib/scripts/lookup.agi
@@ -0,0 +1,90 @@
+#!/usr/bin/perl
+#
+# Use Reverse Lookups to populate valuable information
+#
+# Copyright (C) 2005 Digium, Inc.
+#
+# Mark Spencer <markster@digium.com>
+#
+# Based on work of Joe Fratantoni - BrakeDanceJ - Joe@UnrealDestination.com.
+#
+# This program is Free Software distributed under the terms of the GNU
+# General Public License version 2. See LICENSE for details.
+#
+#
+use LWP::UserAgent;
+my %AGI;
+my $debug = 0;
+$|=1;
+sub url_decode {
+ my @args = @_;
+ s/%([0-9A-F]{2})/chr hex $1/egios for @args;
+ s/\"//egios for @args;
+ return wantarray ? @args : $args[0];
+}
+
+while(<STDIN>) {
+ chomp;
+ last unless length($_);
+ if (/^agi_(\w+)\:\s+(.*)$/) {
+ $AGI{$1} = $2;
+ }
+}
+
+alarm(4);
+my $number = $AGI{'callerid'};
+$number =~ /(\d+)/;
+$number = $1;
+die("You must specify a number") unless $number;
+my $ua = LWP::UserAgent->new;
+$ua->agent("Asterisk");
+my $req = HTTP::Request->new(POST => 'http://www.411.com/10668/search/Reverse_Phone');
+$req->content_type('application/x-www-form-urlencoded');
+$req->content("phone=$number");
+my $res = $ua->request($req);
+if ($res->is_success) {
+ my $first, $last, $address, $street, $house, $city, $state, $zip, $phone;
+ if ($res->content =~ /PAGE: PHONE_NOT_FOUND/) {
+ # Limited Information
+ $res->content =~ /is a \s+([A-Za-z -]*), ([A-Z]{2}) \s+based phone number and the registered carrier is (.*)\.\s+/;
+ ($city, $state, $last) =
+ map { url_decode($_) } ($1, $2, $3);
+ $cidname = "$city, $state";
+ } else {
+ # Full Information
+ $res->content =~ /RM_HTML_FIRST_ESC_=(.*)&_RM_HTML_LAST_ESC_=(.*)&_RM_HTML_ADDRESS_ESC_=(.*)&_RM_HTML_STREET_ESC_=(.*)&_RM_HTML_HOUSE_ESC_=(.*)&_RM_HTML_CITY_ESC_=(.*)&_RM_HTML_STATE_ESC_=(.*)&_RM_HTML_ZIP_ESC_=(.*)&_RM_HTML_PHONE_ESC_=(.*)&CITY=(.*)&STATE=(.*)/;
+ ($first, $last, $address, $street, $house, $city, $state, $zip, $phone) =
+ map { url_decode($_) } ($1, $2, $3, $4, $5, $6, $7, $8, $9);
+ my $cidname = $last;
+ if ($first) {
+ $cidname = $first . " " . $last;
+ } else {
+ $cidname = $last;
+ }
+ }
+ print STDOUT "SET VARIABLE CALLERID(name) \"$cidname\"\n";
+ <STDIN>;
+ print STDOUT "SET VARIABLE CALLER_ZIP \"$zip\"\n";
+ <STDIN>;
+ print STDOUT "SET VARIABLE CALLER_STATE \"$state\"\n";
+ <STDIN>;
+ print STDOUT "SET VARIABLE CALLER_CITY \"$city\"\n";
+ <STDIN>;
+ print STDOUT "SET VARIABLE CALLER_ADDRESS \"$address\"\n";
+ <STDIN>;
+ print STDOUT "SET VARIABLE CALLER_LAST \"$last\"\n";
+ <STDIN>;
+ print STDOUT "SET VARIABLE CALLER_FIRST \"$first\"\n";
+ <STDIN>;
+ print STDERR "First: $first\n" .
+ "Last: $last\n" .
+ "Address: $address\n" .
+ "Street: $street\n" .
+ "House: $house\n" .
+ "City: $city\n" .
+ "State: $state\n" .
+ "Zip: $zip\n" .
+ "Phone: $phone\n" if $debug;
+} else {
+ print STDERR $res->status_line . "\n";
+}
diff --git a/trunk/contrib/scripts/managerproxy.pl b/trunk/contrib/scripts/managerproxy.pl
new file mode 100644
index 000000000..cdf79a239
--- /dev/null
+++ b/trunk/contrib/scripts/managerproxy.pl
@@ -0,0 +1,242 @@
+#!/usr/bin/perl -w
+#
+# Simple Asterisk Manager Proxy, Version 1.01
+# 2004-09-26
+# Copyright (c) 2004 David C. Troy <dave@popvox.com>
+#
+# This code is based on Flash Operator Panel 'op_server.pl'
+# by Nicolas Gudino
+#  Copyright (C) 2004.
+#
+# David C. Troy <dave@popvox.com>
+# Nicolas Gudino <nicolas@house.com.ar>
+#
+# This program is free software, distributed under the terms of
+# the GNU General Public License.
+#
+# Security consideration: This script will open your manager port
+# for unauthenticated logins. Be careful out there :-)
+#############################
+
+#############################
+# Perl Prerequisites
+#############################
+use strict;
+use IO::Socket;
+use IO::Select;
+use POSIX qw(setsid);
+
+#############################
+# User Configurable Options
+#############################
+# Configuration for logging in to your asterisk server
+# Check you Asterisk config file "manager.conf" for details
+my $manager_host = '127.0.0.1';
+my $manager_port = 5038;
+my $manager_user = 'your_username';
+my $manager_secret = 'your_secret';
+# Port For this proxy
+my $listen_port = 1234;
+my $manager_pid = "/var/run/asterisk_managerproxy.pid";
+
+#############################
+# Declarations
+#############################
+my %proxy_clients;
+my $O;
+my $p;
+my @S;
+my %blocks;
+my $debug = 0;
+
+$SIG{PIPE} = 'IGNORE';
+$SIG{INT} = 'close_all';
+$SIG{USR1} = 'list_clients';
+
+if (defined($ARGV[0]))
+{
+ if ($ARGV[0] eq "-d")
+ {
+ defined(my $pid = fork) or die "Can't Fork: $!";
+ exit if $pid;
+ setsid or die "Can't start a new session: $!";
+ open MYPIDFILE, ">$manager_pid";
+ print MYPIDFILE $$;
+ close MYPIDFILE;
+ }
+} else {
+ $debug = 1;
+}
+
+
+# Connect to manager
+$p =
+ new IO::Socket::INET->new(
+ PeerAddr => $manager_host,
+ PeerPort => $manager_port,
+ Proto => "tcp",
+ Type => SOCK_STREAM
+ )
+ or die "\nCould not connect to Asterisk Manager Port at $manager_host\n";
+
+$p->autoflush(1);
+
+# Login to Manager
+send_command_to_manager( "Action: Login\r\nUsername: $manager_user\r\nSecret: $manager_secret\r\n\r\n" );
+
+# Start up listener for new connections
+my $m =
+ new IO::Socket::INET(Listen => 1, LocalPort => $listen_port, ReuseAddr => 1)
+ or die "\nCan't listen to port $listen_port\n";
+$O = new IO::Select();
+$O->add($m);
+$O->add($p);
+$/ = "\0";
+
+sub manager_reconnect()
+{
+ my $attempt = 1;
+ my $total_attempts = 60;
+
+ do
+ {
+ log_debug("** Attempt reconnection to manager port # $attempt", 16);
+ $p =
+ new IO::Socket::INET->new(
+ PeerAddr => $manager_host,
+ PeerPort => $manager_port,
+ Proto => "tcp",
+ Type => SOCK_STREAM
+ );
+ $attempt++;
+ if ($attempt > $total_attempts)
+ {
+ die("!! Could not reconnect to Asterisk Manager port");
+ }
+ sleep(10); # wait 10 seconds before trying to reconnect
+ } until $p;
+ $O->add($p);
+ send_command_to_manager(
+ "Action: Login\r\nUsername: $manager_user\r\nSecret: $manager_secret\r\n\r\n"
+ );
+}
+
+# Loop, continuously processing new connections, input from those connections, and input from Manager conn
+while (1)
+{
+ while (@S = $O->can_read)
+ {
+ foreach (@S)
+ {
+ if ($_ == $m)
+ {
+ log_debug("** New client connection", 16);
+ my $C = $m->accept;
+ $proxy_clients{$C} = \$C;
+ print "New Connection: $C\n" if $debug;
+ $O->add($C);
+ } else {
+ # It's not a new client connection
+ my $i;
+ my $R = sysread($_, $i, 2); # 2048; interleave every two bytes?
+ if (defined($R) && $R == 0)
+ {
+ # Confirm it's really dead by trying to write to it?
+ my $T = syswrite($_, ' ', 2); # 2048
+ if (!defined($T))
+ {
+ # connection went away...
+ $O->remove($_);
+ $_->close;
+
+ # If we lost the socket for the Asterisk Mgr, then reconnect
+ if ($_ == $p)
+ {
+ log_debug(
+ "** Asterisk Manager connection lost!!!!!",
+ 16);
+ manager_reconnect();
+ } else {
+ # Remove handle from proxy_clients hash
+ print "Closed Connection: $_\n" if $debug;
+ delete $proxy_clients{$_};
+ }
+ }
+ }
+ else # Socket is active and we are ready to read something from it
+ {
+ $blocks{$_} .= $i;
+ next if ($blocks{$_} !~ /\r\n\r\n$/);
+ # do a 'next' unless we have completed a block; we are not ready to continue
+
+ # Process the completed block
+ # If block is from asterisk, send to clients
+ if ($_ == $p) {
+ # block is from asterisk, send to clients
+ print "asterisk: $_\n$blocks{$_}" if $debug;
+ my $cnt = 0;
+ foreach my $client (values %proxy_clients) {
+ print "writing to $$client...\n" if $debug;
+ syswrite($$client, $blocks{$_});
+ $cnt++;
+ }
+ print "sent block to $cnt clients\n" if $debug;
+ } else {
+ # Blocks are from clients, send to asterisk
+ syswrite($p, $blocks{$_});
+ print "client: $_\n$blocks{$_}\n" if $debug;
+ }
+ delete $blocks{$_};
+
+ } # end if read succeeded
+ } # end if new client connection
+ } # end foreach @S -> can read
+ } # while can read
+} # endless loop
+
+sub close_all
+{
+ log_debug("Exiting...", 0);
+
+ foreach my $hd ($O->handles)
+ {
+ $O->remove($hd);
+ close($hd);
+ }
+
+ exit(0);
+}
+
+sub send_command_to_manager
+{
+ my $comando = shift;
+ if (defined $p)
+ {
+ my @lineas = split("\r\n", $comando);
+ foreach my $linea (@lineas)
+ {
+ syswrite($p, "$linea\r\n");
+ log_debug("-> $linea", 2);
+ }
+ log_debug(" ", 2);
+ syswrite($p, "\r\n");
+ }
+}
+
+sub log_debug
+{
+ my $texto = shift;
+ $texto =~ s/\0//g;
+ print "$texto\n" if $debug;
+}
+
+sub list_clients()
+{
+ my $cnt = 0;
+ foreach my $client (values %proxy_clients) {
+ print "client: $$client\n";
+ $cnt++;
+ }
+ print "$cnt clients.\n\n";
+}
+
diff --git a/trunk/contrib/scripts/meetme.sql b/trunk/contrib/scripts/meetme.sql
new file mode 100644
index 000000000..19c4ed745
--- /dev/null
+++ b/trunk/contrib/scripts/meetme.sql
@@ -0,0 +1,12 @@
+--
+-- Table structure for Realtime meetme
+--
+
+CREATE TABLE meetme (
+ confno char(80) DEFAULT '0' NOT NULL,
+ pin char(20) NULL,
+ adminpin char(20) NULL,
+ members integer DEFAULT 0 NOT NULL,
+ PRIMARY KEY (confno)
+);
+
diff --git a/trunk/contrib/scripts/messages-expire.pl b/trunk/contrib/scripts/messages-expire.pl
new file mode 100644
index 000000000..993997899
--- /dev/null
+++ b/trunk/contrib/scripts/messages-expire.pl
@@ -0,0 +1,96 @@
+#!/usr/bin/perl
+#
+# Script to expire voicemail after a specified number of days
+# by Steve Creel <screel@turbs.com>
+#
+
+# Directory housing the voicemail spool for asterisk
+$dir = "/var/spool/asterisk/voicemail";
+
+# Context for which the script should be running
+$context = "default";
+
+# Age (Delete files older than $age days old)
+$age = 31;
+
+# Age for unheard messages (Defaults to same age for all messages)
+# Set to 0 to not delete unheard messages
+$unheardage = $age;
+
+
+# Delete all files older than $age and $unheardage
+# (named msg????.??? to get the audio and txt files,
+# but we don't delete greetings or the user's name)
+
+if($age==$unheardage) {
+
+ # Save time by doing one find if we're treating everything the same
+ system('find '.$dir.'/'.$context.' -name msg????.??? -mtime +'.$age.' -exec rm {} \; -exec echo Deleted {} \;');
+
+} else {
+
+ # Find everything not in a folder called 'INBOX' and delete it after $age days
+ system('find '.$dir.'/'.$context.' -path \'*INBOX*\' -prune -o -name msg????.??? -mtime +'.$age.' -exec rm {} \; -exec echo Deleted {} \;');
+
+ # If unheardage is set to 0, we won't delete any unheard messages
+ if($unheardage > 0) {
+
+ # Delete things that are in a folder called INBOX after $unheardage days
+ system('find '.$dir.'/'.$context.' -path \'*INBOX*\' -name msg????.??? -mtime +'.$unheardage.' -exec rm {} \; -exec echo Deleted {} \;');
+
+ }
+}
+
+# For testing - what number to we start when we renumber?
+$start = "0";
+
+# Rename to msg and a 4 digit number, 0 padded.
+$fnbase = sprintf "msg%04d", $start;
+
+# Make $dir include the context too
+$dir.="/".$context;
+
+( -d $dir ) || die "Can't read list of mailboxes ($dir): $!\n";
+@mailboxes = `ls -A1 $dir`;
+chomp(@mailboxes);
+
+$save_fnbase = $fnbase;
+
+foreach $mailbox (@mailboxes) {
+
+ ( -d $dir."/".$mailbox) || die "Can't read list of folders (".$dir."/".$mailbox."): $!\n";
+ @folders = `ls -A1 $dir/$mailbox`;
+ chomp(@folders);
+
+ foreach $folder (@folders) {
+ if (-d $dir."/".$mailbox."/".$folder) {
+ ( -d $dir."/".$mailbox."/".$folder) || die "Can't read list of messages (".$dir."/".$mailbox."/".$folder.") $!\n";
+ @files = `ls -A1 $dir/$mailbox/$folder/`;
+
+ # Sort so everything is in proper order.
+ @files = sort @files;
+ chomp(@files);
+
+ # If there is still (after deleting old files earlier in the
+ # script) a msg0000.txt, we don't need to shuffle anything
+ # in this folder.
+ if (-f $dir."/".$mailbox."/".$folder."/msg0000.txt") { next; }
+
+ foreach $ext (("WAV", "wav", "gsm", "txt")) {
+ # Reset the fnbase for each file type
+ $fnbase = $save_fnbase;
+
+ foreach $file (@files) {
+ if ( $file =~ /$ext/ ) {
+ chdir($dir."/".$mailbox."/".$folder."/") || die "Can't change folder: $!";
+ print "Renaming: ".$dir."/".$mailbox."/".$folder."/".$file." to ".$fnbase.".".$ext."\n";
+ rename($file, $fnbase.".".$ext) || die "Cannot rename: $!";
+ $fnbase++;
+ }
+ }
+ }
+ }
+ }
+}
+
+__END__ \ No newline at end of file
diff --git a/trunk/contrib/scripts/postgres_cdr.sql b/trunk/contrib/scripts/postgres_cdr.sql
new file mode 100644
index 000000000..a4701bd77
--- /dev/null
+++ b/trunk/contrib/scripts/postgres_cdr.sql
@@ -0,0 +1,33 @@
+
+/*
+ * Id: postgres_cdr.sql,v 1.8.2.11 2003/10/10 11:15:43 pnixon Exp $
+ *
+ * --- Peter Nixon [ codemonkey@peternixon.net ]
+ *
+ * This is a PostgreSQL schema for doing CDR accounting with Asterisk
+ *
+ * The calls will automatically be logged as long as the module is loaded.
+ *
+ */
+
+
+CREATE TABLE cdr (
+ AcctId BIGSERIAL PRIMARY KEY,
+ calldate TIMESTAMP with time zone NOT NULL DEFAULT now(),
+ clid VARCHAR(80) NOT NULL default '',
+ src VARCHAR(80) NOT NULL default '',
+ dst VARCHAR(80) NOT NULL default '',
+ dcontext VARCHAR(80) NOT NULL default '',
+ channel VARCHAR(80) NOT NULL default '',
+ dstchannel VARCHAR(80) NOT NULL default '',
+ lastapp VARCHAR(80) NOT NULL default '',
+ lastdata VARCHAR(80) NOT NULL default '',
+ duration INTEGER NOT NULL default '0',
+ billsec INTEGER NOT NULL default '0',
+ disposition VARCHAR(45) NOT NULL default '',
+ amaflags INTEGER NOT NULL default '0',
+ accountcode VARCHAR(20) NOT NULL default '',
+ uniqueid VARCHAR(32) NOT NULL default '',
+ userfield VARCHAR(255) NOT NULL default ''
+);
+
diff --git a/trunk/contrib/scripts/qview.pl b/trunk/contrib/scripts/qview.pl
new file mode 100644
index 000000000..940e474f7
--- /dev/null
+++ b/trunk/contrib/scripts/qview.pl
@@ -0,0 +1,100 @@
+#!/usr/bin/perl
+#
+# Asterisk Queue Viewer
+# Uses management interface to query call queues on a machine
+# (C) 2003 David C. Troy -- dave@toad.net
+#
+# This program is free software, distributed under the terms of the
+# GNU General Public License
+#
+
+use IO::Socket;
+use CGI qw(:standard);
+use CGI::Carp qw/fatalsToBrowser/;
+
+$host = "asterisk.yourdomain.com";
+$port = 5038;
+$user = "manager_user";
+$secret = "Manager_secret";
+$EOL = "\015\012";
+$BLANK = $EOL x 2;
+$queue = param('queue');
+
+$remote = IO::Socket::INET->new(
+ Proto => 'tcp', # protocol
+ PeerAddr=> $host, # Address of server
+ PeerPort=> $port, # port of server
+ Reuse => 1
+ ) or die "$!";
+
+$remote->autoflush(1); # Send immediately
+
+# Login and get our booty from Asterisk
+$logres = send_cmd("Action: Login${EOL}Username: $user${EOL}Secret: $secret$BLANK");
+$qinfo = send_cmd("Action: queues$BLANK$EOL");
+$logres = send_cmd("Action: Logoff$BLANK");
+close $remote; # Close socket
+
+my %qcalls = map { /(\S+)\s+has (\d+) calls.*?\n\n/sg; } $qinfo;
+my %qmax = map { /(\S+)\s+has \d+ calls \(max (\S+)\).*?\n\n/sg; } $qinfo;
+my %qstrat = map { /(\S+)\s+has \d+ calls \(max \S+\) in (\S+) strategy.*?\n\n/sg; } $qinfo;
+my %qmems = map { /(\S+)\s+has \d+ calls.*?Members:.*?\s{6}(.*?)\s{3}\S*?\s*?Callers/sg; } $qinfo;
+my %qcallers = map { /(\S+)\s+has \d+ calls.*?([No ]*Callers.*?)\n\n/sg; } $qinfo;
+
+print header();
+print start_html(-head=>meta({-http_equiv=>'Refresh', -content=>'120'}),
+ -title=>"PBX Queue Viewer",
+ -style=>{'src'=>'/pbxinfo.css'});
+print "<table width=850><tr>";
+
+$col = 0;
+
+foreach $q (keys %qcalls) {
+
+ $mems = $qmems{$q};
+ $mems =~ s/ //g;
+ $mems =~ s/\n/<br>\n/g;
+ $callers = $qcallers{$q};
+ $callers =~ s/ //g;
+ $callers =~ s/Callers:.*\n//g;
+ $callers =~ s/\n/<br>/g;
+
+ print qq{<td valign=top width=48%><table width=100%>
+<tr><th colspan=2><A HREF=/mrtg/qmon-$q.html>$q</A>&nbsp;&nbsp;$qcalls{$q} calls (max $qmax{$q}), $qstrat{$q} strategy</th></tr>
+<tr><td valign=top width=55%>$mems</td><td valign=top width=45%>$callers</td></tr>
+</table></td>
+};
+
+ print "</tr><tr>" if $col;
+ $col = 0 if $col++;
+
+}
+
+print "</table>";
+
+print end_html();
+
+exit(0);
+
+sub read_conn {
+
+ my $buf="";
+ while (<$remote>) {
+ last if $_ eq $EOL;
+ s/$EOL/\n/g;
+ $buf .= $_;
+ }
+
+ return $buf
+}
+
+sub send_cmd {
+ my $cmd = @_[0];
+
+ my $buf="";
+ print $remote $cmd;
+
+ $buf = read_conn();
+
+ return $buf;
+}
diff --git a/trunk/contrib/scripts/realtime_pgsql.sql b/trunk/contrib/scripts/realtime_pgsql.sql
new file mode 100644
index 000000000..c0de544ab
--- /dev/null
+++ b/trunk/contrib/scripts/realtime_pgsql.sql
@@ -0,0 +1,141 @@
+drop table extensions_conf;
+
+CREATE TABLE extensions_conf (
+id serial NOT NULL,
+context character varying(20) DEFAULT '' NOT NULL,
+exten character varying(20) DEFAULT '' NOT NULL,
+priority smallint DEFAULT 0 NOT NULL,
+app character varying(20) DEFAULT '' NOT NULL,
+appdata character varying(128)
+);
+
+drop table cdr;
+CREATE TABLE cdr (
+calldate timestamp with time zone DEFAULT now() NOT NULL,
+clid character varying(80) DEFAULT '' NOT NULL,
+src character varying(80) DEFAULT '' NOT NULL,
+dst character varying(80) DEFAULT '' NOT NULL,
+dcontext character varying(80) DEFAULT '' NOT NULL,
+channel character varying(80) DEFAULT '' NOT NULL,
+dstchannel character varying(80) DEFAULT '' NOT NULL,
+lastapp character varying(80) DEFAULT '' NOT NULL,
+lastdata character varying(80) DEFAULT '' NOT NULL,
+duration bigint DEFAULT 0::bigint NOT NULL,
+billsec bigint DEFAULT 0::bigint NOT NULL,
+disposition character varying(45) DEFAULT '' NOT NULL,
+amaflags bigint DEFAULT 0::bigint NOT NULL,
+accountcode character varying(20) DEFAULT '' NOT NULL,
+uniqueid character varying(32) DEFAULT '' NOT NULL,
+userfield character varying(255) DEFAULT '' NOT NULL
+);
+
+drop table sip_conf;
+CREATE TABLE sip_conf (
+id serial NOT NULL,
+name character varying(80) DEFAULT '' NOT NULL,
+accountcode character varying(20),
+amaflags character varying(7),
+callgroup character varying(10),
+callerid character varying(80),
+canreinvite character varying(3) DEFAULT 'yes',
+context character varying(80),
+defaultip character varying(15),
+dtmfmode character varying(7),
+fromuser character varying(80),
+fromdomain character varying(80),
+host character varying(31) DEFAULT '' NOT NULL,
+insecure character varying(4),
+"language" character varying(2),
+mailbox character varying(50),
+md5secret character varying(80),
+nat character varying(5) DEFAULT 'no' NOT NULL,
+permit character varying(95),
+deny character varying(95),
+mask character varying(95),
+pickupgroup character varying(10),
+port character varying(5) DEFAULT '' NOT NULL,
+qualify character varying(3),
+restrictcid character varying(1),
+rtptimeout character varying(3),
+rtpholdtimeout character varying(3),
+secret character varying(80),
+"type" character varying DEFAULT 'friend' NOT NULL,
+username character varying(80) DEFAULT '' NOT NULL,
+disallow character varying(100) DEFAULT 'all',
+allow character varying(100) DEFAULT 'g729;ilbc;gsm;ulaw;alaw',
+musiconhold character varying(100),
+regseconds bigint DEFAULT 0::bigint NOT NULL,
+ipaddr character varying(15) DEFAULT '' NOT NULL,
+regexten character varying(80) DEFAULT '' NOT NULL,
+cancallforward character varying(3) DEFAULT 'yes'
+);
+
+drop table voicemail_users;
+CREATE TABLE voicemail_users (
+id serial NOT NULL,
+customer_id bigint DEFAULT (0)::bigint NOT NULL,
+context character varying(50) DEFAULT '' NOT NULL,
+mailbox bigint DEFAULT (0)::bigint NOT NULL,
+"password" character varying(4) DEFAULT '0' NOT NULL,
+fullname character varying(50) DEFAULT '' NOT NULL,
+email character varying(50) DEFAULT '' NOT NULL,
+pager character varying(50) DEFAULT '' NOT NULL,
+stamp timestamp(6) without time zone NOT NULL
+);
+
+drop table queue_table;
+CREATE TABLE queue_table (
+name varchar(128),
+musiconhold varchar(128),
+announce varchar(128),
+context varchar(128),
+timeout int8,
+monitor_join bool,
+monitor_format varchar(128),
+queue_youarenext varchar(128),
+queue_thereare varchar(128),
+queue_callswaiting varchar(128),
+queue_holdtime varchar(128),
+queue_minutes varchar(128),
+queue_seconds varchar(128),
+queue_lessthan varchar(128),
+queue_thankyou varchar(128),
+queue_reporthold varchar(128),
+announce_frequency int8,
+announce_round_seconds int8,
+announce_holdtime varchar(128),
+retry int8,
+wrapuptime int8,
+maxlen int8,
+servicelevel int8,
+strategy varchar(128),
+joinempty varchar(128),
+leavewhenempty varchar(128),
+eventmemberstatus bool,
+eventwhencalled bool,
+reportholdtime bool,
+memberdelay int8,
+weight int8,
+timeoutrestart bool,
+PRIMARY KEY (name)
+) WITHOUT OIDS;
+ALTER TABLE queue_table OWNER TO asterisk;
+
+drop table queue_member_table;
+CREATE TABLE queue_member_table
+(
+queue_name varchar(128),
+interface varchar(128),
+penalty int8,
+PRIMARY KEY (queue_name, interface)
+) WITHOUT OIDS;
+
+GRANT ALL ON TABLE cdr TO asterisk;
+GRANT ALL ON TABLE extensions_conf TO asterisk;
+GRANT ALL ON TABLE sip_conf TO asterisk;
+GRANT ALL ON TABLE voicemail_users TO asterisk;
+GRANT ALL ON TABLE queue_member_table TO asterisk;
+GRANT ALL ON TABLE queue_table TO asterisk;
+
+
+
diff --git a/trunk/contrib/scripts/retrieve_extensions_from_mysql.pl b/trunk/contrib/scripts/retrieve_extensions_from_mysql.pl
new file mode 100644
index 000000000..ca195cfe5
--- /dev/null
+++ b/trunk/contrib/scripts/retrieve_extensions_from_mysql.pl
@@ -0,0 +1,113 @@
+#!/usr/bin/perl -Tw
+# Use these commands to create the appropriate tables in MySQL
+# If flags is 1 then this record is not included in the output extensions file
+#
+#CREATE TABLE extensions (
+# context CHAR(20) DEFAULT 'default' NOT NULL,
+# extension CHAR(20) NOT NULL,
+# priority INT(2) DEFAULT '1' NOT NULL,
+# application CHAR(20) NOT NULL,
+# args CHAR(50),
+# descr TEXT,
+# flags INT(1) DEFAULT '0' NOT NULL,
+# PRIMARY KEY(context, extension, priority)
+#);
+#
+#CREATE TABLE globals (
+# variable CHAR(20) NOT NULL,
+# value CHAR(50) NOT NULL,
+# PRIMARY KEY(variable, value)
+#);
+
+use DBI;
+################### BEGIN OF CONFIGURATION ####################
+
+# the name of the extensions table
+$table_name = "extensions";
+# the name of the globals table
+$global_table_name = "globals";
+# the path to the extensions.conf file
+# WARNING: this file will be substituted by the output of this program
+$extensions_conf = "/etc/asterisk/extensions.conf";
+# the name of the box the MySQL database is running on
+$hostname = "localhost";
+# the name of the database our tables are kept
+$database = "user";
+# username to connect to the database
+$username = "";
+# password to connect to the database
+$password = "";
+
+################### END OF CONFIGURATION #######################
+
+open EXTEN, ">$extensions_conf" || die "Cannot create/overwrite extensions file: $extensions_conf\n";
+
+$dbh = DBI->connect("dbi:mysql:dbname=$database;host=$hostname", "$username", "$password");
+$statement = "SELECT * from $global_table_name order by variable";
+my $result = $dbh->selectall_arrayref($statement);
+unless ($result) {
+ # check for errors after every single database call
+ print "dbh->selectall_arrayref($statement) failed!\n";
+ print "DBI::err=[$DBI::err]\n";
+ print "DBI::errstr=[$DBI::errstr]\n";
+ exit;
+}
+my @resultSet = @{$result};
+if ( $#resultSet > -1 ) {
+ print EXTEN "[globals]\n";
+ foreach $row (@{ $result }) {
+ my @result = @{ $row };
+ print EXTEN "$result[0] = $result[1]\n";
+ }
+ print EXTEN "\n";
+}
+
+$statement = "SELECT context from $table_name group by context";
+
+$result = $dbh->selectall_arrayref($statement);
+unless ($result) {
+ # check for errors after every single database call
+ print "dbh->selectall_arrayref($statement) failed!\n";
+ print "DBI::err=[$DBI::err]\n";
+ print "DBI::errstr=[$DBI::errstr]\n";
+}
+
+@resultSet = @{$result};
+if ( $#resultSet == -1 ) {
+ print "No extensions defined in $table_name\n";
+ exit;
+}
+
+foreach my $row ( @{ $result } ) {
+ my $context = @{ $row }[0];
+ print EXTEN "[$context]\n";
+ $statement = "SELECT * from $table_name where context='$context' order by extension, priority";
+ my $result = $dbh->selectall_arrayref($statement);
+ unless ($result) {
+ # check for errors after every single database call
+ print "dbh->selectall_arrayref($statement) failed!\n";
+ print "DBI::err=[$DBI::err]\n";
+ print "DBI::errstr=[$DBI::errstr]\n";
+ exit;
+ }
+
+ my @resSet = @{$result};
+ if ( $#resSet == -1 ) {
+ print "no results\n";
+ exit;
+ }
+ foreach my $row ( @{ $result } ) {
+ my @result = @{ $row };
+ if ($result[6] == 0) {
+ print EXTEN "exten => $result[1],$result[2],$result[3]";
+ print EXTEN "($result[4])" if defined $result[4];
+ print EXTEN "\t" if not defined $result[4];
+ print EXTEN "\t; $result[5]" if defined $result[5];
+ print EXTEN "\n";
+ }
+ }
+ print EXTEN "\n";
+}
+
+exit 0;
+
diff --git a/trunk/contrib/scripts/retrieve_extensions_from_sql.pl b/trunk/contrib/scripts/retrieve_extensions_from_sql.pl
new file mode 100644
index 000000000..cf17d0351
--- /dev/null
+++ b/trunk/contrib/scripts/retrieve_extensions_from_sql.pl
@@ -0,0 +1,158 @@
+#!/usr/bin/perl -Tw
+# Author: Peter Nixon <codemonkey@peternixon.net>
+# Date: April 2004
+# Copy Policy: GNU Public Licence Version 2 or later
+# URL: http://www.peternixon.net/code/
+# Supported: PostgreSQL, Oracle, MySQL
+# Copyright: 2004 Peter Nixon <codemonkey@petenixon.net>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# $Id$
+#
+# Use these commands to create the appropriate SQL tables
+# If flags is 1 then the record is not included in the output extensions file
+#
+#CREATE TABLE extensions (
+# context VARCHAR(20) DEFAULT 'default' NOT NULL,
+# extension VARCHAR(20) NOT NULL,
+# priority INTEGER DEFAULT '1' NOT NULL,
+# application VARCHAR(20) NOT NULL,
+# args VARCHAR(50),
+# descr TEXT,
+# flags BOOLEAN DEFAULT '0' NOT NULL,
+# PRIMARY KEY(context, extension, priority)
+#);
+
+#CREATE TABLE globals (
+# variable VARCHAR(20) NOT NULL,
+# value VARCHAR(50) NOT NULL,
+# PRIMARY KEY(variable, value)
+#);
+
+use strict; # Make sure we write decent perl code
+
+require DBI; # We need database drivers for this thing to work
+
+################### BEGIN OF CONFIGURATION ####################
+
+my $table_name = "extensions"; # name of the extensions table
+my $global_table_name = "globals"; # name of the globals table
+my $extensions_conf = "/etc/asterisk/extensions.conf"; # path to extensions.conf
+# WARNING: this file will be substituted by the output of this program
+my $dbbrand = "Pg"; # Hint: "mysql" or any other Perl DBI driver.
+my $hostname = "localhost"; # The SQL server's hostname or IP
+my $database = "peter"; # the name of the database our tables are kept
+my $username = "peter"; # username to connect to the database
+my $password = ""; # password to connect to the database
+my $verbose = 1; # Verbosity Level (0 - 2)
+
+################### END OF CONFIGURATION #######################
+
+# You should not need to edit anything below here
+my $dbh;
+
+sub db_connect {
+ if ($verbose > 1) { print "DEBUG: Connecting to Database Host: $hostname\n" }
+ if ($hostname eq 'localhost') {
+ if ($verbose > 1) { print "DEBUG: SQL server is on localhost so using UNIX socket instead of network socket.\n" }
+ $dbh = DBI->connect("DBI:$dbbrand:dbname=$database", "$username", "$password")
+ or die "Couldn't connect to database: " . DBI->errstr;
+ }
+ else {
+ $dbh = DBI->connect("DBI:$dbbrand:dbname=$database;host=$hostname", "$username", "$password")
+ or die "Couldn't connect to database: " . DBI->errstr;
+ }
+}
+
+sub db_disconnect {
+ if ($verbose > 1) { print "DEBUG: Disconnecting from Database Host: $hostname\n" }
+ $dbh->disconnect
+ or warn "Disconnection failed: $DBI::errstr\n";
+}
+
+sub get_globals {
+ if ($verbose > 0) { print "Checking Database for [global] variables\n"; }
+ my $sth = $dbh->prepare("SELECT variable, value FROM $global_table_name ORDER BY variable")
+ or die "Couldn't prepare statement: " . $dbh->errstr;
+
+ $sth->execute() # Execute the query
+ or die "Couldn't execute SELECT statement: " . $sth->errstr;
+
+ if ($sth->rows > 0) {
+ print EXTEN "[globals]\n";
+ while (my @global = $sth->fetchrow_array()) {
+ print EXTEN "$global[0] = $global[1]\n";
+ }
+ print EXTEN "\n";
+ } else {
+ print "WARNING: You have no global variables set\n";
+ }
+ $sth->finish;
+}
+
+sub get_contexts {
+ if ($verbose > 0) { print "Checking Database for contexts\n"; }
+ my $sth = $dbh->prepare("SELECT context FROM $table_name GROUP BY context")
+ or die "Couldn't prepare statement: " . $dbh->errstr;
+
+ $sth->execute() # Execute the query
+ or die "Couldn't execute SELECT statement: " . $sth->errstr;
+
+ if ($sth->rows > 0) {
+ while (my @context = $sth->fetchrow_array()) {
+ print EXTEN "[$context[0]]\n";
+ &get_extensions($context[0]);
+ print EXTEN "\n";
+ }
+ print EXTEN "\n";
+ } else {
+ print "WARNING: You have no contexts defined in the $table_name table\n";
+ }
+ $sth->finish;
+}
+
+sub get_extensions {
+ my $context = $_[0]; my @extension;
+ if ($verbose > 0) { print " Checking Database for [$context] extensions\n"; }
+ my $sth = $dbh->prepare("SELECT extension, priority, application, args, descr FROM $table_name WHERE context='$context' AND flags = '0' ORDER BY extension, priority")
+ or die "Couldn't prepare statement: " . $dbh->errstr;
+
+ $sth->execute() # Execute the query
+ or die "Couldn't execute SELECT statement: " . $sth->errstr;
+
+ if ($sth->rows > 0) {
+ while (@extension = $sth->fetchrow_array()) {
+ print EXTEN "exten => $extension[0],$extension[1],$extension[2]";
+ print EXTEN "($extension[3])" if defined $extension[3];
+ print EXTEN " ; $extension[4]" if defined $extension[4];
+ print EXTEN "\n";
+ }
+ } else {
+ print "WARNING: You have no extensions for [$context]\n";
+ }
+ $sth->finish;
+}
+
+
+sub main {
+ open EXTEN, ">$extensions_conf" || die "Cannot create/overwrite extensions file: $extensions_conf\n";
+ &db_connect;
+ &get_globals;
+ &get_contexts;
+ &db_disconnect;
+ close EXTEN; # Close the file handle
+ if ($verbose > 0) { print "New $extensions_conf successfully written.\n"; }
+ return 1;
+}
+
+
+exit &main();
diff --git a/trunk/contrib/scripts/retrieve_sip_conf_from_mysql.pl b/trunk/contrib/scripts/retrieve_sip_conf_from_mysql.pl
new file mode 100644
index 000000000..03395a125
--- /dev/null
+++ b/trunk/contrib/scripts/retrieve_sip_conf_from_mysql.pl
@@ -0,0 +1,93 @@
+#!/usr/bin/perl -Tw
+# Retrieves the sip user/peer entries from the database
+# Use these commands to create the appropriate tables in MySQL
+#
+#CREATE TABLE sip (id INT(11) DEFAULT -1 NOT NULL,keyword VARCHAR(20) NOT NULL,data VARCHAR(50) NOT NULL, flags INT(1) DEFAULT 0 NOT NULL,PRIMARY KEY (id,keyword));
+#
+# if flags = 1 then the records are not included in the output file
+
+use DBI;
+################### BEGIN OF CONFIGURATION ####################
+
+# the name of the extensions table
+$table_name = "sip";
+# the path to the extensions.conf file
+# WARNING: this file will be substituted by the output of this program
+$sip_conf = "/etc/asterisk/sip_additional.conf";
+# the name of the box the MySQL database is running on
+$hostname = "localhost";
+# the name of the database our tables are kept
+$database = "sip";
+# username to connect to the database
+$username = "root";
+# password to connect to the database
+$password = "";
+
+################### END OF CONFIGURATION #######################
+
+$additional = "";
+
+open EXTEN, ">$sip_conf" || die "Cannot create/overwrite extensions file: $sip_conf\n";
+
+$dbh = DBI->connect("dbi:mysql:dbname=$database;host=$hostname", "$username", "$password");
+$statement = "SELECT keyword,data from $table_name where id=0 and keyword <> 'account' and flags <> 1";
+my $result = $dbh->selectall_arrayref($statement);
+unless ($result) {
+ # check for errors after every single database call
+ print "dbh->selectall_arrayref($statement) failed!\n";
+ print "DBI::err=[$DBI::err]\n";
+ print "DBI::errstr=[$DBI::errstr]\n";
+ exit;
+}
+my @resultSet = @{$result};
+if ( $#resultSet > -1 ) {
+ foreach $row (@{ $result }) {
+ my @result = @{ $row };
+ $additional .= $result[0]."=".$result[1]."\n";
+ }
+}
+
+$statement = "SELECT data,id from $table_name where keyword='account' and flags <> 1 group by data";
+
+$result = $dbh->selectall_arrayref($statement);
+unless ($result) {
+ # check for errors after every single database call
+ print "dbh->selectall_arrayref($statement) failed!\n";
+ print "DBI::err=[$DBI::err]\n";
+ print "DBI::errstr=[$DBI::errstr]\n";
+}
+
+@resultSet = @{$result};
+if ( $#resultSet == -1 ) {
+ print "No sip accounts defined in $table_name\n";
+ exit;
+}
+
+foreach my $row ( @{ $result } ) {
+ my $account = @{ $row }[0];
+ my $id = @{ $row }[1];
+ print EXTEN "[$account]\n";
+ $statement = "SELECT keyword,data from $table_name where id=$id and keyword <> 'account' and flags <> 1 order by keyword";
+ my $result = $dbh->selectall_arrayref($statement);
+ unless ($result) {
+ # check for errors after every single database call
+ print "dbh->selectall_arrayref($statement) failed!\n";
+ print "DBI::err=[$DBI::err]\n";
+ print "DBI::errstr=[$DBI::errstr]\n";
+ exit;
+ }
+
+ my @resSet = @{$result};
+ if ( $#resSet == -1 ) {
+ print "no results\n";
+ exit;
+ }
+ foreach my $row ( @{ $result } ) {
+ my @result = @{ $row };
+ print EXTEN "$result[0]=$result[1]\n";
+ }
+ print EXTEN "$additional\n";
+}
+
+exit 0;
+
diff --git a/trunk/contrib/scripts/safe_asterisk b/trunk/contrib/scripts/safe_asterisk
new file mode 100644
index 000000000..05e44d895
--- /dev/null
+++ b/trunk/contrib/scripts/safe_asterisk
@@ -0,0 +1,184 @@
+#!/bin/bash
+# vim:textwidth=80:tabstop=4:shiftwidth=4:smartindent:autoindent
+
+CLIARGS="$*" # Grab any args passed to safe_asterisk
+TTY=9 # TTY (if you want one) for Asterisk to run on
+CONSOLE=yes # Whether or not you want a console
+#NOTIFY=ben@alkaloid.net # Who to notify about crashes
+#EXEC=/path/to/somescript # Run this command if Asterisk crashes
+#LOGFILE=/path/to/logfile # Where to place the normal logfile (disabled if blank)
+#SYSLOG=local0 # Which syslog facility to use (disabled if blank)
+MACHINE=`hostname` # To specify which machine has crashed when getting the mail
+DUMPDROP=/tmp
+SLEEPSECS=4
+ASTSBINDIR=__ASTERISK_SBIN_DIR__
+ASTPIDFILE=__ASTERISK_VARRUN_DIR__/asterisk.pid
+
+# comment this line out to have this script _not_ kill all mpg123 processes when
+# asterisk exits
+KILLALLMPG123=1
+
+# run asterisk with this priority
+PRIORITY=0
+
+# set system filemax on supported OSes if this variable is set
+# SYSMAXFILES=262144
+
+# set max files open with ulimit. On linux systems, this will be automatically
+# set to the system's maximum files open devided by two, if not set here.
+# MAXFILES=32768
+
+function message() {
+ echo "$1" >&2
+ if [ "$SYSLOG" != "" ]; then
+ logger -p "${SYSLOG}.warn" -t safe_asterisk[$$] "$1"
+ fi
+ if [ "$LOGFILE" != "" ]; then
+ echo "safe_asterisk[$$]: $1" >> "$LOGFILE"
+ fi
+}
+
+# since we're going to change priority and open files limits, we need to be
+# root. if running asterisk as other users, pass that to asterisk on the command
+# line.
+# if we're not root, fall back to standard everything.
+if [ `id -u` != 0 ]
+then
+ echo "Oops. I'm not root. Falling back to standard prio and file max." >&2
+ echo "This is NOT suitable for large systems." >&2
+ PRIORITY=0
+ message "safe_asterisk was started by `id -n` (uid `id -u`)."
+else
+ if `echo $OSTYPE | grep linux 2>&1 > /dev/null `
+ then
+ # maximum number of open files is set to the system maximum divided by two if
+ # MAXFILES is not set.
+ if [ "$MAXFILES" = "" ]
+ then
+ # just check if file-max is readable
+ if [ -r /proc/sys/fs/file-max ]
+ then
+ MAXFILES=$(( `cat /proc/sys/fs/file-max` / 2 ))
+ fi
+ fi
+ SYSCTL_MAXFILES="fs.file-max"
+ elif `echo $OSTYPE | grep darwin 2>&1 > /dev/null `
+ then
+ SYSCTL_MAXFILES="kern.maxfiles"
+ fi
+
+
+ if [ "$SYSMAXFILES" != "" ]
+ then
+ if [ "$SYSCTL_MAXFILES" != "" ]
+ then
+ sysctl -w $SYSCTL_MAXFILES=$SYSMAXFILES
+ fi
+ fi
+
+ # set the process's filemax to whatever set above
+ ulimit -n $MAXFILES
+
+fi
+
+#
+# Let Asterisk dump core
+#
+ulimit -c unlimited
+
+#
+# Don't fork when running "safely"
+#
+ASTARGS=""
+if [ "$TTY" != "" ]; then
+ if [ -c /dev/tty${TTY} ]; then
+ TTY=tty${TTY}
+ elif [ -c /dev/vc/${TTY} ]; then
+ TTY=vc/${TTY}
+ else
+ message "Cannot find specified TTY (${TTY})"
+ exit 1
+ fi
+ ASTARGS="${ASTARGS} -vvvg"
+ if [ "$CONSOLE" != "no" ]; then
+ ASTARGS="${ASTARGS} -c"
+ fi
+fi
+if [ ! -w ${DUMPDROP} ]; then
+ message "Cannot write to ${DUMPDROP}"
+ exit 1
+fi
+
+#
+# Don't die if stdout/stderr can't be written to
+#
+trap '' PIPE
+
+#
+# Run scripts to set any environment variables or do any other system-specific setup needed
+#
+
+if [ -d /etc/asterisk/startup.d ]; then
+ for script in /etc/asterisk/startup.d/*.sh; do
+ if [ -x ${script} ]; then
+ source ${script}
+ fi
+ done
+fi
+
+run_asterisk()
+{
+ while :; do
+
+ if [ "$TTY" != "" ]; then
+ cd /tmp
+ stty sane < /dev/${TTY}
+ nice -n $PRIORITY ${ASTSBINDIR}/asterisk -f ${CLIARGS} ${ASTARGS} >& /dev/${TTY} < /dev/${TTY}
+ else
+ cd /tmp
+ nice -n $PRIORITY ${ASTSBINDIR}/asterisk -f ${CLIARGS} ${ASTARGS}
+ fi
+ EXITSTATUS=$?
+ message "Asterisk ended with exit status $EXITSTATUS"
+ if [ "$EXITSTATUS" = "0" ]; then
+ # Properly shutdown....
+ message "Asterisk shutdown normally."
+ exit 0
+ elif [ $EXITSTATUS -gt 128 ]; then
+ let EXITSIGNAL=EXITSTATUS-128
+ echo "Asterisk exited on signal $EXITSIGNAL."
+ if [ "$NOTIFY" != "" ]; then
+ echo "Asterisk on $MACHINE exited on signal $EXITSIGNAL. Might want to take a peek." | \
+ mail -s "Asterisk Died" $NOTIFY
+ message "Exited on signal $EXITSIGNAL"
+ fi
+ if [ "$EXEC" != "" ]; then
+ $EXEC
+ fi
+
+ PID=`cat ${ASTPIDFILE}`
+ if [ -f /tmp/core.${PID} ]; then
+ mv /tmp/core.${PID} ${DUMPDROP}/core.`hostname`-`date -Iseconds` &
+ elif [ -f /tmp/core ]; then
+ mv /tmp/core ${DUMPDROP}/core.`hostname`-`date -Iseconds` &
+ fi
+ else
+ message "Asterisk died with code $EXITSTATUS."
+
+ PID=`cat ${ASTPIDFILE}`
+ if [ -f /tmp/core.${PID} ]; then
+ mv /tmp/core.${PID} ${DUMPDROP}/core.`hostname`-`date -Iseconds` &
+ elif [ -f /tmp/core ]; then
+ mv /tmp/core ${DUMPDROP}/core.`hostname`-`date -Iseconds` &
+ fi
+ fi
+ message "Automatically restarting Asterisk."
+ sleep $SLEEPSECS
+ if [ $KILLALLMPG123 ]
+ then
+ killall -9 mpg123
+ fi
+ done
+}
+
+run_asterisk &
diff --git a/trunk/contrib/scripts/safe_asterisk.8 b/trunk/contrib/scripts/safe_asterisk.8
new file mode 100644
index 000000000..ebd95142a
--- /dev/null
+++ b/trunk/contrib/scripts/safe_asterisk.8
@@ -0,0 +1,69 @@
+.TH SAFE_ASTERISK 8 "Jun 30th, 2005" "Asterisk" "Linux Programmer's Manual"
+.SH NAME
+.B safe_asterisk
+\(em A wrapper to run the asterisk executable in a loop
+.SH SYNOPSIS
+.PP
+.B safe_asterisk
+.I [ asterisk_params ]
+
+.SH DESCRIPTION
+.B safe_asterisk
+is a script that runs asterisk in a loop, which can be useful if you
+fear asterisk may crash.
+
+The script does not run in the background like a standard service. Rather,
+it runs in its own linux virtual console (9, by default).
+It also uses the option '-c' of asterisk(8) to avoid detaching asterisk
+from that terminal.
+
+safe_asterisk also runs asterisk with unlimited core file size, and thus
+asterisk will dump core in case of a crash.
+
+To get a "picture" of console 9, from another terminal (e.g: from a
+remote shell session) you can use:
+
+ screendump 9
+
+The init script of the Debian package should be able to run safe_asterisk
+as the asterisk service, if so configured. See coments in
+/etc/default/asterisk
+
+.SH FILES
+.B /tmp
+.RS
+safe_asterisk runs in that directory, rather than in / as usual.
+.RE
+
+.B /tmp/core
+.RS
+If core files were generated there, they may be
+.RE
+
+.B /etc/asterisk/startup.d
+.RS
+Files in this directory will be 'source'd by the safe_asterisk script before
+it starts Asterisk proper, allowing them to set additional environment variables
+or run any other steps that are needed for your system.
+.RE
+
+.SH BUGS
+While showing the output on a console is useful, using screen(1) as
+the terminal may be better.
+
+The script does not read configuration from standard location under /etc
+
+It uses fixed locations under /tmp , and thus may be exposed to a
+symlink attacks.
+
+.SH SEE ALSO
+asterisk(8), screendump(9)
+
+.SH "AUTHOR"
+This manual page was written by Tzafrir Cohen <tzafrir.cohen@xorcom.com>
+Permission is granted to copy, distribute and/or modify this document under
+the terms of the GNU General Public License, Version 2 any
+later version published by the Free Software Foundation.
+
+On Debian systems, the complete text of the GNU General Public
+License can be found in /usr/share/common-licenses/GPL.
diff --git a/trunk/contrib/scripts/safe_asterisk_restart b/trunk/contrib/scripts/safe_asterisk_restart
new file mode 100644
index 000000000..81783149a
--- /dev/null
+++ b/trunk/contrib/scripts/safe_asterisk_restart
@@ -0,0 +1,110 @@
+#!/bin/bash
+# vim:textwidth=80:tabstop=4:shiftwidth=4:smartindent
+#
+# this scripts prompts the user thrice, then tells asterisk to please shut down,
+# then kills asterisk and related processes with SIGTERM, then kills asterisk
+# and related processes with SIGKILL, and then starts asterisk with
+# safe_asterisk. Three arguments are currently supported, --no-countdown,
+# --no-prompt and --no-stop-now-first
+
+LOGFILE=/var/log/asterisk/safe_asterisk_restart.log
+ASTERISK=/usr/sbin/asterisk
+SAFE_ASTERISK=/usr/sbin/safe_asterisk
+
+DELAY=1 # Seconds between steps in countdown
+COUNTDOWN_FROM=5 # Steps to count down
+DO_COUNTDOWN=1 # Should I do a countdown before restarting asterisk?
+DO_PROMPT=1 # Should I prompt the user?
+TRY_STOP_NOW_FIRST=1 # Attempt a 'stop now' before killing processes. Note
+ # that this might make this script hang if asterisk
+ # can't respond to the command.
+
+# processes to kill. Please list all AGI scripts here as well as the asterisk
+# processes, since asterisk may leave them unkilled.
+PROCVICTIMS="safe_asterisk asterisk mpg123"
+
+# helper functions
+# die ["string to print"]
+function die {
+ if [[ "$1" != "" ]]; then
+ echo $1
+ else
+ echo "ok. no harm done..."
+ fi
+ exit
+}
+
+# docmd "string to print" "cmd"
+function docmd {
+ printf "$1..."
+ `$2 >> $LOGFILE 2>&1`
+ RETCODE=$?
+ sleep $DELAY
+ if [[ "$RETCODE" == "0" ]]; then
+ echo " OK"
+ else
+ echo " FAILED"
+ fi
+}
+
+# prompt "string" "positive answer"
+function prompt {
+ printf "$1"
+ read answer
+ if [[ "$answer" != "$2" ]]; then
+ die
+ fi
+}
+
+# countdown secs
+function countdown {
+ echo -n "$1 "
+ if [[ $1 > 0 ]]; then
+ sleep 1
+ countdown $[ $1 - 1 ]
+ else
+ echo "boom!"
+ fi
+}
+
+# am I really root?
+if [[ "$UID" != "0" ]]; then
+ echo "Sorry, only root can do this." >&2
+ exit;
+fi
+
+echo "`date`: $0 invoked" >> $LOGFILE
+
+# bash
+for i
+do
+ if [[ "$i" == "--no-countdown" ]]
+ then
+ unset DO_COUNTDOWN
+ fi
+ if [[ "$i" == "--no-prompt" ]]
+ then
+ unset DO_PROMPT
+ fi
+ if [[ "$i" == "--no-stop-now-first" ]]
+ then
+ unset TRY_STOP_NOW_FIRST
+ fi
+done
+
+[[ $DO_PROMPT ]] && prompt "Are you sure you want to restart asterisk? (yes/no)? " "yes"
+[[ $DO_PROMPT ]] && prompt "Really sure? (yes/no)? " "yes"
+[[ $DO_PROMPT ]] && prompt "Absolutely positive? (YES/no)? " "YES"
+
+[[ $DO_COUNTDOWN ]] && echo "OK, I'll do it, but if you're not sure about this, press ctrl+c now."
+[[ $DO_COUNTDOWN ]] && countdown $COUNTDOWN_FROM
+
+# doing the dirty work
+[[ $TRY_STOP_NOW_FIRST ]] && docmd "Asking asterisk kindly to shutdown" "$ASTERISK -rx 'stop now'"
+docmd "Sending asterisk processes the TERM signal" "killall -15 $PROCVICTIMS"
+docmd "Sending asterisk processes KILL signal" "killall -9 $PROCVICTIMS"
+docmd "Starting safe_asterisk" "$SAFE_ASTERISK"
+for i in $PROCVICTIMS
+do
+ ps axf | grep -w $i | grep -v grep
+done
diff --git a/trunk/contrib/scripts/sip-friends.sql b/trunk/contrib/scripts/sip-friends.sql
new file mode 100644
index 000000000..15d7cb393
--- /dev/null
+++ b/trunk/contrib/scripts/sip-friends.sql
@@ -0,0 +1,14 @@
+#
+# Table structure for table `sipfriends`
+#
+
+CREATE TABLE `sipfriends` (
+ `name` varchar(40) NOT NULL default '',
+ `secret` varchar(40) NOT NULL default '',
+ `context` varchar(40) NOT NULL default '',
+ `username` varchar(40) default '',
+ `ipaddr` varchar(20) NOT NULL default '',
+ `port` int(6) NOT NULL default '0',
+ `regseconds` int(11) NOT NULL default '0',
+ PRIMARY KEY (`name`)
+) TYPE=MyISAM;
diff --git a/trunk/contrib/scripts/vmail.cgi b/trunk/contrib/scripts/vmail.cgi
new file mode 100644
index 000000000..a87fc1e84
--- /dev/null
+++ b/trunk/contrib/scripts/vmail.cgi
@@ -0,0 +1,1099 @@
+#!/usr/bin/perl
+#
+# Web based Voicemail for Asterisk
+#
+# Copyright (C) 2002, Linux Support Services, Inc.
+#
+# Distributed under the terms of the GNU General Public License
+#
+# Written by Mark Spencer <markster@linux-support.net>
+#
+# (icky, I know.... if you know better perl please help!)
+#
+#
+# Synchronization added by GDS Partners (www.gdspartners.com)
+# Stojan Sljivic (stojan.sljivic@gdspartners.com)
+#
+use CGI qw/:standard/;
+use Carp::Heavy;
+use CGI::Carp qw(fatalsToBrowser);
+use DBI;
+use Fcntl qw ( O_WRONLY O_CREAT O_EXCL );
+use Time::HiRes qw ( usleep );
+
+$context=""; # Define here your by default context (so you dont need to put voicemail@context in the login
+
+@validfolders = ( "INBOX", "Old", "Work", "Family", "Friends", "Cust1", "Cust2", "Cust3", "Cust4", "Cust5" );
+
+%formats = (
+ "wav" => {
+ name => "Uncompressed WAV",
+ mime => "audio/x-wav",
+ pref => 1
+ },
+ "WAV" => {
+ name => "GSM Compressed WAV",
+ mime => "audio/x-wav",
+ pref => 2
+ },
+ "gsm" => {
+ name => "Raw GSM Audio",
+ mime => "audio/x-gsm",
+ pref => 3
+ }
+);
+
+$astpath = "/_asterisk";
+
+$stdcontainerstart = "<table align=center width=600><tr><td>\n";
+$footer = "<hr><font size=-1><a href=\"http://www.asterisk.org\">The Asterisk Open Source PBX</a> Copyright 2004, <a href=\"http://www.digium.com\">Digium, Inc.</a></a>";
+$stdcontainerend = "</td></tr><tr><td align=right>$footer</td></tr></table>\n";
+
+sub lock_path() {
+
+ my($path) = @_;
+ my $rand;
+ my $rfile;
+ my $start;
+ my $res;
+
+ $rand = rand 99999999;
+ $rfile = "$path/.lock-$rand";
+
+ sysopen(RFILE, $rfile, O_WRONLY | O_CREAT | O_EXCL, 0666) or return -1;
+ close(RFILE);
+
+ $res = link($rfile, "$path/.lock");
+ $start = time;
+ if ($res == 0) {
+ while (($res == 0) && (time - $start <= 5)) {
+ $res = link($rfile, "$path/.lock");
+ usleep(1);
+ }
+ }
+ unlink($rfile);
+
+ if ($res == 0) {
+ return -1;
+ } else {
+ return 0;
+ }
+}
+
+sub unlock_path() {
+
+ my($path) = @_;
+
+ unlink("$path/.lock");
+}
+
+sub untaint() {
+
+ my($data) = @_;
+
+ if ($data =~ /^([-\@\w.]+)$/) {
+ $data = $1;
+ } else {
+ die "Security violation.";
+ }
+
+ return $data;
+}
+
+sub login_screen() {
+ print header;
+ my ($message) = @_;
+ print <<_EOH;
+
+<TITLE>Asterisk Web-Voicemail</TITLE>
+<BODY BGCOLOR="white">
+$stdcontainerstart
+<FORM METHOD="post">
+<input type=hidden name="action" value="login">
+<table align=center>
+<tr><td valign=top align=center rowspan=6><img align=center src="$astpath/animlogo.gif"></td></tr>
+<tr><td align=center colspan=2><font size=+2>Comedian Mail Login</font></td></tr>
+<tr><td align=center colspan=2><font size=+1>$message</font></td></tr>
+<tr><td>Mailbox:</td><td><input type=text name="mailbox"></td></tr>
+<tr><td>Password:</td><td><input type=password name="password"></td></tr>
+<tr><td align=right colspan=2><input value="Login" type=submit></td></tr>
+<input type=hidden name="context" value="$context">
+</table>
+</FORM>
+$stdcontainerend
+</BODY>\n
+_EOH
+
+}
+
+sub check_login()
+{
+ local ($filename, $startcat) = @_;
+ local ($mbox, $context) = split(/\@/, param('mailbox'));
+ local $pass = param('password');
+ local $category = $startcat;
+ local @fields;
+ local $tmp;
+ local (*VMAIL);
+ if (!$category) {
+ $category = "general";
+ }
+ if (!$context) {
+ $context = param('context');
+ }
+ if (!$context) {
+ $context = "default";
+ }
+ if (!$filename) {
+ $filename = "/etc/asterisk/voicemail.conf";
+ }
+# print header;
+# print "Including <h2>$filename</h2> while in <h2>$category</h2>...\n";
+ open(VMAIL, "<$filename") || die("Bleh, no $filename");
+ while(<VMAIL>) {
+ chomp;
+ if (/include\s\"([^\"]+)\"$/) {
+ ($tmp, $category) = &check_login("/etc/asterisk/$1", $category);
+ if (length($tmp)) {
+# print "Got '$tmp'\n";
+ return ($tmp, $category);
+ }
+ } elsif (/\[(.*)\]/) {
+ $category = $1;
+ } elsif ($category eq "general") {
+ if (/([^\s]+)\s*\=\s*(.*)/) {
+ if ($1 eq "dbname") {
+ $dbname = $2;
+ } elsif ($1 eq "dbpass") {
+ $dbpass = $2;
+ } elsif ($1 eq "dbhost") {
+ $dbhost = $2;
+ } elsif ($1 eq "dbuser") {
+ $dbuser = $2;
+ }
+ }
+ if ($dbname and $dbpass and $dbhost and $dbuser) {
+
+ # db variables are present. Use db for authentication.
+ my $dbh = DBI->connect("DBI:mysql:$dbname:$dbhost",$dbuser,$dbpass);
+ my $sth = $dbh->prepare(qq{select fullname,context from voicemail where mailbox='$mbox' and password='$pass' and context='$context'});
+ $sth->execute();
+ if (($fullname, $category) = $sth->fetchrow_array()) {;
+ return ($fullname ? $fullname : "Extension $mbox in $context",$category);
+ }
+ }
+ } elsif (($category ne "general") && ($category ne "zonemessages")) {
+ if (/([^\s]+)\s*\=\>?\s*(.*)/) {
+ @fields = split(/\,\s*/, $2);
+# print "<p>Mailbox is $1\n";
+ if (($mbox eq $1) && (($pass eq $fields[0]) || ("-${pass}" eq $fields[0])) && ($context eq $category)) {
+ return ($fields[1] ? $fields[1] : "Extension $mbox in $context", $category);
+ }
+ }
+ }
+ }
+ close(VMAIL);
+ return ("", $category);
+}
+
+sub validmailbox()
+{
+ local ($context, $mbox, $filename, $startcat) = @_;
+ local $category = $startcat;
+ local @fields;
+ local (*VMAIL);
+ if (!$context) {
+ $context = param('context');
+ }
+ if (!$context) {
+ $context = "default";
+ }
+ if (!$filename) {
+ $filename = "/etc/asterisk/voicemail.conf";
+ }
+ if (!$category) {
+ $category = "general";
+ }
+ open(VMAIL, "<$filename") || die("Bleh, no $filename");
+ while(<VMAIL>) {
+ chomp;
+ if (/include\s\"([^\"]+)\"$/) {
+ ($tmp, $category) = &validmailbox($mbox, $context, "/etc/asterisk/$1");
+ if ($tmp) {
+ return ($tmp, $category);
+ }
+ } elsif (/\[(.*)\]/) {
+ $category = $1;
+ } elsif ($category eq "general") {
+ if (/([^\s]+)\s*\=\s*(.*)/) {
+ if ($1 eq "dbname") {
+ $dbname = $2;
+ } elsif ($1 eq "dbpass") {
+ $dbpass = $2;
+ } elsif ($1 eq "dbhost") {
+ $dbhost = $2;
+ } elsif ($1 eq "dbuser") {
+ $dbuser = $2;
+ }
+ }
+ if ($dbname and $dbpass and $dbhost and $dbuser) {
+
+ # db variables are present. Use db for authentication.
+ my $dbh = DBI->connect("DBI:mysql:$dbname:$dbhost",$dbuser,$dbpass);
+ my $sth = $dbh->prepare(qq{select fullname,context from voicemail where mailbox='$mbox' and password='$pass' and context='$context'});
+ $sth->execute();
+ if (($fullname, $context) = $sth->fetchrow_array()) {;
+ return ($fullname ? $fullname : "unknown", $category);
+ }
+ }
+ } elsif (($category ne "general") && ($category ne "zonemessages") && ($category eq $context)) {
+ if (/([^\s]+)\s*\=\>?\s*(.*)/) {
+ @fields = split(/\,\s*/, $2);
+ if (($mbox eq $1) && ($context eq $category)) {
+ return ($fields[2] ? $fields[2] : "unknown", $category);
+ }
+ }
+ }
+ }
+ return ("", $category);
+}
+
+sub mailbox_options()
+{
+ local($context, $current, $filename, $category) = @_;
+ local (*VMAIL);
+ local $tmp2;
+ local $tmp;
+ if (!$filename) {
+ $filename = "/etc/asterisk/voicemail.conf";
+ }
+ if (!$category) {
+ $category = "general";
+ }
+# print header;
+# print "Including <h2>$filename</h2> while in <h2>$category</h2>...\n";
+ open(VMAIL, "<$filename") || die("Bleh, no voicemail.conf");
+ while(<VMAIL>) {
+ chomp;
+ s/\;.*$//;
+ if (/include\s\"([^\"]+)\"$/) {
+ ($tmp2, $category) = &mailbox_options($context, $current, "/etc/asterisk/$1", $category);
+# print "Got '$tmp2'...\n";
+ $tmp .= $tmp2;
+ } elsif (/\[(.*)\]/) {
+ $category = $1;
+ } elsif ($category eq "general") {
+ if (/([^\s]+)\s*\=\s*(.*)/) {
+ if ($1 eq "dbname") {
+ $dbname = $2;
+ } elsif ($1 eq "dbpass") {
+ $dbpass = $2;
+ } elsif ($1 eq "dbhost") {
+ $dbhost = $2;
+ } elsif ($1 eq "dbuser") {
+ $dbuser = $2;
+ }
+ }
+ if ($dbname and $dbpass and $dbhost and $dbuser) {
+
+ # db variables are present. Use db for authentication.
+ my $dbh = DBI->connect("DBI:mysql:$dbname:$dbhost",$dbuser,$dbpass);
+ my $sth = $dbh->prepare(qq{select mailbox,fullname,context from voicemail where context='$context' order by mailbox});
+ $sth->execute();
+ while (($mailbox, $fullname, $category) = $sth->fetchrow_array()) {
+ $text = $mailbox;
+ if ($fullname) {
+ $text .= " (".$fullname.")";
+ }
+ if ($mailbox eq $current) {
+ $tmp .= "<OPTION SELECTED>$text</OPTION>\n";
+ } else {
+ $tmp .= "<OPTION>$text</OPTION>\n";
+ }
+ }
+ return ($tmp, $category);
+ }
+ } elsif (($category ne "general") && ($category ne "zonemessages")) {
+ if (/([^\s]+)\s*\=\>?\s*(.*)/) {
+ @fields = split(/\,\s*/, $2);
+ $text = "$1";
+ if ($fields[1]) {
+ $text .= " ($fields[1])";
+ }
+ if ($1 eq $current) {
+ $tmp .= "<OPTION SELECTED>$text</OPTION>\n";
+ } else {
+ $tmp .= "<OPTION>$text</OPTION>\n";
+ }
+
+ }
+ }
+ }
+ close(VMAIL);
+ return ($tmp, $category);
+}
+
+sub mailbox_list()
+{
+ local ($name, $context, $current) = @_;
+ local $tmp;
+ local $text;
+ local $tmp;
+ local $opts;
+ if (!$context) {
+ $context = "default";
+ }
+ $tmp = "<SELECT name=\"$name\">\n";
+ ($opts) = &mailbox_options($context, $current);
+ $tmp .= $opts;
+ $tmp .= "</SELECT>\n";
+
+}
+
+sub msgcount()
+{
+ my ($context, $mailbox, $folder) = @_;
+ my $path = "/var/spool/asterisk/voicemail/$context/$mailbox/$folder";
+ if (opendir(DIR, $path)) {
+ my @msgs = grep(/^msg....\.txt$/, readdir(DIR));
+ closedir(DIR);
+ return sprintf "%d", $#msgs + 1;
+ }
+ return "0";
+}
+
+sub msgcountstr()
+{
+ my ($context, $mailbox, $folder) = @_;
+ my $count = &msgcount($context, $mailbox, $folder);
+ if ($count > 1) {
+ "$count messages";
+ } elsif ($count > 0) {
+ "$count message";
+ } else {
+ "no messages";
+ }
+}
+sub messages()
+{
+ my ($context, $mailbox, $folder) = @_;
+ my $path = "/var/spool/asterisk/voicemail/$context/$mailbox/$folder";
+ if (opendir(DIR, $path)) {
+ my @msgs = sort grep(/^msg....\.txt$/, readdir(DIR));
+ closedir(DIR);
+ return map { s/^msg(....)\.txt$/$1/; $_ } @msgs;
+ }
+ return ();
+}
+
+sub getcookie()
+{
+ my ($var) = @_;
+ return cookie($var);
+}
+
+sub makecookie()
+{
+ my ($format) = @_;
+ cookie(-name => "format", -value =>["$format"], -expires=>"+1y");
+}
+
+sub getfields()
+{
+ my ($context, $mailbox, $folder, $msg) = @_;
+ my $fields;
+ if (open(MSG, "</var/spool/asterisk/voicemail/$context/$mailbox/$folder/msg${msg}.txt")) {
+ while(<MSG>) {
+ s/\#.*$//g;
+ if (/^(\w+)\s*\=\s*(.*)$/) {
+ $fields->{$1} = $2;
+ }
+ }
+ close(MSG);
+ $fields->{'msgid'} = $msg;
+ } else { print "<BR>Unable to open '$msg' in '$mailbox', '$folder'\n<B>"; }
+ $fields;
+}
+
+sub message_prefs()
+{
+ my ($nextaction, $msgid) = @_;
+ my $folder = param('folder');
+ my $mbox = param('mailbox');
+ my $context = param('context');
+ my $passwd = param('password');
+ my $format = param('format');
+ if (!$format) {
+ $format = &getcookie('format');
+ }
+ print header;
+ print <<_EOH;
+
+<TITLE>Asterisk Web-Voicemail: Preferences</TITLE>
+<BODY BGCOLOR="white">
+$stdcontainerstart
+<FORM METHOD="post">
+<table width=100% align=center>
+<tr><td align=right colspan=3><font size=+2>Web Voicemail Preferences</font></td></tr>
+<tr><td align=left><font size=+1>Preferred&nbsp;Audio&nbsp;Format:</font></td><td colspan=2></td></tr>
+_EOH
+
+foreach $fmt (sort { $formats{$a}->{'pref'} <=> $formats{$b}->{'pref'} } keys %formats) {
+ my $clicked = "checked" if $fmt eq $format;
+ print "<tr><td></td><td align=left><input type=radio name=\"format\" $clicked value=\"$fmt\"></td><td width=100%>&nbsp;$formats{$fmt}->{name}</td></tr>\n";
+}
+
+print <<_EOH;
+<tr><td align=right colspan=3><input type=submit value="save settings..."></td></tr>
+</table>
+<input type=hidden name="action" value="$nextaction">
+<input type=hidden name="folder" value="$folder">
+<input type=hidden name="mailbox" value="$mbox">
+<input type=hidden name="context" value="$context">
+<input type=hidden name="password" value="$passwd">
+<input type=hidden name="msgid" value="$msgid">
+$stdcontainerend
+</BODY>\n
+_EOH
+
+}
+
+sub message_play()
+{
+ my ($message, $msgid) = @_;
+ my $folder = param('folder');
+ my ($mbox, $context) = split(/\@/, param('mailbox'));
+ my $passwd = param('password');
+ my $format = param('format');
+
+ my $fields;
+ if (!$context) {
+ $context = param('context');
+ }
+ if (!$context) {
+ $context = "default";
+ }
+
+ my $folders = &folder_list('newfolder', $context, $mbox, $folder);
+ my $mailboxes = &mailbox_list('forwardto', $context, $mbox);
+ if (!$format) {
+ $format = &getcookie('format');
+ }
+ if (!$format) {
+ &message_prefs("play", $msgid);
+ } else {
+ print header(-cookie => &makecookie($format));
+ $fields = &getfields($context, $mbox, $folder, $msgid);
+ if (!$fields) {
+ print "<BR>Bah!\n";
+ return;
+ }
+ my $duration = $fields->{'duration'};
+ if ($duration) {
+ $duration = sprintf "%d:%02d", $duration/60, $duration % 60;
+ } else {
+ $duration = "<i>Unknown</i>";
+ }
+ print <<_EOH;
+
+<TITLE>Asterisk Web-Voicemail: $folder Message $msgid</TITLE>
+<BODY BGCOLOR="white">
+$stdcontainerstart
+<FORM METHOD="post">
+<table width=100% align=center>
+<tr><td align=right colspan=3><font size=+1>$folder Message $msgid</font></td></tr>
+_EOH
+
+ print <<_EOH;
+<tr><td align=center colspan=3>
+<table>
+ <tr><td colspan=2 align=center><font size=+1>$folder <b>$msgid</b></font></td></tr>
+ <tr><td><b>Message:</b></td><td>$msgid</td></tr>\n
+ <tr><td><b>Mailbox:</b></td><td>$mbox\@$context</td></tr>\n
+ <tr><td><b>Folder:</b></td><td>$folder</td></tr>\n
+ <tr><td><b>From:</b></td><td>$fields->{callerid}</td></tr>\n
+ <tr><td><b>Duration:</b></td><td>$duration</td></tr>\n
+ <tr><td><b>Original Date:</b></td><td>$fields->{origdate}</td></tr>\n
+ <tr><td><b>Original Mailbox:</b></td><td>$fields->{origmailbox}</td></tr>\n
+ <tr><td><b>Caller Channel:</b></td><td>$fields->{callerchan}</td></tr>\n
+ <tr><td align=center colspan=2>
+ <input name="action" type=submit value="index">&nbsp;
+ <input name="action" type=submit value="delete ">&nbsp;
+ <input name="action" type=submit value="forward to -> ">&nbsp;
+ $mailboxes&nbsp;
+ <input name="action" type=submit value="save to ->">
+ $folders&nbsp;
+ <input name="action" type=submit value="play ">
+ <input name="action" type=submit value="download">
+</td></tr>
+<tr><td colspan=2 align=center>
+<embed width=400 height=40 src="vmail.cgi?action=audio&folder=$folder&mailbox=$mbox&context=$context&password=$passwd&msgid=$msgid&format=$format&dontcasheme=$$.$format" autostart=yes loop=false></embed>
+</td></tr></table>
+</td></tr>
+</table>
+<input type=hidden name="folder" value="$folder">
+<input type=hidden name="mailbox" value="$mbox">
+<input type=hidden name="context" value="$context">
+<input type=hidden name="password" value="$passwd">
+<input type=hidden name="msgid" value="$msgid">
+$stdcontainerend
+</BODY>\n
+_EOH
+ }
+}
+
+sub message_audio()
+{
+ my ($forcedownload) = @_;
+ my $folder = &untaint(param('folder'));
+ my $msgid = &untaint(param('msgid'));
+ my $mailbox = &untaint(param('mailbox'));
+ my $context = &untaint(param('context'));
+ my $format = param('format');
+ if (!$format) {
+ $format = &getcookie('format');
+ }
+ &untaint($format);
+
+ my $path = "/var/spool/asterisk/voicemail/$context/$mailbox/$folder/msg${msgid}.$format";
+
+ $msgid =~ /^\d\d\d\d$/ || die("Msgid Liar ($msgid)!");
+ grep(/^${format}$/, keys %formats) || die("Format Liar ($format)!");
+
+ # Mailbox and folder are already verified
+ if (open(AUDIO, "<$path")) {
+ $size = -s $path;
+ $|=1;
+ if ($forcedownload) {
+ print header(-type=>$formats{$format}->{'mime'}, -Content_length => $size, -attachment => "msg${msgid}.$format");
+ } else {
+ print header(-type=>$formats{$format}->{'mime'}, -Content_length => $size);
+ }
+
+ while(($amt = sysread(AUDIO, $data, 4096)) > 0) {
+ syswrite(STDOUT, $data, $amt);
+ }
+ close(AUDIO);
+ } else {
+ die("Hrm, can't seem to open $path\n");
+ }
+}
+
+sub message_index()
+{
+ my ($folder, $message) = @_;
+ my ($mbox, $context) = split(/\@/, param('mailbox'));
+ my $passwd = param('password');
+ my $message2;
+ my $msgcount;
+ my $hasmsg;
+ my $newmessages, $oldmessages;
+ my $format = param('format');
+ if (!$format) {
+ $format = &getcookie('format');
+ }
+ if (!$context) {
+ $context = param('context');
+ }
+ if (!$context) {
+ $context = "default";
+ }
+ if ($folder) {
+ $msgcount = &msgcountstr($context, $mbox, $folder);
+ $message2 = "&nbsp;&nbsp;&nbsp;Folder '$folder' has " . &msgcountstr($context, $mbox, $folder);
+ } else {
+ $newmessages = &msgcount($context, $mbox, "INBOX");
+ $oldmessages = &msgcount($context, $mbox, "Old");
+ if (($newmessages > 0) || ($oldmessages < 1)) {
+ $folder = "INBOX";
+ } else {
+ $folder = "Old";
+ }
+ $message2 = "You have";
+ if ($newmessages > 0) {
+ $message2 .= " <b>$newmessages</b> NEW";
+ if ($oldmessages > 0) {
+ $message2 .= "and <b>$oldmessages</b> OLD";
+ if ($oldmessages != 1) {
+ $message2 .= " messages.";
+ } else {
+ $message2 .= "message.";
+ }
+ } else {
+ if ($newmessages != 1) {
+ $message2 .= " messages.";
+ } else {
+ $message2 .= " message.";
+ }
+ }
+ } else {
+ if ($oldmessages > 0) {
+ $message2 .= " <b>$oldmessages</b> OLD";
+ if ($oldmessages != 1) {
+ $message2 .= " messages.";
+ } else {
+ $message2 .= " message.";
+ }
+ } else {
+ $message2 .= " <b>no</b> messages.";
+ }
+ }
+ }
+
+ my $folders = &folder_list('newfolder', $context, $mbox, $folder);
+ my $cfolders = &folder_list('changefolder', $context, $mbox, $folder);
+ my $mailboxes = &mailbox_list('forwardto', $context, $mbox);
+ print header(-cookie => &makecookie($format));
+ print <<_EOH;
+
+<TITLE>Asterisk Web-Voicemail: $mbox\@$context $folder</TITLE>
+<BODY BGCOLOR="white">
+$stdcontainerstart
+<FORM METHOD="post">
+<table width=100% align=center>
+<tr><td align=center colspan=2><font size=+2><I>$message</I></font></td></tr>
+<tr><td align=right colspan=2><font size=+1><b>$folder</b> Messages</font> <input type=submit name="action" value="change to ->">$cfolders</td></tr>
+<tr><td align=left colspan=2><font size=+1>$message2</font></td></tr>
+</table>
+<table width=100% align=center cellpadding=0 cellspacing=0>
+_EOH
+
+print "<tr><td>&nbsp;Msg</td><td>&nbsp;From</td><td>&nbsp;Duration</td><td>&nbsp;Date</td><td>&nbsp;</td></tr>\n";
+print "<tr><td><hr></td><td><hr></td><td><hr></td><td><hr></td><td></td></tr>\n";
+foreach $msg (&messages($context, $mbox, $folder)) {
+
+ $fields = &getfields($context, $mbox, $folder, $msg);
+ $duration = $fields->{'duration'};
+ if ($duration) {
+ $duration = sprintf "%d:%02d", $duration / 60, $duration % 60;
+ } else {
+ $duration = "<i>Unknown</i>";
+ }
+ $hasmsg++;
+ print "<tr><td><input type=checkbox name=\"msgselect\" value=\"$msg\">&nbsp;<b>$msg</b></td><td>$fields->{'callerid'}</td><td>$duration</td><td>$fields->{'origdate'}</td><td><input name='play$msg' alt=\"Play message $msg\" border=0 type=image align=left src=\"$astpath/play.gif\"></td></tr>\n";
+
+}
+if (!$hasmsg) {
+ print "<tr><td colspan=4 align=center><P><b><i>No messages</i></b><P></td></tr>";
+}
+
+print <<_EOH;
+</table>
+<table width=100% align=center>
+<tr><td align=right colspan=2>
+ <input type="submit" name="action" value="refresh">&nbsp;
+_EOH
+
+if ($hasmsg) {
+print <<_EOH;
+ <input type="submit" name="action" value="delete">&nbsp;
+ <input type="submit" name="action" value="save to ->">
+ $folders&nbsp;
+ <input type="submit" name="action" value="forward to ->">
+ $mailboxes
+_EOH
+}
+
+print <<_EOH;
+</td></tr>
+<tr><td align=right colspan=2>
+ <input type="submit" name="action" value="preferences">
+ <input type="submit" name="action" value="logout">
+</td></tr>
+</table>
+<input type=hidden name="folder" value="$folder">
+<input type=hidden name="mailbox" value="$mbox">
+<input type=hidden name="context" value="$context">
+<input type=hidden name="password" value="$passwd">
+</FORM>
+$stdcontainerend
+</BODY>\n
+_EOH
+}
+
+sub validfolder()
+{
+ my ($folder) = @_;
+ return grep(/^$folder$/, @validfolders);
+}
+
+sub folder_list()
+{
+ my ($name, $context, $mbox, $selected) = @_;
+ my $f;
+ my $count;
+ my $tmp = "<SELECT name=\"$name\">\n";
+ foreach $f (@validfolders) {
+ $count = &msgcount($context, $mbox, $f);
+ if ($f eq $selected) {
+ $tmp .= "<OPTION SELECTED>$f ($count)</OPTION>\n";
+ } else {
+ $tmp .= "<OPTION>$f ($count)</OPTION>\n";
+ }
+ }
+ $tmp .= "</SELECT>";
+}
+
+sub message_rename()
+{
+ my ($context, $mbox, $oldfolder, $old, $newfolder, $new) = @_;
+ my $oldfile, $newfile;
+ return if ($old eq $new) && ($oldfolder eq $newfolder);
+
+ if ($context =~ /^(\w+)$/) {
+ $context = $1;
+ } else {
+ die("Invalid Context<BR>\n");
+ }
+
+ if ($mbox =~ /^(\w+)$/) {
+ $mbox = $1;
+ } else {
+ die ("Invalid mailbox<BR>\n");
+ }
+
+ if ($oldfolder =~ /^(\w+)$/) {
+ $oldfolder = $1;
+ } else {
+ die("Invalid old folder<BR>\n");
+ }
+
+ if ($newfolder =~ /^(\w+)$/) {
+ $newfolder = $1;
+ } else {
+ die("Invalid new folder ($newfolder)<BR>\n");
+ }
+
+ if ($old =~ /^(\d\d\d\d)$/) {
+ $old = $1;
+ } else {
+ die("Invalid old Message<BR>\n");
+ }
+
+ if ($new =~ /^(\d\d\d\d)$/) {
+ $new = $1;
+ } else {
+ die("Invalid old Message<BR>\n");
+ }
+
+ my $path = "/var/spool/asterisk/voicemail/$context/$mbox/$newfolder";
+ $path =~ /^(.*)$/;
+ $path = $1;
+ mkdir $path, 0770;
+ my $path = "/var/spool/asterisk/voicemail/$context/$mbox/$oldfolder";
+ opendir(DIR, $path) || die("Unable to open directory\n");
+ my @files = grep /^msg${old}\.\w+$/, readdir(DIR);
+ closedir(DIR);
+ foreach $oldfile (@files) {
+ my $tmp = $oldfile;
+ if ($tmp =~ /^(msg${old}.\w+)$/) {
+ $tmp = $1;
+ $oldfile = $path . "/$tmp";
+ $tmp =~ s/msg${old}/msg${new}/;
+ $newfile = "/var/spool/asterisk/voicemail/$context/$mbox/$newfolder/$tmp";
+# print "Renaming $oldfile to $newfile<BR>\n";
+ rename($oldfile, $newfile);
+ }
+ }
+}
+
+sub file_copy()
+{
+ my ($orig, $new) = @_;
+ my $res;
+ my $data;
+ $orig =~ /^(.*)$/;
+ $orig = $1;
+ $new =~ /^(.*)$/;
+ $new = $1;
+ open(IN, "<$orig") || die("Unable to open '$orig'\n");
+ open(OUT, ">$new") || DIE("Unable to open '$new'\n");
+ while(($res = sysread(IN, $data, 4096)) > 0) {
+ syswrite(OUT, $data, $res);
+ }
+ close(OUT);
+ close(IN);
+}
+
+sub message_copy()
+{
+ my ($context, $mbox, $newmbox, $oldfolder, $old, $new) = @_;
+ my $oldfile, $newfile;
+ return if ($mbox eq $newmbox);
+
+ if ($mbox =~ /^(\w+)$/) {
+ $mbox = $1;
+ } else {
+ die ("Invalid mailbox<BR>\n");
+ }
+
+ if ($newmbox =~ /^(\w+)$/) {
+ $newmbox = $1;
+ } else {
+ die ("Invalid new mailbox<BR>\n");
+ }
+
+ if ($oldfolder =~ /^(\w+)$/) {
+ $oldfolder = $1;
+ } else {
+ die("Invalid old folder<BR>\n");
+ }
+
+ if ($old =~ /^(\d\d\d\d)$/) {
+ $old = $1;
+ } else {
+ die("Invalid old Message<BR>\n");
+ }
+
+ if ($new =~ /^(\d\d\d\d)$/) {
+ $new = $1;
+ } else {
+ die("Invalid old Message<BR>\n");
+ }
+
+ my $path = "/var/spool/asterisk/voicemail/$context/$newmbox";
+ $path =~ /^(.*)$/;
+ $path = $1;
+ mkdir $path, 0770;
+ my $path = "/var/spool/asterisk/voicemail/$context/$newmbox/INBOX";
+ $path =~ /^(.*)$/;
+ $path = $1;
+ mkdir $path, 0770;
+ my $path = "/var/spool/asterisk/voicemail/$context/$mbox/$oldfolder";
+ opendir(DIR, $path) || die("Unable to open directory\n");
+ my @files = grep /^msg${old}\.\w+$/, readdir(DIR);
+ closedir(DIR);
+ foreach $oldfile (@files) {
+ my $tmp = $oldfile;
+ if ($tmp =~ /^(msg${old}.\w+)$/) {
+ $tmp = $1;
+ $oldfile = $path . "/$tmp";
+ $tmp =~ s/msg${old}/msg${new}/;
+ $newfile = "/var/spool/asterisk/voicemail/$context/$newmbox/INBOX/$tmp";
+# print "Copying $oldfile to $newfile<BR>\n";
+ &file_copy($oldfile, $newfile);
+ }
+ }
+}
+
+sub message_delete()
+{
+ my ($context, $mbox, $folder, $msg) = @_;
+ if ($mbox =~ /^(\w+)$/) {
+ $mbox = $1;
+ } else {
+ die ("Invalid mailbox<BR>\n");
+ }
+ if ($context =~ /^(\w+)$/) {
+ $context = $1;
+ } else {
+ die ("Invalid context<BR>\n");
+ }
+ if ($folder =~ /^(\w+)$/) {
+ $folder = $1;
+ } else {
+ die("Invalid folder<BR>\n");
+ }
+ if ($msg =~ /^(\d\d\d\d)$/) {
+ $msg = $1;
+ } else {
+ die("Invalid Message<BR>\n");
+ }
+ my $path = "/var/spool/asterisk/voicemail/$context/$mbox/$folder";
+ opendir(DIR, $path) || die("Unable to open directory\n");
+ my @files = grep /^msg${msg}\.\w+$/, readdir(DIR);
+ closedir(DIR);
+ foreach $oldfile (@files) {
+ if ($oldfile =~ /^(msg${msg}.\w+)$/) {
+ $oldfile = $path . "/$1";
+# print "Deleting $oldfile<BR>\n";
+ unlink($oldfile);
+ }
+ }
+}
+
+sub message_forward()
+{
+ my ($toindex, @msgs) = @_;
+ my $folder = param('folder');
+ my ($mbox, $context) = split(/\@/, param('mailbox'));
+ my $newmbox = param('forwardto');
+ my $msg;
+ my $msgcount;
+ if (!$context) {
+ $context = param('context');
+ }
+ if (!$context) {
+ $context = "default";
+ }
+ $newmbox =~ s/(\w+)(\s+.*)?$/$1/;
+ if (!&validmailbox($context, $newmbox)) {
+ die("Bah! Not a valid mailbox '$newmbox'\n");
+ return "";
+ }
+
+ my $txt;
+ $context = &untaint($context);
+ $newmbox = &untaint($newmbox);
+ my $path = "/var/spool/asterisk/voicemail/$context/$newmbox/INBOX";
+ if (&lock_path($path) == 0) {
+ $msgcount = &msgcount($context, $newmbox, "INBOX");
+
+ if ($newmbox ne $mbox) {
+# print header;
+ foreach $msg (@msgs) {
+# print "Forwarding $msg from $mbox to $newmbox<BR>\n";
+ &message_copy($context, $mbox, $newmbox, $folder, $msg, sprintf "%04d", $msgcount);
+ $msgcount++;
+ }
+ $txt = "Forwarded messages " . join(', ', @msgs) . "to $newmbox";
+ } else {
+ $txt = "Can't forward messages to yourself!\n";
+ }
+ &unlock_path($path);
+ } else {
+ $txt = "Cannot forward messages: Unable to lock path.\n";
+ }
+ if ($toindex) {
+ &message_index($folder, $txt);
+ } else {
+ &message_play($txt, $msgs[0]);
+ }
+}
+
+sub message_delete_or_move()
+{
+ my ($toindex, $del, @msgs) = @_;
+ my $txt;
+ my $path;
+ my $y, $x;
+ my $folder = param('folder');
+ my $newfolder = param('newfolder') unless $del;
+ $newfolder =~ s/^(\w+)\s+.*$/$1/;
+ my ($mbox, $context) = split(/\@/, param('mailbox'));
+ if (!$context) {
+ $context = param('context');
+ }
+ if (!$context) {
+ $context = "default";
+ }
+ my $passwd = param('password');
+ $context = &untaint($context);
+ $mbox = &untaint($mbox);
+ $folder = &untaint($folder);
+ my $path = "/var/spool/asterisk/voicemail/$context/$mbox/$folder";
+ if (&lock_path($path) == 0) {
+ my $msgcount = &msgcount($context, $mbox, $folder);
+ my $omsgcount = &msgcount($context, $mbox, $newfolder) if $newfolder;
+ # print header;
+ if ($newfolder ne $folder) {
+ $y = 0;
+ for ($x=0;$x<$msgcount;$x++) {
+ my $msg = sprintf "%04d", $x;
+ my $newmsg = sprintf "%04d", $y;
+ if (grep(/^$msg$/, @msgs)) {
+ if ($newfolder) {
+ &message_rename($context, $mbox, $folder, $msg, $newfolder, sprintf "%04d", $omsgcount);
+ $omsgcount++;
+ } else {
+ &message_delete($context, $mbox, $folder, $msg);
+ }
+ } else {
+ &message_rename($context, $mbox, $folder, $msg, $folder, $newmsg);
+ $y++;
+ }
+ }
+ if ($del) {
+ $txt = "Deleted messages " . join (', ', @msgs);
+ } else {
+ $txt = "Moved messages " . join (', ', @msgs) . " to $newfolder";
+ }
+ } else {
+ $txt = "Can't move a message to the same folder they're in already";
+ }
+ &unlock_path($path);
+ } else {
+ $txt = "Cannot move/delete messages: Unable to lock path.\n";
+ }
+ # Not as many messages now
+ $msgcount--;
+ if ($toindex || ($msgs[0] >= $msgcount)) {
+ &message_index($folder, $txt);
+ } else {
+ &message_play($txt, $msgs[0]);
+ }
+}
+
+if (param()) {
+ my $folder = param('folder');
+ my $changefolder = param('changefolder');
+ $changefolder =~ s/(\w+)\s+.*$/$1/;
+
+ my $newfolder = param('newfolder');
+ $newfolder =~ s/^(\w+)\s+.*$/$1/;
+ if ($newfolder && !&validfolder($newfolder)) {
+ print header;
+ die("Bah! new folder '$newfolder' isn't a folder.");
+ }
+ $action = param('action');
+ $msgid = param('msgid');
+ if (!$action) {
+ my ($tmp) = grep /^play\d\d\d\d\.x$/, param;
+ if ($tmp =~ /^play(\d\d\d\d)/) {
+ $msgid = $1;
+ $action = "play";
+ } else {
+ print header;
+ print "No message?<BR>\n";
+ return;
+ }
+ }
+ @msgs = param('msgselect');
+ @msgs = ($msgid) unless @msgs;
+ {
+ ($mailbox) = &check_login();
+ if (length($mailbox)) {
+ if ($action eq 'login') {
+ &message_index($folder, "Welcome, $mailbox");
+ } elsif (($action eq 'refresh') || ($action eq 'index')) {
+ &message_index($folder, "Welcome, $mailbox");
+ } elsif ($action eq 'change to ->') {
+ if (&validfolder($changefolder)) {
+ $folder = $changefolder;
+ &message_index($folder, "Welcome, $mailbox");
+ } else {
+ die("Bah! Not a valid change to folder '$changefolder'\n");
+ }
+ } elsif ($action eq 'play') {
+ &message_play("$mailbox $folder $msgid", $msgid);
+ } elsif ($action eq 'preferences') {
+ &message_prefs("refresh", $msgid);
+ } elsif ($action eq 'download') {
+ &message_audio(1);
+ } elsif ($action eq 'play ') {
+ &message_audio(0);
+ } elsif ($action eq 'audio') {
+ &message_audio(0);
+ } elsif ($action eq 'delete') {
+ &message_delete_or_move(1, 1, @msgs);
+ } elsif ($action eq 'delete ') {
+ &message_delete_or_move(0, 1, @msgs);
+ } elsif ($action eq 'forward to ->') {
+ &message_forward(1, @msgs);
+ } elsif ($action eq 'forward to -> ') {
+ &message_forward(0, @msgs);
+ } elsif ($action eq 'save to ->') {
+ &message_delete_or_move(1, 0, @msgs);
+ } elsif ($action eq 'save to -> ') {
+ &message_delete_or_move(0, 0, @msgs);
+ } elsif ($action eq 'logout') {
+ &login_screen("Logged out!\n");
+ }
+ } else {
+ sleep(1);
+ &login_screen("Login Incorrect!\n");
+ }
+ }
+} else {
+ &login_screen("\&nbsp;");
+}
diff --git a/trunk/contrib/scripts/vmdb.sql b/trunk/contrib/scripts/vmdb.sql
new file mode 100644
index 000000000..0b1fc38f1
--- /dev/null
+++ b/trunk/contrib/scripts/vmdb.sql
@@ -0,0 +1,66 @@
+DROP TABLE IF EXISTS voicemail;
+CREATE TABLE voicemail (
+ -- All of these column names are very specific, including "uniqueid". Do not change them if you wish voicemail to work.
+ uniqueid INT(5) NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ -- Mailbox context.
+ context CHAR(80) NOT NULL DEFAULT 'default',
+ -- Mailbox number. Should be numeric.
+ mailbox CHAR(80) NOT NULL,
+ -- Must be numeric. Negative if you don't want it to be changed from VoicemailMain
+ password CHAR(80) NOT NULL,
+ -- Used in email and for Directory app
+ fullname CHAR(80),
+ -- Email address (will get sound file if attach=yes)
+ email CHAR(80),
+ -- Email address (won't get sound file)
+ pager CHAR(80),
+ -- Attach sound file to email - YES/no
+ attach CHAR(3),
+ -- Which sound format to attach
+ attachfmt CHAR(10),
+ -- Send email from this address
+ serveremail CHAR(80),
+ -- Prompts in alternative language
+ language CHAR(20),
+ -- Alternative timezone, as defined in voicemail.conf
+ tz CHAR(30),
+ -- Delete voicemail from server after sending email notification - yes/NO
+ deletevoicemail CHAR(3),
+ -- Read back CallerID information during playback - yes/NO
+ saycid CHAR(3),
+ -- Allow user to send voicemail from within VoicemailMain - YES/no
+ sendvoicemail CHAR(3),
+ -- Listen to voicemail and approve before sending - yes/NO
+ review CHAR(3),
+ -- Warn user a temporary greeting exists - yes/NO
+ tempgreetwarn CHAR(3),
+ -- Allow '0' to jump out during greeting - yes/NO
+ operator CHAR(3),
+ -- Hear date/time of message within VoicemailMain - YES/no
+ envelope CHAR(3),
+ -- Hear length of message within VoicemailMain - yes/NO
+ sayduration CHAR(3),
+ -- Minimum duration in minutes to say
+ saydurationm INT(3),
+ -- Force new user to record name when entering voicemail - yes/NO
+ forcename CHAR(3),
+ -- Force new user to record greetings when entering voicemail - yes/NO
+ forcegreetings CHAR(3),
+ -- Context in which to dial extension for callback
+ callback CHAR(80),
+ -- Context in which to dial extension (from advanced menu)
+ dialout CHAR(80),
+ -- Context in which to execute 0 or * escape during greeting
+ exitcontext CHAR(80),
+ -- Maximum length of message (in seconds)
+ maxmessage INT(5),
+ -- Maximum messages in a folder (100 if not specified)
+ maxmsg INT(5),
+ -- Increase DB gain on recorded message by this amount (0.0 means none)
+ volgain DECIMAL(5,2),
+ -- IMAP user for authentication (if using IMAP storage)
+ imapuser VARCHAR(80),
+ -- IMAP password for authentication (if using IMAP storage)
+ imappassword VARCHAR(80),
+ stamp timestamp
+);
diff --git a/trunk/contrib/thirdparty/spexxilbcfix_xlite.reg b/trunk/contrib/thirdparty/spexxilbcfix_xlite.reg
new file mode 100644
index 000000000..821fd5e2b
--- /dev/null
+++ b/trunk/contrib/thirdparty/spexxilbcfix_xlite.reg
Binary files differ
diff --git a/trunk/contrib/thirdparty/spexxilbcfix_xpro.reg b/trunk/contrib/thirdparty/spexxilbcfix_xpro.reg
new file mode 100644
index 000000000..472dcb44f
--- /dev/null
+++ b/trunk/contrib/thirdparty/spexxilbcfix_xpro.reg
Binary files differ
diff --git a/trunk/contrib/utils/README.rawplayer b/trunk/contrib/utils/README.rawplayer
new file mode 100644
index 000000000..146898a5c
--- /dev/null
+++ b/trunk/contrib/utils/README.rawplayer
@@ -0,0 +1,37 @@
+rawplayer is a simple C applet to stream raw music files in place of mpg123
+
+INSTALL
+
+compile the .c file and install:
+gcc -O2 rawplayer.c -o /usr/bin/rawplayer
+
+
+
+Converting MP3 to RAW
+
+Make track01.mp3 into track01.raw with sox (if compiled with mp3 support).
+sox -c 1 track01.mp3 -t raw -r 8000 -c 1 -s -w track01.raw
+
+Otherwise, use whatever app to turn track01.mp3 into track01.wav then use sox on the wav.
+sox -c 1 track01.wav -t raw -r 8000 -c 1 -s -w track01.raw
+
+
+Once you have the raw files put them in any dir on your system (eg /var/lib/asterisk/holdmusic_raw).
+and set up a class in musiconhold.conf like so:
+
+[classes]
+default => custom:/var/lib/asterisk/holdmusic_raw,/usr/bin/rawplayer
+
+
+This is the most efficient way to implement moh because no cpu usage is required to
+explode the very compressed mp3 data then downsample the music to the 8khz mono on the fly
+instead the data is already stored on the disk in the format that asterisk needs it to be
+and the player does little more than pick up frames from the file and hand them to right
+to the asterisk pipe where the audio is shared into all the channels who require it.
+
+
+If you have cpu to spare and want a simple mp3 solution consider the format_mp3 from
+asterisk-addons and the files based moh.
+
+
+
diff --git a/trunk/contrib/utils/eagi_proxy.c b/trunk/contrib/utils/eagi_proxy.c
new file mode 100644
index 000000000..03c7e0640
--- /dev/null
+++ b/trunk/contrib/utils/eagi_proxy.c
@@ -0,0 +1,419 @@
+/*
+ * Asterisk EAGI -> TCP/IP proxy
+ * by Danijel Korzinek (devil_slayer _at_ hotmail.com)
+ *
+ * This simple C application allows you to control asterisk thru one TCP/IP
+ * socket and listen to the conversation thru another socket.
+ *
+ * Great for ASR or wizzard-of-oz telephony systems!
+ *
+ * HOWTO:
+ * The program is compiled using the following command:
+ * gcc eagi_proxy.c -o eagi_proxy -lpthread
+ *
+ * In the dialplan, you can add something like this to the main context:
+ * exten => s,1,Answer
+ * exten => s,n,EAGI(/path/to/eagi_proxy)
+ * exten => s,n,Hangup
+ *
+ * To test the program you can use the netcat utility:
+ * (http://netcat.sourceforge.net/)
+ *
+ * -in one console run:
+ * nc -vv -l -p 8418 > /path/to/file.raw
+ * -in another run:
+ * nc -vv -l -p 8417
+ * -you can use any file for the signal or even /dev/null
+ * -you can change the port numbers in the sourcecode below
+ *
+ * Once you make the call, both programs will accept the incoming
+ * connection. The program on port 8417 will print out the enviornemnt
+ * (unless the appropriate define below is commented) and you can write
+ * any AGI command there (http://www.voip-info.org/wiki-Asterisk+AGI),
+ * e.g.:
+ * GET DATA /path/to/gsm/file 10000 4
+ *
+ * Finally, you can open the RAW file in any sound editor. The format is:
+ * RAW little-endian 8kHz 16bit
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <string.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <ctype.h>
+#include <pthread.h>
+
+/* DEFINES */
+#define SIGNAL_PORT 8418
+#define COMMAND_PORT 8417
+#define SEND_ENVIORNMENT /*send the enviornment thru the socket*/
+/************************/
+
+
+#define BUFSIZE 1024
+char buf[BUFSIZE];
+
+#define WINSIZE 400 /* 25 ms @ 8 kHz and 16bit */
+char window[WINSIZE];
+
+#define WINBUF_NUM 2400 /* number of WINSIZE windows = 1 minute */
+char* winbuf;
+char *end, *bs, *be;
+/* winbuf - start of buffer
+ * end - end of buffer
+ * bs - start of data
+ * be - end of data
+ */
+
+int command_desc; /* command transfer descriptor */
+int speech_desc; /* speech signal descrriptor */
+char connected=1; /* connection state */
+
+int connect_to_host(char* host, int port); /* connect to a given host (name or IP) and given port number in nonblocking mode returning socket descriptor*/
+
+void read_full(int file, char* buffer, int num); /* read EXACTLY "num" ammount of bytes from "file" descriptor to "buffer"*/
+int read_some(int file, char* buffer, int size); /* read AT MOST "size" ammount of bytes */
+
+void write_buf(int file, char* buffer, int num); /* write "num" ammount of bytes to "file" descriptor and buffer the surplus if the write would block */
+int write_amap(int file, char* buffer, int num); /*write AT MOST "num" ammount of bytes and return ammount that was written*/
+
+void setnonblocking(int desc); /*sets the socket non-blocking; for polling */
+
+void finalize(); /* this function is run at exit */
+
+pthread_mutex_t command_mutex;/* command socket mutex */
+pthread_t stdin_thread,signal_thread;
+void* readStdin(void* ptr);
+void* readSignal(void* ptr);
+
+/* The program creates 3 threads:
+ * 1) Main thread - reads commands from the socket and sends them to asterisk
+ * 2) stdin_thread - reads asterisk output and sends it to the command socket
+ * 3) signal_thread - reads the sound from asterisk and sends it to the signal socket
+ */
+
+int main()
+{
+ int ret;
+
+ atexit(finalize);
+
+ setlinebuf(stdin);
+ setlinebuf(stdout);
+
+ winbuf=(char*)malloc(WINSIZE*WINBUF_NUM);
+ end=winbuf+WINSIZE*WINBUF_NUM;
+ bs=be=winbuf;
+
+ speech_desc=connect_to_host("localhost",SIGNAL_PORT);
+ if(speech_desc<0)
+ {
+ perror("signal socket");
+ return -1;
+ }
+
+
+ command_desc=connect_to_host("localhost",COMMAND_PORT);
+ if(command_desc<0)
+ {
+ perror("command socket");
+ return -1;
+ }
+
+ pthread_mutex_init(&command_mutex,NULL);
+ pthread_create(&stdin_thread,NULL,readStdin,NULL);
+ pthread_create(&signal_thread,NULL,readSignal,NULL);
+
+ while(connected)
+ {
+ pthread_mutex_lock(&command_mutex);
+ ret=read_some(command_desc,buf,BUFSIZE);
+ pthread_mutex_unlock(&command_mutex);
+ if(ret>0)
+ {
+ buf[ret]=0;
+ printf("%s",buf);
+ }
+ }
+
+ return 0;
+}
+
+void finalize()
+{
+ close(command_desc);
+ close(speech_desc);
+ free(winbuf);
+}
+
+void* readStdin(void* ptr)
+{
+ while(1)/*read enviornment*/
+ {
+ fgets(buf,BUFSIZE,stdin);
+ #ifdef SEND_ENVIORNMENT
+ pthread_mutex_lock(&command_mutex);
+ write_buf(command_desc,buf,strlen(buf));
+ pthread_mutex_unlock(&command_mutex);
+ #endif
+ if(feof(stdin) || buf[0]=='\n')
+ {
+ break;
+ }
+ }
+
+ while(connected)
+ {
+ fgets(buf,BUFSIZE,stdin);
+ pthread_mutex_lock(&command_mutex);
+ write_buf(command_desc,buf,strlen(buf));
+ pthread_mutex_unlock(&command_mutex);
+ }
+
+ pthread_exit(NULL);
+}
+
+void* readSignal(void* ptr)
+{
+ while(connected)
+ {
+ read_full(3,window,WINSIZE);
+ write_buf(speech_desc,window,WINSIZE);
+ }
+
+ pthread_exit(NULL);
+}
+
+
+void read_full(int file, char* buffer, int num)
+{
+ int count,pos=0;
+
+ while(num)
+ {
+ count=read(file,buffer+pos,num);
+ if(count==0 || (count<0 && errno!=EAGAIN))
+ {
+ connected=0;
+ return;
+ }
+ num-=count;
+ pos+=count;
+ }
+}
+
+int connect_to_host(char* name, int port)
+{
+ int address;
+ struct hostent* host_entity;
+ int res,desc;
+ int opts;
+ struct sockaddr_in host;
+
+
+ /* get adress */
+ if(!strcmp(name,"localhost"))
+ address=htonl(2130706433); /*127.0.0.1*/
+ else
+ {
+ address=inet_addr(name); /* check if it's an IP that's written in the string */
+ if(address==(in_addr_t)-1)
+ {
+ host_entity = gethostbyname(name); /* search for the host under this name */
+
+ if(!host_entity)
+ {
+ fprintf(stderr,"EAGI proxy: Wrong address!\n"); /* can't find anything*/
+ return -1;
+ }
+ address=*((int*)host_entity->h_addr);
+ }
+ }
+
+ desc=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
+ if(desc<0)
+ {
+ fprintf(stderr,"EAGI proxy: Cannot create socket!\n");
+ return -1;
+ }
+
+ memset((void*)&host,0,sizeof(struct sockaddr_in));
+
+ host.sin_family=AF_INET;
+ host.sin_port=htons(port);
+ host.sin_addr.s_addr=address;
+
+ res=connect(desc,(struct sockaddr*)&host,sizeof(host));
+ if(res<0)
+ {
+ fprintf(stderr,"EAGI proxy: Cannot connect!\n");
+ return -1;
+ }
+
+ /* set to non-blocking mode */
+ opts = fcntl(desc,F_GETFL);
+ if (opts < 0) {
+ perror("fcntl(F_GETFL)");
+ exit(EXIT_FAILURE);
+ }
+ opts = (opts | O_NONBLOCK);
+ if (fcntl(desc,F_SETFL,opts) < 0) {
+ perror("fcntl(F_SETFL)");
+ exit(EXIT_FAILURE);
+ }
+
+
+ return desc;
+}
+
+int read_some(int desc, char* buffer, int size)
+{
+ unsigned char c;
+ int res,i=0;
+
+ for(;;)
+ {
+ res=read(desc,&c,1);
+ if(res<1)
+ {
+ if(errno!=EAGAIN)
+ {
+ perror("Error reading");
+ connected=0;
+ }
+ break;
+ }
+ if(res==0)
+ {
+ connected=0;
+ break;
+ }
+
+ buffer[i]=c;
+ i++;
+ }
+
+ return i;
+}
+
+/* This is a tricky function! */
+void write_buf(int desc, char* buf, int size)
+{
+ int ret;
+
+ /*NOTE: AMAP -> as much as possible */
+
+ if(be!=bs)/* if data left in buffer */
+ {
+ if(be>bs)/* if buffer not split */
+ {
+ ret=write_amap(desc,bs,be-bs);/* write AMAP */
+ bs+=ret;/* shift the start of the buffer */
+ }
+ else/* if buffer is split */
+ {
+ ret=write_amap(desc,bs,end-bs);/* write higher part first */
+ if(ret==end-bs)/* if wrote whole of the higher part */
+ {
+ ret=write_amap(desc,winbuf,be-winbuf);/* write lower part */
+ bs=winbuf+ret;/* shift start to new position */
+ }
+ else bs+=ret;/* if not wrote whole of higher part, only shift start */
+ }
+ }
+
+ if(be==bs)/* if buffer is empty now */
+ {
+ ret=write_amap(desc,buf,size);/* write AMAP of the new data */
+ buf+=ret;/* shift start of new data */
+ size-=ret;/* lower size of new data */
+ }
+
+ if(size)/* if new data still remains unsent */
+ {
+ if(be>=bs)/* if data not split */
+ {
+ if(size>end-be)/* if new data size doesn't fit higher end */
+ {
+ size-=end-be;/* reduce new data size by the higher end size */
+ memcpy(be,buf,end-be);/* copy to higher end */
+ be=winbuf;/* shift end to begining of buffer */
+ buf+=end-be;/* shift start of new data */
+ }
+ else/* if new data fits the higher end */
+ {
+ memcpy(be,buf,size);/* copy to higher end */
+ be+=size;/* shift end by size */
+ if(be>=end)/* if end goes beyond the buffer */
+ be=winbuf;/* restart */
+ size=0;/* everything copied */
+ }
+ }
+
+ if(size)/* if new data still remains */
+ {
+ if(size>=bs-be)/* if new data doesn't fit between end and start */
+ {
+ fprintf(stderr,"Buffer overflow!\n");
+ size=bs-be-1;/* reduce the size that we can copy */
+ }
+
+ if(size)/* if we can copy anything */
+ {
+ memcpy(be,buf,size);/* copy the new data between end and start */
+ be+=size;/* shift end by size */
+ }
+ }
+ }
+}
+
+int write_amap(int desc, char* buf, int size)
+{
+ int ret;
+ ret=write(desc,buf,size);
+ if(ret<0)
+ {
+ if(errno!=EAGAIN)
+ {
+ perror("Error writing");
+ connected=0;
+ }
+ return 0;
+ }
+ if(ret==0)
+ connected=0;
+
+ return ret;
+}
+
+
+void setnonblocking(int desc)
+{
+ int opts;
+
+ opts = fcntl(desc,F_GETFL);
+ if(opts < 0)
+ {
+ perror("fcntl(F_GETFL)");
+ exit(-1);
+ }
+
+ opts = (opts | O_NONBLOCK );
+ if(fcntl(desc,F_SETFL,opts) < 0)
+ {
+ perror("fcntl(F_SETFL)");
+ exit(-1);
+ }
+}
diff --git a/trunk/contrib/utils/rawplayer.c b/trunk/contrib/utils/rawplayer.c
new file mode 100644
index 000000000..2733264a0
--- /dev/null
+++ b/trunk/contrib/utils/rawplayer.c
@@ -0,0 +1,46 @@
+/*
+ Rawplayer.c simple raw file stdout player
+ (c) Anthony C Minessale II <anthmct@yahoo.com>
+
+ 2006-03-10: Bruno Rocha <bruno@3gnt.net>
+ - include <stdlib.h> to remove compiler warning on some platforms
+ - check for read/write errors (avoid 100% CPU usage in some asterisk failures)
+*/
+
+#define BUFLEN 320
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+
+static int deliver_file(char *path, int fdout) {
+ int fd = 0, bytes = 0, error = 0;
+ short buf[BUFLEN];
+
+ if ((fd = open(path,O_RDONLY))) {
+ while ((bytes=read(fd, buf, BUFLEN)) > 0) {
+ if(write(fdout, buf, bytes) < 0){
+ error = -2;
+ break;
+ }
+ }
+ if(fd)
+ close(fd);
+ } else
+ return -1;
+
+ return error;
+}
+
+
+int main(int argc, char *argv[]) {
+ int x = 0, fdout = 0;
+ fdout = fileno(stdout);
+ for (;;)
+ for (x = 1; x < argc ; x++) {
+ if(deliver_file(argv[x], fdout))
+ exit(1);
+ }
+}
+
diff --git a/trunk/contrib/utils/zones2indications.c b/trunk/contrib/utils/zones2indications.c
new file mode 100644
index 000000000..645cd0ed5
--- /dev/null
+++ b/trunk/contrib/utils/zones2indications.c
@@ -0,0 +1,153 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 1999 - 2006, Digium, Inc.
+ *
+ * Tzafrir Cohen <tzafrir.cohen@xorcom.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 print libtonozone data as Asterisk indications.conf
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <zaptel/tonezone.h>
+#include <unistd.h>
+
+#define PROGRAM "zones2indication"
+
+void print_tone_zone_sound(struct ind_tone_zone *zone_data, const char* name,
+ int toneid) {
+ int i;
+ for (i=0; i<ZT_TONE_MAX; i++) {
+ if (zone_data->tones[i].toneid == toneid){
+ printf("%s = %s\n", name, zone_data->tones[i].data);
+ break;
+ }
+ }
+}
+
+void print_indications(struct ind_tone_zone *zone_data) {
+ int i;
+
+ printf (
+ "[%s]\n"
+ "; Source: libtonezone.\n"
+ "description = %s\n"
+ "\n",
+ zone_data->country, zone_data->description
+ );
+
+ printf(
+ "ringcadence = "
+ );
+ for(i=0; ; i++) {
+ if (zone_data->ringcadence[i] == 0)
+ break;
+ if (i != 0)
+ putchar(',');
+ printf("%d",zone_data->ringcadence[i]);
+ }
+ putchar('\n');
+
+ print_tone_zone_sound(zone_data, "dial", ZT_TONE_DIALTONE);
+ print_tone_zone_sound(zone_data, "busy", ZT_TONE_BUSY);
+ print_tone_zone_sound(zone_data, "ring", ZT_TONE_RINGTONE);
+ print_tone_zone_sound(zone_data, "congestion", ZT_TONE_CONGESTION);
+ print_tone_zone_sound(zone_data, "callwaiting", ZT_TONE_CALLWAIT);
+ print_tone_zone_sound(zone_data, "dialrecall", ZT_TONE_DIALRECALL);
+ print_tone_zone_sound(zone_data, "record", ZT_TONE_RECORDTONE);
+ print_tone_zone_sound(zone_data, "info", ZT_TONE_INFO);
+ print_tone_zone_sound(zone_data, "stutter", ZT_TONE_STUTTER);
+ printf("\n\n");
+}
+
+int print_zone_by_id(int zone_num) {
+ struct tone_zone *zone_data = tone_zone_find_by_num(zone_num);
+
+ if (zone_data == NULL)
+ return 1;
+
+ print_indications(zone_data);
+
+ return 0;
+}
+
+int print_zone_by_country(char* country) {
+ struct tone_zone *zone_data = tone_zone_find(country);
+
+ if (zone_data == NULL)
+ return 1;
+
+ print_indications(zone_data);
+
+ return 0;
+}
+
+int print_all() {
+ int i;
+ /* loop over all possible zones */
+ for (i=0; ; i++) {
+ if (print_zone_by_id(i))
+ break;
+ }
+ return 0;
+}
+
+void usage() {
+ fprintf(stderr,
+ PROGRAM ": print libtonozone data as Asterisk indications.conf\n"
+ "\n"
+ "Usage:\n"
+ " " PROGRAM " -a Print all countries\n"
+ " " PROGRAM " -c <code> Select country by two-letter country code\n"
+ " " PROGRAM " -n <num> Select country by its internal libtonezone number\n"
+ " " PROGRAM " -h Print this text.\n"
+ );
+}
+
+int main(int argc, char* argv[]){
+ int country_code = -1;
+ int opt_print_all = 0;
+ int opt;
+ char* endptr = NULL;
+
+ while((opt = getopt(argc, argv, "ac:hn:")) != -1) {
+ switch(opt) {
+ case 'a':
+ return print_all();
+ case 'c':
+ return print_zone_by_country(optarg);
+ case 'h':
+ usage();
+ return 0;
+ case 'n':
+ printf("number is %s.\n", optarg);
+ country_code = strtol(optarg, &endptr, 10);
+ return print_zone_by_id(country_code);
+ /* FIXME: what if this is not a number?
+ if (endptr != NULL) {
+ fprintf(stderr, "Error: Invalid country code %s, %d.\n",optarg, country_code);
+ usage();
+ exit(1);
+ }
+ */
+ break;
+ }
+ }
+
+ /* If we got here, the user selected no option */
+ usage();
+ return 2;
+}
diff --git a/trunk/contrib/valgrind-RedHat-8.0.supp b/trunk/contrib/valgrind-RedHat-8.0.supp
new file mode 100644
index 000000000..a404d43fa
--- /dev/null
+++ b/trunk/contrib/valgrind-RedHat-8.0.supp
@@ -0,0 +1,41 @@
+#This valgrind suppresion file is supposed to be working with
+#Red Hat Linux release 8.0 (Psyche)
+#You can use it by calling valgrind this way:
+#cd /usr/src/asterisk
+#valgrind --gdb-attach=yes --suppressions=valgrind-RedHat-8.0.supp asterisk -vvv
+
+{
+ library_1
+ PThread
+ fun:pthread_error
+ fun:__pthread_mutex_destroy
+ obj:/lib/i686/libc-2.2.93.so
+}
+
+{
+ library 2
+ Cond
+ fun:elf_dynamic_do_rel.7
+ fun:_dl_relocate_object_internal
+ obj:/lib/i686/libc-2.2.93.so
+ fun:_dl_catch_error_internal
+}
+
+#==21922== Thread 16:
+#==21922== Syscall param ioctl(generic) contains uninitialised or
+#unaddressable byte(s)
+#==21922== at 0x420D3454: (within /lib/i686/libc-2.2.93.so)
+#==21922== by 0x8058D45: ast_call (channel.c:1356)
+#==21922== by 0x463027A7: ??? (app_dial.c:472)
+#==21922== by 0x805E2AE: pbx_exec (pbx.c:318)
+#==21922== Address 0x0 is not stack'd, malloc'd or free'd
+
+{
+ ioctl(........,NULL);
+ Param
+ ioctl(generic)
+ obj:/lib/i686/libc-2.2.93.so
+ fun:ast_call
+ fun:
+ fun:pbx_exec
+}