diff options
Diffstat (limited to 'trunk/contrib')
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 Binary files differnew file mode 100644 index 000000000..6f06c4cdb --- /dev/null +++ b/trunk/contrib/firmware/iax/iaxy.bin 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> $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 Audio 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%> $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"> + <input name="action" type=submit value="delete "> + <input name="action" type=submit value="forward to -> "> + $mailboxes + <input name="action" type=submit value="save to ->"> + $folders + <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 = " 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> Msg</td><td> From</td><td> Duration</td><td> Date</td><td> </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\"> <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"> +_EOH + +if ($hasmsg) { +print <<_EOH; + <input type="submit" name="action" value="delete"> + <input type="submit" name="action" value="save to ->"> + $folders + <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("\ "); +} 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 Binary files differnew file mode 100644 index 000000000..821fd5e2b --- /dev/null +++ b/trunk/contrib/thirdparty/spexxilbcfix_xlite.reg diff --git a/trunk/contrib/thirdparty/spexxilbcfix_xpro.reg b/trunk/contrib/thirdparty/spexxilbcfix_xpro.reg Binary files differnew file mode 100644 index 000000000..472dcb44f --- /dev/null +++ b/trunk/contrib/thirdparty/spexxilbcfix_xpro.reg 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 +} |